From 0ea73384d4506c83bcd9f721a13fd5be11d1cc33 Mon Sep 17 00:00:00 2001 From: Dr Scofield Date: Fri, 18 Jul 2008 15:31:28 +0000 Subject: [PATCH] simplifying OSHTtpHandler (a bit), adding query string matching, adapting OSHttpXmlRpcHandler accordingly. NOTE: this code is not live. --- OpenSim/Framework/Servers/OSHttpHandler.cs | 22 ++- .../Framework/Servers/OSHttpRequestPump.cs | 145 +++++++++--------- .../Framework/Servers/OSHttpXmlRpcHandler.cs | 79 +++++----- 3 files changed, 122 insertions(+), 124 deletions(-) diff --git a/OpenSim/Framework/Servers/OSHttpHandler.cs b/OpenSim/Framework/Servers/OSHttpHandler.cs index 8b65438893..6e8f6fb081 100644 --- a/OpenSim/Framework/Servers/OSHttpHandler.cs +++ b/OpenSim/Framework/Servers/OSHttpHandler.cs @@ -92,6 +92,16 @@ namespace OpenSim.Framework.Servers } protected Regex _path; + /// + /// Dictionary of (query name, regular expression) tuples, + /// allowing us to match on URI query fields. + /// + public virtual Dictionary Query + { + get { return _query; } + } + protected Dictionary _query; + /// /// Dictionary of (header name, regular expression) tuples, /// allowing us to match on HTTP header fields. @@ -118,18 +128,6 @@ namespace OpenSim.Framework.Servers protected Regex _ipEndPointRegex; - /// - /// An OSHttpHandler that matches on the "content-type" header can - /// supply an OSHttpContentTypeChecker delegate which will be - /// invoked by the request matcher in OSHttpRequestPump. - /// - /// true if the handler is interested in the content; - /// false otherwise - internal virtual OSHttpContentTypeChecker ContentTypeChecker - { - get { return null; } - } - /// /// Base class constructor. /// diff --git a/OpenSim/Framework/Servers/OSHttpRequestPump.cs b/OpenSim/Framework/Servers/OSHttpRequestPump.cs index d05e70673d..8d4dc0dea5 100644 --- a/OpenSim/Framework/Servers/OSHttpRequestPump.cs +++ b/OpenSim/Framework/Servers/OSHttpRequestPump.cs @@ -175,18 +175,13 @@ 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; - // initial anchor scoredHandlers[h] = 0; // first, check whether IPEndPointWhitelist applies // and, if it does, whether client is on that white // list. - if (null != endPointsRegex) + if (null != h.IPEndPointWhitelist) { // TODO: following code requires code changes to // HttpServer.HttpRequest to become functional @@ -194,84 +189,65 @@ namespace OpenSim.Framework.Servers IPEndPoint remote = req.RemoteIPEndPoint; if (null != remote) { - Match epm = endPointsRegex.Match(remote.ToString()); - if (!epm.Success) continue; + Match epm = h.IPEndPointWhitelist.Match(remote.ToString()); + if (!epm.Success) + { + scoredHandlers.Remove(h); + continue; + } } } - if (null != methodRegex) + if (null != h.Method) { - Match m = methodRegex.Match(req.HttpMethod); - if (!m.Success) continue; - + Match m = h.Method.Match(req.HttpMethod); + if (!m.Success) + { + scoredHandlers.Remove(h); + continue; + } scoredHandlers[h]++; } // whitelist ok, now check path - if (null != pathRegex) + if (null != h.Path) { - Match m = pathRegex.Match(req.RawUrl); - if (!m.Success) continue; - - scoredHandlers[h] = m.ToString().Length; - } - - // whitelist & path ok, now check headers - if (null != headerRegexs) - { - int headersMatch = 0; - - // go through all header Regexs and evaluate - // match: - // if header field not present or does not match: - // remove handler from scoredHandlers - // continue - // else: - // add increment headersMatch - NameValueCollection headers = req.HttpRequest.Headers; - foreach (string tag in headerRegexs.Keys) + Match m = h.Path.Match(req.RawUrl); + if (!m.Success) { - // do we have a header "tag"? - if (null == headers[tag]) - { - // no: remove the handler if it was added - // earlier and on to the next one - _log.DebugFormat("[{0}] dropping handler for {1}: null {2} header field: {3}", EngineID, req, tag, h); - - scoredHandlers.Remove(h); - break; - } - - // does the content of header "tag" match - // the supplied regex? - Match hm = headerRegexs[tag].Match(headers[tag]); - if (!hm.Success) { - // no: remove the handler if it was added - // earlier and on to the next one - _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; - } - - // if we are looking at the "content-type" tag, - // check wether h has a ContentTypeChecker and - // invoke it if it has - if ((null != h.ContentTypeChecker) && !h.ContentTypeChecker(req)) - { - scoredHandlers.Remove(h); - _log.DebugFormat("[{0}] dropping handler for {1}: content checker returned false: {2}", EngineID, req, h); - break; - } - - // ok: header matches - headersMatch++; - _log.DebugFormat("[{0}] MatchHandlers: found handler for {1}: {2}", EngineID, req, h.ToString()); + scoredHandlers.Remove(h); continue; } - // check whether h got kicked out - if (!scoredHandlers.ContainsKey(h)) continue; + scoredHandlers[h] += m.ToString().Length; + } + // whitelist & path ok, now check query string + if (null != h.Query) + { + int queriesMatch = MatchOnNameValueCollection(req.QueryString, h.Query); + if (0 == queriesMatch) + { + _log.DebugFormat("[{0}] request {1}", EngineID, req); + _log.DebugFormat("[{0}] dropping handler {1}", EngineID, h); + + scoredHandlers.Remove(h); + continue; + } + scoredHandlers[h] += queriesMatch; + } + + // whitelist, path, query string ok, now check headers + if (null != h.Headers) + { + int headersMatch = MatchOnNameValueCollection(req.Headers, h.Headers); + if (0 == headersMatch) + { + _log.DebugFormat("[{0}] request {1}", EngineID, req); + _log.DebugFormat("[{0}] dropping handler {1}", EngineID, h); + + scoredHandlers.Remove(h); + continue; + } scoredHandlers[h] += headersMatch; } } @@ -285,6 +261,33 @@ namespace OpenSim.Framework.Servers return matchingHandlers; } + protected int MatchOnNameValueCollection(NameValueCollection collection, Dictionary regexs) + { + int matched = 0; + + foreach (string tag in regexs.Keys) + { + // do we have a header "tag"? + if (null == collection[tag]) + { + return 0; + } + + // does the content of collection[tag] match + // the supplied regex? + Match cm = regexs[tag].Match(collection[tag]); + if (!cm.Success) { + return 0; + } + + // ok: matches + matched++; + continue; + } + + return matched; + } + [ConditionalAttribute("DEBUGGING")] private void LogDumpHandlerList(List l) { diff --git a/OpenSim/Framework/Servers/OSHttpXmlRpcHandler.cs b/OpenSim/Framework/Servers/OSHttpXmlRpcHandler.cs index f9ce5b1ba4..2c31cfd3de 100644 --- a/OpenSim/Framework/Servers/OSHttpXmlRpcHandler.cs +++ b/OpenSim/Framework/Servers/OSHttpXmlRpcHandler.cs @@ -51,48 +51,42 @@ namespace OpenSim.Framework.Servers /// /// true if the handler is interested in the content; /// false otherwise - internal override OSHttpContentTypeChecker ContentTypeChecker - { - get - { - return delegate(OSHttpRequest req) + protected bool XmlRpcMethodMatch(OSHttpRequest req) + { + XmlRpcRequest xmlRpcRequest = null; + + // check whether req is already reified + // if not: reify (and post to whiteboard) + try + { + if (req.Whiteboard.ContainsKey("xmlrequest")) { - XmlRpcRequest xmlRpcRequest = null; - - // check whether req is already reified - // if not: reify (and post to whiteboard) - try - { - if (req.Whiteboard.ContainsKey("xmlrequest")) - { - xmlRpcRequest = req.Whiteboard["xmlrequest"] as XmlRpcRequest; - } - else - { - StreamReader body = new StreamReader(req.InputStream); - string requestBody = body.ReadToEnd(); - xmlRpcRequest = (XmlRpcRequest)(new XmlRpcRequestDeserializer()).Deserialize(requestBody); - req.Whiteboard["xmlrequest"] = xmlRpcRequest; - } - } - catch (XmlException) - { - _log.ErrorFormat("[OSHttpXmlRpcHandler] failed to deserialize XmlRpcRequest from {0}", req.ToString()); - return false; - } - - // check against methodName - if ((null != xmlRpcRequest) - && !String.IsNullOrEmpty(xmlRpcRequest.MethodName) - && xmlRpcRequest.MethodName == _methodName) - { - _log.DebugFormat("[OSHttpXmlRpcHandler] located handler {0} for {1}", _methodName, req.ToString()); - return true; - } - - return false; - }; + xmlRpcRequest = req.Whiteboard["xmlrequest"] as XmlRpcRequest; + } + else + { + StreamReader body = new StreamReader(req.InputStream); + string requestBody = body.ReadToEnd(); + xmlRpcRequest = (XmlRpcRequest)(new XmlRpcRequestDeserializer()).Deserialize(requestBody); + req.Whiteboard["xmlrequest"] = xmlRpcRequest; + } } + catch (XmlException) + { + _log.ErrorFormat("[OSHttpXmlRpcHandler] failed to deserialize XmlRpcRequest from {0}", req.ToString()); + return false; + } + + // check against methodName + if ((null != xmlRpcRequest) + && !String.IsNullOrEmpty(xmlRpcRequest.MethodName) + && xmlRpcRequest.MethodName == _methodName) + { + _log.DebugFormat("[OSHttpXmlRpcHandler] located handler {0} for {1}", _methodName, req.ToString()); + return true; + } + + return false; } // contains handler for processing XmlRpc Request @@ -149,8 +143,11 @@ namespace OpenSim.Framework.Servers XmlRpcResponse xmlRpcResponse; string responseString; + // check whether we are interested in this request + if (!XmlRpcMethodMatch(request)) return OSHttpHandlerResult.Pass; + + OSHttpResponse resp = new OSHttpResponse(request); - try { // reified XmlRpcRequest must still be on the whiteboard