diff options
Diffstat (limited to 'OpenSim/Region')
-rw-r--r-- | OpenSim/Region/CoreModules/Scripting/LSLHttp/UrlModule.cs | 108 |
1 files changed, 73 insertions, 35 deletions
diff --git a/OpenSim/Region/CoreModules/Scripting/LSLHttp/UrlModule.cs b/OpenSim/Region/CoreModules/Scripting/LSLHttp/UrlModule.cs index 61afc76..5c05500 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 | |||
64 | public string uri; | 64 | public string uri; |
65 | } | 65 | } |
66 | 66 | ||
67 | /// <summary> | ||
68 | /// This module provides external URLs for in-world scripts. | ||
69 | /// </summary> | ||
67 | public class UrlModule : ISharedRegionModule, IUrlModule | 70 | public class UrlModule : ISharedRegionModule, IUrlModule |
68 | { | 71 | { |
69 | private static readonly ILog m_log = | 72 | private static readonly ILog m_log = |
70 | LogManager.GetLogger( | 73 | LogManager.GetLogger( |
71 | MethodBase.GetCurrentMethod().DeclaringType); | 74 | MethodBase.GetCurrentMethod().DeclaringType); |
72 | 75 | ||
73 | private Dictionary<UUID, UrlData> m_RequestMap = | 76 | /// <summary> |
74 | new Dictionary<UUID, UrlData>(); | 77 | /// Indexs the URL request metadata (which script requested it, outstanding requests, etc.) by the request ID |
78 | /// randomly generated when a request is received for this URL. | ||
79 | /// </summary> | ||
80 | private Dictionary<UUID, UrlData> m_RequestMap = new Dictionary<UUID, UrlData>(); | ||
75 | 81 | ||
76 | private Dictionary<string, UrlData> m_UrlMap = | 82 | /// <summary> |
77 | new Dictionary<string, UrlData>(); | 83 | /// Indexs the URL request metadata (which script requested it, outstanding requests, etc.) by the full URL |
84 | /// </summary> | ||
85 | private Dictionary<string, UrlData> m_UrlMap = new Dictionary<string, UrlData>(); | ||
78 | 86 | ||
79 | /// <summary> | 87 | /// <summary> |
80 | /// Maximum number of external urls that can be set up by this module. | 88 | /// Maximum number of external urls that can be set up by this module. |
@@ -224,7 +232,6 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp | |||
224 | urlData.urlcode = urlcode; | 232 | urlData.urlcode = urlcode; |
225 | urlData.requests = new Dictionary<UUID, RequestData>(); | 233 | urlData.requests = new Dictionary<UUID, RequestData>(); |
226 | 234 | ||
227 | |||
228 | m_UrlMap[url] = urlData; | 235 | m_UrlMap[url] = urlData; |
229 | 236 | ||
230 | string uri = "/lslhttps/" + urlcode.ToString() + "/"; | 237 | string uri = "/lslhttps/" + urlcode.ToString() + "/"; |
@@ -286,7 +293,7 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp | |||
286 | { | 293 | { |
287 | if (m_RequestMap.ContainsKey(requestId)) | 294 | if (m_RequestMap.ContainsKey(requestId)) |
288 | { | 295 | { |
289 | UrlData urlData=m_RequestMap[requestId]; | 296 | UrlData urlData = m_RequestMap[requestId]; |
290 | string value; | 297 | string value; |
291 | if (urlData.requests[requestId].headers.TryGetValue(header,out value)) | 298 | if (urlData.requests[requestId].headers.TryGetValue(header,out value)) |
292 | return value; | 299 | return value; |
@@ -295,6 +302,7 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp | |||
295 | { | 302 | { |
296 | m_log.Warn("[HttpRequestHandler] There was no http-in request with id " + requestId); | 303 | m_log.Warn("[HttpRequestHandler] There was no http-in request with id " + requestId); |
297 | } | 304 | } |
305 | |||
298 | return String.Empty; | 306 | return String.Empty; |
299 | } | 307 | } |
300 | 308 | ||
@@ -339,6 +347,7 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp | |||
339 | { | 347 | { |
340 | RemoveUrl(url.Value); | 348 | RemoveUrl(url.Value); |
341 | removeURLs.Add(url.Key); | 349 | removeURLs.Add(url.Key); |
350 | |||
342 | foreach (UUID req in url.Value.requests.Keys) | 351 | foreach (UUID req in url.Value.requests.Keys) |
343 | m_RequestMap.Remove(req); | 352 | m_RequestMap.Remove(req); |
344 | } | 353 | } |
@@ -349,20 +358,31 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp | |||
349 | } | 358 | } |
350 | } | 359 | } |
351 | 360 | ||
352 | |||
353 | private void RemoveUrl(UrlData data) | 361 | private void RemoveUrl(UrlData data) |
354 | { | 362 | { |
355 | m_HttpServer.RemoveHTTPHandler("", "/lslhttp/"+data.urlcode.ToString()+"/"); | 363 | m_HttpServer.RemoveHTTPHandler("", "/lslhttp/" + data.urlcode.ToString() + "/"); |
356 | } | 364 | } |
357 | 365 | ||
358 | private Hashtable NoEvents(UUID requestID, UUID sessionID) | 366 | private Hashtable NoEvents(UUID requestID, UUID sessionID) |
359 | { | 367 | { |
360 | Hashtable response = new Hashtable(); | 368 | Hashtable response = new Hashtable(); |
361 | UrlData url; | 369 | UrlData url; |
370 | |||
362 | lock (m_RequestMap) | 371 | lock (m_RequestMap) |
363 | { | 372 | { |
373 | // We need to return a 404 here in case the request URL was removed at exactly the same time that a | ||
374 | // request was made. In this case, the request thread can outrace llRemoveURL() and still be polling | ||
375 | // for the request ID. | ||
364 | if (!m_RequestMap.ContainsKey(requestID)) | 376 | if (!m_RequestMap.ContainsKey(requestID)) |
377 | { | ||
378 | response["int_response_code"] = 404; | ||
379 | response["str_response_string"] = ""; | ||
380 | response["keepalive"] = false; | ||
381 | response["reusecontext"] = false; | ||
382 | |||
365 | return response; | 383 | return response; |
384 | } | ||
385 | |||
366 | url = m_RequestMap[requestID]; | 386 | url = m_RequestMap[requestID]; |
367 | } | 387 | } |
368 | 388 | ||
@@ -384,53 +404,57 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp | |||
384 | return response; | 404 | return response; |
385 | } | 405 | } |
386 | 406 | ||
387 | |||
388 | return response; | 407 | return response; |
389 | } | 408 | } |
390 | 409 | ||
391 | private bool HasEvents(UUID requestID, UUID sessionID) | 410 | private bool HasEvents(UUID requestID, UUID sessionID) |
392 | { | 411 | { |
393 | UrlData url=null; | 412 | UrlData url = null; |
394 | 413 | ||
395 | lock (m_RequestMap) | 414 | lock (m_RequestMap) |
396 | { | 415 | { |
416 | // We return true here because an external URL request that happened at the same time as an llRemoveURL() | ||
417 | // can still make it through to HttpRequestHandler(). That will return without setting up a request | ||
418 | // when it detects that the URL has been removed. The poller, however, will continue to ask for | ||
419 | // events for that request, so here we will signal that there are events and in GetEvents we will | ||
420 | // return a 404. | ||
397 | if (!m_RequestMap.ContainsKey(requestID)) | 421 | if (!m_RequestMap.ContainsKey(requestID)) |
398 | { | 422 | { |
399 | return false; | 423 | return true; |
400 | } | 424 | } |
425 | |||
401 | url = m_RequestMap[requestID]; | 426 | url = m_RequestMap[requestID]; |
402 | if (!url.requests.ContainsKey(requestID)) | 427 | if (!url.requests.ContainsKey(requestID)) |
403 | { | 428 | { |
404 | return false; | 429 | return true; |
405 | } | 430 | } |
406 | } | 431 | } |
407 | 432 | ||
408 | if (System.Environment.TickCount-url.requests[requestID].startTime>25000) | 433 | // Trigger return of timeout response. |
434 | if (System.Environment.TickCount - url.requests[requestID].startTime > 25000) | ||
409 | { | 435 | { |
410 | return true; | 436 | return true; |
411 | } | 437 | } |
412 | 438 | ||
413 | if (url.requests[requestID].requestDone) | 439 | return url.requests[requestID].requestDone; |
414 | return true; | ||
415 | else | ||
416 | return false; | ||
417 | |||
418 | } | 440 | } |
441 | |||
419 | private Hashtable GetEvents(UUID requestID, UUID sessionID, string request) | 442 | private Hashtable GetEvents(UUID requestID, UUID sessionID, string request) |
420 | { | 443 | { |
421 | UrlData url = null; | 444 | UrlData url = null; |
422 | RequestData requestData = null; | 445 | RequestData requestData = null; |
423 | 446 | ||
424 | lock (m_RequestMap) | 447 | lock (m_RequestMap) |
425 | { | 448 | { |
426 | if (!m_RequestMap.ContainsKey(requestID)) | 449 | if (!m_RequestMap.ContainsKey(requestID)) |
427 | return NoEvents(requestID,sessionID); | 450 | return NoEvents(requestID, sessionID); |
451 | |||
428 | url = m_RequestMap[requestID]; | 452 | url = m_RequestMap[requestID]; |
429 | requestData = url.requests[requestID]; | 453 | requestData = url.requests[requestID]; |
430 | } | 454 | } |
431 | 455 | ||
432 | if (!requestData.requestDone) | 456 | if (!requestData.requestDone) |
433 | return NoEvents(requestID,sessionID); | 457 | return NoEvents(requestID, sessionID); |
434 | 458 | ||
435 | Hashtable response = new Hashtable(); | 459 | Hashtable response = new Hashtable(); |
436 | 460 | ||
@@ -443,6 +467,7 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp | |||
443 | response["reusecontext"] = false; | 467 | response["reusecontext"] = false; |
444 | return response; | 468 | return response; |
445 | } | 469 | } |
470 | |||
446 | //put response | 471 | //put response |
447 | response["int_response_code"] = requestData.responseCode; | 472 | response["int_response_code"] = requestData.responseCode; |
448 | response["str_response_string"] = requestData.responseBody; | 473 | response["str_response_string"] = requestData.responseBody; |
@@ -459,6 +484,7 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp | |||
459 | 484 | ||
460 | return response; | 485 | return response; |
461 | } | 486 | } |
487 | |||
462 | public void HttpRequestHandler(UUID requestID, Hashtable request) | 488 | public void HttpRequestHandler(UUID requestID, Hashtable request) |
463 | { | 489 | { |
464 | lock (request) | 490 | lock (request) |
@@ -483,11 +509,22 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp | |||
483 | 509 | ||
484 | pathInfo = uri.Substring(pos3); | 510 | pathInfo = uri.Substring(pos3); |
485 | 511 | ||
486 | UrlData url = null; | 512 | UrlData urlData = null; |
487 | if (!is_ssl) | 513 | |
488 | url = m_UrlMap["http://" + m_ExternalHostNameForLSL + ":" + m_HttpServer.Port.ToString() + uri_tmp]; | 514 | lock (m_UrlMap) |
489 | else | 515 | { |
490 | url = m_UrlMap["https://" + m_ExternalHostNameForLSL + ":" + m_HttpsServer.Port.ToString() + uri_tmp]; | 516 | string url; |
517 | |||
518 | if (is_ssl) | ||
519 | url = "https://" + m_ExternalHostNameForLSL + ":" + m_HttpsServer.Port.ToString() + uri_tmp; | ||
520 | else | ||
521 | url = "http://" + m_ExternalHostNameForLSL + ":" + m_HttpServer.Port.ToString() + uri_tmp; | ||
522 | |||
523 | // Avoid a race - the request URL may have been released via llRequestUrl() whilst this | ||
524 | // request was being processed. | ||
525 | if (!m_UrlMap.TryGetValue(url, out urlData)) | ||
526 | return; | ||
527 | } | ||
491 | 528 | ||
492 | //for llGetHttpHeader support we need to store original URI here | 529 | //for llGetHttpHeader support we need to store original URI here |
493 | //to make x-path-info / x-query-string / x-script-url / x-remote-ip headers | 530 | //to make x-path-info / x-query-string / x-script-url / x-remote-ip headers |
@@ -520,11 +557,10 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp | |||
520 | queryString = queryString + key + "=" + val + "&"; | 557 | queryString = queryString + key + "=" + val + "&"; |
521 | } | 558 | } |
522 | } | 559 | } |
560 | |||
523 | if (queryString.Length > 1) | 561 | if (queryString.Length > 1) |
524 | queryString = queryString.Substring(0, queryString.Length - 1); | 562 | queryString = queryString.Substring(0, queryString.Length - 1); |
525 | |||
526 | } | 563 | } |
527 | |||
528 | } | 564 | } |
529 | 565 | ||
530 | //if this machine is behind DNAT/port forwarding, currently this is being | 566 | //if this machine is behind DNAT/port forwarding, currently this is being |
@@ -532,26 +568,28 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp | |||
532 | requestData.headers["x-remote-ip"] = requestData.headers["remote_addr"]; | 568 | requestData.headers["x-remote-ip"] = requestData.headers["remote_addr"]; |
533 | requestData.headers["x-path-info"] = pathInfo; | 569 | requestData.headers["x-path-info"] = pathInfo; |
534 | requestData.headers["x-query-string"] = queryString; | 570 | requestData.headers["x-query-string"] = queryString; |
535 | requestData.headers["x-script-url"] = url.url; | 571 | requestData.headers["x-script-url"] = urlData.url; |
536 | 572 | ||
537 | //requestData.ev = new ManualResetEvent(false); | 573 | //requestData.ev = new ManualResetEvent(false); |
538 | lock (url.requests) | 574 | lock (urlData.requests) |
539 | { | 575 | { |
540 | url.requests.Add(requestID, requestData); | 576 | urlData.requests.Add(requestID, requestData); |
541 | } | 577 | } |
578 | |||
542 | lock (m_RequestMap) | 579 | lock (m_RequestMap) |
543 | { | 580 | { |
544 | //add to request map | 581 | m_RequestMap.Add(requestID, urlData); |
545 | m_RequestMap.Add(requestID, url); | ||
546 | } | 582 | } |
547 | 583 | ||
548 | url.engine.PostScriptEvent(url.itemID, "http_request", new Object[] { requestID.ToString(), request["http-method"].ToString(), request["body"].ToString() }); | 584 | urlData.engine.PostScriptEvent( |
585 | urlData.itemID, | ||
586 | "http_request", | ||
587 | new Object[] { requestID.ToString(), request["http-method"].ToString(), request["body"].ToString() }); | ||
549 | 588 | ||
550 | //send initial response? | 589 | //send initial response? |
551 | // Hashtable response = new Hashtable(); | 590 | // Hashtable response = new Hashtable(); |
552 | 591 | ||
553 | return; | 592 | return; |
554 | |||
555 | } | 593 | } |
556 | catch (Exception we) | 594 | catch (Exception we) |
557 | { | 595 | { |