diff --git a/OpenSim/Framework/Servers/BaseHttpServer.cs b/OpenSim/Framework/Servers/BaseHttpServer.cs index eeb63e1035..51cb36eaec 100644 --- a/OpenSim/Framework/Servers/BaseHttpServer.cs +++ b/OpenSim/Framework/Servers/BaseHttpServer.cs @@ -49,8 +49,9 @@ namespace OpenSim.Framework.Servers protected HttpListener m_httpListener; protected Dictionary m_rpcHandlers = new Dictionary(); protected LLSDMethod m_llsdHandler = null; - protected Dictionary m_streamHandlers = new Dictionary(); - protected Dictionary m_HTTPHandlers = new Dictionary(); + protected Dictionary m_streamHandlers = new Dictionary(); + protected Dictionary m_HTTPHandlers = new Dictionary(); + protected Dictionary m_agentHandlers = new Dictionary(); protected uint m_port; protected bool m_ssl = false; @@ -119,6 +120,18 @@ namespace OpenSim.Framework.Servers return false; } + public bool AddAgentHandler(string agent, IHttpAgentHandler handler) + { + if (!m_agentHandlers.ContainsKey(agent)) + { + m_agentHandlers.Add(agent, handler); + return true; + } + + //must already have a handler for that path so return false + return false; + } + public bool SetLLSDHandler(LLSDMethod handler) { m_llsdHandler = handler; @@ -139,30 +152,43 @@ namespace OpenSim.Framework.Servers OSHttpRequest request = new OSHttpRequest(context.Request); OSHttpResponse response = new OSHttpResponse(context.Response); - response.KeepAlive = false; + if (request.UserAgent != null) + { + + IHttpAgentHandler agentHandler; + + if (TryGetAgentHandler(request.UserAgent, out agentHandler)) + { + m_log.DebugFormat("[HTTP-AGENT] Handler located for {0}", request.UserAgent); + HandleAgentRequest(agentHandler, request, response); + } + return; + } + + IRequestHandler requestHandler; + response.KeepAlive = false; response.SendChunked = false; string path = request.RawUrl; string handlerKey = GetHandlerKey(request.HttpMethod, path); //m_log.DebugFormat("[BASE HTTP SERVER]: Handling {0} request for {1}", request.HttpMethod, path); - - IRequestHandler requestHandler; - + if (TryGetStreamHandler(handlerKey, out requestHandler)) { + // Okay, so this is bad, but should be considered temporary until everything is IStreamHandler. byte[] buffer; if (requestHandler is IStreamedRequestHandler) { IStreamedRequestHandler streamedRequestHandler = requestHandler as IStreamedRequestHandler; - + buffer = streamedRequestHandler.Handle(path, request.InputStream, request, response); } else { IStreamHandler streamHandler = (IStreamHandler) requestHandler; - + using (MemoryStream memoryStream = new MemoryStream()) { streamHandler.Handle(path, request.InputStream, memoryStream, request, response); @@ -170,11 +196,11 @@ namespace OpenSim.Framework.Servers buffer = memoryStream.ToArray(); } } - + request.InputStream.Close(); if (!response.IsContentTypeSet) response.ContentType = requestHandler.ContentType; response.ContentLength64 = buffer.LongLength; - + try { response.OutputStream.Write(buffer, 0, buffer.Length); @@ -184,24 +210,25 @@ namespace OpenSim.Framework.Servers { m_log.WarnFormat("[BASE HTTP SERVER]: HTTP request abnormally terminated."); } + return; } - else + + switch (request.ContentType) { - switch (request.ContentType) - { - case null: - case "text/html": - HandleHTTPRequest(request, response); - break; - case "application/xml+llsd": - HandleLLSDRequests(request, response); - break; - case "text/xml": - case "application/xml": - default: - HandleXmlRpcRequests(request, response); - break; - } + case null: + case "text/html": + HandleHTTPRequest(request, response); + return; + + case "application/xml+llsd": + HandleLLSDRequests(request, response); + return; + + case "text/xml": + case "application/xml": + default: + HandleXmlRpcRequests(request, response); + return; } } catch (SocketException) @@ -274,6 +301,26 @@ namespace OpenSim.Framework.Servers } } + private bool TryGetAgentHandler(string agent, out IHttpAgentHandler agentHandler) + { + agentHandler = null; + try + { + foreach(IHttpAgentHandler handler in m_agentHandlers.Values) + { + if(handler.Match(agent)) + { + agentHandler = handler; + return true; + } + } + } + catch(KeyNotFoundException) {} + + return false; + + } + /// /// Try all the registered xmlrpc handlers when an xmlrpc request is received. /// Sends back an XMLRPC unknown request response if no handler is registered for the requested method. @@ -416,6 +463,36 @@ namespace OpenSim.Framework.Servers } } + /// + /// A specific agent handler was provided. Such a handler is expecetd to have an + /// intimate, and highly specific relationship with the client. Consequently, + /// nothing is done here. + /// + /// + /// + /// + + private void HandleAgentRequest(IHttpAgentHandler handler, OSHttpRequest request, OSHttpResponse response) + { + + // In the case of REST, then handler is responsible for ALL aspects of + // the request/response handling. Nothing is done here, not even encoding. + + try + { + handler.Handle(request, response); + } + catch (Exception e) + { + m_log.Warn("[HTTP-AGENT]: Error - " + e.Message); + response.SendChunked = false; + response.KeepAlive = false; + response.StatusCode = 500; + response.OutputStream.Close(); + } + + } + public void HandleHTTPRequest(OSHttpRequest request, OSHttpResponse response) { switch (request.HttpMethod) diff --git a/OpenSim/Framework/Servers/IHttpAgentHandler.cs b/OpenSim/Framework/Servers/IHttpAgentHandler.cs new file mode 100644 index 0000000000..9bca150369 --- /dev/null +++ b/OpenSim/Framework/Servers/IHttpAgentHandler.cs @@ -0,0 +1,39 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSim Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System.Collections; +using System.IO; +using System.Net; + +namespace OpenSim.Framework.Servers +{ + public interface IHttpAgentHandler + { + void Handle(OSHttpRequest req, OSHttpResponse resp); + bool Match(string agent); + } +}