* Replacing Net.HttpListener with HttpServer.

* This is a HUGE update..  and should be considered fraut with peril.
* SSL Mode isn't available *yet* but I'll work on that next.
* DrScofld is still working on a radical new thread pump scheme for this which will be implemented soon.
* This could break the Build!  This could break your Grid!
0.6.0-stable
Teravus Ovares 2008-09-30 16:56:33 +00:00
parent d683fe36ea
commit 79b2e5ac71
6 changed files with 300 additions and 94 deletions

View File

@ -367,11 +367,14 @@ namespace OpenSim.Framework.Communications
agent.AgentOnline = true; agent.AgentOnline = true;
if (request.Params.Count > 1) if (request.Params.Count > 1)
{
if (request.Params[1] != null)
{ {
IPEndPoint RemoteIPEndPoint = (IPEndPoint)request.Params[1]; IPEndPoint RemoteIPEndPoint = (IPEndPoint)request.Params[1];
agent.AgentIP = RemoteIPEndPoint.Address.ToString(); agent.AgentIP = RemoteIPEndPoint.Address.ToString();
agent.AgentPort = (uint)RemoteIPEndPoint.Port; agent.AgentPort = (uint)RemoteIPEndPoint.Port;
} }
}
// Generate sessions // Generate sessions
RNGCryptoServiceProvider rand = new RNGCryptoServiceProvider(); RNGCryptoServiceProvider rand = new RNGCryptoServiceProvider();

View File

@ -40,7 +40,9 @@ using System.Xml;
using OpenMetaverse.StructuredData; using OpenMetaverse.StructuredData;
using log4net; using log4net;
using Nwc.XmlRpc; using Nwc.XmlRpc;
using CoolHTTPListener = HttpServer.HttpListener;
using IHttpClientContext = HttpServer.IHttpClientContext;
using IHttpRequest = HttpServer.IHttpRequest;
namespace OpenSim.Framework.Servers namespace OpenSim.Framework.Servers
{ {
@ -50,6 +52,7 @@ namespace OpenSim.Framework.Servers
protected Thread m_workerThread; protected Thread m_workerThread;
protected HttpListener m_httpListener; protected HttpListener m_httpListener;
protected CoolHTTPListener m_httpListener2;
protected Dictionary<string, XmlRpcMethod> m_rpcHandlers = new Dictionary<string, XmlRpcMethod>(); protected Dictionary<string, XmlRpcMethod> m_rpcHandlers = new Dictionary<string, XmlRpcMethod>();
protected DefaultLLSDMethod m_defaultLlsdHandler = null; // <-- Moving away from the monolithic.. and going to /registered/ protected DefaultLLSDMethod m_defaultLlsdHandler = null; // <-- Moving away from the monolithic.. and going to /registered/
protected Dictionary<string, LLSDMethod> m_llsdHandlers = new Dictionary<string, LLSDMethod>(); protected Dictionary<string, LLSDMethod> m_llsdHandlers = new Dictionary<string, LLSDMethod>();
@ -102,13 +105,14 @@ namespace OpenSim.Framework.Servers
m_port = port; m_port = port;
if (m_ssl) if (m_ssl)
{ {
SetupSsl((int)sslport, CN); //SetupSsl((int)sslport, CN);
m_sslport = sslport; m_sslport = sslport;
} }
} }
/*
*
public bool SetupSsl(int port, string CN) public bool SetupSsl(int port, string CN)
{ {
string searchCN = Environment.MachineName.ToUpper(); string searchCN = Environment.MachineName.ToUpper();
@ -211,7 +215,7 @@ namespace OpenSim.Framework.Servers
} }
} }
*/
/// <summary> /// <summary>
/// Add a stream handler to the http server. If the handler already exists, then nothing happens. /// Add a stream handler to the http server. If the handler already exists, then nothing happens.
@ -308,23 +312,135 @@ namespace OpenSim.Framework.Servers
} }
/// <summary> /// <summary>
/// Handle an individual http request. This method is given to a worker in the thread pool. /// HttpListener Handle an individual http request. This method is given to a worker in the thread pool.
/// </summary> /// </summary>
/// <param name="stateinfo"></param> /// <param name="stateinfo"></param>
public virtual void HandleRequest(Object stateinfo) public virtual void HandleRequest(Object stateinfo)
{ {
// force the culture to en-US // force the culture to en-US
Culture.SetCurrentCulture();
// If we don't catch the exception here it will just disappear into the thread pool and we'll be none the wiser // If we don't catch the exception here it will just disappear into the thread pool and we'll be none the wiser
try try
{ {
HttpListenerContext context = (HttpListenerContext) stateinfo; HttpListenerContext context = (HttpListenerContext)stateinfo;
OSHttpRequest request = new OSHttpRequest(context.Request); OSHttpRequest request = new OSHttpRequest(context.Request);
OSHttpResponse response = new OSHttpResponse(context.Response); OSHttpResponse response = new OSHttpResponse(context.Response);
context.Response.ProtocolVersion = new Version("1.0");
context.Response.KeepAlive = false; HandleRequest(request, response);
}
catch (SocketException e)
{
// At least on linux, it appears that if the client makes a request without requiring the response,
// an unconnected socket exception is thrown when we close the response output stream. There's no
// obvious way to tell if the client didn't require the response, so instead we'll catch and ignore
// the exception instead.
//
// An alternative may be to turn off all response write exceptions on the HttpListener, but let's go
// with the minimum first
m_log.WarnFormat("[BASE HTTP SERVER]: HandleRequest threw {0}.\nNOTE: this may be spurious on Linux", e);
}
catch (Exception e)
{
m_log.ErrorFormat("[BASE HTTP SERVER]: HandleRequest() threw {0}", e);
}
}
/*
/// <summary>
/// HttpListener Handle an individual http request. This method is given to a worker in the thread pool.
/// </summary>
/// <param name="stateinfo"></param>
public virtual void HandleRequestHttpServer(Object stateinfo)
{
// force the culture to en-US
// If we don't catch the exception here it will just disappear into the thread pool and we'll be none the wiser
try
{
HttpServerContextObj context = (HttpServerContextObj)stateinfo;
OSHttpRequest request = new OSHttpRequest(context.Request);
OSHttpResponse response = new OSHttpResponse(context.Response);
HandleRequest(request, response);
}
catch (SocketException e)
{
// At least on linux, it appears that if the client makes a request without requiring the response,
// an unconnected socket exception is thrown when we close the response output stream. There's no
// obvious way to tell if the client didn't require the response, so instead we'll catch and ignore
// the exception instead.
//
// An alternative may be to turn off all response write exceptions on the HttpListener, but let's go
// with the minimum first
m_log.WarnFormat("[BASE HTTP SERVER]: HandleRequest threw {0}.\nNOTE: this may be spurious on Linux", e);
}
catch (Exception e)
{
m_log.ErrorFormat("[BASE HTTP SERVER]: HandleRequest() threw {0}", e);
}
}
*/
public void OnHandleRequestIOThread(IHttpClientContext context, IHttpRequest request)
{
OSHttpRequest req = new OSHttpRequest(context, request);
OSHttpResponse resp = new OSHttpResponse(new HttpServer.HttpResponse(context, request));
//HttpServerContextObj objstate= new HttpServerContextObj(req,resp);
//ThreadPool.QueueUserWorkItem(new WaitCallback(ConvertIHttpClientContextToOSHttp), (object)objstate);
HandleRequest(req, resp);
}
public void ConvertIHttpClientContextToOSHttp(object stateinfo)
{
HttpServerContextObj objstate = (HttpServerContextObj)stateinfo;
//OSHttpRequest request = new OSHttpRequest(objstate.context,objstate.req);
//OSHttpResponse resp = new OSHttpResponse(new HttpServer.HttpResponse(objstate.context, objstate.req));
OSHttpRequest request = objstate.oreq;
OSHttpResponse resp = objstate.oresp;
//OSHttpResponse resp = new OSHttpResponse(new HttpServer.HttpResponse(objstate.context, objstate.req));
/*
request.AcceptTypes = objstate.req.AcceptTypes;
request.ContentLength = (long)objstate.req.ContentLength;
request.Headers = objstate.req.Headers;
request.HttpMethod = objstate.req.Method;
request.InputStream = objstate.req.Body;
foreach (string str in request.Headers)
{
if (str.ToLower().Contains("content-type: "))
{
request.ContentType = str.Substring(13, str.Length - 13);
break;
}
}
//request.KeepAlive = objstate.req.
foreach (HttpServer.HttpInput httpinput in objstate.req.QueryString)
{
request.QueryString.Add(httpinput.Name, httpinput[httpinput.Name]);
}
//request.Query = objstate.req.//objstate.req.QueryString;
//foreach (
//request.QueryString = objstate.req.QueryString;
*/
HandleRequest(request,resp);
}
public virtual void HandleRequest(OSHttpRequest request, OSHttpResponse response)
{
try
{
Culture.SetCurrentCulture();
// This is the REST agent interface. We require an agent to properly identify // This is the REST agent interface. We require an agent to properly identify
// itself. If the REST handler recognizes the prefix it will attempt to // itself. If the REST handler recognizes the prefix it will attempt to
// satisfy the request. If it is not recognizable, and no damage has occurred // satisfy the request. If it is not recognizable, and no damage has occurred
@ -431,12 +547,22 @@ namespace OpenSim.Framework.Servers
try try
{ {
response.OutputStream.Write(buffer, 0, buffer.Length); response.OutputStream.Write(buffer, 0, buffer.Length);
response.OutputStream.Close(); //response.OutputStream.Close();
} }
catch (HttpListenerException) catch (HttpListenerException)
{ {
m_log.WarnFormat("[BASE HTTP SERVER]: HTTP request abnormally terminated."); m_log.WarnFormat("[BASE HTTP SERVER]: HTTP request abnormally terminated.");
} }
//response.OutputStream.Close();
try
{
response.Send();
}
catch (SocketException e)
{
// This has to be here to prevent a Linux/Mono crash
m_log.WarnFormat("[BASE HTTP SERVER] XmlRpcRequest issue {0}.\nNOTE: this may be spurious on Linux.", e);
}
return; return;
} }
@ -489,7 +615,7 @@ namespace OpenSim.Framework.Servers
// with the minimum first // with the minimum first
m_log.WarnFormat("[BASE HTTP SERVER]: HandleRequest threw {0}.\nNOTE: this may be spurious on Linux", e); m_log.WarnFormat("[BASE HTTP SERVER]: HandleRequest threw {0}.\nNOTE: this may be spurious on Linux", e);
} }
catch (Exception e) catch (EndOfStreamException e)
{ {
m_log.ErrorFormat("[BASE HTTP SERVER]: HandleRequest() threw {0}", e); m_log.ErrorFormat("[BASE HTTP SERVER]: HandleRequest() threw {0}", e);
} }
@ -739,7 +865,16 @@ namespace OpenSim.Framework.Servers
} }
finally finally
{ {
response.OutputStream.Close(); //response.OutputStream.Close();
try
{
response.Send();
}
catch (SocketException e)
{
// This has to be here to prevent a Linux/Mono crash
m_log.WarnFormat("[BASE HTTP SERVER] XmlRpcRequest issue {0}.\nNOTE: this may be spurious on Linux.", e);
}
} }
} }
@ -883,7 +1018,16 @@ namespace OpenSim.Framework.Servers
response.SendChunked = false; response.SendChunked = false;
response.KeepAlive = false; response.KeepAlive = false;
response.StatusCode = (int)OSHttpStatusCode.ServerErrorInternalError; response.StatusCode = (int)OSHttpStatusCode.ServerErrorInternalError;
response.OutputStream.Close(); //response.OutputStream.Close();
try
{
response.Send();
}
catch (SocketException f)
{
// This has to be here to prevent a Linux/Mono crash
m_log.WarnFormat("[BASE HTTP SERVER] XmlRpcRequest issue {0}.\nNOTE: this may be spurious on Linux.", f);
}
} }
catch(Exception) catch(Exception)
{ {
@ -996,6 +1140,10 @@ namespace OpenSim.Framework.Servers
{ {
response.StatusDescription = (string)responsedata["error_status_text"]; response.StatusDescription = (string)responsedata["error_status_text"];
} }
if (responsedata.ContainsKey("http_protocol_version"))
{
response.ProtocolVersion = (string)responsedata["http_protocol_version"];
}
if (responsedata.ContainsKey("keepalive")) if (responsedata.ContainsKey("keepalive"))
{ {
@ -1049,7 +1197,16 @@ namespace OpenSim.Framework.Servers
} }
finally finally
{ {
response.OutputStream.Close(); //response.OutputStream.Close();
try
{
response.Send();
}
catch (SocketException e)
{
// This has to be here to prevent a Linux/Mono crash
m_log.WarnFormat("[BASE HTTP SERVER] XmlRpcRequest issue {0}.\nNOTE: this may be spurious on Linux.", e);
}
} }
} }
@ -1077,7 +1234,16 @@ namespace OpenSim.Framework.Servers
} }
finally finally
{ {
response.OutputStream.Close(); //response.OutputStream.Close();
try
{
response.Send();
}
catch (SocketException e)
{
// This has to be here to prevent a Linux/Mono crash
m_log.WarnFormat("[BASE HTTP SERVER] XmlRpcRequest issue {0}.\nNOTE: this may be spurious on Linux.", e);
}
} }
} }
@ -1103,7 +1269,16 @@ namespace OpenSim.Framework.Servers
} }
finally finally
{ {
response.OutputStream.Close(); //response.OutputStream.Close();
try
{
response.Send();
}
catch (SocketException e)
{
// This has to be here to prevent a Linux/Mono crash
m_log.WarnFormat("[BASE HTTP SERVER] XmlRpcRequest issue {0}.\nNOTE: this may be spurious on Linux.", e);
}
} }
} }
@ -1111,11 +1286,12 @@ namespace OpenSim.Framework.Servers
{ {
m_log.Info("[HTTPD]: Starting up HTTP Server"); m_log.Info("[HTTPD]: Starting up HTTP Server");
m_workerThread = new Thread(new ThreadStart(StartHTTP)); //m_workerThread = new Thread(new ThreadStart(StartHTTP));
m_workerThread.Name = "HttpThread"; //m_workerThread.Name = "HttpThread";
m_workerThread.IsBackground = true; //m_workerThread.IsBackground = true;
m_workerThread.Start(); //m_workerThread.Start();
ThreadTracker.Add(m_workerThread); //ThreadTracker.Add(m_workerThread);
StartHTTP();
} }
private void StartHTTP() private void StartHTTP()
@ -1123,31 +1299,30 @@ namespace OpenSim.Framework.Servers
try try
{ {
m_log.Info("[HTTPD]: Spawned main thread OK"); m_log.Info("[HTTPD]: Spawned main thread OK");
m_httpListener = new HttpListener(); //m_httpListener = new HttpListener();
if (!m_ssl) if (!m_ssl)
{ {
m_httpListener.Prefixes.Add("http://+:" + m_port + "/"); //m_httpListener.Prefixes.Add("http://+:" + m_port + "/");
//m_httpListener.Prefixes.Add("http://10.1.1.5:" + m_port + "/"); //m_httpListener.Prefixes.Add("http://10.1.1.5:" + m_port + "/");
m_httpListener2 = new HttpServer.HttpListener(IPAddress.Any, (int)m_port);
} }
else else
{ {
m_httpListener.Prefixes.Add("https://+:" + (m_sslport) + "/"); //m_httpListener.Prefixes.Add("https://+:" + (m_sslport) + "/");
m_httpListener.Prefixes.Add("http://+:" + m_port + "/"); //m_httpListener.Prefixes.Add("http://+:" + m_port + "/");
} }
HttpListenerPrefixCollection prefixs = m_httpListener.Prefixes;
foreach (string prefix in prefixs) m_httpListener2.RequestHandler += OnHandleRequestIOThread;
System.Console.WriteLine("Listening on: " + prefix); //m_httpListener.Start();
m_httpListener2.Start(5);
m_httpListener.Start(); //HttpListenerContext context;
//while (true)
HttpListenerContext context; //{
while (true) // context = m_httpListener.GetContext();
{ // ThreadPool.QueueUserWorkItem(new WaitCallback(HandleRequest), context);
context = m_httpListener.GetContext(); // }
ThreadPool.QueueUserWorkItem(new WaitCallback(HandleRequest), context);
}
} }
catch (Exception e) catch (Exception e)
{ {
@ -1244,4 +1419,25 @@ namespace OpenSim.Framework.Servers
return "<HTML><HEAD><TITLE>500 Internal Server Error</TITLE><BODY><BR /><H1>Ooops!</H1><P>The server you requested is overun by knomes! Find hippos quick!</P></BODY></HTML>"; return "<HTML><HEAD><TITLE>500 Internal Server Error</TITLE><BODY><BR /><H1>Ooops!</H1><P>The server you requested is overun by knomes! Find hippos quick!</P></BODY></HTML>";
} }
} }
public class HttpServerContextObj
{
public IHttpClientContext context = null;
public IHttpRequest req = null;
public OSHttpRequest oreq = null;
public OSHttpResponse oresp = null;
public HttpServerContextObj(IHttpClientContext contxt, IHttpRequest reqs)
{
context = contxt;
req = reqs;
}
public HttpServerContextObj(OSHttpRequest osreq, OSHttpResponse osresp)
{
oreq = osreq;
oresp = osresp;
}
}
} }

View File

@ -199,40 +199,40 @@ namespace OpenSim.Framework.Servers
// _isAuthenticated = req.IsAuthenticated; // _isAuthenticated = req.IsAuthenticated;
} }
// public OSHttpRequest(HttpClientContext context, HttpRequest req) public OSHttpRequest(HttpServer.IHttpClientContext context, HttpServer.IHttpRequest req)
// { {
// _context = context; //_context = context;
// _request = req; HttpServer.IHttpRequest _request = req;
// _acceptTypes = req.AcceptTypes; _acceptTypes = req.AcceptTypes;
// if (null != req.Headers["content-encoding"]) if (null != req.Headers["content-encoding"])
// _contentEncoding = Encoding.GetEncoding(_request.Headers["content-encoding"]); _contentEncoding = Encoding.GetEncoding(_request.Headers["content-encoding"]);
// _contentLength64 = req.ContentLength; _contentLength64 = req.ContentLength;
// if (null != req.Headers["content-type"]) if (null != req.Headers["content-type"])
// _contentType = _request.Headers["content-type"]; _contentType = _request.Headers["content-type"];
// _headers = req.Headers; _headers = req.Headers;
// _httpMethod = req.Method; _httpMethod = req.Method;
// _hasbody = req.ContentLength != 0; _hasbody = req.ContentLength != 0;
// _inputStream = req.Body; _inputStream = req.Body;
// _keepAlive = ConnectionType.KeepAlive == req.Connection; _keepAlive = ConnectionType.KeepAlive == req.Connection;
// _rawUrl = req.Uri.AbsolutePath; _rawUrl = req.Uri.AbsolutePath;
// _url = req.Uri; _url = req.Uri;
// if (null != req.Headers["user-agent"]) if (null != req.Headers["user-agent"])
// _userAgent = req.Headers["user-agent"]; _userAgent = req.Headers["user-agent"];
// _queryString = new NameValueCollection(); _queryString = new NameValueCollection();
// _query = new Hashtable(); _query = new Hashtable();
// foreach (KeyValuePair<string, HttpInputItem> q in req.QueryString) foreach (KeyValuePair<string, HttpInputItem> q in req.QueryString)
// { {
// _queryString.Add(q.Key, q.Value.Value); _queryString.Add(q.Key, q.Value.Value);
// _query[q.Key] = q.Value.Value; _query[q.Key] = q.Value.Value;
// } }
// // TODO: requires change to HttpServer.HttpRequest // TODO: requires change to HttpServer.HttpRequest
// _ipEndPoint = null; _ipEndPoint = null;
// // _cookies = req.Cookies; // _cookies = req.Cookies;
// // _isSecureConnection = req.IsSecureConnection; // _isSecureConnection = req.IsSecureConnection;
// // _isAuthenticated = req.IsAuthenticated; // _isAuthenticated = req.IsAuthenticated;
// } }
public override string ToString() public override string ToString()
{ {

View File

@ -200,19 +200,21 @@ namespace OpenSim.Framework.Servers
} }
} }
public Version ProtocolVersion public string ProtocolVersion
{ {
get get
{ {
if (!HttpServer) if (HttpServer)
return _httpListenerResponse.ProtocolVersion; return _httpResponse.ProtocolVersion;
else
return new Version("1.0"); return _httpListenerResponse.ProtocolVersion.ToString();
} }
set set
{ {
if (!HttpServer) if (HttpServer)
_httpListenerResponse.ProtocolVersion = value; _httpResponse.ProtocolVersion = value;
else
_httpListenerResponse.ProtocolVersion = new Version(value); ;
} }
} }
@ -321,10 +323,10 @@ namespace OpenSim.Framework.Servers
private HttpResponse _httpResponse; private HttpResponse _httpResponse;
private HttpListenerResponse _httpListenerResponse; private HttpListenerResponse _httpListenerResponse;
// internal HttpResponse HttpResponse internal HttpResponse HttpResponse
// { {
// get { return _httpResponse; } get { return _httpResponse; }
// } }
public OSHttpResponse() public OSHttpResponse()
{ {
@ -342,7 +344,10 @@ namespace OpenSim.Framework.Servers
{ {
_httpListenerResponse = resp; _httpListenerResponse = resp;
} }
public OSHttpResponse(HttpServer.HttpResponse resp)
{
_httpResponse = resp;
}
/// <summary> /// <summary>
/// Instantiate an OSHttpResponse object from an OSHttpRequest /// Instantiate an OSHttpResponse object from an OSHttpRequest
/// object. /// object.
@ -378,6 +383,7 @@ namespace OpenSim.Framework.Servers
{ {
_httpResponse.Body.Flush(); _httpResponse.Body.Flush();
_httpResponse.Send(); _httpResponse.Send();
} }
else else
{ {

View File

@ -224,15 +224,16 @@ namespace OpenSim.Region.Environment.Modules.Framework
lock (m_ids) lock (m_ids)
thisID = m_ids[agentID]; thisID = m_ids[agentID];
//if (element == null) if (element == null)
//{ {
// responsedata["int_response_code"] = 502; responsedata["int_response_code"] = 502;
// responsedata["content_type"] = "text/plain"; responsedata["content_type"] = "text/plain";
// responsedata["keepalive"] = false; responsedata["keepalive"] = false;
// responsedata["str_response_string"] = "Upstream error: "; responsedata["str_response_string"] = "Upstream error: ";
// responsedata["error_status_text"] = "Upstream error:"; responsedata["error_status_text"] = "Upstream error:";
// return responsedata; responsedata["http_protocol_version"] = "HTTP/1.0";
//} return responsedata;
}
if (thisID == -1) // close-request if (thisID == -1) // close-request
{ {

Binary file not shown.