simplifying OSHTtpHandler (a bit), adding query string matching,

adapting OSHttpXmlRpcHandler accordingly.

NOTE: this code is not live.
0.6.0-stable
Dr Scofield 2008-07-18 15:31:28 +00:00
parent df1485fc51
commit 0ea73384d4
3 changed files with 122 additions and 124 deletions

View File

@ -92,6 +92,16 @@ namespace OpenSim.Framework.Servers
} }
protected Regex _path; protected Regex _path;
/// <summary>
/// Dictionary of (query name, regular expression) tuples,
/// allowing us to match on URI query fields.
/// </summary>
public virtual Dictionary<string, Regex> Query
{
get { return _query; }
}
protected Dictionary<string, Regex> _query;
/// <summary> /// <summary>
/// Dictionary of (header name, regular expression) tuples, /// Dictionary of (header name, regular expression) tuples,
/// allowing us to match on HTTP header fields. /// allowing us to match on HTTP header fields.
@ -118,18 +128,6 @@ namespace OpenSim.Framework.Servers
protected Regex _ipEndPointRegex; protected Regex _ipEndPointRegex;
/// <summary>
/// An OSHttpHandler that matches on the "content-type" header can
/// supply an OSHttpContentTypeChecker delegate which will be
/// invoked by the request matcher in OSHttpRequestPump.
/// </summary>
/// <returns>true if the handler is interested in the content;
/// false otherwise</returns>
internal virtual OSHttpContentTypeChecker ContentTypeChecker
{
get { return null; }
}
/// <summary> /// <summary>
/// Base class constructor. /// Base class constructor.
/// </summary> /// </summary>

View File

@ -175,18 +175,13 @@ namespace OpenSim.Framework.Servers
_log.DebugFormat("[{0}] MatchHandlers for {1}", EngineID, req); _log.DebugFormat("[{0}] MatchHandlers for {1}", EngineID, req);
foreach (OSHttpHandler h in handlers) foreach (OSHttpHandler h in handlers)
{ {
Regex methodRegex = h.Method;
Regex pathRegex = h.Path;
Dictionary<string, Regex> headerRegexs = h.Headers;
Regex endPointsRegex = h.IPEndPointWhitelist;
// initial anchor // initial anchor
scoredHandlers[h] = 0; scoredHandlers[h] = 0;
// first, check whether IPEndPointWhitelist applies // first, check whether IPEndPointWhitelist applies
// and, if it does, whether client is on that white // and, if it does, whether client is on that white
// list. // list.
if (null != endPointsRegex) if (null != h.IPEndPointWhitelist)
{ {
// TODO: following code requires code changes to // TODO: following code requires code changes to
// HttpServer.HttpRequest to become functional // HttpServer.HttpRequest to become functional
@ -194,84 +189,65 @@ namespace OpenSim.Framework.Servers
IPEndPoint remote = req.RemoteIPEndPoint; IPEndPoint remote = req.RemoteIPEndPoint;
if (null != remote) if (null != remote)
{ {
Match epm = endPointsRegex.Match(remote.ToString()); Match epm = h.IPEndPointWhitelist.Match(remote.ToString());
if (!epm.Success) continue; if (!epm.Success)
{
scoredHandlers.Remove(h);
continue;
}
} }
} }
if (null != methodRegex) if (null != h.Method)
{ {
Match m = methodRegex.Match(req.HttpMethod); Match m = h.Method.Match(req.HttpMethod);
if (!m.Success) continue; if (!m.Success)
{
scoredHandlers.Remove(h);
continue;
}
scoredHandlers[h]++; scoredHandlers[h]++;
} }
// whitelist ok, now check path // whitelist ok, now check path
if (null != pathRegex) if (null != h.Path)
{ {
Match m = pathRegex.Match(req.RawUrl); Match m = h.Path.Match(req.RawUrl);
if (!m.Success) continue; if (!m.Success)
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)
{ {
// do we have a header "tag"? scoredHandlers.Remove(h);
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());
continue; continue;
} }
// check whether h got kicked out scoredHandlers[h] += m.ToString().Length;
if (!scoredHandlers.ContainsKey(h)) continue; }
// 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; scoredHandlers[h] += headersMatch;
} }
} }
@ -285,6 +261,33 @@ namespace OpenSim.Framework.Servers
return matchingHandlers; return matchingHandlers;
} }
protected int MatchOnNameValueCollection(NameValueCollection collection, Dictionary<string, Regex> 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")] [ConditionalAttribute("DEBUGGING")]
private void LogDumpHandlerList(List<OSHttpHandler> l) private void LogDumpHandlerList(List<OSHttpHandler> l)
{ {

View File

@ -51,48 +51,42 @@ namespace OpenSim.Framework.Servers
/// </summary> /// </summary>
/// <returns>true if the handler is interested in the content; /// <returns>true if the handler is interested in the content;
/// false otherwise</returns> /// false otherwise</returns>
internal override OSHttpContentTypeChecker ContentTypeChecker protected bool XmlRpcMethodMatch(OSHttpRequest req)
{ {
get XmlRpcRequest xmlRpcRequest = null;
{
return delegate(OSHttpRequest req) // check whether req is already reified
// if not: reify (and post to whiteboard)
try
{
if (req.Whiteboard.ContainsKey("xmlrequest"))
{ {
XmlRpcRequest xmlRpcRequest = null; xmlRpcRequest = req.Whiteboard["xmlrequest"] as XmlRpcRequest;
}
// check whether req is already reified else
// if not: reify (and post to whiteboard) {
try StreamReader body = new StreamReader(req.InputStream);
{ string requestBody = body.ReadToEnd();
if (req.Whiteboard.ContainsKey("xmlrequest")) xmlRpcRequest = (XmlRpcRequest)(new XmlRpcRequestDeserializer()).Deserialize(requestBody);
{ req.Whiteboard["xmlrequest"] = xmlRpcRequest;
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;
};
} }
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 // contains handler for processing XmlRpc Request
@ -149,8 +143,11 @@ namespace OpenSim.Framework.Servers
XmlRpcResponse xmlRpcResponse; XmlRpcResponse xmlRpcResponse;
string responseString; string responseString;
// check whether we are interested in this request
if (!XmlRpcMethodMatch(request)) return OSHttpHandlerResult.Pass;
OSHttpResponse resp = new OSHttpResponse(request); OSHttpResponse resp = new OSHttpResponse(request);
try try
{ {
// reified XmlRpcRequest must still be on the whiteboard // reified XmlRpcRequest must still be on the whiteboard