29 using System.Threading;
30 using System.Collections.Generic;
31 using System.Collections;
32 using System.Reflection;
37 using OpenSim.Framework;
38 using OpenSim.Framework.Servers;
39 using OpenSim.Framework.Servers.HttpServer;
40 using OpenSim.Region.Framework.Interfaces;
41 using OpenSim.Region.Framework.Scenes;
61 public Dictionary<string, string>
headers;
65 public string responseType =
"text/plain";
71 public bool allowResponseType =
false;
79 [Extension(Path =
"/OpenSim/RegionModules", NodeName =
"RegionModule", Id =
"UrlModule")]
82 private static readonly ILog m_log =
84 MethodBase.GetCurrentMethod().DeclaringType);
86 private Dictionary<UUID, UrlData> m_RequestMap =
87 new Dictionary<UUID, UrlData>();
89 private Dictionary<string, UrlData> m_UrlMap =
90 new Dictionary<string, UrlData>();
92 private uint m_HttpsPort = 0;
96 public string ExternalHostNameForLSL {
get;
private set; }
101 public const int DefaultTotalUrls = 15000;
106 public int TotalUrls {
get; set; }
108 public Type ReplaceableInterface
115 get {
return "UrlModule"; }
120 IConfig networkConfig = config.Configs[
"Network"];
122 if (networkConfig != null)
124 ExternalHostNameForLSL = config.Configs[
"Network"].GetString(
"ExternalHostNameForLSL", null);
126 bool ssl_enabled = config.Configs[
"Network"].GetBoolean(
"https_listener",
false);
129 m_HttpsPort = (uint)config.Configs[
"Network"].GetInt(
"https_port", (
int)m_HttpsPort);
132 if (ExternalHostNameForLSL == null)
133 ExternalHostNameForLSL = System.Environment.MachineName;
135 IConfig llFunctionsConfig = config.Configs[
"LL-Functions"];
137 if (llFunctionsConfig != null)
138 TotalUrls = llFunctionsConfig.GetInt(
"max_external_urls_per_simulator", DefaultTotalUrls);
140 TotalUrls = DefaultTotalUrls;
149 if (m_HttpServer == null)
153 m_HttpServer = MainServer.Instance;
158 m_HttpsServer = MainServer.GetHttpServer(m_HttpsPort);
162 scene.RegisterModuleInterface<
IUrlModule>(
this);
164 scene.EventManager.OnScriptReset += OnScriptReset;
180 foreach (KeyValuePair<string, UrlData> kvp
in m_UrlMap)
182 if (kvp.Value.scene == scene)
183 kvp.Value.scene = null;
185 foreach (KeyValuePair<UUID, UrlData> kvp
in m_RequestMap)
187 if (kvp.Value.scene == scene)
188 kvp.Value.scene = null;
198 UUID urlcode = UUID.Random();
202 if (m_UrlMap.Count >= TotalUrls)
204 engine.PostScriptEvent(itemID,
"http_request",
new Object[] { urlcode.ToString(),
"URL_REQUEST_DENIED",
"" });
207 string url =
"http://" + ExternalHostNameForLSL +
":" + m_HttpServer.Port.ToString() +
"/lslhttp/" + urlcode.ToString() +
"/";
210 urlData.hostID = host.UUID;
211 urlData.itemID = itemID;
212 urlData.engine = engine;
214 urlData.urlcode = urlcode;
215 urlData.isSsl =
false;
216 urlData.requests =
new Dictionary<UUID, RequestData>();
217 urlData.scene = host.ParentGroup.Scene;
218 urlData.allowXss =
false;
220 if (options != null && options[
"allowXss"] != null)
221 urlData.allowXss =
true;
223 m_UrlMap[url] = urlData;
225 string uri =
"/lslhttp/" + urlcode.ToString() +
"/";
228 =
new PollServiceEventArgs(HttpRequestHandler, uri, HasEvents, GetEvents, NoEvents, urlcode, 25000);
229 args.Type = PollServiceEventArgs.EventType.LslHttp;
230 m_HttpServer.AddPollServiceHTTPHandler(uri, args);
236 engine.PostScriptEvent(itemID,
"http_request",
new Object[] { urlcode.ToString(),
"URL_REQUEST_GRANTED", url });
244 UUID urlcode = UUID.Random();
246 if (m_HttpsServer == null)
248 engine.PostScriptEvent(itemID,
"http_request",
new Object[] { urlcode.ToString(),
"URL_REQUEST_DENIED",
"" });
254 if (m_UrlMap.Count >= TotalUrls)
256 engine.PostScriptEvent(itemID,
"http_request",
new Object[] { urlcode.ToString(),
"URL_REQUEST_DENIED",
"" });
259 string url =
"https://" + ExternalHostNameForLSL +
":" + m_HttpsServer.Port.ToString() +
"/lslhttps/" + urlcode.ToString() +
"/";
262 urlData.hostID = host.UUID;
263 urlData.itemID = itemID;
264 urlData.engine = engine;
266 urlData.urlcode = urlcode;
267 urlData.isSsl =
true;
268 urlData.requests =
new Dictionary<UUID, RequestData>();
269 urlData.allowXss =
false;
271 if (options != null && options[
"allowXss"] != null)
272 urlData.allowXss =
true;
274 m_UrlMap[url] = urlData;
276 string uri =
"/lslhttps/" + urlcode.ToString() +
"/";
279 =
new PollServiceEventArgs(HttpRequestHandler, uri, HasEvents, GetEvents, NoEvents, urlcode, 25000);
280 args.Type = PollServiceEventArgs.EventType.LslHttp;
281 m_HttpsServer.AddPollServiceHTTPHandler(uri, args);
287 engine.PostScriptEvent(itemID,
"http_request",
new Object[] { urlcode.ToString(),
"URL_REQUEST_GRANTED", url });
299 if (!m_UrlMap.TryGetValue(url, out data))
306 foreach (
UUID req
in data.requests.Keys)
307 m_RequestMap.Remove(req);
315 m_UrlMap.Remove(url);
323 if (m_RequestMap.ContainsKey(request))
325 UrlData urlData = m_RequestMap[request];
326 urlData.requests[request].responseType = type;
330 m_log.Info(
"[HttpRequestHandler] There is no http-in request with id " + request.ToString());
339 if (m_RequestMap.ContainsKey(request))
341 UrlData urlData = m_RequestMap[request];
342 if (!urlData.
requests[request].responseSent)
344 string responseBody = body;
347 if (!urlData.
requests[request].allowResponseType)
348 urlData.requests[request].responseType =
"text/plain";
350 if (urlData.
requests[request].responseType.Equals(
"text/plain"))
353 if (urlData.
requests[request].headers.TryGetValue(
"user-agent", out value))
355 if (value != null && value.IndexOf(
"MSIE") >= 0)
359 responseBody =
"<html>" + System.Web.HttpUtility.HtmlEncode(body) +
"</html>";
364 urlData.requests[request].responseCode = status;
365 urlData.requests[request].responseBody = responseBody;
367 urlData.requests[request].requestDone =
true;
368 urlData.requests[request].responseSent =
true;
373 m_log.Info(
"[HttpRequestHandler] There is no http-in request with id " + request.ToString());
382 if (m_RequestMap.ContainsKey(requestId))
384 UrlData urlData = m_RequestMap[requestId];
386 if (urlData.
requests[requestId].headers.TryGetValue(header, out value))
391 m_log.Warn(
"[HttpRequestHandler] There was no http-in request with id " + requestId);
400 return TotalUrls - m_UrlMap.Count;
409 List<string> removeURLs =
new List<string>();
411 foreach (KeyValuePair<string, UrlData> url
in m_UrlMap)
413 if (url.Value.itemID == itemID)
415 RemoveUrl(url.Value);
416 removeURLs.Add(url.Key);
419 foreach (
UUID req
in url.Value.requests.Keys)
420 m_RequestMap.Remove(req);
425 foreach (
string urlname
in removeURLs)
426 m_UrlMap.Remove(urlname);
434 List<string> removeURLs =
new List<string>();
436 foreach (KeyValuePair<string, UrlData> url
in m_UrlMap)
438 if (url.Value.hostID == objectID)
440 RemoveUrl(url.Value);
441 removeURLs.Add(url.Key);
444 foreach (
UUID req
in url.Value.requests.Keys)
445 m_RequestMap.Remove(req);
450 foreach (
string urlname
in removeURLs)
451 m_UrlMap.Remove(urlname);
456 private void RemoveUrl(
UrlData data)
459 m_HttpsServer.RemoveHTTPHandler(
"",
"/lslhttps/"+data.urlcode.ToString()+
"/");
461 m_HttpServer.RemoveHTTPHandler(
"",
"/lslhttp/"+data.urlcode.ToString()+
"/");
464 private Hashtable NoEvents(UUID requestID, UUID sessionID)
466 Hashtable response =
new Hashtable();
471 if (!m_RequestMap.ContainsKey(requestID))
473 url = m_RequestMap[requestID];
474 startTime = url.requests[requestID].startTime;
477 if (System.Environment.TickCount - startTime > 25000)
479 response[
"int_response_code"] = 500;
480 response[
"str_response_string"] =
"Script timeout";
481 response[
"content_type"] =
"text/plain";
482 response[
"keepalive"] =
false;
483 response[
"reusecontext"] =
false;
488 url.requests.Remove(requestID);
492 m_RequestMap.Remove(requestID);
502 private bool HasEvents(UUID requestID, UUID sessionID)
508 if (!m_RequestMap.ContainsKey(requestID))
512 url = m_RequestMap[requestID];
516 if (!url.requests.ContainsKey(requestID))
522 if (System.Environment.TickCount - url.requests[requestID].startTime > 25000)
526 if (url.requests[requestID].requestDone)
533 private Hashtable GetEvents(UUID requestID, UUID sessionID)
536 RequestData requestData = null;
540 if (!m_RequestMap.ContainsKey(requestID))
541 return NoEvents(requestID,sessionID);
542 url = m_RequestMap[requestID];
546 requestData = url.requests[requestID];
549 if (!requestData.requestDone)
550 return NoEvents(requestID,sessionID);
552 Hashtable response =
new Hashtable();
554 if (System.Environment.TickCount - requestData.startTime > 25000)
556 response[
"int_response_code"] = 500;
557 response[
"str_response_string"] =
"Script timeout";
558 response[
"content_type"] =
"text/plain";
559 response[
"keepalive"] =
false;
560 response[
"reusecontext"] =
false;
564 response[
"int_response_code"] = requestData.responseCode;
565 response[
"str_response_string"] = requestData.responseBody;
566 response[
"content_type"] = requestData.responseType;
567 response[
"keepalive"] =
false;
568 response[
"reusecontext"] =
false;
571 response[
"access_control_allow_origin"] =
"*";
576 url.requests.Remove(requestID);
580 m_RequestMap.Remove(requestID);
590 string uri = request[
"uri"].ToString();
591 bool is_ssl = uri.Contains(
"lslhttps");
595 Hashtable headers = (Hashtable)request[
"headers"];
599 int pos1 = uri.IndexOf(
"/");
600 int pos2 = uri.IndexOf(
"/", pos1 + 1);
601 int pos3 = uri.IndexOf(
"/", pos2 + 1);
603 string uri_tmp = uri.Substring(0, pos3 + 1);
609 pathInfo = uri.Substring(pos3);
614 urlkey =
"http://" + ExternalHostNameForLSL +
":" + m_HttpServer.Port.ToString() + uri_tmp;
617 urlkey =
"https://" + ExternalHostNameForLSL +
":" + m_HttpsServer.Port.ToString() + uri_tmp;
619 if (m_UrlMap.ContainsKey(urlkey))
621 url = m_UrlMap[urlkey];
634 requestData.requestID = requestID;
635 requestData.requestDone =
false;
636 requestData.startTime = System.Environment.TickCount;
637 requestData.uri = uri;
638 requestData.hostID = url.hostID;
639 requestData.scene = url.scene;
640 if (requestData.
headers == null)
641 requestData.headers =
new Dictionary<string, string>();
643 foreach (DictionaryEntry header
in headers)
645 string key = (string)header.Key;
646 string value = (
string)header.Value;
647 requestData.headers.Add(
key, value);
650 string[] parts = value.Split(
new char[] {
'='});
651 if (parts[0] ==
"agni_sl_session_id" && parts.Length > 1)
653 string cookie = Uri.UnescapeDataString(parts[1]);
654 string[] crumbs = cookie.Split(
new char[] {
':'});
656 if (crumbs.Length == 2 &&
UUID.TryParse(crumbs[0], out owner))
658 if (crumbs[1].Length == 32)
660 Scene scene = requestData.scene;
667 requestData.allowResponseType =
true;
675 foreach (DictionaryEntry de
in request)
677 if (de.Key.ToString() ==
"querystringkeys")
679 System.String[] keys = (System.String[])de.Value;
682 if (request.ContainsKey(
key))
687 queryString = queryString +
key +
"=" + val +
"&";
691 queryString = queryString + val +
"&";
695 if (queryString.Length > 1)
696 queryString = queryString.Substring(0, queryString.Length - 1);
704 requestData.headers[
"x-remote-ip"] = requestData.headers[
"remote_addr"];
705 requestData.headers[
"x-path-info"] = pathInfo;
706 requestData.headers[
"x-query-string"] = queryString;
707 requestData.headers[
"x-script-url"] = url.url;
712 url.requests.Add(requestID, requestData);
717 m_RequestMap.Add(requestID, url);
720 url.engine.PostScriptEvent(url.itemID,
"http_request",
new Object[] { requestID.ToString(), request[
"http-method"].ToString(), request[
"body"].ToString() });
731 m_log.Warn(
"[HttpRequestHandler]: http-in request failed");
732 m_log.Warn(we.Message);
733 m_log.Warn(we.StackTrace);
738 private void OnScriptReset(uint localID,
UUID itemID)
Dictionary< string, string > headers
void HttpRequestHandler(UUID requestID, Hashtable request)
void ReleaseURL(string url)
void ScriptRemoved(UUID itemID)
UUID RequestSecureURL(IScriptModule engine, SceneObjectPart host, UUID itemID, Hashtable options)
This module provides external URLs for in-world scripts.
void PostInitialise()
This is called exactly once after all the shared region-modules have been instanciated and IRegionMod...
UUID RequestURL(IScriptModule engine, SceneObjectPart host, UUID itemID, Hashtable options)
void HttpContentType(UUID request, string type)
Interface to OpenSimulator's built in HTTP server. Use this to register handlers (http, llsd, xmlrpc, etc.) for given URLs.
OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString key
delegate void ObjectRemoved(UUID prim)
void Initialise(IConfigSource config)
This is called to initialize the region module. For shared modules, this is called exactly once...
void HttpResponse(UUID request, int status, string body)
void RemoveRegion(Scene scene)
This is called whenever a Scene is removed. For shared modules, this can happen several times...
Interactive OpenSim region server
string GetHttpHeader(UUID requestId, string header)
delegate void ScriptRemoved(UUID script)
void Close()
This is the inverse to Initialise. After a Close(), this instance won't be usable anymore...
void RegionLoaded(Scene scene)
This will be called once for every scene loaded. In a shared module this will be multiple times in on...
void AddRegion(Scene scene)
This is called whenever a Scene is added. For shared modules, this can happen several times...
void ObjectRemoved(UUID objectID)
Dictionary< UUID, RequestData > requests