From 7625438adeb2211ee9c3f6532819eea2a0673c5d Mon Sep 17 00:00:00 2001 From: Sean Dague Date: Wed, 12 Dec 2007 22:14:43 +0000 Subject: From Michael Osias (IBM) This patch implements the llHttpRequest function via a region module, HttpScriptsRequest. There were bits and peices in LSLLong_cmd_handler, which I moved into the region module, and just check for completed requests and dispatch the http_response callback event instead. works for me as of r2674 --- .../Environment/Modules/ScriptsHttpRequests.cs | 319 ++++++++++++++++++++- OpenSim/Region/Environment/Modules/XMLRPCModule.cs | 2 +- 2 files changed, 318 insertions(+), 3 deletions(-) (limited to 'OpenSim/Region/Environment/Modules') diff --git a/OpenSim/Region/Environment/Modules/ScriptsHttpRequests.cs b/OpenSim/Region/Environment/Modules/ScriptsHttpRequests.cs index 5ac0b39..dc4ef35 100644 --- a/OpenSim/Region/Environment/Modules/ScriptsHttpRequests.cs +++ b/OpenSim/Region/Environment/Modules/ScriptsHttpRequests.cs @@ -26,9 +26,324 @@ * */ +using System; +using System.IO; +using System.Net; +using System.Text; +using OpenSim.Region.Environment.Interfaces; +using OpenSim.Region.Environment.Scenes; +using System.Collections; +using System.Collections.Generic; +using System.Threading; +using libsecondlife; +using Nini.Config; +using Nwc.XmlRpc; +using OpenSim.Framework.Servers; + +/***************************************************** + * + * ScriptsHttpRequests + * + * Implements the llHttpRequest and http_response + * callback. + * + * Some stuff was already in LSLLongCmdHandler, and then + * there was this file with a stub class in it. So, + * I am moving some of the objects and functions out of + * LSLLongCmdHandler, such as the HttpRequestClass, the + * start and stop methods, and setting up pending and + * completed queues. These are processed in the + * LSLLongCmdHandler polling loop. Similiar to the + * XMLRPCModule, since that seems to work. + * + * //TODO + * + * This probably needs some throttling mechanism but + * its wide open right now. This applies to both + * number of requests and data volume. + * + * Linden puts all kinds of header fields in the requests. + * Not doing any of that: + * User-Agent + * X-SecondLife-Shard + * X-SecondLife-Object-Name + * X-SecondLife-Object-Key + * X-SecondLife-Region + * X-SecondLife-Local-Position + * X-SecondLife-Local-Velocity + * X-SecondLife-Local-Rotation + * X-SecondLife-Owner-Name + * X-SecondLife-Owner-Key + * + * HTTPS support + * + * Configurable timeout? + * Configurable max repsonse size? + * Configurable + * + * **************************************************/ + namespace OpenSim.Region.Environment.Modules { - internal class ScriptsHttpRequests + public class ScriptHTTPRequests : IRegionModule, IHttpRequests + { + private Scene m_scene; + private Queue rpcQueue = new Queue(); + private object HttpListLock = new object(); + private string m_name = "HttpScriptRequests"; + private int httpTimeout = 300; + + // + private Dictionary m_pendingRequests; + + public ScriptHTTPRequests() + { + } + + public void Initialise(Scene scene, IConfigSource config) + { + m_scene = scene; + + m_scene.RegisterModuleInterface(this); + + m_pendingRequests = new Dictionary(); + } + + public void PostInitialise() + { + } + + public void Close() + { + } + + public string Name + { + get { return m_name; } + } + + public bool IsSharedModule + { + get { return true; } + } + + public LLUUID MakeHttpRequest(string url, string parameters, string body) { + return LLUUID.Zero; + } + + public LLUUID StartHttpRequest(uint localID, LLUUID itemID, string url, List parameters, string body) + { + LLUUID reqID = LLUUID.Random(); + HttpRequestClass htc = new HttpRequestClass(); + + // Parameters are expected in {key, value, ... , key, value} + if( parameters != null ) + { + string[] parms = parameters.ToArray(); + for (int i = 0; i < parms.Length / 2; i += 2) + { + switch( Int32.Parse(parms[i]) ) + { + case HttpRequestClass.HTTP_METHOD: + + htc.httpMethod = parms[i + 1]; + break; + + case HttpRequestClass.HTTP_MIMETYPE: + + htc.httpMIMEType = parms[i + 1]; + break; + + case HttpRequestClass.HTTP_BODY_MAXLENGTH: + + // TODO implement me + break; + + case HttpRequestClass.HTTP_VERIFY_CERT: + + // TODO implement me + break; + } + } + } + + htc.localID = localID; + htc.itemID = itemID; + htc.url = url; + htc.reqID = reqID; + htc.httpTimeout = httpTimeout; + htc.outbound_body = body; + + lock (HttpListLock) + { + m_pendingRequests.Add(reqID, htc); + } + + htc.process(); + + return reqID; + } + + public void StopHttpRequest(uint m_localID, LLUUID m_itemID) + { + lock (HttpListLock) + { + + HttpRequestClass tmpReq; + if (m_pendingRequests.TryGetValue(m_itemID, out tmpReq)) + { + tmpReq.Stop(); + m_pendingRequests.Remove(m_itemID); + } + } + } + + /* + * TODO + * Not sure how important ordering is is here - the next first + * one completed in the list is returned, based soley on its list + * position, not the order in which the request was started or + * finsihed. I thought about setting up a queue for this, but + * it will need some refactoring and this works 'enough' right now + */ + public HttpRequestClass GetNextCompletedRequest() + { + lock (HttpListLock) + { + foreach (LLUUID luid in m_pendingRequests.Keys) + { + HttpRequestClass tmpReq; + + if (m_pendingRequests.TryGetValue(luid, out tmpReq)) + { + if (tmpReq.finished) + { + m_pendingRequests.Remove(luid); + return tmpReq; + } + } + } + } + return null; + } + + + } + + // + // HTTP REAQUEST + // This class was originally in LSLLongCmdHandler + // + // TODO: setter/getter methods, maybe pass some in + // constructor + // + + public class HttpRequestClass { + // Constants for parameters + public const int HTTP_METHOD = 0; + public const int HTTP_MIMETYPE = 1; + public const int HTTP_BODY_MAXLENGTH = 2; + public const int HTTP_VERIFY_CERT = 3; + + // Parameter members and default values + public string httpMethod = "GET"; + public string httpMIMEType = "text/plain;charset=utf-8"; + public int httpBodyMaxLen = 2048; // not implemented + public bool httpVerifyCert = true; // not implemented + + // Request info + public uint localID; + public LLUUID itemID; + public LLUUID reqID; + public int httpTimeout; + public string url; + public string outbound_body; + public DateTime next; + public int status; + public bool finished; + public List response_metadata; + public string response_body; + public HttpWebRequest request; + private Thread httpThread; + + public void process() + { + httpThread = new Thread(SendRequest); + httpThread.Name = "HttpRequestThread"; + httpThread.Priority = ThreadPriority.BelowNormal; + httpThread.IsBackground = true; + httpThread.Start(); + } + + /* + * TODO: More work on the response codes. Right now + * returning 200 for success or 499 for exception + */ + public void SendRequest() + { + + HttpWebResponse response = null; + StringBuilder sb = new StringBuilder(); + byte[] buf = new byte[8192]; + string tempString = null; + int count = 0; + + try + { + request = (HttpWebRequest) + WebRequest.Create(url); + request.Method = httpMethod; + request.ContentType = httpMIMEType; + + request.Timeout = httpTimeout; + // execute the request + response = (HttpWebResponse) + request.GetResponse(); + + Stream resStream = response.GetResponseStream(); + + do + { + // fill the buffer with data + count = resStream.Read(buf, 0, buf.Length); + + // make sure we read some data + if (count != 0) + { + // translate from bytes to ASCII text + tempString = Encoding.ASCII.GetString(buf, 0, count); + + // continue building the string + sb.Append(tempString); + } + } + while (count > 0); // any more data to read? + + response_body = sb.ToString(); + + } + catch (Exception e) + { + status = 499; + response_body = e.Message; + finished = true; + return; + } + + status = 200; + finished = true; + + } + + public void Stop() + { + try + { + httpThread.Abort(); + } + catch (Exception e) { } + } } -} \ No newline at end of file + + } \ No newline at end of file diff --git a/OpenSim/Region/Environment/Modules/XMLRPCModule.cs b/OpenSim/Region/Environment/Modules/XMLRPCModule.cs index 1223f5c..2618b17 100644 --- a/OpenSim/Region/Environment/Modules/XMLRPCModule.cs +++ b/OpenSim/Region/Environment/Modules/XMLRPCModule.cs @@ -121,7 +121,7 @@ namespace OpenSim.Region.Environment.Modules public bool IsSharedModule { - get { return false; } + get { return true; } } /********************************************** -- cgit v1.1