aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/CoreModules
diff options
context:
space:
mode:
authorJustin Clark-Casey (justincc)2012-06-22 23:49:52 +0100
committerJustin Clark-Casey (justincc)2012-06-22 23:49:52 +0100
commit78143769bfdf316bbec63e6232bf9be993eb078a (patch)
tree1b215148f8c1e1eaf4caa0c077a8d5087d26f3b5 /OpenSim/Region/CoreModules
parentAvoid a race condition where an incoming request to a script external URL can... (diff)
downloadopensim-SC-78143769bfdf316bbec63e6232bf9be993eb078a.zip
opensim-SC-78143769bfdf316bbec63e6232bf9be993eb078a.tar.gz
opensim-SC-78143769bfdf316bbec63e6232bf9be993eb078a.tar.bz2
opensim-SC-78143769bfdf316bbec63e6232bf9be993eb078a.tar.xz
Resolve various race conditions between accessing and removing external script URLs by more consistently locking on m_UrlMap
Diffstat (limited to 'OpenSim/Region/CoreModules')
-rw-r--r--OpenSim/Region/CoreModules/Scripting/LSLHttp/UrlModule.cs280
1 files changed, 148 insertions, 132 deletions
diff --git a/OpenSim/Region/CoreModules/Scripting/LSLHttp/UrlModule.cs b/OpenSim/Region/CoreModules/Scripting/LSLHttp/UrlModule.cs
index 5c05500..05d54f0 100644
--- a/OpenSim/Region/CoreModules/Scripting/LSLHttp/UrlModule.cs
+++ b/OpenSim/Region/CoreModules/Scripting/LSLHttp/UrlModule.cs
@@ -41,13 +41,39 @@ using OpenSim.Region.Framework.Scenes;
41 41
42namespace OpenSim.Region.CoreModules.Scripting.LSLHttp 42namespace OpenSim.Region.CoreModules.Scripting.LSLHttp
43{ 43{
44 /// <summary>
45 /// Data describing an external URL set up by a script.
46 /// </summary>
44 public class UrlData 47 public class UrlData
45 { 48 {
49 /// <summary>
50 /// Scene object part hosting the script
51 /// </summary>
46 public UUID hostID; 52 public UUID hostID;
53
54 /// <summary>
55 /// The item ID of the script that requested the URL.
56 /// </summary>
47 public UUID itemID; 57 public UUID itemID;
58
59 /// <summary>
60 /// The script engine that runs the script.
61 /// </summary>
48 public IScriptModule engine; 62 public IScriptModule engine;
63
64 /// <summary>
65 /// The generated URL.
66 /// </summary>
49 public string url; 67 public string url;
68
69 /// <summary>
70 /// The random UUID component of the generated URL.
71 /// </summary>
50 public UUID urlcode; 72 public UUID urlcode;
73
74 /// <summary>
75 /// The external requests currently being processed or awaiting retrieval for this URL.
76 /// </summary>
51 public Dictionary<UUID, RequestData> requests; 77 public Dictionary<UUID, RequestData> requests;
52 } 78 }
53 79
@@ -77,6 +103,10 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp
77 /// Indexs the URL request metadata (which script requested it, outstanding requests, etc.) by the request ID 103 /// 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. 104 /// randomly generated when a request is received for this URL.
79 /// </summary> 105 /// </summary>
106 /// <remarks>
107 /// Manipulation or retrieval from this dictionary must be locked on m_UrlMap to preserve consistency with
108 /// m_UrlMap
109 /// </remarks>
80 private Dictionary<UUID, UrlData> m_RequestMap = new Dictionary<UUID, UrlData>(); 110 private Dictionary<UUID, UrlData> m_RequestMap = new Dictionary<UUID, UrlData>();
81 111
82 /// <summary> 112 /// <summary>
@@ -113,10 +143,9 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp
113 { 143 {
114 m_ExternalHostNameForLSL = config.Configs["Network"].GetString("ExternalHostNameForLSL", System.Environment.MachineName); 144 m_ExternalHostNameForLSL = config.Configs["Network"].GetString("ExternalHostNameForLSL", System.Environment.MachineName);
115 bool ssl_enabled = config.Configs["Network"].GetBoolean("https_listener",false); 145 bool ssl_enabled = config.Configs["Network"].GetBoolean("https_listener",false);
146
116 if (ssl_enabled) 147 if (ssl_enabled)
117 {
118 https_port = (uint) config.Configs["Network"].GetInt("https_port",0); 148 https_port = (uint) config.Configs["Network"].GetInt("https_port",0);
119 }
120 149
121 IConfig llFunctionsConfig = config.Configs["LL-Functions"]; 150 IConfig llFunctionsConfig = config.Configs["LL-Functions"];
122 151
@@ -275,32 +304,38 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp
275 304
276 public void HttpResponse(UUID request, int status, string body) 305 public void HttpResponse(UUID request, int status, string body)
277 { 306 {
278 if (m_RequestMap.ContainsKey(request)) 307 lock (m_UrlMap)
279 {
280 UrlData urlData = m_RequestMap[request];
281 urlData.requests[request].responseCode = status;
282 urlData.requests[request].responseBody = body;
283 //urlData.requests[request].ev.Set();
284 urlData.requests[request].requestDone =true;
285 }
286 else
287 { 308 {
288 m_log.Info("[HttpRequestHandler] There is no http-in request with id " + request.ToString()); 309 if (m_RequestMap.ContainsKey(request))
310 {
311 UrlData urlData = m_RequestMap[request];
312 urlData.requests[request].responseCode = status;
313 urlData.requests[request].responseBody = body;
314 //urlData.requests[request].ev.Set();
315 urlData.requests[request].requestDone =true;
316 }
317 else
318 {
319 m_log.Info("[HttpRequestHandler] There is no http-in request with id " + request.ToString());
320 }
289 } 321 }
290 } 322 }
291 323
292 public string GetHttpHeader(UUID requestId, string header) 324 public string GetHttpHeader(UUID requestId, string header)
293 { 325 {
294 if (m_RequestMap.ContainsKey(requestId)) 326 lock (m_UrlMap)
295 {
296 UrlData urlData = m_RequestMap[requestId];
297 string value;
298 if (urlData.requests[requestId].headers.TryGetValue(header,out value))
299 return value;
300 }
301 else
302 { 327 {
303 m_log.Warn("[HttpRequestHandler] There was no http-in request with id " + requestId); 328 if (m_RequestMap.ContainsKey(requestId))
329 {
330 UrlData urlData = m_RequestMap[requestId];
331 string value;
332 if (urlData.requests[requestId].headers.TryGetValue(header, out value))
333 return value;
334 }
335 else
336 {
337 m_log.Warn("[HttpRequestHandler] There was no http-in request with id " + requestId);
338 }
304 } 339 }
305 340
306 return String.Empty; 341 return String.Empty;
@@ -308,7 +343,8 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp
308 343
309 public int GetFreeUrls() 344 public int GetFreeUrls()
310 { 345 {
311 return m_TotalUrls - m_UrlMap.Count; 346 lock (m_UrlMap)
347 return m_TotalUrls - m_UrlMap.Count;
312 } 348 }
313 349
314 public void ScriptRemoved(UUID itemID) 350 public void ScriptRemoved(UUID itemID)
@@ -366,9 +402,9 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp
366 private Hashtable NoEvents(UUID requestID, UUID sessionID) 402 private Hashtable NoEvents(UUID requestID, UUID sessionID)
367 { 403 {
368 Hashtable response = new Hashtable(); 404 Hashtable response = new Hashtable();
369 UrlData url; 405 UrlData urlData;
370 406
371 lock (m_RequestMap) 407 lock (m_UrlMap)
372 { 408 {
373 // We need to return a 404 here in case the request URL was removed at exactly the same time that a 409 // 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 410 // request was made. In this case, the request thread can outrace llRemoveURL() and still be polling
@@ -383,25 +419,22 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp
383 return response; 419 return response;
384 } 420 }
385 421
386 url = m_RequestMap[requestID]; 422 urlData = m_RequestMap[requestID];
387 }
388
389 if (System.Environment.TickCount - url.requests[requestID].startTime > 25000)
390 {
391 response["int_response_code"] = 500;
392 response["str_response_string"] = "Script timeout";
393 response["content_type"] = "text/plain";
394 response["keepalive"] = false;
395 response["reusecontext"] = false;
396 423
397 //remove from map 424 if (System.Environment.TickCount - urlData.requests[requestID].startTime > 25000)
398 lock (url)
399 { 425 {
400 url.requests.Remove(requestID); 426 response["int_response_code"] = 500;
427 response["str_response_string"] = "Script timeout";
428 response["content_type"] = "text/plain";
429 response["keepalive"] = false;
430 response["reusecontext"] = false;
431
432 //remove from map
433 urlData.requests.Remove(requestID);
401 m_RequestMap.Remove(requestID); 434 m_RequestMap.Remove(requestID);
402 }
403 435
404 return response; 436 return response;
437 }
405 } 438 }
406 439
407 return response; 440 return response;
@@ -409,9 +442,7 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp
409 442
410 private bool HasEvents(UUID requestID, UUID sessionID) 443 private bool HasEvents(UUID requestID, UUID sessionID)
411 { 444 {
412 UrlData url = null; 445 lock (m_UrlMap)
413
414 lock (m_RequestMap)
415 { 446 {
416 // We return true here because an external URL request that happened at the same time as an llRemoveURL() 447 // 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 448 // can still make it through to HttpRequestHandler(). That will return without setting up a request
@@ -423,61 +454,61 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp
423 return true; 454 return true;
424 } 455 }
425 456
426 url = m_RequestMap[requestID]; 457 UrlData urlData = m_RequestMap[requestID];
427 if (!url.requests.ContainsKey(requestID)) 458
459 if (!urlData.requests.ContainsKey(requestID))
428 { 460 {
429 return true; 461 return true;
430 } 462 }
431 }
432 463
433 // Trigger return of timeout response. 464 // Trigger return of timeout response.
434 if (System.Environment.TickCount - url.requests[requestID].startTime > 25000) 465 if (System.Environment.TickCount - urlData.requests[requestID].startTime > 25000)
435 { 466 {
436 return true; 467 return true;
437 } 468 }
438 469
439 return url.requests[requestID].requestDone; 470 return urlData.requests[requestID].requestDone;
471 }
440 } 472 }
441 473
442 private Hashtable GetEvents(UUID requestID, UUID sessionID, string request) 474 private Hashtable GetEvents(UUID requestID, UUID sessionID, string request)
443 { 475 {
444 UrlData url = null; 476 Hashtable response;
445 RequestData requestData = null;
446 477
447 lock (m_RequestMap) 478 lock (m_UrlMap)
448 { 479 {
480 UrlData url = null;
481 RequestData requestData = null;
482
449 if (!m_RequestMap.ContainsKey(requestID)) 483 if (!m_RequestMap.ContainsKey(requestID))
450 return NoEvents(requestID, sessionID); 484 return NoEvents(requestID, sessionID);
451 485
452 url = m_RequestMap[requestID]; 486 url = m_RequestMap[requestID];
453 requestData = url.requests[requestID]; 487 requestData = url.requests[requestID];
454 }
455 488
456 if (!requestData.requestDone) 489 if (!requestData.requestDone)
457 return NoEvents(requestID, sessionID); 490 return NoEvents(requestID, sessionID);
458
459 Hashtable response = new Hashtable();
460 491
461 if (System.Environment.TickCount - requestData.startTime > 25000) 492 response = new Hashtable();
462 { 493
463 response["int_response_code"] = 500; 494 if (System.Environment.TickCount - requestData.startTime > 25000)
464 response["str_response_string"] = "Script timeout"; 495 {
496 response["int_response_code"] = 500;
497 response["str_response_string"] = "Script timeout";
498 response["content_type"] = "text/plain";
499 response["keepalive"] = false;
500 response["reusecontext"] = false;
501 return response;
502 }
503
504 //put response
505 response["int_response_code"] = requestData.responseCode;
506 response["str_response_string"] = requestData.responseBody;
465 response["content_type"] = "text/plain"; 507 response["content_type"] = "text/plain";
466 response["keepalive"] = false; 508 response["keepalive"] = false;
467 response["reusecontext"] = false; 509 response["reusecontext"] = false;
468 return response;
469 }
470 510
471 //put response 511 //remove from map
472 response["int_response_code"] = requestData.responseCode;
473 response["str_response_string"] = requestData.responseBody;
474 response["content_type"] = "text/plain";
475 response["keepalive"] = false;
476 response["reusecontext"] = false;
477
478 //remove from map
479 lock (url)
480 {
481 url.requests.Remove(requestID); 512 url.requests.Remove(requestID);
482 m_RequestMap.Remove(requestID); 513 m_RequestMap.Remove(requestID);
483 } 514 }
@@ -487,44 +518,41 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp
487 518
488 public void HttpRequestHandler(UUID requestID, Hashtable request) 519 public void HttpRequestHandler(UUID requestID, Hashtable request)
489 { 520 {
490 lock (request) 521 string uri = request["uri"].ToString();
491 { 522 bool is_ssl = uri.Contains("lslhttps");
492 string uri = request["uri"].ToString();
493 bool is_ssl = uri.Contains("lslhttps");
494 523
495 try 524 try
496 { 525 {
497 Hashtable headers = (Hashtable)request["headers"]; 526 Hashtable headers = (Hashtable)request["headers"];
498 527
499// string uri_full = "http://" + m_ExternalHostNameForLSL + ":" + m_HttpServer.Port.ToString() + uri;// "/lslhttp/" + urlcode.ToString() + "/"; 528// string uri_full = "http://" + m_ExternalHostNameForLSL + ":" + m_HttpServer.Port.ToString() + uri;// "/lslhttp/" + urlcode.ToString() + "/";
500 529
501 int pos1 = uri.IndexOf("/");// /lslhttp 530 int pos1 = uri.IndexOf("/");// /lslhttp
502 int pos2 = uri.IndexOf("/", pos1 + 1);// /lslhttp/ 531 int pos2 = uri.IndexOf("/", pos1 + 1);// /lslhttp/
503 int pos3 = uri.IndexOf("/", pos2 + 1);// /lslhttp/<UUID>/ 532 int pos3 = uri.IndexOf("/", pos2 + 1);// /lslhttp/<UUID>/
504 string uri_tmp = uri.Substring(0, pos3 + 1); 533 string uri_tmp = uri.Substring(0, pos3 + 1);
505 //HTTP server code doesn't provide us with QueryStrings 534 //HTTP server code doesn't provide us with QueryStrings
506 string pathInfo; 535 string pathInfo;
507 string queryString; 536 string queryString;
508 queryString = ""; 537 queryString = "";
509 538
510 pathInfo = uri.Substring(pos3); 539 pathInfo = uri.Substring(pos3);
511 540
512 UrlData urlData = null; 541 UrlData urlData = null;
513 542
514 lock (m_UrlMap) 543 lock (m_UrlMap)
515 { 544 {
516 string url; 545 string url;
517 546
518 if (is_ssl) 547 if (is_ssl)
519 url = "https://" + m_ExternalHostNameForLSL + ":" + m_HttpsServer.Port.ToString() + uri_tmp; 548 url = "https://" + m_ExternalHostNameForLSL + ":" + m_HttpsServer.Port.ToString() + uri_tmp;
520 else 549 else
521 url = "http://" + m_ExternalHostNameForLSL + ":" + m_HttpServer.Port.ToString() + uri_tmp; 550 url = "http://" + m_ExternalHostNameForLSL + ":" + m_HttpServer.Port.ToString() + uri_tmp;
522 551
523 // Avoid a race - the request URL may have been released via llRequestUrl() whilst this 552 // Avoid a race - the request URL may have been released via llRequestUrl() whilst this
524 // request was being processed. 553 // request was being processed.
525 if (!m_UrlMap.TryGetValue(url, out urlData)) 554 if (!m_UrlMap.TryGetValue(url, out urlData))
526 return; 555 return;
527 }
528 556
529 //for llGetHttpHeader support we need to store original URI here 557 //for llGetHttpHeader support we need to store original URI here
530 //to make x-path-info / x-query-string / x-script-url / x-remote-ip headers 558 //to make x-path-info / x-query-string / x-script-url / x-remote-ip headers
@@ -544,6 +572,7 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp
544 string value = (string)header.Value; 572 string value = (string)header.Value;
545 requestData.headers.Add(key, value); 573 requestData.headers.Add(key, value);
546 } 574 }
575
547 foreach (DictionaryEntry de in request) 576 foreach (DictionaryEntry de in request)
548 { 577 {
549 if (de.Key.ToString() == "querystringkeys") 578 if (de.Key.ToString() == "querystringkeys")
@@ -570,34 +599,21 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp
570 requestData.headers["x-query-string"] = queryString; 599 requestData.headers["x-query-string"] = queryString;
571 requestData.headers["x-script-url"] = urlData.url; 600 requestData.headers["x-script-url"] = urlData.url;
572 601
573 //requestData.ev = new ManualResetEvent(false); 602 urlData.requests.Add(requestID, requestData);
574 lock (urlData.requests) 603 m_RequestMap.Add(requestID, urlData);
575 {
576 urlData.requests.Add(requestID, requestData);
577 }
578
579 lock (m_RequestMap)
580 {
581 m_RequestMap.Add(requestID, urlData);
582 }
583
584 urlData.engine.PostScriptEvent(
585 urlData.itemID,
586 "http_request",
587 new Object[] { requestID.ToString(), request["http-method"].ToString(), request["body"].ToString() });
588
589 //send initial response?
590// Hashtable response = new Hashtable();
591
592 return;
593 }
594 catch (Exception we)
595 {
596 //Hashtable response = new Hashtable();
597 m_log.Warn("[HttpRequestHandler]: http-in request failed");
598 m_log.Warn(we.Message);
599 m_log.Warn(we.StackTrace);
600 } 604 }
605
606 urlData.engine.PostScriptEvent(
607 urlData.itemID,
608 "http_request",
609 new Object[] { requestID.ToString(), request["http-method"].ToString(), request["body"].ToString() });
610 }
611 catch (Exception we)
612 {
613 //Hashtable response = new Hashtable();
614 m_log.Warn("[HttpRequestHandler]: http-in request failed");
615 m_log.Warn(we.Message);
616 m_log.Warn(we.StackTrace);
601 } 617 }
602 } 618 }
603 619
@@ -606,4 +622,4 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp
606 ScriptRemoved(itemID); 622 ScriptRemoved(itemID);
607 } 623 }
608 } 624 }
609} 625} \ No newline at end of file