From 79b2e5ac71794dd4e55228e0ac146b527fb71ddf Mon Sep 17 00:00:00 2001
From: Teravus Ovares
Date: Tue, 30 Sep 2008 16:56:33 +0000
Subject: * 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!

---
 .../Framework/Communications/UserManagerBase.cs    |   9 +-
 OpenSim/Framework/Servers/BaseHttpServer.cs        | 272 ++++++++++++++++++---
 OpenSim/Framework/Servers/OSHttpRequest.cs         |  68 +++---
 OpenSim/Framework/Servers/OSHttpResponse.cs        |  30 ++-
 .../Modules/Framework/EventQueueGetModule.cs       |  19 +-
 bin/HttpServer.dll                                 | Bin 143872 -> 139264 bytes
 6 files changed, 302 insertions(+), 96 deletions(-)

diff --git a/OpenSim/Framework/Communications/UserManagerBase.cs b/OpenSim/Framework/Communications/UserManagerBase.cs
index b7f9f5a..aa68367 100644
--- a/OpenSim/Framework/Communications/UserManagerBase.cs
+++ b/OpenSim/Framework/Communications/UserManagerBase.cs
@@ -368,9 +368,12 @@ namespace OpenSim.Framework.Communications
 
             if (request.Params.Count > 1)
             {
-                IPEndPoint RemoteIPEndPoint = (IPEndPoint)request.Params[1];
-                agent.AgentIP = RemoteIPEndPoint.Address.ToString();
-                agent.AgentPort = (uint)RemoteIPEndPoint.Port;
+                if (request.Params[1] != null)
+                {
+                    IPEndPoint RemoteIPEndPoint = (IPEndPoint)request.Params[1];
+                    agent.AgentIP = RemoteIPEndPoint.Address.ToString();
+                    agent.AgentPort = (uint)RemoteIPEndPoint.Port;
+                }
             }
 
             // Generate sessions
diff --git a/OpenSim/Framework/Servers/BaseHttpServer.cs b/OpenSim/Framework/Servers/BaseHttpServer.cs
index 707f621..6090d1f 100644
--- a/OpenSim/Framework/Servers/BaseHttpServer.cs
+++ b/OpenSim/Framework/Servers/BaseHttpServer.cs
@@ -40,7 +40,9 @@ using System.Xml;
 using OpenMetaverse.StructuredData;
 using log4net;
 using Nwc.XmlRpc;
-
+using CoolHTTPListener = HttpServer.HttpListener;
+using IHttpClientContext = HttpServer.IHttpClientContext;
+using IHttpRequest = HttpServer.IHttpRequest;
 
 namespace OpenSim.Framework.Servers
 {
@@ -50,6 +52,7 @@ namespace OpenSim.Framework.Servers
 
         protected Thread m_workerThread;
         protected HttpListener m_httpListener;
+        protected CoolHTTPListener m_httpListener2;
         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 Dictionary<string, LLSDMethod> m_llsdHandlers         = new Dictionary<string, LLSDMethod>();
@@ -102,13 +105,14 @@ namespace OpenSim.Framework.Servers
             m_port = port;
             if (m_ssl)
             {
-                SetupSsl((int)sslport, CN);
+                //SetupSsl((int)sslport, CN);
                 m_sslport = sslport;
             }
         }
 
         
-        
+        /*
+         * 
         public bool SetupSsl(int port, string CN)
         {
             string searchCN = Environment.MachineName.ToUpper();
@@ -211,7 +215,7 @@ namespace OpenSim.Framework.Servers
             }
             
         }
-
+        */
 
         /// <summary>
         /// 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>
-        /// 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>
         /// <param name="stateinfo"></param>
         public virtual void HandleRequest(Object stateinfo)
         {
             // 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
             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);
-                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
                 //  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
@@ -431,12 +547,22 @@ namespace OpenSim.Framework.Servers
                     try
                     {
                         response.OutputStream.Write(buffer, 0, buffer.Length);
-                        response.OutputStream.Close();
+                        //response.OutputStream.Close();
                     }
                     catch (HttpListenerException)
                     {
                         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;
                 }
 
@@ -489,7 +615,7 @@ namespace OpenSim.Framework.Servers
                 // with the minimum first
                 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);
             }
@@ -739,7 +865,16 @@ namespace OpenSim.Framework.Servers
             }
             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.KeepAlive     = false;
                     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)
                 {
@@ -996,6 +1140,10 @@ namespace OpenSim.Framework.Servers
             {
                 response.StatusDescription = (string)responsedata["error_status_text"];
             }
+            if (responsedata.ContainsKey("http_protocol_version"))
+            {
+                response.ProtocolVersion = (string)responsedata["http_protocol_version"];
+            }
 
             if (responsedata.ContainsKey("keepalive"))
             {
@@ -1049,7 +1197,16 @@ namespace OpenSim.Framework.Servers
             }
             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
             {
-                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
             {
-                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_workerThread = new Thread(new ThreadStart(StartHTTP));
-            m_workerThread.Name = "HttpThread";
-            m_workerThread.IsBackground = true;
-            m_workerThread.Start();
-            ThreadTracker.Add(m_workerThread);
+            //m_workerThread = new Thread(new ThreadStart(StartHTTP));
+            //m_workerThread.Name = "HttpThread";
+            //m_workerThread.IsBackground = true;
+            //m_workerThread.Start();
+            //ThreadTracker.Add(m_workerThread);
+            StartHTTP();
         }
 
         private void StartHTTP()
@@ -1123,31 +1299,30 @@ namespace OpenSim.Framework.Servers
             try
             {
                 m_log.Info("[HTTPD]: Spawned main thread OK");
-                m_httpListener = new HttpListener();
-
+                //m_httpListener = new HttpListener();
+                
                 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_httpListener2 = new HttpServer.HttpListener(IPAddress.Any, (int)m_port);
                 }
                 else
                 {
-                    m_httpListener.Prefixes.Add("https://+:" + (m_sslport) + "/");
-                    m_httpListener.Prefixes.Add("http://+:" + m_port + "/");
+                    //m_httpListener.Prefixes.Add("https://+:" + (m_sslport) + "/");
+                    //m_httpListener.Prefixes.Add("http://+:" + m_port + "/");
                 }
-                HttpListenerPrefixCollection prefixs = m_httpListener.Prefixes;
 
-                foreach (string prefix in prefixs)
-                    System.Console.WriteLine("Listening on: " + prefix);
-                
-                m_httpListener.Start();
+                m_httpListener2.RequestHandler += OnHandleRequestIOThread;
+                //m_httpListener.Start();
+                m_httpListener2.Start(5);
 
-                HttpListenerContext context;
-                while (true)
-                {
-                    context = m_httpListener.GetContext();
-                    ThreadPool.QueueUserWorkItem(new WaitCallback(HandleRequest), context);
-                }
+                //HttpListenerContext context;
+                //while (true)
+                //{
+                //    context = m_httpListener.GetContext();
+                //    ThreadPool.QueueUserWorkItem(new WaitCallback(HandleRequest), context);
+               // }
             }
             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>";
         }
     }
+
+    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;
+        }
+
+    }
 }
diff --git a/OpenSim/Framework/Servers/OSHttpRequest.cs b/OpenSim/Framework/Servers/OSHttpRequest.cs
index 9c1053c..28f4337 100644
--- a/OpenSim/Framework/Servers/OSHttpRequest.cs
+++ b/OpenSim/Framework/Servers/OSHttpRequest.cs
@@ -199,40 +199,40 @@ namespace OpenSim.Framework.Servers
             // _isAuthenticated = req.IsAuthenticated;
         }
 
-        // public OSHttpRequest(HttpClientContext context, HttpRequest req)
-        // {
-        //     _context = context;
-        //     _request = req;
-
-        //     _acceptTypes = req.AcceptTypes;
-        //     if (null != req.Headers["content-encoding"])
-        //         _contentEncoding = Encoding.GetEncoding(_request.Headers["content-encoding"]);
-        //     _contentLength64 = req.ContentLength;
-        //     if (null != req.Headers["content-type"])
-        //         _contentType = _request.Headers["content-type"];
-        //     _headers = req.Headers;
-        //     _httpMethod = req.Method;
-        //     _hasbody = req.ContentLength != 0;
-        //     _inputStream = req.Body;
-        //     _keepAlive = ConnectionType.KeepAlive == req.Connection;
-        //     _rawUrl = req.Uri.AbsolutePath;
-        //     _url = req.Uri;
-        //     if (null != req.Headers["user-agent"])
-        //         _userAgent = req.Headers["user-agent"];
-        //     _queryString = new NameValueCollection();
-        //     _query = new Hashtable();
-        //     foreach (KeyValuePair<string, HttpInputItem> q in req.QueryString)
-        //     {
-        //         _queryString.Add(q.Key, q.Value.Value);
-        //         _query[q.Key] = q.Value.Value;
-        //     }
-        //     // TODO: requires change to HttpServer.HttpRequest
-        //     _ipEndPoint = null;
-
-        //     // _cookies = req.Cookies;
-        //     // _isSecureConnection = req.IsSecureConnection;
-        //     // _isAuthenticated = req.IsAuthenticated;
-        // }
+         public OSHttpRequest(HttpServer.IHttpClientContext context, HttpServer.IHttpRequest req)
+         {
+             //_context = context;
+             HttpServer.IHttpRequest _request = req;
+
+             _acceptTypes = req.AcceptTypes;
+             if (null != req.Headers["content-encoding"])
+                 _contentEncoding = Encoding.GetEncoding(_request.Headers["content-encoding"]);
+             _contentLength64 = req.ContentLength;
+             if (null != req.Headers["content-type"])
+                 _contentType = _request.Headers["content-type"];
+             _headers = req.Headers;
+             _httpMethod = req.Method;
+             _hasbody = req.ContentLength != 0;
+             _inputStream = req.Body;
+             _keepAlive = ConnectionType.KeepAlive == req.Connection;
+             _rawUrl = req.Uri.AbsolutePath;
+             _url = req.Uri;
+             if (null != req.Headers["user-agent"])
+                 _userAgent = req.Headers["user-agent"];
+             _queryString = new NameValueCollection();
+             _query = new Hashtable();
+             foreach (KeyValuePair<string, HttpInputItem> q in req.QueryString)
+             {
+                 _queryString.Add(q.Key, q.Value.Value);
+                 _query[q.Key] = q.Value.Value;
+             }
+             // TODO: requires change to HttpServer.HttpRequest
+             _ipEndPoint = null;
+
+             // _cookies = req.Cookies;
+             // _isSecureConnection = req.IsSecureConnection;
+             // _isAuthenticated = req.IsAuthenticated;
+         }
 
         public override string ToString()
         {
diff --git a/OpenSim/Framework/Servers/OSHttpResponse.cs b/OpenSim/Framework/Servers/OSHttpResponse.cs
index f881a22..549ac27 100644
--- a/OpenSim/Framework/Servers/OSHttpResponse.cs
+++ b/OpenSim/Framework/Servers/OSHttpResponse.cs
@@ -200,19 +200,21 @@ namespace OpenSim.Framework.Servers
             }
         }
 
-        public Version ProtocolVersion
+        public string ProtocolVersion
         {
             get
             {
-                if (!HttpServer)
-                    return _httpListenerResponse.ProtocolVersion;
-             
-                return new Version("1.0");
+                if (HttpServer)
+                    return _httpResponse.ProtocolVersion;
+                else
+                    return _httpListenerResponse.ProtocolVersion.ToString();
             }
             set
             {
-                if (!HttpServer)
-                    _httpListenerResponse.ProtocolVersion = value;
+                if (HttpServer)
+                    _httpResponse.ProtocolVersion = value;
+                else
+                    _httpListenerResponse.ProtocolVersion = new Version(value); ;
                 
             }
         }
@@ -321,10 +323,10 @@ namespace OpenSim.Framework.Servers
         private HttpResponse _httpResponse;
         private HttpListenerResponse _httpListenerResponse;
 
-        // internal HttpResponse HttpResponse
-        // {
-        //     get { return _httpResponse; }
-        // }
+        internal HttpResponse HttpResponse
+        {
+             get { return _httpResponse; }
+        }
 
         public OSHttpResponse()
         {
@@ -342,7 +344,10 @@ namespace OpenSim.Framework.Servers
         {
             _httpListenerResponse = resp;
         }
-
+        public OSHttpResponse(HttpServer.HttpResponse resp)
+        {
+            _httpResponse = resp;
+        }
         /// <summary>
         /// Instantiate an OSHttpResponse object from an OSHttpRequest
         /// object.
@@ -378,6 +383,7 @@ namespace OpenSim.Framework.Servers
             {
                 _httpResponse.Body.Flush();
                 _httpResponse.Send();
+                
             }
             else
             {
diff --git a/OpenSim/Region/Environment/Modules/Framework/EventQueueGetModule.cs b/OpenSim/Region/Environment/Modules/Framework/EventQueueGetModule.cs
index 4f4c6ea..c11a4db 100644
--- a/OpenSim/Region/Environment/Modules/Framework/EventQueueGetModule.cs
+++ b/OpenSim/Region/Environment/Modules/Framework/EventQueueGetModule.cs
@@ -224,15 +224,16 @@ namespace OpenSim.Region.Environment.Modules.Framework
             lock (m_ids) 
                 thisID = m_ids[agentID];
 
-            //if (element == null)
-            //{
-            //    responsedata["int_response_code"] = 502;
-            //    responsedata["content_type"] = "text/plain";
-            //    responsedata["keepalive"] = false;
-            //    responsedata["str_response_string"] = "Upstream error: ";
-            //    responsedata["error_status_text"] = "Upstream error:";
-            //    return responsedata;
-            //}
+            if (element == null)
+            {
+                responsedata["int_response_code"] = 502;
+                responsedata["content_type"] = "text/plain";
+                responsedata["keepalive"] = false;
+                responsedata["str_response_string"] = "Upstream error: ";
+                responsedata["error_status_text"] = "Upstream error:";
+                responsedata["http_protocol_version"] = "HTTP/1.0";
+                return responsedata;
+            }
 
             if (thisID == -1) // close-request
             {
diff --git a/bin/HttpServer.dll b/bin/HttpServer.dll
index 55f0609..39860be 100644
Binary files a/bin/HttpServer.dll and b/bin/HttpServer.dll differ
-- 
cgit v1.1