29 using System.Collections.Generic;
32 using System.Net.Mail;
33 using System.Net.Security;
35 using System.Threading;
36 using System.Security.Cryptography.X509Certificates;
39 using OpenSim.Framework;
40 using OpenSim.Framework.Servers;
41 using OpenSim.Framework.Servers.HttpServer;
42 using OpenSim.Region.Framework.Interfaces;
43 using OpenSim.Region.Framework.Scenes;
92 [Extension(Path =
"/OpenSim/RegionModules", NodeName =
"RegionModule", Id =
"HttpRequestModule")]
97 private object HttpListLock =
new object();
98 private int httpTimeout = 30000;
99 private string m_name =
"HttpScriptRequests";
102 private string m_proxyurl =
"";
103 private string m_proxyexcepts =
"";
106 private Dictionary<UUID, HttpRequestClass> m_pendingRequests;
107 private Scene m_scene;
113 ServicePointManager.ServerCertificateValidationCallback +=ValidateServerCertificate;
118 X509Certificate certificate,
120 SslPolicyErrors sslPolicyErrors)
124 if (sender is HttpWebRequest)
126 HttpWebRequest Request = (HttpWebRequest)sender;
127 ServicePoint sp = Request.ServicePoint;
130 if (Request.Headers.Get(
"NoVerifyCert") != null)
136 if ((((
int)sslPolicyErrors) & ~4) != 0)
140 #pragma warning disable 0618
141 if (ServicePointManager.CertificatePolicy != null)
143 return ServicePointManager.CertificatePolicy.CheckValidationResult (sp, certificate, Request, 0);
145 #pragma warning restore 0618
151 if ((((
int)sslPolicyErrors) & ~4) != 0)
156 #region IHttpRequestModule Members
164 uint localID, UUID itemID,
string url, List<string> parameters, Dictionary<string, string> headers,
string body,
167 UUID reqID = UUID.Random();
174 if (parameters != null)
176 string[] parms = parameters.ToArray();
177 for (
int i = 0; i < parms.Length; i += 2)
179 switch (Int32.Parse(parms[i]))
181 case (
int)HttpRequestConstants.HTTP_METHOD:
183 htc.HttpMethod = parms[i + 1];
186 case (
int)HttpRequestConstants.HTTP_MIMETYPE:
188 htc.HttpMIMEType = parms[i + 1];
191 case (
int)HttpRequestConstants.HTTP_BODY_MAXLENGTH:
194 if(
int.TryParse(parms[i + 1], out len))
197 len = HttpRequestClass.HttpBodyMaxLenMAX;
200 htc.HttpBodyMaxLen = len;
204 case (
int)HttpRequestConstants.HTTP_VERIFY_CERT:
205 htc.HttpVerifyCert = (int.Parse(parms[i + 1]) != 0);
208 case (
int)HttpRequestConstants.HTTP_VERBOSE_THROTTLE:
213 case (
int)HttpRequestConstants.HTTP_CUSTOM_HEADER:
220 for (
int count = 1; count <= 8; ++count)
223 if (parms.Length - i < 2)
230 if (Char.IsDigit(parms[i][0]))
233 if (htc.HttpCustomHeaders == null)
234 htc.HttpCustomHeaders =
new List<string>();
236 htc.HttpCustomHeaders.Add(parms[i]);
237 htc.HttpCustomHeaders.Add(parms[i+1]);
243 case (
int)HttpRequestConstants.HTTP_PRAGMA_NO_CACHE:
244 htc.HttpPragmaNoCache = (int.Parse(parms[i + 1]) != 0);
250 htc.RequestModule =
this;
251 htc.LocalID = localID;
255 htc.HttpTimeout = httpTimeout;
256 htc.OutboundBody = body;
257 htc.ResponseHeaders = headers;
258 htc.proxyurl = m_proxyurl;
259 htc.proxyexcepts = m_proxyexcepts;
262 htc.MaxRedirects = 50;
264 if (StartHttpRequest(htc))
266 status = HttpInitialRequestStatus.OK;
271 status = HttpInitialRequestStatus.DISALLOWED_BY_FILTER;
282 return m_outboundUrlFilter.CheckAllowed(url);
287 if (!CheckAllowed(
new Uri(req.
Url)))
292 m_pendingRequests.Add(req.ReqID, req);
302 if (m_pendingRequests != null)
307 if (m_pendingRequests.TryGetValue(m_itemID, out tmpReq))
310 m_pendingRequests.Remove(m_itemID);
329 foreach (
UUID luid
in m_pendingRequests.Keys)
333 if (m_pendingRequests.TryGetValue(luid, out tmpReq))
350 if (m_pendingRequests.TryGetValue(
id, out tmpReq))
354 m_pendingRequests.Remove(id);
361 #region ISharedRegionModule Members
365 m_proxyurl = config.Configs[
"Startup"].GetString(
"HttpProxy");
366 m_proxyexcepts = config.Configs[
"Startup"].GetString(
"HttpProxyExceptions");
368 HttpRequestClass.HttpBodyMaxLenMAX = config.Configs[
"Network"].GetInt(
"HttpBodyMaxLenMAX", 16384);
371 m_outboundUrlFilter =
new OutboundUrlFilter(
"Script HTTP request module", config);
374 IConfig httpConfig = config.Configs[
"HttpRequestModule"];
375 if (httpConfig != null)
377 maxThreads = httpConfig.GetInt(
"MaxPoolThreads", maxThreads);
380 m_pendingRequests =
new Dictionary<UUID, HttpRequestClass>();
383 if (ThreadPool == null)
385 STPStartInfo startInfo =
new STPStartInfo();
386 startInfo.IdleTimeout = 20000;
387 startInfo.MaxWorkerThreads = maxThreads;
388 startInfo.MinWorkerThreads = 1;
389 startInfo.ThreadPriority = ThreadPriority.BelowNormal;
390 startInfo.StartSuspended =
true;
391 startInfo.ThreadPoolName =
"ScriptsHttpReq";
408 if (scene == m_scene)
426 get {
return m_name; }
429 public Type ReplaceableInterface
453 private bool _finished;
456 get {
return _finished; }
459 public static int HttpBodyMaxLenMAX = 16384;
462 public int HttpBodyMaxLen = 2048;
463 public string HttpMethod =
"GET";
464 public string HttpMIMEType =
"text/plain;charset=utf-8";
466 public bool HttpVerifyCert =
true;
467 public IWorkItemResult WorkItem = null;
470 public List<string> HttpCustomHeaders = null;
471 public bool HttpPragmaNoCache =
true;
474 private UUID _itemID;
477 get {
return _itemID; }
478 set { _itemID = value; }
480 private uint _localID;
483 get {
return _localID; }
484 set { _localID = value; }
493 public int Redirects {
get;
private set; }
498 public int MaxRedirects {
get; set; }
504 get {
return _reqID; }
505 set { _reqID = value; }
519 WorkItem = HttpRequestModule.ThreadPool.QueueWorkItem(
new WorkItemCallback(StpSendWrapper), null);
522 private object StpSendWrapper(
object o)
535 HttpWebResponse response = null;
536 Stream resStream = null;
537 byte[] buf =
new byte[HttpBodyMaxLenMAX + 16];
538 string tempString = null;
543 Request = (HttpWebRequest)WebRequest.Create(
Url);
544 Request.AllowAutoRedirect =
false;
547 Request.ServicePoint.Expect100Continue =
false;
549 Request.Method = HttpMethod;
550 Request.ContentType = HttpMIMEType;
556 Request.Headers.Add(
"NoVerifyCert",
"true");
563 if (!HttpPragmaNoCache)
565 Request.Headers.Add(
"Pragma",
"no-cache");
568 if (HttpCustomHeaders != null)
570 for (
int i = 0; i < HttpCustomHeaders.Count; i += 2)
571 Request.Headers.Add(HttpCustomHeaders[i],
572 HttpCustomHeaders[i+1]);
575 if (!
string.IsNullOrEmpty(proxyurl))
577 if (!
string.IsNullOrEmpty(proxyexcepts))
579 string[] elist = proxyexcepts.Split(
';');
580 Request.Proxy =
new WebProxy(proxyurl,
true, elist);
584 Request.Proxy =
new WebProxy(proxyurl,
true);
588 foreach (KeyValuePair<string, string> entry
in ResponseHeaders)
589 if (entry.Key.ToLower().Equals(
"user-agent"))
590 Request.UserAgent = entry.Value;
592 Request.Headers[entry.Key] = entry.Value;
595 if (!
string.IsNullOrEmpty(OutboundBody))
597 byte[] data = Util.UTF8.GetBytes(OutboundBody);
599 Request.ContentLength = data.Length;
600 using (Stream bstream = Request.GetRequestStream())
601 bstream.Write(data, 0, data.Length);
604 Request.Timeout = HttpTimeout;
608 response = (HttpWebResponse) Request.GetResponse();
610 catch (WebException e)
612 if (e.Status != WebExceptionStatus.ProtocolError)
616 response = (HttpWebResponse)e.Response;
619 Status = (int)response.StatusCode;
621 resStream = response.GetResponseStream();
622 int totalBodyBytes = 0;
623 int maxBytes = HttpBodyMaxLen;
624 if(maxBytes > buf.Length)
625 maxBytes = buf.Length;
631 count = resStream.Read(buf, totalBodyBytes, maxBytes - totalBodyBytes);
632 totalBodyBytes += count;
633 if (totalBodyBytes >= maxBytes)
638 if(totalBodyBytes > 0)
640 tempString = Util.UTF8.GetString(buf, 0, totalBodyBytes);
641 ResponseBody = tempString.Replace(
"\r",
"");
646 catch (WebException e)
648 if (e.Status == WebExceptionStatus.ProtocolError)
650 HttpWebResponse webRsp = (HttpWebResponse)((WebException)e).Response;
651 Status = (int)webRsp.StatusCode;
654 using (Stream responseStream = webRsp.GetResponseStream())
656 using (StreamReader reader =
new StreamReader(responseStream))
657 ResponseBody = reader.ReadToEnd();
662 ResponseBody = webRsp.StatusDescription;
668 ResponseBody = e.Message;
671 if (ResponseBody == null)
672 ResponseBody = String.Empty;
683 if (resStream != null)
685 if (response != null)
691 (Status == (
int)HttpStatusCode.MovedPermanently
692 || Status == (int)HttpStatusCode.Found
693 || Status == (
int)HttpStatusCode.SeeOther
694 || Status == (int)HttpStatusCode.TemporaryRedirect))
696 if (Redirects >= MaxRedirects)
699 ResponseBody =
"Number of redirects exceeded max redirects";
704 string location = response.Headers[
"Location"];
706 if (location == null)
709 ResponseBody =
"HTTP redirect code but no location header";
712 else if (!RequestModule.CheckAllowed(
new Uri(location)))
715 ResponseBody =
"URL from HTTP redirect blocked: " + location;
721 Url = response.Headers[
"Location"];
737 if (ResponseBody == null)
738 ResponseBody = String.Empty;
747 if (!WorkItem.Cancel())
749 WorkItem.Cancel(
true);
bool StartHttpRequest(HttpRequestClass req)
void RemoveRegion(Scene scene)
This is called whenever a Scene is removed. For shared modules, this can happen several times...
void StopHttpRequest(uint m_localID, UUID m_itemID)
Stop and remove all http requests for the given script.
void RemoveCompletedRequest(UUID id)
bool CheckAllowed(Uri url)
Would a caller to this module be allowed to make a request to the given URL?
UUID StartHttpRequest(uint localID, UUID itemID, string url, List< string > parameters, Dictionary< string, string > headers, string body, out HttpInitialRequestStatus status)
Starts the http request.
void Initialise(IConfigSource config)
This is called to initialize the region module. For shared modules, this is called exactly once...
void AddRegion(Scene scene)
This is called whenever a Scene is added. For shared modules, this can happen several times...
UUID MakeHttpRequest(string url, string parameters, string body)
Dictionary< string, string > ResponseHeaders
void PostInitialise()
This is called exactly once after all the shared region-modules have been instanciated and IRegionMod...
List< string > ResponseMetadata
void Close()
This is the inverse to Initialise. After a Close(), this instance won't be usable anymore...
Interactive OpenSim region server
HttpInitialRequestStatus
The initial status of the request before it is placed on the wire.
IServiceRequest GetNextCompletedRequest()
void RegionLoaded(Scene scene)
This will be called once for every scene loaded. In a shared module this will be multiple times in on...
static SmartThreadPool ThreadPool
OSHttpStatusCode
HTTP status codes (almost) as defined by W3C in http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html and IETF in http://tools.ietf.org/html/rfc6585
static bool ValidateServerCertificate(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
static int HttpBodyMaxLenMAX