From ed4241583f60ff43209b7c6e7c966efc6d96280e Mon Sep 17 00:00:00 2001 From: Dr Scofield Date: Thu, 17 Jul 2008 12:54:15 +0000 Subject: [PATCH] morphing OSHttpHandler interface into an abstract base class. adding HTTP method matching support. adapting OSHttpXmlRpcHandler accordingly. dropping OSHttpXmlProcessor delegate in favour of good old XmlRpcMethodHandler delegate (was the same signature). --- OpenSim/Framework/Servers/OSHttpHandler.cs | 99 +++++++++++++++---- .../Framework/Servers/OSHttpRequestPump.cs | 58 ++++------- .../Framework/Servers/OSHttpXmlRpcHandler.cs | 60 ++--------- 3 files changed, 108 insertions(+), 109 deletions(-) diff --git a/OpenSim/Framework/Servers/OSHttpHandler.cs b/OpenSim/Framework/Servers/OSHttpHandler.cs index a9f42f3e92..8b65438893 100644 --- a/OpenSim/Framework/Servers/OSHttpHandler.cs +++ b/OpenSim/Framework/Servers/OSHttpHandler.cs @@ -27,6 +27,7 @@ using System; using System.Collections.Generic; +using System.IO; using System.Text.RegularExpressions; namespace OpenSim.Framework.Servers @@ -43,16 +44,10 @@ namespace OpenSim.Framework.Servers /// handler did not process the request /// /// - /// Handled + /// Done /// handler did process the request, OSHttpServer /// can clean up and close the request /// - /// - /// Detached - /// handler handles the request, OSHttpServer - /// can forget about the request and should not touch it as - /// the handler has taken control - /// /// /// public enum OSHttpHandlerResult @@ -71,26 +66,41 @@ namespace OpenSim.Framework.Servers /// false otherwise public delegate bool OSHttpContentTypeChecker(OSHttpRequest req); - public interface OSHttpHandler + public abstract class OSHttpHandler { /// - /// Regular expression used to match against path of incoming - /// HTTP request. If you want to match any string either use - /// '.*' or null. To match for the emtpy string use '^$' + /// Regular expression used to match against method of + /// the incoming HTTP request. If you want to match any string + /// either use '.*' or null. To match on the empty string use + /// '^$'. /// - Regex Path + public virtual Regex Method { - get; + get { return _method; } } + protected Regex _method; + + /// + /// Regular expression used to match against path of the + /// incoming HTTP request. If you want to match any string + /// either use '.*' or null. To match on the emtpy string use + /// '^$'. + /// + public virtual Regex Path + { + get { return _path; } + } + protected Regex _path; /// /// Dictionary of (header name, regular expression) tuples, /// allowing us to match on HTTP header fields. /// - Dictionary Headers + public virtual Dictionary Headers { - get; + get { return _headers; } } + protected Dictionary _headers; /// /// Dictionary of (header name, regular expression) tuples, @@ -101,10 +111,11 @@ namespace OpenSim.Framework.Servers /// (trivial) changes to HttpServer.HttpListener that have not /// been implemented. /// - Regex IPEndPointWhitelist + public virtual Regex IPEndPointWhitelist { - get; + get { return _ipEndPointRegex; } } + protected Regex _ipEndPointRegex; /// @@ -114,11 +125,59 @@ namespace OpenSim.Framework.Servers /// /// true if the handler is interested in the content; /// false otherwise - OSHttpContentTypeChecker ContentTypeChecker + internal virtual OSHttpContentTypeChecker ContentTypeChecker { - get; + get { return null; } } - OSHttpHandlerResult Process(OSHttpRequest request); + /// + /// Base class constructor. + /// + /// null or path regex + /// null or dictionary of header + /// regexs + /// null or content type + /// regex + /// null or IP address regex + public OSHttpHandler(Regex method, Regex path, Dictionary headers, Regex contentType, Regex whitelist) + { + _method = method; + _path = path; + _ipEndPointRegex = whitelist; + + if (null == _headers && null != contentType) + { + _headers = new Dictionary(); + _headers.Add("content-type", contentType); + } + } + + + /// + /// Process an incoming OSHttpRequest that matched our + /// requirements. + /// + /// + /// OSHttpHandlerResult.Pass if we are after all not + /// interested in the request; OSHttpHandlerResult.Done if we + /// did process the request. + /// + public abstract OSHttpHandlerResult Process(OSHttpRequest request); + + public override string ToString() + { + StringWriter sw = new StringWriter(); + sw.WriteLine("{0}", base.ToString()); + sw.WriteLine(" method regex {0}", null == Method ? "null" : Method.ToString()); + sw.WriteLine(" path regex {0}", null == Path ? "null": Path.ToString()); + foreach (string tag in Headers.Keys) + { + sw.WriteLine(" header {0} : {1}", tag, Headers[tag].ToString()); + } + sw.WriteLine(" IP whitelist {0}", null == IPEndPointWhitelist ? "null" : IPEndPointWhitelist.ToString()); + sw.WriteLine(); + sw.Close(); + return sw.ToString(); + } } } \ No newline at end of file diff --git a/OpenSim/Framework/Servers/OSHttpRequestPump.cs b/OpenSim/Framework/Servers/OSHttpRequestPump.cs index be4c3ffb54..d05e70673d 100644 --- a/OpenSim/Framework/Servers/OSHttpRequestPump.cs +++ b/OpenSim/Framework/Servers/OSHttpRequestPump.cs @@ -175,6 +175,7 @@ namespace OpenSim.Framework.Servers _log.DebugFormat("[{0}] MatchHandlers for {1}", EngineID, req); foreach (OSHttpHandler h in handlers) { + Regex methodRegex = h.Method; Regex pathRegex = h.Path; Dictionary headerRegexs = h.Headers; Regex endPointsRegex = h.IPEndPointWhitelist; @@ -198,10 +199,18 @@ namespace OpenSim.Framework.Servers } } + if (null != methodRegex) + { + Match m = methodRegex.Match(req.HttpMethod); + if (!m.Success) continue; + + scoredHandlers[h]++; + } + // whitelist ok, now check path if (null != pathRegex) { - Match m = pathRegex.Match(req.HttpRequest.Uri.AbsolutePath); + Match m = pathRegex.Match(req.RawUrl); if (!m.Success) continue; scoredHandlers[h] = m.ToString().Length; @@ -227,8 +236,7 @@ namespace OpenSim.Framework.Servers { // no: remove the handler if it was added // earlier and on to the next one - _LogDumpOSHttpHandler(String.Format("[{0}] dropping handler for {1}: null {2} header field", - EngineID, req, tag), h); + _log.DebugFormat("[{0}] dropping handler for {1}: null {2} header field: {3}", EngineID, req, tag, h); scoredHandlers.Remove(h); break; @@ -240,8 +248,8 @@ namespace OpenSim.Framework.Servers if (!hm.Success) { // no: remove the handler if it was added // earlier and on to the next one - _LogDumpOSHttpHandler(String.Format("[{0}] dropping handler for {1}: {2} header field content \"{3}\" does not match regex {4}", - EngineID, req, tag, headers[tag], headerRegexs[tag].ToString()), h); + _log.DebugFormat("[{0}] dropping handler for {1}: {2} header field content \"{3}\" does not match regex {4}: {5}", + EngineID, req, tag, headers[tag], headerRegexs[tag].ToString(), h); scoredHandlers.Remove(h); break; } @@ -252,14 +260,13 @@ namespace OpenSim.Framework.Servers if ((null != h.ContentTypeChecker) && !h.ContentTypeChecker(req)) { scoredHandlers.Remove(h); - _LogDumpOSHttpHandler(String.Format("[{0}] dropping handler for {1}: content checker returned false", - EngineID, req), h); + _log.DebugFormat("[{0}] dropping handler for {1}: content checker returned false: {2}", EngineID, req, h); break; } // ok: header matches headersMatch++; - _LogDumpOSHttpHandler(String.Format("[{0}] MatchHandlers: found handler for {1}", EngineID, req), h); + _log.DebugFormat("[{0}] MatchHandlers: found handler for {1}: {2}", EngineID, req, h.ToString()); continue; } // check whether h got kicked out @@ -269,48 +276,21 @@ namespace OpenSim.Framework.Servers } } - foreach (OSHttpHandler hh in scoredHandlers.Keys) - { - _LogDumpOSHttpHandler("scoredHandlers:", hh); - } - List matchingHandlers = new List(scoredHandlers.Keys); - _LogDumpOSHttpHandlerList("before sort: ", matchingHandlers); matchingHandlers.Sort(delegate(OSHttpHandler x, OSHttpHandler y) { return scoredHandlers[x] - scoredHandlers[y]; }); - - _LogDumpOSHttpHandlerList("after sort: ", matchingHandlers); - + LogDumpHandlerList(matchingHandlers); return matchingHandlers; } [ConditionalAttribute("DEBUGGING")] - private void _LogDumpOSHttpHandler(string msg, OSHttpHandler h) + private void LogDumpHandlerList(List l) { - _log.Debug(msg); - - StringWriter sw = new StringWriter(); - sw.WriteLine("{0}", h.ToString()); - sw.WriteLine(" path regex {0}", null == h.Path ? "null": h.Path.ToString()); - foreach (string tag in h.Headers.Keys) - { - sw.WriteLine(" header[{0}] {1}", tag, h.Headers[tag].ToString()); - } - sw.WriteLine(" IP whitelist {0}", null == h.IPEndPointWhitelist ? "null" : h.IPEndPointWhitelist.ToString()); - sw.WriteLine(); - sw.Close(); - - _log.Debug(sw.ToString()); - } - - [ConditionalAttribute("DEBUGGING")] - private void _LogDumpOSHttpHandlerList(string msg, List l) - { - _log.DebugFormat("OSHttpHandlerList dump: {0}", msg); + _log.DebugFormat("[{0}] OSHttpHandlerList dump:", EngineID); foreach (OSHttpHandler h in l) - _LogDumpOSHttpHandler("OSHttpHandler", h); + _log.DebugFormat(" ", h.ToString()); } } } diff --git a/OpenSim/Framework/Servers/OSHttpXmlRpcHandler.cs b/OpenSim/Framework/Servers/OSHttpXmlRpcHandler.cs index 420554774e..f9ce5b1ba4 100644 --- a/OpenSim/Framework/Servers/OSHttpXmlRpcHandler.cs +++ b/OpenSim/Framework/Servers/OSHttpXmlRpcHandler.cs @@ -44,42 +44,6 @@ namespace OpenSim.Framework.Servers { private static readonly ILog _log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - /// - /// Regular expression used to match against path of incoming - /// HTTP request. If you want to match any string either use - /// '.*' or null. To match for the emtpy string use '^$' - /// - public Regex Path - { - get { return _pathsRegex; } - } - private Regex _pathsRegex; - - /// - /// Dictionary of (header name, regular expression) tuples, - /// allowing us to match on HTTP header fields. - /// - public Dictionary Headers - { - get { return _headers; } - } - private Dictionary _headers; - - /// - /// Regex to whitelist IP end points. A null value disables - /// checking of IP end points. - /// - /// - /// This feature is currently not implemented as it requires - /// (trivial) changes to HttpServer.HttpListener that have not - /// been implemented. - /// - public Regex IPEndPointWhitelist - { - get { return _ipEndPointRegex; } - } - private Regex _ipEndPointRegex; - /// /// An OSHttpHandler that matches on the "content-type" header can /// supply an OSHttpContentTypeChecker delegate which will be @@ -87,7 +51,7 @@ namespace OpenSim.Framework.Servers /// /// true if the handler is interested in the content; /// false otherwise - public OSHttpContentTypeChecker ContentTypeChecker + internal override OSHttpContentTypeChecker ContentTypeChecker { get { @@ -132,7 +96,7 @@ namespace OpenSim.Framework.Servers } // contains handler for processing XmlRpc Request - private OSHttpXmlRpcProcessor _handler; + private XmlRpcMethod _handler; // contains XmlRpc method name private string _methodName; @@ -141,7 +105,7 @@ namespace OpenSim.Framework.Servers /// /// Instantiate an XmlRpc handler. /// - /// OSHttpXmlRpcProcessor + /// XmlRpcMethod /// delegate /// XmlRpc method name /// XmlRpc path prefix (regular expression) @@ -154,28 +118,24 @@ namespace OpenSim.Framework.Servers /// can be null, in which case they are not taken into account /// when the handler is being looked up. /// - public OSHttpXmlRpcHandler(OSHttpXmlRpcProcessor handler, string methodName, Regex path, + public OSHttpXmlRpcHandler(XmlRpcMethod handler, string methodName, Regex path, Dictionary headers, Regex whitelist) + : base(new Regex(@"^POST$", RegexOptions.IgnoreCase | RegexOptions.Compiled), path, headers, + new Regex(@"^(text|application)/xml", RegexOptions.IgnoreCase | RegexOptions.Compiled), + whitelist) { _handler = handler; - _pathsRegex = path; _methodName = methodName; - - if (null == _headers) _headers = new Dictionary(); - _headers.Add("content-type", new Regex(@"^(text|application)/xml", RegexOptions.IgnoreCase | - RegexOptions.Compiled)); - - _ipEndPointRegex = whitelist; } /// /// Instantiate an XmlRpc handler. /// - /// OSHttpXmlRpcProcessor + /// XmlRpcMethod /// delegate /// XmlRpc method name - public OSHttpXmlRpcHandler(OSHttpXmlRpcProcessor handler, string methodName) + public OSHttpXmlRpcHandler(XmlRpcMethod handler, string methodName) : this(handler, methodName, null, null, null) { } @@ -184,7 +144,7 @@ namespace OpenSim.Framework.Servers /// /// Invoked by OSHttpRequestPump. /// - public OSHttpHandlerResult Process(OSHttpRequest request) + public override OSHttpHandlerResult Process(OSHttpRequest request) { XmlRpcResponse xmlRpcResponse; string responseString;