aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/CoreModules/Scripting/HttpRequest/ScriptsHttpRequests.cs
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region/CoreModules/Scripting/HttpRequest/ScriptsHttpRequests.cs')
-rw-r--r--OpenSim/Region/CoreModules/Scripting/HttpRequest/ScriptsHttpRequests.cs253
1 files changed, 155 insertions, 98 deletions
diff --git a/OpenSim/Region/CoreModules/Scripting/HttpRequest/ScriptsHttpRequests.cs b/OpenSim/Region/CoreModules/Scripting/HttpRequest/ScriptsHttpRequests.cs
index c3f6d6b..83d91c4 100644
--- a/OpenSim/Region/CoreModules/Scripting/HttpRequest/ScriptsHttpRequests.cs
+++ b/OpenSim/Region/CoreModules/Scripting/HttpRequest/ScriptsHttpRequests.cs
@@ -27,6 +27,7 @@
27 27
28using System; 28using System;
29using System.Collections.Generic; 29using System.Collections.Generic;
30using System.Collections.Concurrent;
30using System.IO; 31using System.IO;
31using System.Net; 32using System.Net;
32using System.Net.Mail; 33using System.Net.Mail;
@@ -94,18 +95,31 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest
94 { 95 {
95// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 96// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
96 97
97 private object HttpListLock = new object(); 98 private object m_httpListLock = new object();
98 private int httpTimeout = 30000; 99 private int m_httpTimeout = 30000;
99 private string m_name = "HttpScriptRequests"; 100 private string m_name = "HttpScriptRequests";
100 101
101 private OutboundUrlFilter m_outboundUrlFilter; 102 private OutboundUrlFilter m_outboundUrlFilter;
102 private string m_proxyurl = ""; 103 private string m_proxyurl = "";
103 private string m_proxyexcepts = ""; 104 private string m_proxyexcepts = "";
104 105
106 private float m_primPerSec = 1.0f;
107 private float m_primBurst = 3.0f;
108 private float m_primOwnerPerSec = 25.0f;
109 private float m_primOwnerBurst = 5.0f;
110
111 private struct ThrottleData
112 {
113 public double lastTime;
114 public float count;
115 }
116
105 // <request id, HttpRequestClass> 117 // <request id, HttpRequestClass>
106 private Dictionary<UUID, HttpRequestClass> m_pendingRequests; 118 private Dictionary<UUID, HttpRequestClass> m_pendingRequests;
107 private Scene m_scene; 119 private ConcurrentQueue<HttpRequestClass> m_CompletedRequests;
108 // private Queue<HttpRequestClass> rpcQueue = new Queue<HttpRequestClass>(); 120 private ConcurrentDictionary<uint, ThrottleData> m_RequestsThrottle;
121 private ConcurrentDictionary<UUID, ThrottleData> m_OwnerRequestsThrottle;
122
109 public static SmartThreadPool ThreadPool = null; 123 public static SmartThreadPool ThreadPool = null;
110 124
111 public HttpRequestModule() 125 public HttpRequestModule()
@@ -119,10 +133,77 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest
119 return UUID.Zero; 133 return UUID.Zero;
120 } 134 }
121 135
136 public bool CheckThrottle(uint localID, UUID ownerID)
137 {
138 ThrottleData th;
139 double now = Util.GetTimeStamp();
140 bool ret;
141
142 if (m_RequestsThrottle.TryGetValue(localID, out th))
143 {
144 double delta = now - th.lastTime;
145 th.lastTime = now;
146
147 float add = (float)(m_primPerSec * delta);
148 th.count += add;
149 if (th.count > m_primBurst)
150 th.count = m_primBurst;
151
152 ret = th.count > 0;
153 if (ret)
154 th.count--;
155 }
156 else
157 {
158 th = new ThrottleData()
159 {
160 lastTime = now,
161 count = m_primBurst - 1
162 };
163 ret = true;
164 }
165 m_RequestsThrottle[localID] = th;
166
167 if(!ret)
168 return false;
169
170 if (m_OwnerRequestsThrottle.TryGetValue(ownerID, out th))
171 {
172 double delta = now - th.lastTime;
173 th.lastTime = now;
174
175 float add = (float)(m_primOwnerPerSec * delta);
176 th.count += add;
177 if (th.count > m_primOwnerBurst)
178 th.count = m_primOwnerBurst;
179
180 ret = th.count > 0;
181 if (ret)
182 th.count--;
183 }
184 else
185 {
186 th = new ThrottleData()
187 {
188 lastTime = now,
189 count = m_primOwnerBurst - 1
190 };
191 }
192 m_OwnerRequestsThrottle[ownerID] = th;
193
194 return ret;
195 }
196
122 public UUID StartHttpRequest( 197 public UUID StartHttpRequest(
123 uint localID, UUID itemID, string url, List<string> parameters, Dictionary<string, string> headers, string body, 198 uint localID, UUID itemID, string url, List<string> parameters, Dictionary<string, string> headers, string body,
124 out HttpInitialRequestStatus status) 199 out HttpInitialRequestStatus status)
125 { 200 {
201 if (!CheckAllowed(new Uri(url)))
202 {
203 status = HttpInitialRequestStatus.DISALLOWED_BY_FILTER;
204 return UUID.Zero;
205 }
206
126 UUID reqID = UUID.Random(); 207 UUID reqID = UUID.Random();
127 HttpRequestClass htc = new HttpRequestClass(); 208 HttpRequestClass htc = new HttpRequestClass();
128 209
@@ -207,7 +288,7 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest
207 htc.ItemID = itemID; 288 htc.ItemID = itemID;
208 htc.Url = url; 289 htc.Url = url;
209 htc.ReqID = reqID; 290 htc.ReqID = reqID;
210 htc.HttpTimeout = httpTimeout; 291 htc.HttpTimeout = m_httpTimeout;
211 htc.OutboundBody = body; 292 htc.OutboundBody = body;
212 htc.ResponseHeaders = headers; 293 htc.ResponseHeaders = headers;
213 htc.proxyurl = m_proxyurl; 294 htc.proxyurl = m_proxyurl;
@@ -216,16 +297,12 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest
216 // Same number as default HttpWebRequest.MaximumAutomaticRedirections 297 // Same number as default HttpWebRequest.MaximumAutomaticRedirections
217 htc.MaxRedirects = 50; 298 htc.MaxRedirects = 50;
218 299
219 if (StartHttpRequest(htc)) 300 lock (m_httpListLock)
220 { 301 m_pendingRequests.Add(reqID, htc);
221 status = HttpInitialRequestStatus.OK; 302
222 return htc.ReqID; 303 htc.Process();
223 } 304 status = HttpInitialRequestStatus.OK;
224 else 305 return reqID;
225 {
226 status = HttpInitialRequestStatus.DISALLOWED_BY_FILTER;
227 return UUID.Zero;
228 }
229 } 306 }
230 307
231 /// <summary> 308 /// <summary>
@@ -237,34 +314,21 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest
237 return m_outboundUrlFilter.CheckAllowed(url); 314 return m_outboundUrlFilter.CheckAllowed(url);
238 } 315 }
239 316
240 public bool StartHttpRequest(HttpRequestClass req)
241 {
242 if (!CheckAllowed(new Uri(req.Url)))
243 return false;
244
245 lock (HttpListLock)
246 {
247 m_pendingRequests.Add(req.ReqID, req);
248 }
249
250 req.Process();
251
252 return true;
253 }
254
255 public void StopHttpRequest(uint m_localID, UUID m_itemID) 317 public void StopHttpRequest(uint m_localID, UUID m_itemID)
256 { 318 {
257 if (m_pendingRequests != null) 319 List<UUID> toremove = new List<UUID>();
320 lock (m_httpListLock)
258 { 321 {
259 lock (HttpListLock) 322 foreach (HttpRequestClass tmpReq in m_pendingRequests.Values)
260 { 323 {
261 HttpRequestClass tmpReq; 324 if(tmpReq.ItemID == m_itemID)
262 if (m_pendingRequests.TryGetValue(m_itemID, out tmpReq))
263 { 325 {
264 tmpReq.Stop(); 326 tmpReq.Stop();
265 m_pendingRequests.Remove(m_itemID); 327 toremove.Add(tmpReq.ReqID);
266 } 328 }
267 } 329 }
330 foreach(UUID id in toremove)
331 m_pendingRequests.Remove(id);
268 } 332 }
269 } 333 }
270 334
@@ -276,37 +340,35 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest
276 * finished. I thought about setting up a queue for this, but 340 * finished. I thought about setting up a queue for this, but
277 * it will need some refactoring and this works 'enough' right now 341 * it will need some refactoring and this works 'enough' right now
278 */ 342 */
343 public void GotCompletedRequest(HttpRequestClass req)
344 {
345 lock (m_httpListLock)
346 {
347 if (req.Removed)
348 return;
349 m_pendingRequests.Remove(req.ReqID);
350 m_CompletedRequests.Enqueue(req);
351 }
352 }
279 353
280 public IServiceRequest GetNextCompletedRequest() 354 public IServiceRequest GetNextCompletedRequest()
281 { 355 {
282 lock (HttpListLock) 356 HttpRequestClass req;
283 { 357 if(m_CompletedRequests.TryDequeue(out req))
284 foreach (UUID luid in m_pendingRequests.Keys) 358 return req;
285 {
286 HttpRequestClass tmpReq;
287 359
288 if (m_pendingRequests.TryGetValue(luid, out tmpReq))
289 {
290 if (tmpReq.Finished)
291 {
292 return tmpReq;
293 }
294 }
295 }
296 }
297 return null; 360 return null;
298 } 361 }
299 362
300 public void RemoveCompletedRequest(UUID id) 363 public void RemoveCompletedRequest(UUID reqId)
301 { 364 {
302 lock (HttpListLock) 365 lock (m_httpListLock)
303 { 366 {
304 HttpRequestClass tmpReq; 367 HttpRequestClass tmpReq;
305 if (m_pendingRequests.TryGetValue(id, out tmpReq)) 368 if (m_pendingRequests.TryGetValue(reqId, out tmpReq))
306 { 369 {
307 tmpReq.Stop(); 370 tmpReq.Stop();
308 tmpReq = null; 371 m_pendingRequests.Remove(reqId);
309 m_pendingRequests.Remove(id);
310 } 372 }
311 } 373 }
312 } 374 }
@@ -322,17 +384,28 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest
322 384
323 HttpRequestClass.HttpBodyMaxLenMAX = config.Configs["Network"].GetInt("HttpBodyMaxLenMAX", 16384); 385 HttpRequestClass.HttpBodyMaxLenMAX = config.Configs["Network"].GetInt("HttpBodyMaxLenMAX", 16384);
324 386
325
326 m_outboundUrlFilter = new OutboundUrlFilter("Script HTTP request module", config); 387 m_outboundUrlFilter = new OutboundUrlFilter("Script HTTP request module", config);
327 int maxThreads = 15;
328 388
329 IConfig httpConfig = config.Configs["HttpRequestModule"]; 389 int maxThreads = 8;
390 IConfig httpConfig = config.Configs["ScriptsHttpRequestModule"];
330 if (httpConfig != null) 391 if (httpConfig != null)
331 { 392 {
332 maxThreads = httpConfig.GetInt("MaxPoolThreads", maxThreads); 393 maxThreads = httpConfig.GetInt("MaxPoolThreads", maxThreads);
394 m_primBurst = httpConfig.GetFloat("PrimRequestsBurst", m_primBurst);
395 m_primPerSec = httpConfig.GetFloat("PrimRequestsPerSec", m_primPerSec);
396 m_primOwnerBurst = httpConfig.GetFloat("PrimOwnerRequestsBurst", m_primOwnerBurst);
397 m_primOwnerPerSec = httpConfig.GetFloat("PrimOwnerRequestsPerSec", m_primOwnerPerSec);
398 m_httpTimeout = httpConfig.GetInt("RequestsTimeOut", m_httpTimeout);
399 if(m_httpTimeout > 60000)
400 m_httpTimeout = 60000;
401 else if(m_httpTimeout < 200)
402 m_httpTimeout = 200;
333 } 403 }
334 404
335 m_pendingRequests = new Dictionary<UUID, HttpRequestClass>(); 405 m_pendingRequests = new Dictionary<UUID, HttpRequestClass>();
406 m_CompletedRequests = new ConcurrentQueue<HttpRequestClass>();
407 m_RequestsThrottle = new ConcurrentDictionary<uint, ThrottleData>();
408 m_OwnerRequestsThrottle = new ConcurrentDictionary<UUID, ThrottleData>();
336 409
337 // First instance sets this up for all sims 410 // First instance sets this up for all sims
338 if (ThreadPool == null) 411 if (ThreadPool == null)
@@ -352,16 +425,12 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest
352 425
353 public void AddRegion(Scene scene) 426 public void AddRegion(Scene scene)
354 { 427 {
355 m_scene = scene; 428 scene.RegisterModuleInterface<IHttpRequestModule>(this);
356
357 m_scene.RegisterModuleInterface<IHttpRequestModule>(this);
358 } 429 }
359 430
360 public void RemoveRegion(Scene scene) 431 public void RemoveRegion(Scene scene)
361 { 432 {
362 scene.UnregisterModuleInterface<IHttpRequestModule>(this); 433 scene.UnregisterModuleInterface<IHttpRequestModule>(this);
363 if (scene == m_scene)
364 m_scene = null;
365 } 434 }
366 435
367 public void PostInitialise() 436 public void PostInitialise()
@@ -406,11 +475,8 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest
406 /// </summary> 475 /// </summary>
407 public HttpRequestModule RequestModule { get; set; } 476 public HttpRequestModule RequestModule { get; set; }
408 477
409 private bool _finished; 478 public bool Finished { get; private set;}
410 public bool Finished 479 public bool Removed{ get; set;}
411 {
412 get { return _finished; }
413 }
414 480
415 public static int HttpBodyMaxLenMAX = 16384; 481 public static int HttpBodyMaxLenMAX = 16384;
416 482
@@ -427,19 +493,10 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest
427 public bool HttpPragmaNoCache = true; 493 public bool HttpPragmaNoCache = true;
428 494
429 // Request info 495 // Request info
430 private UUID _itemID; 496 public UUID ReqID { get; set; }
431 public UUID ItemID 497 public UUID ItemID { get; set;}
432 { 498 public uint LocalID { get; set;}
433 get { return _itemID; } 499
434 set { _itemID = value; }
435 }
436 private uint _localID;
437 public uint LocalID
438 {
439 get { return _localID; }
440 set { _localID = value; }
441 }
442 public DateTime Next;
443 public string proxyurl; 500 public string proxyurl;
444 public string proxyexcepts; 501 public string proxyexcepts;
445 502
@@ -454,12 +511,7 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest
454 public int MaxRedirects { get; set; } 511 public int MaxRedirects { get; set; }
455 512
456 public string OutboundBody; 513 public string OutboundBody;
457 private UUID _reqID; 514
458 public UUID ReqID
459 {
460 get { return _reqID; }
461 set { _reqID = value; }
462 }
463 public HttpWebRequest Request; 515 public HttpWebRequest Request;
464 public string ResponseBody; 516 public string ResponseBody;
465 public List<string> ResponseMetadata; 517 public List<string> ResponseMetadata;
@@ -469,10 +521,7 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest
469 521
470 public void Process() 522 public void Process()
471 { 523 {
472 _finished = false; 524 WorkItem = HttpRequestModule.ThreadPool.QueueWorkItem(new WorkItemCallback(StpSendWrapper), null);
473
474 lock (HttpRequestModule.ThreadPool)
475 WorkItem = HttpRequestModule.ThreadPool.QueueWorkItem(new WorkItemCallback(StpSendWrapper), null);
476 } 525 }
477 526
478 private object StpSendWrapper(object o) 527 private object StpSendWrapper(object o)
@@ -521,6 +570,9 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest
521 570
522 public void SendRequest() 571 public void SendRequest()
523 { 572 {
573 if(Removed)
574 return;
575
524 HttpWebResponse response = null; 576 HttpWebResponse response = null;
525 Stream resStream = null; 577 Stream resStream = null;
526 byte[] buf = new byte[HttpBodyMaxLenMAX + 16]; 578 byte[] buf = new byte[HttpBodyMaxLenMAX + 16];
@@ -534,6 +586,7 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest
534 586
535 Request.AllowAutoRedirect = false; 587 Request.AllowAutoRedirect = false;
536 Request.KeepAlive = false; 588 Request.KeepAlive = false;
589 Request.Timeout = HttpTimeout;
537 590
538 //This works around some buggy HTTP Servers like Lighttpd 591 //This works around some buggy HTTP Servers like Lighttpd
539 Request.ServicePoint.Expect100Continue = false; 592 Request.ServicePoint.Expect100Continue = false;
@@ -593,7 +646,6 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest
593 bstream.Write(data, 0, data.Length); 646 bstream.Write(data, 0, data.Length);
594 } 647 }
595 648
596 Request.Timeout = HttpTimeout;
597 try 649 try
598 { 650 {
599 // execute the request 651 // execute the request
@@ -672,7 +724,6 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest
672 if (response != null) 724 if (response != null)
673 response.Close(); 725 response.Close();
674 726
675
676 // We need to resubmit 727 // We need to resubmit
677 if ( 728 if (
678 (Status == (int)HttpStatusCode.MovedPermanently 729 (Status == (int)HttpStatusCode.MovedPermanently
@@ -684,7 +735,8 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest
684 { 735 {
685 Status = (int)OSHttpStatusCode.ClientErrorJoker; 736 Status = (int)OSHttpStatusCode.ClientErrorJoker;
686 ResponseBody = "Number of redirects exceeded max redirects"; 737 ResponseBody = "Number of redirects exceeded max redirects";
687 _finished = true; 738 WorkItem = null;
739 RequestModule.GotCompletedRequest(this);
688 } 740 }
689 else 741 else
690 { 742 {
@@ -694,13 +746,15 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest
694 { 746 {
695 Status = (int)OSHttpStatusCode.ClientErrorJoker; 747 Status = (int)OSHttpStatusCode.ClientErrorJoker;
696 ResponseBody = "HTTP redirect code but no location header"; 748 ResponseBody = "HTTP redirect code but no location header";
697 _finished = true; 749 WorkItem = null;
750 RequestModule.GotCompletedRequest(this);
698 } 751 }
699 else if (!RequestModule.CheckAllowed(new Uri(location))) 752 else if (!RequestModule.CheckAllowed(new Uri(location)))
700 { 753 {
701 Status = (int)OSHttpStatusCode.ClientErrorJoker; 754 Status = (int)OSHttpStatusCode.ClientErrorJoker;
702 ResponseBody = "URL from HTTP redirect blocked: " + location; 755 ResponseBody = "URL from HTTP redirect blocked: " + location;
703 _finished = true; 756 WorkItem = null;
757 RequestModule.GotCompletedRequest(this);
704 } 758 }
705 else 759 else
706 { 760 {
@@ -717,9 +771,10 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest
717 } 771 }
718 else 772 else
719 { 773 {
720 _finished = true; 774 WorkItem = null;
721 if (ResponseBody == null) 775 if (ResponseBody == null)
722 ResponseBody = String.Empty; 776 ResponseBody = String.Empty;
777 RequestModule.GotCompletedRequest(this);
723 } 778 }
724 } 779 }
725 } 780 }
@@ -728,10 +783,12 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest
728 { 783 {
729 try 784 try
730 { 785 {
786 Removed = true;
787 if(WorkItem == null)
788 return;
789
731 if (!WorkItem.Cancel()) 790 if (!WorkItem.Cancel())
732 {
733 WorkItem.Cancel(true); 791 WorkItem.Cancel(true);
734 }
735 } 792 }
736 catch (Exception) 793 catch (Exception)
737 { 794 {