diff --git a/OpenSim/Framework/Servers/HttpServer/PollServiceEventArgs.cs b/OpenSim/Framework/Servers/HttpServer/PollServiceEventArgs.cs index 9d512c6249..3089351a69 100644 --- a/OpenSim/Framework/Servers/HttpServer/PollServiceEventArgs.cs +++ b/OpenSim/Framework/Servers/HttpServer/PollServiceEventArgs.cs @@ -28,6 +28,7 @@ using System; using System.Collections; using OpenMetaverse; + namespace OpenSim.Framework.Servers.HttpServer { public delegate void RequestMethod(UUID requestID, Hashtable request); @@ -44,7 +45,11 @@ namespace OpenSim.Framework.Servers.HttpServer public NoEventsMethod NoEvents; public RequestMethod Request; public UUID Id; - public PollServiceEventArgs(RequestMethod pRequest, HasEventsMethod pHasEvents, GetEventsMethod pGetEvents, NoEventsMethod pNoEvents,UUID pId) + + public PollServiceEventArgs( + RequestMethod pRequest, + HasEventsMethod pHasEvents, GetEventsMethod pGetEvents, NoEventsMethod pNoEvents, + UUID pId) { Request = pRequest; HasEvents = pHasEvents; @@ -53,4 +58,4 @@ namespace OpenSim.Framework.Servers.HttpServer Id = pId; } } -} +} \ No newline at end of file diff --git a/OpenSim/Framework/Servers/HttpServer/PollServiceHttpRequest.cs b/OpenSim/Framework/Servers/HttpServer/PollServiceHttpRequest.cs index 553a7eb123..723530ae15 100644 --- a/OpenSim/Framework/Servers/HttpServer/PollServiceHttpRequest.cs +++ b/OpenSim/Framework/Servers/HttpServer/PollServiceHttpRequest.cs @@ -31,7 +31,6 @@ using OpenMetaverse; namespace OpenSim.Framework.Servers.HttpServer { - public class PollServiceHttpRequest { public readonly PollServiceEventArgs PollServiceArgs; @@ -39,7 +38,9 @@ namespace OpenSim.Framework.Servers.HttpServer public readonly IHttpRequest Request; public readonly int RequestTime; public readonly UUID RequestID; - public PollServiceHttpRequest(PollServiceEventArgs pPollServiceArgs, IHttpClientContext pHttpContext, IHttpRequest pRequest) + + public PollServiceHttpRequest( + PollServiceEventArgs pPollServiceArgs, IHttpClientContext pHttpContext, IHttpRequest pRequest) { PollServiceArgs = pPollServiceArgs; HttpContext = pHttpContext; @@ -48,4 +49,4 @@ namespace OpenSim.Framework.Servers.HttpServer RequestID = UUID.Random(); } } -} +} \ No newline at end of file diff --git a/OpenSim/Region/CoreModules/Scripting/LSLHttp/UrlModule.cs b/OpenSim/Region/CoreModules/Scripting/LSLHttp/UrlModule.cs index ff5548b43a..f9069977e4 100644 --- a/OpenSim/Region/CoreModules/Scripting/LSLHttp/UrlModule.cs +++ b/OpenSim/Region/CoreModules/Scripting/LSLHttp/UrlModule.cs @@ -64,17 +64,25 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp public string uri; } + /// + /// This module provides external URLs for in-world scripts. + /// public class UrlModule : ISharedRegionModule, IUrlModule { private static readonly ILog m_log = LogManager.GetLogger( MethodBase.GetCurrentMethod().DeclaringType); - private Dictionary m_RequestMap = - new Dictionary(); + /// + /// Indexs the URL request metadata (which script requested it, outstanding requests, etc.) by the request ID + /// randomly generated when a request is received for this URL. + /// + private Dictionary m_RequestMap = new Dictionary(); - private Dictionary m_UrlMap = - new Dictionary(); + /// + /// Indexs the URL request metadata (which script requested it, outstanding requests, etc.) by the full URL + /// + private Dictionary m_UrlMap = new Dictionary(); /// /// Maximum number of external urls that can be set up by this module. @@ -215,7 +223,6 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp urlData.urlcode = urlcode; urlData.requests = new Dictionary(); - m_UrlMap[url] = urlData; string uri = "/lslhttps/" + urlcode.ToString() + "/"; @@ -269,7 +276,7 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp { if (m_RequestMap.ContainsKey(requestId)) { - UrlData urlData=m_RequestMap[requestId]; + UrlData urlData = m_RequestMap[requestId]; string value; if (urlData.requests[requestId].headers.TryGetValue(header,out value)) return value; @@ -278,6 +285,7 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp { m_log.Warn("[HttpRequestHandler] There was no http-in request with id " + requestId); } + return String.Empty; } @@ -322,6 +330,7 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp { RemoveUrl(url.Value); removeURLs.Add(url.Key); + foreach (UUID req in url.Value.requests.Keys) m_RequestMap.Remove(req); } @@ -332,20 +341,31 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp } } - private void RemoveUrl(UrlData data) { - m_HttpServer.RemoveHTTPHandler("", "/lslhttp/"+data.urlcode.ToString()+"/"); + m_HttpServer.RemoveHTTPHandler("", "/lslhttp/" + data.urlcode.ToString() + "/"); } private Hashtable NoEvents(UUID requestID, UUID sessionID) { Hashtable response = new Hashtable(); UrlData url; + lock (m_RequestMap) { + // We need to return a 404 here in case the request URL was removed at exactly the same time that a + // request was made. In this case, the request thread can outrace llRemoveURL() and still be polling + // for the request ID. if (!m_RequestMap.ContainsKey(requestID)) + { + response["int_response_code"] = 404; + response["str_response_string"] = ""; + response["keepalive"] = false; + response["reusecontext"] = false; + return response; + } + url = m_RequestMap[requestID]; } @@ -367,53 +387,57 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp return response; } - return response; } private bool HasEvents(UUID requestID, UUID sessionID) { - UrlData url=null; + UrlData url = null; lock (m_RequestMap) { + // We return true here because an external URL request that happened at the same time as an llRemoveURL() + // can still make it through to HttpRequestHandler(). That will return without setting up a request + // when it detects that the URL has been removed. The poller, however, will continue to ask for + // events for that request, so here we will signal that there are events and in GetEvents we will + // return a 404. if (!m_RequestMap.ContainsKey(requestID)) { - return false; + return true; } + url = m_RequestMap[requestID]; if (!url.requests.ContainsKey(requestID)) { - return false; + return true; } } - if (System.Environment.TickCount-url.requests[requestID].startTime>25000) + // Trigger return of timeout response. + if (System.Environment.TickCount - url.requests[requestID].startTime > 25000) { return true; } - if (url.requests[requestID].requestDone) - return true; - else - return false; - + return url.requests[requestID].requestDone; } + private Hashtable GetEvents(UUID requestID, UUID sessionID, string request) { - UrlData url = null; + UrlData url = null; RequestData requestData = null; lock (m_RequestMap) { if (!m_RequestMap.ContainsKey(requestID)) - return NoEvents(requestID,sessionID); + return NoEvents(requestID, sessionID); + url = m_RequestMap[requestID]; requestData = url.requests[requestID]; } if (!requestData.requestDone) - return NoEvents(requestID,sessionID); + return NoEvents(requestID, sessionID); Hashtable response = new Hashtable(); @@ -426,6 +450,7 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp response["reusecontext"] = false; return response; } + //put response response["int_response_code"] = requestData.responseCode; response["str_response_string"] = requestData.responseBody; @@ -442,6 +467,7 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp return response; } + public void HttpRequestHandler(UUID requestID, Hashtable request) { lock (request) @@ -466,11 +492,22 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp pathInfo = uri.Substring(pos3); - UrlData url = null; - if (!is_ssl) - url = m_UrlMap["http://" + m_ExternalHostNameForLSL + ":" + m_HttpServer.Port.ToString() + uri_tmp]; - else - url = m_UrlMap["https://" + m_ExternalHostNameForLSL + ":" + m_HttpsServer.Port.ToString() + uri_tmp]; + UrlData urlData = null; + + lock (m_UrlMap) + { + string url; + + if (is_ssl) + url = "https://" + m_ExternalHostNameForLSL + ":" + m_HttpsServer.Port.ToString() + uri_tmp; + else + url = "http://" + m_ExternalHostNameForLSL + ":" + m_HttpServer.Port.ToString() + uri_tmp; + + // Avoid a race - the request URL may have been released via llRequestUrl() whilst this + // request was being processed. + if (!m_UrlMap.TryGetValue(url, out urlData)) + return; + } //for llGetHttpHeader support we need to store original URI here //to make x-path-info / x-query-string / x-script-url / x-remote-ip headers @@ -503,11 +540,10 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp queryString = queryString + key + "=" + val + "&"; } } + if (queryString.Length > 1) queryString = queryString.Substring(0, queryString.Length - 1); - } - } //if this machine is behind DNAT/port forwarding, currently this is being @@ -515,26 +551,28 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp requestData.headers["x-remote-ip"] = requestData.headers["remote_addr"]; requestData.headers["x-path-info"] = pathInfo; requestData.headers["x-query-string"] = queryString; - requestData.headers["x-script-url"] = url.url; + requestData.headers["x-script-url"] = urlData.url; //requestData.ev = new ManualResetEvent(false); - lock (url.requests) + lock (urlData.requests) { - url.requests.Add(requestID, requestData); - } - lock (m_RequestMap) - { - //add to request map - m_RequestMap.Add(requestID, url); + urlData.requests.Add(requestID, requestData); } - url.engine.PostScriptEvent(url.itemID, "http_request", new Object[] { requestID.ToString(), request["http-method"].ToString(), request["body"].ToString() }); + lock (m_RequestMap) + { + m_RequestMap.Add(requestID, urlData); + } + + urlData.engine.PostScriptEvent( + urlData.itemID, + "http_request", + new Object[] { requestID.ToString(), request["http-method"].ToString(), request["body"].ToString() }); //send initial response? // Hashtable response = new Hashtable(); return; - } catch (Exception we) {