diff options
Diffstat (limited to 'OpenSim/Region/CoreModules/Scripting/HttpRequest/ScriptsHttpRequests.cs')
-rw-r--r-- | OpenSim/Region/CoreModules/Scripting/HttpRequest/ScriptsHttpRequests.cs | 229 |
1 files changed, 137 insertions, 92 deletions
diff --git a/OpenSim/Region/CoreModules/Scripting/HttpRequest/ScriptsHttpRequests.cs b/OpenSim/Region/CoreModules/Scripting/HttpRequest/ScriptsHttpRequests.cs index 1a62405..6eb25ef 100644 --- a/OpenSim/Region/CoreModules/Scripting/HttpRequest/ScriptsHttpRequests.cs +++ b/OpenSim/Region/CoreModules/Scripting/HttpRequest/ScriptsHttpRequests.cs | |||
@@ -28,15 +28,12 @@ | |||
28 | using System; | 28 | using System; |
29 | using System.Collections.Generic; | 29 | using System.Collections.Generic; |
30 | using System.IO; | 30 | using System.IO; |
31 | using System.Linq; | ||
32 | using System.Net; | 31 | using System.Net; |
33 | using System.Net.Mail; | 32 | using System.Net.Mail; |
34 | using System.Net.Security; | 33 | using System.Net.Security; |
35 | using System.Reflection; | ||
36 | using System.Text; | 34 | using System.Text; |
37 | using System.Threading; | 35 | using System.Threading; |
38 | using System.Security.Cryptography.X509Certificates; | 36 | using System.Security.Cryptography.X509Certificates; |
39 | using log4net; | ||
40 | using Nini.Config; | 37 | using Nini.Config; |
41 | using OpenMetaverse; | 38 | using OpenMetaverse; |
42 | using OpenSim.Framework; | 39 | using OpenSim.Framework; |
@@ -45,6 +42,7 @@ using OpenSim.Framework.Servers.HttpServer; | |||
45 | using OpenSim.Region.Framework.Interfaces; | 42 | using OpenSim.Region.Framework.Interfaces; |
46 | using OpenSim.Region.Framework.Scenes; | 43 | using OpenSim.Region.Framework.Scenes; |
47 | using Mono.Addins; | 44 | using Mono.Addins; |
45 | using Amib.Threading; | ||
48 | 46 | ||
49 | /***************************************************** | 47 | /***************************************************** |
50 | * | 48 | * |
@@ -105,6 +103,7 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest | |||
105 | private Dictionary<UUID, HttpRequestClass> m_pendingRequests; | 103 | private Dictionary<UUID, HttpRequestClass> m_pendingRequests; |
106 | private Scene m_scene; | 104 | private Scene m_scene; |
107 | // private Queue<HttpRequestClass> rpcQueue = new Queue<HttpRequestClass>(); | 105 | // private Queue<HttpRequestClass> rpcQueue = new Queue<HttpRequestClass>(); |
106 | public static SmartThreadPool ThreadPool = null; | ||
108 | 107 | ||
109 | public HttpRequestModule() | 108 | public HttpRequestModule() |
110 | { | 109 | { |
@@ -253,29 +252,18 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest | |||
253 | return reqID; | 252 | return reqID; |
254 | } | 253 | } |
255 | 254 | ||
256 | public void StopHttpRequestsForScript(UUID id) | 255 | public void StopHttpRequest(uint m_localID, UUID m_itemID) |
257 | { | 256 | { |
258 | if (m_pendingRequests != null) | 257 | if (m_pendingRequests != null) |
259 | { | 258 | { |
260 | List<UUID> keysToRemove = null; | ||
261 | |||
262 | lock (HttpListLock) | 259 | lock (HttpListLock) |
263 | { | 260 | { |
264 | foreach (HttpRequestClass req in m_pendingRequests.Values) | 261 | HttpRequestClass tmpReq; |
262 | if (m_pendingRequests.TryGetValue(m_itemID, out tmpReq)) | ||
265 | { | 263 | { |
266 | if (req.ItemID == id) | 264 | tmpReq.Stop(); |
267 | { | 265 | m_pendingRequests.Remove(m_itemID); |
268 | req.Stop(); | ||
269 | |||
270 | if (keysToRemove == null) | ||
271 | keysToRemove = new List<UUID>(); | ||
272 | |||
273 | keysToRemove.Add(req.ReqID); | ||
274 | } | ||
275 | } | 266 | } |
276 | |||
277 | if (keysToRemove != null) | ||
278 | keysToRemove.ForEach(keyToRemove => m_pendingRequests.Remove(keyToRemove)); | ||
279 | } | 267 | } |
280 | } | 268 | } |
281 | } | 269 | } |
@@ -293,13 +281,19 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest | |||
293 | { | 281 | { |
294 | lock (HttpListLock) | 282 | lock (HttpListLock) |
295 | { | 283 | { |
296 | foreach (HttpRequestClass req in m_pendingRequests.Values) | 284 | foreach (UUID luid in m_pendingRequests.Keys) |
297 | { | 285 | { |
298 | if (req.Finished) | 286 | HttpRequestClass tmpReq; |
299 | return req; | 287 | |
288 | if (m_pendingRequests.TryGetValue(luid, out tmpReq)) | ||
289 | { | ||
290 | if (tmpReq.Finished) | ||
291 | { | ||
292 | return tmpReq; | ||
293 | } | ||
294 | } | ||
300 | } | 295 | } |
301 | } | 296 | } |
302 | |||
303 | return null; | 297 | return null; |
304 | } | 298 | } |
305 | 299 | ||
@@ -326,7 +320,30 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest | |||
326 | m_proxyurl = config.Configs["Startup"].GetString("HttpProxy"); | 320 | m_proxyurl = config.Configs["Startup"].GetString("HttpProxy"); |
327 | m_proxyexcepts = config.Configs["Startup"].GetString("HttpProxyExceptions"); | 321 | m_proxyexcepts = config.Configs["Startup"].GetString("HttpProxyExceptions"); |
328 | 322 | ||
323 | int maxThreads = 50; | ||
324 | |||
325 | IConfig httpConfig = config.Configs["HttpRequestModule"]; | ||
326 | if (httpConfig != null) | ||
327 | { | ||
328 | maxThreads = httpConfig.GetInt("MaxPoolThreads", maxThreads); | ||
329 | } | ||
330 | |||
329 | m_pendingRequests = new Dictionary<UUID, HttpRequestClass>(); | 331 | m_pendingRequests = new Dictionary<UUID, HttpRequestClass>(); |
332 | |||
333 | // First instance sets this up for all sims | ||
334 | if (ThreadPool == null) | ||
335 | { | ||
336 | STPStartInfo startInfo = new STPStartInfo(); | ||
337 | startInfo.IdleTimeout = 20000; | ||
338 | startInfo.MaxWorkerThreads = maxThreads; | ||
339 | startInfo.MinWorkerThreads = 5; | ||
340 | startInfo.ThreadPriority = ThreadPriority.BelowNormal; | ||
341 | startInfo.StartSuspended = true; | ||
342 | |||
343 | ThreadPool = new SmartThreadPool(startInfo); | ||
344 | |||
345 | ThreadPool.Start(); | ||
346 | } | ||
330 | } | 347 | } |
331 | 348 | ||
332 | public void AddRegion(Scene scene) | 349 | public void AddRegion(Scene scene) |
@@ -370,8 +387,6 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest | |||
370 | 387 | ||
371 | public class HttpRequestClass: IServiceRequest | 388 | public class HttpRequestClass: IServiceRequest |
372 | { | 389 | { |
373 | // private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
374 | |||
375 | // Constants for parameters | 390 | // Constants for parameters |
376 | // public const int HTTP_BODY_MAXLENGTH = 2; | 391 | // public const int HTTP_BODY_MAXLENGTH = 2; |
377 | // public const int HTTP_METHOD = 0; | 392 | // public const int HTTP_METHOD = 0; |
@@ -392,6 +407,8 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest | |||
392 | public string HttpMIMEType = "text/plain;charset=utf-8"; | 407 | public string HttpMIMEType = "text/plain;charset=utf-8"; |
393 | public int HttpTimeout; | 408 | public int HttpTimeout; |
394 | public bool HttpVerifyCert = true; | 409 | public bool HttpVerifyCert = true; |
410 | public IWorkItemResult WorkItem = null; | ||
411 | |||
395 | //public bool HttpVerboseThrottle = true; // not implemented | 412 | //public bool HttpVerboseThrottle = true; // not implemented |
396 | public List<string> HttpCustomHeaders = null; | 413 | public List<string> HttpCustomHeaders = null; |
397 | public bool HttpPragmaNoCache = true; | 414 | public bool HttpPragmaNoCache = true; |
@@ -419,7 +436,7 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest | |||
419 | get { return _reqID; } | 436 | get { return _reqID; } |
420 | set { _reqID = value; } | 437 | set { _reqID = value; } |
421 | } | 438 | } |
422 | public WebRequest Request; | 439 | public HttpWebRequest Request; |
423 | public string ResponseBody; | 440 | public string ResponseBody; |
424 | public List<string> ResponseMetadata; | 441 | public List<string> ResponseMetadata; |
425 | public Dictionary<string, string> ResponseHeaders; | 442 | public Dictionary<string, string> ResponseHeaders; |
@@ -428,14 +445,38 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest | |||
428 | 445 | ||
429 | public void Process() | 446 | public void Process() |
430 | { | 447 | { |
448 | _finished = false; | ||
449 | |||
450 | lock (HttpRequestModule.ThreadPool) | ||
451 | WorkItem = HttpRequestModule.ThreadPool.QueueWorkItem(new WorkItemCallback(StpSendWrapper), null); | ||
452 | } | ||
453 | |||
454 | private object StpSendWrapper(object o) | ||
455 | { | ||
431 | SendRequest(); | 456 | SendRequest(); |
457 | return null; | ||
432 | } | 458 | } |
433 | 459 | ||
460 | /* | ||
461 | * TODO: More work on the response codes. Right now | ||
462 | * returning 200 for success or 499 for exception | ||
463 | */ | ||
464 | |||
434 | public void SendRequest() | 465 | public void SendRequest() |
435 | { | 466 | { |
467 | HttpWebResponse response = null; | ||
468 | StringBuilder sb = new StringBuilder(); | ||
469 | byte[] buf = new byte[8192]; | ||
470 | string tempString = null; | ||
471 | int count = 0; | ||
472 | |||
436 | try | 473 | try |
437 | { | 474 | { |
438 | Request = WebRequest.Create(Url); | 475 | Request = (HttpWebRequest) WebRequest.Create(Url); |
476 | |||
477 | //This works around some buggy HTTP Servers like Lighttpd | ||
478 | Request.ServicePoint.Expect100Continue = false; | ||
479 | |||
439 | Request.Method = HttpMethod; | 480 | Request.Method = HttpMethod; |
440 | Request.ContentType = HttpMIMEType; | 481 | Request.ContentType = HttpMIMEType; |
441 | 482 | ||
@@ -443,7 +484,6 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest | |||
443 | { | 484 | { |
444 | // We could hijack Connection Group Name to identify | 485 | // We could hijack Connection Group Name to identify |
445 | // a desired security exception. But at the moment we'll use a dummy header instead. | 486 | // a desired security exception. But at the moment we'll use a dummy header instead. |
446 | // Request.ConnectionGroupName = "NoVerify"; | ||
447 | Request.Headers.Add("NoVerifyCert", "true"); | 487 | Request.Headers.Add("NoVerifyCert", "true"); |
448 | } | 488 | } |
449 | // else | 489 | // else |
@@ -473,17 +513,14 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest | |||
473 | } | 513 | } |
474 | } | 514 | } |
475 | 515 | ||
476 | if (ResponseHeaders != null) | 516 | foreach (KeyValuePair<string, string> entry in ResponseHeaders) |
477 | { | 517 | if (entry.Key.ToLower().Equals("user-agent")) |
478 | foreach (KeyValuePair<string, string> entry in ResponseHeaders) | 518 | Request.UserAgent = entry.Value; |
479 | if (entry.Key.ToLower().Equals("user-agent") && Request is HttpWebRequest) | 519 | else |
480 | ((HttpWebRequest)Request).UserAgent = entry.Value; | 520 | Request.Headers[entry.Key] = entry.Value; |
481 | else | ||
482 | Request.Headers[entry.Key] = entry.Value; | ||
483 | } | ||
484 | 521 | ||
485 | // Encode outbound data | 522 | // Encode outbound data |
486 | if (OutboundBody != null && OutboundBody.Length > 0) | 523 | if (OutboundBody.Length > 0) |
487 | { | 524 | { |
488 | byte[] data = Util.UTF8.GetBytes(OutboundBody); | 525 | byte[] data = Util.UTF8.GetBytes(OutboundBody); |
489 | 526 | ||
@@ -493,12 +530,11 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest | |||
493 | bstream.Close(); | 530 | bstream.Close(); |
494 | } | 531 | } |
495 | 532 | ||
533 | Request.Timeout = HttpTimeout; | ||
496 | try | 534 | try |
497 | { | 535 | { |
498 | IAsyncResult result = (IAsyncResult)Request.BeginGetResponse(ResponseCallback, null); | 536 | // execute the request |
499 | 537 | response = (HttpWebResponse) Request.GetResponse(); | |
500 | ThreadPool.RegisterWaitForSingleObject( | ||
501 | result.AsyncWaitHandle, new WaitOrTimerCallback(TimeoutCallback), null, HttpTimeout, true); | ||
502 | } | 538 | } |
503 | catch (WebException e) | 539 | catch (WebException e) |
504 | { | 540 | { |
@@ -506,82 +542,91 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest | |||
506 | { | 542 | { |
507 | throw; | 543 | throw; |
508 | } | 544 | } |
545 | response = (HttpWebResponse)e.Response; | ||
546 | } | ||
509 | 547 | ||
510 | HttpWebResponse response = (HttpWebResponse)e.Response; | 548 | Status = (int)response.StatusCode; |
511 | 549 | ||
512 | Status = (int)response.StatusCode; | 550 | Stream resStream = response.GetResponseStream(); |
513 | ResponseBody = response.StatusDescription; | ||
514 | _finished = true; | ||
515 | } | ||
516 | } | ||
517 | catch (Exception e) | ||
518 | { | ||
519 | // m_log.Debug( | ||
520 | // string.Format("[SCRIPTS HTTP REQUESTS]: Exception on request to {0} for {1} ", Url, ItemID), e); | ||
521 | 551 | ||
522 | Status = (int)OSHttpStatusCode.ClientErrorJoker; | 552 | do |
523 | ResponseBody = e.Message; | 553 | { |
524 | _finished = true; | 554 | // fill the buffer with data |
525 | } | 555 | count = resStream.Read(buf, 0, buf.Length); |
526 | } | ||
527 | 556 | ||
528 | private void ResponseCallback(IAsyncResult ar) | 557 | // make sure we read some data |
529 | { | 558 | if (count != 0) |
530 | HttpWebResponse response = null; | 559 | { |
560 | // translate from bytes to ASCII text | ||
561 | tempString = Util.UTF8.GetString(buf, 0, count); | ||
531 | 562 | ||
532 | try | 563 | // continue building the string |
564 | sb.Append(tempString); | ||
565 | if (sb.Length > 2048) | ||
566 | break; | ||
567 | } | ||
568 | } while (count > 0); // any more data to read? | ||
569 | |||
570 | ResponseBody = sb.ToString().Replace("\r", ""); | ||
571 | } | ||
572 | catch (WebException e) | ||
533 | { | 573 | { |
534 | try | 574 | if (e.Status == WebExceptionStatus.ProtocolError) |
535 | { | ||
536 | response = (HttpWebResponse)Request.EndGetResponse(ar); | ||
537 | } | ||
538 | catch (WebException e) | ||
539 | { | 575 | { |
540 | if (e.Status != WebExceptionStatus.ProtocolError) | 576 | HttpWebResponse webRsp = (HttpWebResponse)((WebException)e).Response; |
577 | Status = (int)webRsp.StatusCode; | ||
578 | try | ||
541 | { | 579 | { |
542 | throw; | 580 | using (Stream responseStream = webRsp.GetResponseStream()) |
581 | { | ||
582 | ResponseBody = responseStream.GetStreamString(); | ||
583 | } | ||
584 | } | ||
585 | catch | ||
586 | { | ||
587 | ResponseBody = webRsp.StatusDescription; | ||
543 | } | 588 | } |
544 | 589 | } | |
545 | response = (HttpWebResponse)e.Response; | 590 | else |
591 | { | ||
592 | Status = (int)OSHttpStatusCode.ClientErrorJoker; | ||
593 | ResponseBody = e.Message; | ||
546 | } | 594 | } |
547 | 595 | ||
548 | Status = (int)response.StatusCode; | 596 | if (ResponseBody == null) |
597 | ResponseBody = String.Empty; | ||
549 | 598 | ||
550 | using (Stream stream = response.GetResponseStream()) | 599 | _finished = true; |
551 | { | 600 | return; |
552 | StreamReader reader = new StreamReader(stream, Encoding.UTF8); | ||
553 | ResponseBody = reader.ReadToEnd(); | ||
554 | } | ||
555 | } | 601 | } |
556 | catch (Exception e) | 602 | catch (Exception e) |
557 | { | 603 | { |
558 | Status = (int)OSHttpStatusCode.ClientErrorJoker; | 604 | // Don't crash on anything else |
559 | ResponseBody = e.Message; | ||
560 | |||
561 | // m_log.Debug( | ||
562 | // string.Format("[SCRIPTS HTTP REQUESTS]: Exception on response to {0} for {1} ", Url, ItemID), e); | ||
563 | } | 605 | } |
564 | finally | 606 | finally |
565 | { | 607 | { |
566 | if (response != null) | 608 | if (response != null) |
567 | response.Close(); | 609 | response.Close(); |
568 | |||
569 | _finished = true; | ||
570 | } | 610 | } |
571 | } | ||
572 | 611 | ||
573 | private void TimeoutCallback(object state, bool timedOut) | 612 | if (ResponseBody == null) |
574 | { | 613 | ResponseBody = String.Empty; |
575 | if (timedOut) | 614 | |
576 | Request.Abort(); | 615 | _finished = true; |
577 | } | 616 | } |
578 | 617 | ||
579 | public void Stop() | 618 | public void Stop() |
580 | { | 619 | { |
581 | // m_log.DebugFormat("[SCRIPTS HTTP REQUESTS]: Stopping request to {0} for {1} ", Url, ItemID); | 620 | try |
582 | 621 | { | |
583 | if (Request != null) | 622 | if (!WorkItem.Cancel()) |
584 | Request.Abort(); | 623 | { |
624 | WorkItem.Cancel(true); | ||
625 | } | ||
626 | } | ||
627 | catch (Exception) | ||
628 | { | ||
629 | } | ||
585 | } | 630 | } |
586 | } | 631 | } |
587 | } \ No newline at end of file | 632 | } |