mirror of
https://github.com/opensim/opensim.git
synced 2026-08-05 17:05:55 +08:00
Merge branch 'master' of opensimulator.org:/var/git/opensim
This commit is contained in:
@@ -32,6 +32,7 @@ using System.Collections.Specialized;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using System.Net.Security;
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
using System.Reflection;
|
||||
using System.Globalization;
|
||||
@@ -43,10 +44,11 @@ using log4net;
|
||||
using Nwc.XmlRpc;
|
||||
using OpenMetaverse.StructuredData;
|
||||
using CoolHTTPListener = HttpServer.HttpListener;
|
||||
using HttpListener=System.Net.HttpListener;
|
||||
using LogPrio=HttpServer.LogPrio;
|
||||
using HttpListener = System.Net.HttpListener;
|
||||
using LogPrio = HttpServer.LogPrio;
|
||||
using OpenSim.Framework.Monitoring;
|
||||
using System.IO.Compression;
|
||||
using System.Security.Cryptography;
|
||||
|
||||
namespace OpenSim.Framework.Servers.HttpServer
|
||||
{
|
||||
@@ -107,19 +109,26 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||
new Dictionary<string, WebSocketRequestDelegate>();
|
||||
|
||||
protected uint m_port;
|
||||
protected uint m_sslport;
|
||||
protected bool m_ssl;
|
||||
private X509Certificate2 m_cert;
|
||||
protected bool m_firstcaps = true;
|
||||
protected string m_SSLCommonName = "";
|
||||
protected List<string> m_certNames = new List<string>();
|
||||
protected List<string> m_certIPs = new List<string>();
|
||||
protected string m_certCN= "";
|
||||
protected RemoteCertificateValidationCallback m_certificateValidationCallback = null;
|
||||
|
||||
protected IPAddress m_listenIPAddress = IPAddress.Any;
|
||||
|
||||
public PollServiceRequestManager PollServiceRequestManager { get; private set; }
|
||||
|
||||
public string Protocol
|
||||
{
|
||||
get { return m_ssl ? "https://" : "http://"; }
|
||||
}
|
||||
|
||||
public uint SSLPort
|
||||
{
|
||||
get { return m_sslport; }
|
||||
get { return m_port; }
|
||||
}
|
||||
|
||||
public string SSLCommonName
|
||||
@@ -148,27 +157,166 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||
m_port = port;
|
||||
}
|
||||
|
||||
public BaseHttpServer(uint port, bool ssl) : this (port)
|
||||
private void load_cert(string CPath, string CPass)
|
||||
{
|
||||
m_ssl = ssl;
|
||||
}
|
||||
|
||||
public BaseHttpServer(uint port, bool ssl, uint sslport, string CN) : this (port, ssl)
|
||||
{
|
||||
if (m_ssl)
|
||||
try
|
||||
{
|
||||
m_sslport = sslport;
|
||||
m_cert = new X509Certificate2(CPath, CPass);
|
||||
X509Extension ext = m_cert.Extensions["2.5.29.17"];
|
||||
if(ext != null)
|
||||
{
|
||||
AsnEncodedData asndata = new AsnEncodedData(ext.Oid, ext.RawData);
|
||||
string datastr = asndata.Format(true);
|
||||
string[] lines = datastr.Split(new char[] {'\n','\r'});
|
||||
foreach(string s in lines)
|
||||
{
|
||||
if(String.IsNullOrEmpty(s))
|
||||
continue;
|
||||
string[] parts = s.Split(new char[] {'='});
|
||||
if(String.IsNullOrEmpty(parts[0]))
|
||||
continue;
|
||||
string entryName = parts[0].Replace(" ","");
|
||||
if(entryName == "DNSName")
|
||||
m_certNames.Add(parts[1]);
|
||||
else if(entryName == "IPAddress")
|
||||
m_certIPs.Add(parts[1]);
|
||||
else if(entryName == "Unknown(135)") // stupid mono
|
||||
{
|
||||
try
|
||||
{
|
||||
if(parts[1].Length == 8)
|
||||
{
|
||||
long tmp = long.Parse(parts[1], NumberStyles.AllowHexSpecifier);
|
||||
tmp = IPAddress.HostToNetworkOrder(tmp);
|
||||
tmp = (long)((ulong) tmp >> 32);
|
||||
IPAddress ia = new IPAddress(tmp);
|
||||
m_certIPs.Add(ia.ToString());
|
||||
}
|
||||
}
|
||||
catch {}
|
||||
}
|
||||
}
|
||||
}
|
||||
m_certCN = m_cert.GetNameInfo(X509NameType.SimpleName, false);
|
||||
}
|
||||
catch
|
||||
{
|
||||
throw new Exception("SSL cert load error");
|
||||
}
|
||||
}
|
||||
|
||||
public BaseHttpServer(uint port, bool ssl, string CPath, string CPass) : this (port, ssl)
|
||||
public BaseHttpServer(uint port, bool ssl, string CN, string CPath, string CPass)
|
||||
{
|
||||
if (m_ssl)
|
||||
m_port = port;
|
||||
if (ssl)
|
||||
{
|
||||
m_cert = new X509Certificate2(CPath, CPass);
|
||||
if(string.IsNullOrEmpty(CPath))
|
||||
throw new Exception("invalid main http server cert path");
|
||||
|
||||
if(Uri.CheckHostName(CN) == UriHostNameType.Unknown)
|
||||
throw new Exception("invalid main http server CN (ExternalHostName)");
|
||||
|
||||
m_certNames.Clear();
|
||||
m_certIPs.Clear();
|
||||
m_certCN= "";
|
||||
|
||||
m_ssl = true;
|
||||
load_cert(CPath, CPass);
|
||||
|
||||
if(!CheckSSLCertHost(CN))
|
||||
throw new Exception("invalid main http server CN (ExternalHostName)");
|
||||
|
||||
m_SSLCommonName = CN;
|
||||
|
||||
if(m_cert.Issuer == m_cert.Subject )
|
||||
m_log.Warn("Self signed certificate. Clients need to allow this (some viewers debug option NoVerifySSLcert must be set to true");
|
||||
}
|
||||
else
|
||||
m_ssl = false;
|
||||
}
|
||||
|
||||
public BaseHttpServer(uint port, bool ssl, string CPath, string CPass)
|
||||
{
|
||||
m_port = port;
|
||||
if (ssl)
|
||||
{
|
||||
load_cert(CPath, CPass);
|
||||
if(m_cert.Issuer == m_cert.Subject )
|
||||
m_log.Warn("Self signed certificate. Http clients need to allow this");
|
||||
m_ssl = true;
|
||||
}
|
||||
else
|
||||
m_ssl = false;
|
||||
}
|
||||
|
||||
static bool MatchDNS (string hostname, string dns)
|
||||
{
|
||||
int indx = dns.IndexOf ('*');
|
||||
if (indx == -1)
|
||||
return (String.Compare(hostname, dns, true, CultureInfo.InvariantCulture) == 0);
|
||||
|
||||
int dnslen = dns.Length;
|
||||
dnslen--;
|
||||
if(indx == dnslen)
|
||||
return true; // just * ?
|
||||
|
||||
if(indx > dnslen - 2)
|
||||
return false; // 2 short ?
|
||||
|
||||
if (dns[indx + 1] != '.')
|
||||
return false;
|
||||
|
||||
int indx2 = dns.IndexOf ('*', indx + 1);
|
||||
if (indx2 != -1)
|
||||
return false; // there can only be one;
|
||||
|
||||
string end = dns.Substring(indx + 1);
|
||||
int hostlen = hostname.Length;
|
||||
int endlen = end.Length;
|
||||
int length = hostlen - endlen;
|
||||
if (length <= 0)
|
||||
return false;
|
||||
|
||||
if (String.Compare(hostname, length, end, 0, endlen, true, CultureInfo.InvariantCulture) != 0)
|
||||
return false;
|
||||
|
||||
if (indx == 0)
|
||||
{
|
||||
indx2 = hostname.IndexOf ('.');
|
||||
return ((indx2 == -1) || (indx2 >= length));
|
||||
}
|
||||
|
||||
string start = dns.Substring (0, indx);
|
||||
return (String.Compare (hostname, 0, start, 0, start.Length, true, CultureInfo.InvariantCulture) == 0);
|
||||
}
|
||||
|
||||
public bool CheckSSLCertHost(string hostname)
|
||||
{
|
||||
UriHostNameType htype = Uri.CheckHostName(hostname);
|
||||
|
||||
if(htype == UriHostNameType.Unknown || htype == UriHostNameType.Basic)
|
||||
return false;
|
||||
if(htype == UriHostNameType.Dns)
|
||||
{
|
||||
foreach(string name in m_certNames)
|
||||
{
|
||||
if(MatchDNS(hostname, name))
|
||||
return true;
|
||||
}
|
||||
if(MatchDNS(hostname, m_certCN))
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach(string ip in m_certIPs)
|
||||
{
|
||||
if (String.Compare(hostname, ip, true, CultureInfo.InvariantCulture) == 0)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
/// <summary>
|
||||
/// Add a stream handler to the http server. If the handler already exists, then nothing happens.
|
||||
/// </summary>
|
||||
@@ -396,14 +544,10 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||
if (psEvArgs.Request != null)
|
||||
{
|
||||
OSHttpRequest req = new OSHttpRequest(context, request);
|
||||
|
||||
Stream requestStream = req.InputStream;
|
||||
|
||||
string requestBody;
|
||||
Encoding encoding = Encoding.UTF8;
|
||||
StreamReader reader = new StreamReader(requestStream, encoding);
|
||||
|
||||
string requestBody = reader.ReadToEnd();
|
||||
reader.Close();
|
||||
using(StreamReader reader = new StreamReader(req.InputStream, encoding))
|
||||
requestBody = reader.ReadToEnd();
|
||||
|
||||
Hashtable keysvals = new Hashtable();
|
||||
Hashtable headervals = new Hashtable();
|
||||
@@ -461,8 +605,7 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||
}
|
||||
|
||||
OSHttpResponse resp = new OSHttpResponse(new HttpResponse(context, request),context);
|
||||
resp.ReuseContext = true;
|
||||
// resp.ReuseContext = false;
|
||||
|
||||
HandleRequest(req, resp);
|
||||
|
||||
// !!!HACK ALERT!!!
|
||||
@@ -494,6 +637,8 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||
{
|
||||
try
|
||||
{
|
||||
if(request.InputStream != null && request.InputStream.CanRead)
|
||||
request.InputStream.Close();
|
||||
byte[] buffer500 = SendHTML500(response);
|
||||
response.OutputStream.Write(buffer500, 0, buffer500.Length);
|
||||
response.Send();
|
||||
@@ -541,7 +686,6 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||
// }
|
||||
// }
|
||||
|
||||
//response.KeepAlive = true;
|
||||
response.SendChunked = false;
|
||||
|
||||
string path = request.RawUrl;
|
||||
@@ -565,15 +709,11 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||
{
|
||||
//m_log.Debug("[BASE HTTP SERVER]: Found Caps based HTTP Handler");
|
||||
IGenericHTTPHandler HTTPRequestHandler = requestHandler as IGenericHTTPHandler;
|
||||
Stream requestStream = request.InputStream;
|
||||
|
||||
string requestBody;
|
||||
Encoding encoding = Encoding.UTF8;
|
||||
StreamReader reader = new StreamReader(requestStream, encoding);
|
||||
|
||||
string requestBody = reader.ReadToEnd();
|
||||
|
||||
reader.Close();
|
||||
//requestStream.Close();
|
||||
using(StreamReader reader = new StreamReader(request.InputStream, encoding))
|
||||
requestBody = reader.ReadToEnd();
|
||||
|
||||
Hashtable keysvals = new Hashtable();
|
||||
Hashtable headervals = new Hashtable();
|
||||
@@ -613,7 +753,6 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||
else
|
||||
{
|
||||
IStreamHandler streamHandler = (IStreamHandler)requestHandler;
|
||||
|
||||
using (MemoryStream memoryStream = new MemoryStream())
|
||||
{
|
||||
streamHandler.Handle(path, request.InputStream, memoryStream, request, response);
|
||||
@@ -690,7 +829,8 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||
}
|
||||
}
|
||||
|
||||
request.InputStream.Close();
|
||||
if(request.InputStream != null && request.InputStream.CanRead)
|
||||
request.InputStream.Dispose();
|
||||
|
||||
if (buffer != null)
|
||||
{
|
||||
@@ -723,10 +863,6 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||
requestEndTick = Environment.TickCount;
|
||||
|
||||
response.Send();
|
||||
|
||||
//response.OutputStream.Close();
|
||||
|
||||
//response.FreeContext();
|
||||
}
|
||||
catch (SocketException e)
|
||||
{
|
||||
@@ -758,6 +894,9 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||
}
|
||||
finally
|
||||
{
|
||||
if(request.InputStream != null && request.InputStream.CanRead)
|
||||
request.InputStream.Close();
|
||||
|
||||
// Every month or so this will wrap and give bad numbers, not really a problem
|
||||
// since its just for reporting
|
||||
int tickdiff = requestEndTick - requestStartTick;
|
||||
@@ -998,7 +1137,7 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||
{
|
||||
String requestBody;
|
||||
|
||||
Stream requestStream = request.InputStream;
|
||||
Stream requestStream = Util.Copy(request.InputStream);
|
||||
Stream innerStream = null;
|
||||
try
|
||||
{
|
||||
@@ -1009,15 +1148,15 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||
}
|
||||
|
||||
using (StreamReader reader = new StreamReader(requestStream, Encoding.UTF8))
|
||||
{
|
||||
requestBody = reader.ReadToEnd();
|
||||
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (innerStream != null)
|
||||
if (innerStream != null && innerStream.CanRead)
|
||||
innerStream.Dispose();
|
||||
requestStream.Dispose();
|
||||
if (requestStream.CanRead)
|
||||
requestStream.Dispose();
|
||||
}
|
||||
|
||||
//m_log.Debug(requestBody);
|
||||
@@ -1098,6 +1237,17 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||
|
||||
if (gridproxy)
|
||||
xmlRprcRequest.Params.Add("gridproxy"); // Param[4]
|
||||
|
||||
// reserve this for
|
||||
// ... by Fumi.Iseki for DTLNSLMoneyServer
|
||||
// BUT make its presence possible to detect/parse
|
||||
string rcn = request.IHttpClientContext.SSLCommonName;
|
||||
if(!string.IsNullOrWhiteSpace(rcn))
|
||||
{
|
||||
rcn = "SSLCN:" + rcn;
|
||||
xmlRprcRequest.Params.Add(rcn); // Param[4] or Param[5]
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
xmlRpcResponse = method(xmlRprcRequest, request.RemoteIPEndPoint);
|
||||
@@ -1263,15 +1413,12 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||
//m_log.Warn("[BASE HTTP SERVER]: We've figured out it's a LLSD Request");
|
||||
Stream requestStream = request.InputStream;
|
||||
|
||||
string requestBody;
|
||||
Encoding encoding = Encoding.UTF8;
|
||||
StreamReader reader = new StreamReader(requestStream, encoding);
|
||||
|
||||
string requestBody = reader.ReadToEnd();
|
||||
reader.Close();
|
||||
requestStream.Close();
|
||||
using(StreamReader reader = new StreamReader(requestStream, encoding))
|
||||
requestBody= reader.ReadToEnd();
|
||||
|
||||
//m_log.DebugFormat("[OGP]: {0}:{1}", request.RawUrl, requestBody);
|
||||
response.KeepAlive = true;
|
||||
|
||||
OSD llsdRequest = null;
|
||||
OSD llsdResponse = null;
|
||||
@@ -1592,15 +1739,10 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||
byte[] buffer;
|
||||
|
||||
Stream requestStream = request.InputStream;
|
||||
|
||||
string requestBody;
|
||||
Encoding encoding = Encoding.UTF8;
|
||||
StreamReader reader = new StreamReader(requestStream, encoding);
|
||||
|
||||
string requestBody = reader.ReadToEnd();
|
||||
// avoid warning for now
|
||||
reader.ReadToEnd();
|
||||
reader.Close();
|
||||
requestStream.Close();
|
||||
using(StreamReader reader = new StreamReader(requestStream, encoding))
|
||||
requestBody = reader.ReadToEnd();
|
||||
|
||||
Hashtable keysvals = new Hashtable();
|
||||
Hashtable headervals = new Hashtable();
|
||||
@@ -1792,20 +1934,13 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||
{
|
||||
response.ProtocolVersion = (string)responsedata["http_protocol_version"];
|
||||
}
|
||||
/*
|
||||
|
||||
if (responsedata.ContainsKey("keepalive"))
|
||||
{
|
||||
bool keepalive = (bool)responsedata["keepalive"];
|
||||
response.KeepAlive = keepalive;
|
||||
}
|
||||
|
||||
if (responsedata.ContainsKey("reusecontext"))
|
||||
response.ReuseContext = (bool) responsedata["reusecontext"];
|
||||
*/
|
||||
// disable this things
|
||||
response.KeepAlive = false;
|
||||
response.ReuseContext = false;
|
||||
|
||||
// Cross-Origin Resource Sharing with simple requests
|
||||
if (responsedata.ContainsKey("access_control_allow_origin"))
|
||||
response.AddHeader("Access-Control-Allow-Origin", (string)responsedata["access_control_allow_origin"]);
|
||||
@@ -1818,11 +1953,8 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||
contentType = "text/html";
|
||||
}
|
||||
|
||||
|
||||
|
||||
// The client ignores anything but 200 here for web login, so ensure that this is 200 for that
|
||||
|
||||
|
||||
response.StatusCode = responsecode;
|
||||
|
||||
if (responsecode == (int)OSHttpStatusCode.RedirectMovedPermanently)
|
||||
@@ -1832,13 +1964,12 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||
}
|
||||
|
||||
response.AddHeader("Content-Type", contentType);
|
||||
|
||||
if (responsedata.ContainsKey("headers"))
|
||||
{
|
||||
Hashtable headerdata = (Hashtable)responsedata["headers"];
|
||||
|
||||
foreach (string header in headerdata.Keys)
|
||||
response.AddHeader(header, (string)headerdata[header]);
|
||||
response.AddHeader(header, headerdata[header].ToString());
|
||||
}
|
||||
|
||||
byte[] buffer;
|
||||
@@ -1906,7 +2037,7 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||
|
||||
public void Start()
|
||||
{
|
||||
Start(true);
|
||||
Start(true,true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1916,7 +2047,7 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||
/// If true then poll responses are performed asynchronsly.
|
||||
/// Option exists to allow regression tests to perform processing synchronously.
|
||||
/// </param>
|
||||
public void Start(bool performPollResponsesAsync)
|
||||
public void Start(bool performPollResponsesAsync, bool runPool)
|
||||
{
|
||||
m_log.InfoFormat(
|
||||
"[BASE HTTP SERVER]: Starting {0} server on port {1}", UseSSL ? "HTTPS" : "HTTP", Port);
|
||||
@@ -1945,6 +2076,8 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||
//m_httpListener.Prefixes.Add("https://+:" + (m_sslport) + "/");
|
||||
//m_httpListener.Prefixes.Add("http://+:" + m_port + "/");
|
||||
m_httpListener2 = CoolHTTPListener.Create(IPAddress.Any, (int)m_port, m_cert);
|
||||
if(m_certificateValidationCallback != null)
|
||||
m_httpListener2.CertificateValidationCallback = m_certificateValidationCallback;
|
||||
m_httpListener2.ExceptionThrown += httpServerException;
|
||||
m_httpListener2.LogWriter = httpserverlog;
|
||||
}
|
||||
@@ -1954,9 +2087,11 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||
m_httpListener2.Start(64);
|
||||
|
||||
// Long Poll Service Manager with 3 worker threads a 25 second timeout for no events
|
||||
|
||||
PollServiceRequestManager = new PollServiceRequestManager(this, performPollResponsesAsync, 2, 25000);
|
||||
PollServiceRequestManager.Start();
|
||||
if(runPool)
|
||||
{
|
||||
PollServiceRequestManager = new PollServiceRequestManager(this, performPollResponsesAsync, 2, 25000);
|
||||
PollServiceRequestManager.Start();
|
||||
}
|
||||
|
||||
HTTPDRunning = true;
|
||||
|
||||
@@ -1970,7 +2105,7 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||
catch (Exception e)
|
||||
{
|
||||
m_log.Error("[BASE HTTP SERVER]: Error - " + e.Message);
|
||||
m_log.Error("[BASE HTTP SERVER]: Tip: Do you have permission to listen on port " + m_port + ", " + m_sslport + "?");
|
||||
m_log.Error("[BASE HTTP SERVER]: Tip: Do you have permission to listen on port " + m_port + "?");
|
||||
|
||||
// We want this exception to halt the entire server since in current configurations we aren't too
|
||||
// useful without inbound HTTP.
|
||||
@@ -2028,7 +2163,8 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||
|
||||
try
|
||||
{
|
||||
PollServiceRequestManager.Stop();
|
||||
if(PollServiceRequestManager != null)
|
||||
PollServiceRequestManager.Stop();
|
||||
|
||||
m_httpListener2.ExceptionThrown -= httpServerException;
|
||||
//m_httpListener2.DisconnectHandler = null;
|
||||
@@ -2135,10 +2271,9 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||
string file = Path.Combine(".", "http_500.html");
|
||||
if (!File.Exists(file))
|
||||
return getDefaultHTTP500();
|
||||
|
||||
StreamReader sr = File.OpenText(file);
|
||||
string result = sr.ReadToEnd();
|
||||
sr.Close();
|
||||
string result;
|
||||
using(StreamReader sr = File.OpenText(file))
|
||||
result = sr.ReadToEnd();
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@@ -118,7 +118,7 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||
/// </summary>
|
||||
string StatusDescription { get; set; }
|
||||
|
||||
bool ReuseContext { get; set; }
|
||||
// bool ReuseContext { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Add a header field and content to the response.
|
||||
|
||||
@@ -257,25 +257,6 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||
}
|
||||
}
|
||||
|
||||
public bool ReuseContext
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_httpClientContext != null)
|
||||
{
|
||||
return !_httpClientContext.EndWhenDone;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (_httpClientContext != null)
|
||||
{
|
||||
_httpClientContext.EndWhenDone = !value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected IHttpResponse _httpResponse;
|
||||
private IHttpClientContext _httpClientContext;
|
||||
|
||||
|
||||
@@ -37,6 +37,7 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||
public delegate Hashtable GetEventsMethod(UUID requestID, UUID pId);
|
||||
|
||||
public delegate Hashtable NoEventsMethod(UUID requestID, UUID pId);
|
||||
public delegate void DropMethod(UUID requestID, UUID pId);
|
||||
|
||||
public class PollServiceEventArgs : EventArgs
|
||||
{
|
||||
@@ -44,13 +45,14 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||
public GetEventsMethod GetEvents;
|
||||
public NoEventsMethod NoEvents;
|
||||
public RequestMethod Request;
|
||||
public DropMethod Drop;
|
||||
public UUID Id;
|
||||
public int TimeOutms;
|
||||
public EventType Type;
|
||||
|
||||
public enum EventType : int
|
||||
{
|
||||
LongPoll = 0,
|
||||
Poll = 0,
|
||||
LslHttp = 1,
|
||||
Inventory = 2,
|
||||
Texture = 3,
|
||||
@@ -73,16 +75,17 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||
RequestMethod pRequest,
|
||||
string pUrl,
|
||||
HasEventsMethod pHasEvents, GetEventsMethod pGetEvents, NoEventsMethod pNoEvents,
|
||||
UUID pId, int pTimeOutms)
|
||||
DropMethod pDrop, UUID pId, int pTimeOutms)
|
||||
{
|
||||
Request = pRequest;
|
||||
Url = pUrl;
|
||||
HasEvents = pHasEvents;
|
||||
GetEvents = pGetEvents;
|
||||
NoEvents = pNoEvents;
|
||||
Drop = pDrop;
|
||||
Id = pId;
|
||||
TimeOutms = pTimeOutms;
|
||||
Type = EventType.LongPoll;
|
||||
Type = EventType.Poll;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,8 +47,10 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||
public readonly UUID RequestID;
|
||||
public int contextHash;
|
||||
|
||||
/*
|
||||
private void GenContextHash()
|
||||
{
|
||||
|
||||
Random rnd = new Random();
|
||||
contextHash = 0;
|
||||
if (Request.Headers["remote_addr"] != null)
|
||||
@@ -62,8 +64,9 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||
}
|
||||
else
|
||||
contextHash += rnd.Next() & 0xffff;
|
||||
}
|
||||
|
||||
}
|
||||
*/
|
||||
public PollServiceHttpRequest(
|
||||
PollServiceEventArgs pPollServiceArgs, IHttpClientContext pHttpContext, IHttpRequest pRequest)
|
||||
{
|
||||
@@ -72,7 +75,8 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||
Request = pRequest;
|
||||
RequestTime = System.Environment.TickCount;
|
||||
RequestID = UUID.Random();
|
||||
GenContextHash();
|
||||
// GenContextHash();
|
||||
contextHash = HttpContext.contextID;
|
||||
}
|
||||
|
||||
internal void DoHTTPGruntWork(BaseHttpServer server, Hashtable responsedata)
|
||||
@@ -82,10 +86,12 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||
|
||||
byte[] buffer = server.DoHTTPGruntWork(responsedata, response);
|
||||
|
||||
if(Request.Body.CanRead)
|
||||
Request.Body.Dispose();
|
||||
|
||||
response.SendChunked = false;
|
||||
response.ContentLength64 = buffer.Length;
|
||||
response.ContentEncoding = Encoding.UTF8;
|
||||
response.ReuseContext = false;
|
||||
|
||||
try
|
||||
{
|
||||
@@ -114,10 +120,12 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||
OSHttpResponse response
|
||||
= new OSHttpResponse(new HttpResponse(HttpContext, Request), HttpContext);
|
||||
|
||||
if(Request.Body.CanRead)
|
||||
Request.Body.Dispose();
|
||||
|
||||
response.SendChunked = false;
|
||||
response.ContentLength64 = 0;
|
||||
response.ContentEncoding = Encoding.UTF8;
|
||||
response.ReuseContext = false;
|
||||
response.KeepAlive = false;
|
||||
response.SendChunked = false;
|
||||
response.StatusCode = 503;
|
||||
@@ -127,7 +135,7 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||
response.OutputStream.Flush();
|
||||
response.Send();
|
||||
}
|
||||
catch (Exception e)
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,13 +30,10 @@ using System.Collections;
|
||||
using System.Threading;
|
||||
using System.Reflection;
|
||||
using log4net;
|
||||
using HttpServer;
|
||||
using OpenSim.Framework;
|
||||
using OpenSim.Framework.Monitoring;
|
||||
using Amib.Threading;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Concurrent;
|
||||
|
||||
namespace OpenSim.Framework.Servers.HttpServer
|
||||
{
|
||||
@@ -46,21 +43,18 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||
|
||||
private readonly BaseHttpServer m_server;
|
||||
|
||||
private Dictionary<PollServiceHttpRequest, Queue<PollServiceHttpRequest>> m_bycontext;
|
||||
private BlockingQueue<PollServiceHttpRequest> m_requests = new BlockingQueue<PollServiceHttpRequest>();
|
||||
private static Queue<PollServiceHttpRequest> m_slowRequests = new Queue<PollServiceHttpRequest>();
|
||||
private static Queue<PollServiceHttpRequest> m_retryRequests = new Queue<PollServiceHttpRequest>();
|
||||
private Dictionary<int, Queue<PollServiceHttpRequest>> m_bycontext;
|
||||
private BlockingCollection<PollServiceHttpRequest> m_requests = new BlockingCollection<PollServiceHttpRequest>();
|
||||
private static ConcurrentQueue<PollServiceHttpRequest> m_retryRequests = new ConcurrentQueue<PollServiceHttpRequest>();
|
||||
|
||||
private uint m_WorkerThreadCount = 0;
|
||||
private Thread[] m_workerThreads;
|
||||
private Thread m_retrysThread;
|
||||
|
||||
private bool m_running = false;
|
||||
private int slowCount = 0;
|
||||
|
||||
private SmartThreadPool m_threadPool;
|
||||
|
||||
|
||||
public PollServiceRequestManager(
|
||||
BaseHttpServer pSrv, bool performResponsesAsync, uint pWorkerThreadCount, int pTimeout)
|
||||
{
|
||||
@@ -68,8 +62,7 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||
m_WorkerThreadCount = pWorkerThreadCount;
|
||||
m_workerThreads = new Thread[m_WorkerThreadCount];
|
||||
|
||||
PollServiceHttpRequestComparer preqCp = new PollServiceHttpRequestComparer();
|
||||
m_bycontext = new Dictionary<PollServiceHttpRequest, Queue<PollServiceHttpRequest>>(preqCp);
|
||||
m_bycontext = new Dictionary<int, Queue<PollServiceHttpRequest>>(256);
|
||||
|
||||
STPStartInfo startInfo = new STPStartInfo();
|
||||
startInfo.IdleTimeout = 30000;
|
||||
@@ -80,7 +73,6 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||
startInfo.ThreadPoolName = "PoolService";
|
||||
|
||||
m_threadPool = new SmartThreadPool(startInfo);
|
||||
|
||||
}
|
||||
|
||||
public void Start()
|
||||
@@ -95,7 +87,7 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||
PoolWorkerJob,
|
||||
string.Format("PollServiceWorkerThread {0}:{1}", i, m_server.Port),
|
||||
ThreadPriority.Normal,
|
||||
false,
|
||||
true,
|
||||
false,
|
||||
null,
|
||||
int.MaxValue);
|
||||
@@ -105,36 +97,32 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||
this.CheckRetries,
|
||||
string.Format("PollServiceWatcherThread:{0}", m_server.Port),
|
||||
ThreadPriority.Normal,
|
||||
false,
|
||||
true,
|
||||
true,
|
||||
null,
|
||||
1000 * 60 * 10);
|
||||
|
||||
|
||||
}
|
||||
|
||||
private void ReQueueEvent(PollServiceHttpRequest req)
|
||||
{
|
||||
if (m_running)
|
||||
{
|
||||
lock (m_retryRequests)
|
||||
m_retryRequests.Enqueue(req);
|
||||
}
|
||||
m_retryRequests.Enqueue(req);
|
||||
}
|
||||
|
||||
public void Enqueue(PollServiceHttpRequest req)
|
||||
{
|
||||
Queue<PollServiceHttpRequest> ctxQeueue;
|
||||
int rhash = req.contextHash;
|
||||
lock (m_bycontext)
|
||||
{
|
||||
Queue<PollServiceHttpRequest> ctxQeueue;
|
||||
if (m_bycontext.TryGetValue(req, out ctxQeueue))
|
||||
if (m_bycontext.TryGetValue(rhash, out ctxQeueue))
|
||||
{
|
||||
ctxQeueue.Enqueue(req);
|
||||
}
|
||||
else
|
||||
{
|
||||
ctxQeueue = new Queue<PollServiceHttpRequest>();
|
||||
m_bycontext[req] = ctxQeueue;
|
||||
m_bycontext[rhash] = ctxQeueue;
|
||||
EnqueueInt(req);
|
||||
}
|
||||
}
|
||||
@@ -143,9 +131,10 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||
public void byContextDequeue(PollServiceHttpRequest req)
|
||||
{
|
||||
Queue<PollServiceHttpRequest> ctxQeueue;
|
||||
int rhash = req.contextHash;
|
||||
lock (m_bycontext)
|
||||
{
|
||||
if (m_bycontext.TryGetValue(req, out ctxQeueue))
|
||||
if (m_bycontext.TryGetValue(rhash, out ctxQeueue))
|
||||
{
|
||||
if (ctxQeueue.Count > 0)
|
||||
{
|
||||
@@ -154,51 +143,41 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||
}
|
||||
else
|
||||
{
|
||||
m_bycontext.Remove(req);
|
||||
m_bycontext.Remove(rhash);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void DropByContext(PollServiceHttpRequest req)
|
||||
{
|
||||
Queue<PollServiceHttpRequest> ctxQeueue;
|
||||
int rhash = req.contextHash;
|
||||
lock (m_bycontext)
|
||||
{
|
||||
if (m_bycontext.TryGetValue(rhash, out ctxQeueue))
|
||||
{
|
||||
ctxQeueue.Clear();
|
||||
m_bycontext.Remove(rhash);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void EnqueueInt(PollServiceHttpRequest req)
|
||||
{
|
||||
if (m_running)
|
||||
{
|
||||
if (req.PollServiceArgs.Type != PollServiceEventArgs.EventType.LongPoll)
|
||||
{
|
||||
m_requests.Enqueue(req);
|
||||
}
|
||||
else
|
||||
{
|
||||
lock (m_slowRequests)
|
||||
m_slowRequests.Enqueue(req);
|
||||
}
|
||||
}
|
||||
m_requests.Add(req);
|
||||
}
|
||||
|
||||
private void CheckRetries()
|
||||
{
|
||||
PollServiceHttpRequest preq;
|
||||
while (m_running)
|
||||
|
||||
{
|
||||
Thread.Sleep(100); // let the world move .. back to faster rate
|
||||
Thread.Sleep(100);
|
||||
Watchdog.UpdateThread();
|
||||
lock (m_retryRequests)
|
||||
{
|
||||
while (m_retryRequests.Count > 0 && m_running)
|
||||
m_requests.Enqueue(m_retryRequests.Dequeue());
|
||||
}
|
||||
slowCount++;
|
||||
if (slowCount >= 10)
|
||||
{
|
||||
slowCount = 0;
|
||||
|
||||
lock (m_slowRequests)
|
||||
{
|
||||
while (m_slowRequests.Count > 0 && m_running)
|
||||
m_requests.Enqueue(m_slowRequests.Dequeue());
|
||||
}
|
||||
}
|
||||
while (m_running && m_retryRequests.TryDequeue(out preq))
|
||||
m_requests.Add(preq);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -206,117 +185,130 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||
{
|
||||
m_running = false;
|
||||
|
||||
Thread.Sleep(1000); // let the world move
|
||||
Thread.Sleep(100); // let the world move
|
||||
|
||||
foreach (Thread t in m_workerThreads)
|
||||
Watchdog.AbortThread(t.ManagedThreadId);
|
||||
|
||||
m_threadPool.Shutdown();
|
||||
|
||||
// any entry in m_bycontext should have a active request on the other queues
|
||||
// so just delete contents to easy GC
|
||||
foreach (Queue<PollServiceHttpRequest> qu in m_bycontext.Values)
|
||||
qu.Clear();
|
||||
m_bycontext.Clear();
|
||||
|
||||
PollServiceHttpRequest req;
|
||||
try
|
||||
{
|
||||
foreach (PollServiceHttpRequest req in m_retryRequests)
|
||||
{
|
||||
while(m_retryRequests.TryDequeue(out req))
|
||||
req.DoHTTPstop(m_server);
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
|
||||
PollServiceHttpRequest wreq;
|
||||
m_retryRequests.Clear();
|
||||
|
||||
lock (m_slowRequests)
|
||||
try
|
||||
{
|
||||
while(m_requests.TryTake(out req, 0))
|
||||
req.DoHTTPstop(m_server);
|
||||
}
|
||||
catch
|
||||
{
|
||||
while (m_slowRequests.Count > 0)
|
||||
m_requests.Enqueue(m_slowRequests.Dequeue());
|
||||
|
||||
}
|
||||
|
||||
while (m_requests.Count() > 0)
|
||||
{
|
||||
try
|
||||
{
|
||||
wreq = m_requests.Dequeue(0);
|
||||
wreq.DoHTTPstop(m_server);
|
||||
m_requests.Dispose();
|
||||
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
m_requests.Clear();
|
||||
}
|
||||
|
||||
// work threads
|
||||
|
||||
private void PoolWorkerJob()
|
||||
{
|
||||
PollServiceHttpRequest req;
|
||||
while (m_running)
|
||||
{
|
||||
PollServiceHttpRequest req = m_requests.Dequeue(5000);
|
||||
|
||||
Watchdog.UpdateThread();
|
||||
if (req != null)
|
||||
req = null;
|
||||
if(!m_requests.TryTake(out req, 4500) || req == null)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (req.PollServiceArgs.HasEvents(req.RequestID, req.PollServiceArgs.Id))
|
||||
{
|
||||
Hashtable responsedata = req.PollServiceArgs.GetEvents(req.RequestID, req.PollServiceArgs.Id);
|
||||
Watchdog.UpdateThread();
|
||||
continue;
|
||||
}
|
||||
|
||||
Watchdog.UpdateThread();
|
||||
|
||||
try
|
||||
{
|
||||
if(!req.HttpContext.CanSend())
|
||||
{
|
||||
req.PollServiceArgs.Drop(req.RequestID, req.PollServiceArgs.Id);
|
||||
byContextDequeue(req);
|
||||
continue;
|
||||
}
|
||||
|
||||
if(req.HttpContext.IsSending())
|
||||
{
|
||||
if ((Environment.TickCount - req.RequestTime) > req.PollServiceArgs.TimeOutms)
|
||||
{
|
||||
req.PollServiceArgs.Drop(req.RequestID, req.PollServiceArgs.Id);
|
||||
byContextDequeue(req);
|
||||
}
|
||||
else
|
||||
ReQueueEvent(req);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (req.PollServiceArgs.HasEvents(req.RequestID, req.PollServiceArgs.Id))
|
||||
{
|
||||
PollServiceHttpRequest nreq = req;
|
||||
m_threadPool.QueueWorkItem(x =>
|
||||
{
|
||||
try
|
||||
{
|
||||
Hashtable responsedata = nreq.PollServiceArgs.GetEvents(nreq.RequestID, nreq.PollServiceArgs.Id);
|
||||
nreq.DoHTTPGruntWork(m_server, responsedata);
|
||||
}
|
||||
catch (ObjectDisposedException) { }
|
||||
finally
|
||||
{
|
||||
byContextDequeue(nreq);
|
||||
nreq = null;
|
||||
}
|
||||
return null;
|
||||
}, null);
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((Environment.TickCount - req.RequestTime) > req.PollServiceArgs.TimeOutms)
|
||||
{
|
||||
PollServiceHttpRequest nreq = req;
|
||||
m_threadPool.QueueWorkItem(x =>
|
||||
{
|
||||
try
|
||||
{
|
||||
req.DoHTTPGruntWork(m_server, responsedata);
|
||||
byContextDequeue(req);
|
||||
nreq.DoHTTPGruntWork(m_server,
|
||||
nreq.PollServiceArgs.NoEvents(nreq.RequestID, nreq.PollServiceArgs.Id));
|
||||
}
|
||||
catch (ObjectDisposedException) // Browser aborted before we could read body, server closed the stream
|
||||
catch (ObjectDisposedException) {}
|
||||
finally
|
||||
{
|
||||
// Ignore it, no need to reply
|
||||
byContextDequeue(nreq);
|
||||
nreq = null;
|
||||
}
|
||||
return null;
|
||||
}, null);
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((Environment.TickCount - req.RequestTime) > req.PollServiceArgs.TimeOutms)
|
||||
{
|
||||
m_threadPool.QueueWorkItem(x =>
|
||||
{
|
||||
try
|
||||
{
|
||||
req.DoHTTPGruntWork(m_server,
|
||||
req.PollServiceArgs.NoEvents(req.RequestID, req.PollServiceArgs.Id));
|
||||
byContextDequeue(req);
|
||||
}
|
||||
catch (ObjectDisposedException)
|
||||
{
|
||||
// Ignore it, no need to reply
|
||||
}
|
||||
return null;
|
||||
}, null);
|
||||
}
|
||||
else
|
||||
{
|
||||
ReQueueEvent(req);
|
||||
}
|
||||
ReQueueEvent(req);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
m_log.ErrorFormat("Exception in poll service thread: " + e.ToString());
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
m_log.ErrorFormat("Exception in poll service thread: " + e.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,11 +50,10 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||
|
||||
protected override byte[] ProcessRequest(string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse)
|
||||
{
|
||||
string requestBody;
|
||||
Encoding encoding = Encoding.UTF8;
|
||||
StreamReader streamReader = new StreamReader(request, encoding);
|
||||
|
||||
string requestBody = streamReader.ReadToEnd();
|
||||
streamReader.Close();
|
||||
using(StreamReader streamReader = new StreamReader(request,encoding))
|
||||
requestBody = streamReader.ReadToEnd();
|
||||
|
||||
string param = GetParam(path);
|
||||
string responseString = m_restMethod(requestBody, path, param, httpRequest, httpResponse);
|
||||
|
||||
Reference in New Issue
Block a user