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).0.6.0-stable
parent
2a30e85c97
commit
ed4241583f
|
@ -27,6 +27,7 @@
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
|
|
||||||
namespace OpenSim.Framework.Servers
|
namespace OpenSim.Framework.Servers
|
||||||
|
@ -43,16 +44,10 @@ namespace OpenSim.Framework.Servers
|
||||||
/// <description>handler did not process the request</request>
|
/// <description>handler did not process the request</request>
|
||||||
/// </item>
|
/// </item>
|
||||||
/// <item>
|
/// <item>
|
||||||
/// <term>Handled</term>
|
/// <term>Done</term>
|
||||||
/// <description>handler did process the request, OSHttpServer
|
/// <description>handler did process the request, OSHttpServer
|
||||||
/// can clean up and close the request</request>
|
/// can clean up and close the request</request>
|
||||||
/// </item>
|
/// </item>
|
||||||
/// <item>
|
|
||||||
/// <term>Detached</term>
|
|
||||||
/// <description>handler handles the request, OSHttpServer
|
|
||||||
/// can forget about the request and should not touch it as
|
|
||||||
/// the handler has taken control</request>
|
|
||||||
/// </item>
|
|
||||||
/// </list>
|
/// </list>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public enum OSHttpHandlerResult
|
public enum OSHttpHandlerResult
|
||||||
|
@ -71,26 +66,41 @@ namespace OpenSim.Framework.Servers
|
||||||
/// false otherwise</returns>
|
/// false otherwise</returns>
|
||||||
public delegate bool OSHttpContentTypeChecker(OSHttpRequest req);
|
public delegate bool OSHttpContentTypeChecker(OSHttpRequest req);
|
||||||
|
|
||||||
public interface OSHttpHandler
|
public abstract class OSHttpHandler
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Regular expression used to match against path of incoming
|
/// Regular expression used to match against method of
|
||||||
/// HTTP request. If you want to match any string either use
|
/// the incoming HTTP request. If you want to match any string
|
||||||
/// '.*' or null. To match for the emtpy string use '^$'
|
/// either use '.*' or null. To match on the empty string use
|
||||||
|
/// '^$'.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Regex Path
|
public virtual Regex Method
|
||||||
{
|
{
|
||||||
get;
|
get { return _method; }
|
||||||
}
|
}
|
||||||
|
protected Regex _method;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 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
|
||||||
|
/// '^$'.
|
||||||
|
/// </summary>
|
||||||
|
public virtual Regex Path
|
||||||
|
{
|
||||||
|
get { return _path; }
|
||||||
|
}
|
||||||
|
protected Regex _path;
|
||||||
|
|
||||||
/// <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.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Dictionary<string, Regex> Headers
|
public virtual Dictionary<string, Regex> Headers
|
||||||
{
|
{
|
||||||
get;
|
get { return _headers; }
|
||||||
}
|
}
|
||||||
|
protected Dictionary<string, Regex> _headers;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Dictionary of (header name, regular expression) tuples,
|
/// Dictionary of (header name, regular expression) tuples,
|
||||||
|
@ -101,10 +111,11 @@ namespace OpenSim.Framework.Servers
|
||||||
/// (trivial) changes to HttpServer.HttpListener that have not
|
/// (trivial) changes to HttpServer.HttpListener that have not
|
||||||
/// been implemented.
|
/// been implemented.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
Regex IPEndPointWhitelist
|
public virtual Regex IPEndPointWhitelist
|
||||||
{
|
{
|
||||||
get;
|
get { return _ipEndPointRegex; }
|
||||||
}
|
}
|
||||||
|
protected Regex _ipEndPointRegex;
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -114,11 +125,59 @@ 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>
|
||||||
OSHttpContentTypeChecker ContentTypeChecker
|
internal virtual OSHttpContentTypeChecker ContentTypeChecker
|
||||||
{
|
{
|
||||||
get;
|
get { return null; }
|
||||||
}
|
}
|
||||||
|
|
||||||
OSHttpHandlerResult Process(OSHttpRequest request);
|
/// <summary>
|
||||||
|
/// Base class constructor.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="path">null or path regex</param>
|
||||||
|
/// <param name="headers">null or dictionary of header
|
||||||
|
/// regexs</param>
|
||||||
|
/// <param name="contentType">null or content type
|
||||||
|
/// regex</param>
|
||||||
|
/// <param name="whitelist">null or IP address regex</param>
|
||||||
|
public OSHttpHandler(Regex method, Regex path, Dictionary<string, Regex> headers, Regex contentType, Regex whitelist)
|
||||||
|
{
|
||||||
|
_method = method;
|
||||||
|
_path = path;
|
||||||
|
_ipEndPointRegex = whitelist;
|
||||||
|
|
||||||
|
if (null == _headers && null != contentType)
|
||||||
|
{
|
||||||
|
_headers = new Dictionary<string, Regex>();
|
||||||
|
_headers.Add("content-type", contentType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Process an incoming OSHttpRequest that matched our
|
||||||
|
/// requirements.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>
|
||||||
|
/// OSHttpHandlerResult.Pass if we are after all not
|
||||||
|
/// interested in the request; OSHttpHandlerResult.Done if we
|
||||||
|
/// did process the request.
|
||||||
|
/// </returns>
|
||||||
|
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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -175,6 +175,7 @@ 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;
|
Regex pathRegex = h.Path;
|
||||||
Dictionary<string, Regex> headerRegexs = h.Headers;
|
Dictionary<string, Regex> headerRegexs = h.Headers;
|
||||||
Regex endPointsRegex = h.IPEndPointWhitelist;
|
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
|
// whitelist ok, now check path
|
||||||
if (null != pathRegex)
|
if (null != pathRegex)
|
||||||
{
|
{
|
||||||
Match m = pathRegex.Match(req.HttpRequest.Uri.AbsolutePath);
|
Match m = pathRegex.Match(req.RawUrl);
|
||||||
if (!m.Success) continue;
|
if (!m.Success) continue;
|
||||||
|
|
||||||
scoredHandlers[h] = m.ToString().Length;
|
scoredHandlers[h] = m.ToString().Length;
|
||||||
|
@ -227,8 +236,7 @@ namespace OpenSim.Framework.Servers
|
||||||
{
|
{
|
||||||
// no: remove the handler if it was added
|
// no: remove the handler if it was added
|
||||||
// earlier and on to the next one
|
// earlier and on to the next one
|
||||||
_LogDumpOSHttpHandler(String.Format("[{0}] dropping handler for {1}: null {2} header field",
|
_log.DebugFormat("[{0}] dropping handler for {1}: null {2} header field: {3}", EngineID, req, tag, h);
|
||||||
EngineID, req, tag), h);
|
|
||||||
|
|
||||||
scoredHandlers.Remove(h);
|
scoredHandlers.Remove(h);
|
||||||
break;
|
break;
|
||||||
|
@ -240,8 +248,8 @@ namespace OpenSim.Framework.Servers
|
||||||
if (!hm.Success) {
|
if (!hm.Success) {
|
||||||
// no: remove the handler if it was added
|
// no: remove the handler if it was added
|
||||||
// earlier and on to the next one
|
// 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}",
|
_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);
|
EngineID, req, tag, headers[tag], headerRegexs[tag].ToString(), h);
|
||||||
scoredHandlers.Remove(h);
|
scoredHandlers.Remove(h);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -252,14 +260,13 @@ namespace OpenSim.Framework.Servers
|
||||||
if ((null != h.ContentTypeChecker) && !h.ContentTypeChecker(req))
|
if ((null != h.ContentTypeChecker) && !h.ContentTypeChecker(req))
|
||||||
{
|
{
|
||||||
scoredHandlers.Remove(h);
|
scoredHandlers.Remove(h);
|
||||||
_LogDumpOSHttpHandler(String.Format("[{0}] dropping handler for {1}: content checker returned false",
|
_log.DebugFormat("[{0}] dropping handler for {1}: content checker returned false: {2}", EngineID, req, h);
|
||||||
EngineID, req), h);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ok: header matches
|
// ok: header matches
|
||||||
headersMatch++;
|
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;
|
continue;
|
||||||
}
|
}
|
||||||
// check whether h got kicked out
|
// check whether h got kicked out
|
||||||
|
@ -269,48 +276,21 @@ namespace OpenSim.Framework.Servers
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (OSHttpHandler hh in scoredHandlers.Keys)
|
|
||||||
{
|
|
||||||
_LogDumpOSHttpHandler("scoredHandlers:", hh);
|
|
||||||
}
|
|
||||||
|
|
||||||
List<OSHttpHandler> matchingHandlers = new List<OSHttpHandler>(scoredHandlers.Keys);
|
List<OSHttpHandler> matchingHandlers = new List<OSHttpHandler>(scoredHandlers.Keys);
|
||||||
_LogDumpOSHttpHandlerList("before sort: ", matchingHandlers);
|
|
||||||
matchingHandlers.Sort(delegate(OSHttpHandler x, OSHttpHandler y)
|
matchingHandlers.Sort(delegate(OSHttpHandler x, OSHttpHandler y)
|
||||||
{
|
{
|
||||||
return scoredHandlers[x] - scoredHandlers[y];
|
return scoredHandlers[x] - scoredHandlers[y];
|
||||||
});
|
});
|
||||||
|
LogDumpHandlerList(matchingHandlers);
|
||||||
_LogDumpOSHttpHandlerList("after sort: ", matchingHandlers);
|
|
||||||
|
|
||||||
return matchingHandlers;
|
return matchingHandlers;
|
||||||
}
|
}
|
||||||
|
|
||||||
[ConditionalAttribute("DEBUGGING")]
|
[ConditionalAttribute("DEBUGGING")]
|
||||||
private void _LogDumpOSHttpHandler(string msg, OSHttpHandler h)
|
private void LogDumpHandlerList(List<OSHttpHandler> l)
|
||||||
{
|
{
|
||||||
_log.Debug(msg);
|
_log.DebugFormat("[{0}] OSHttpHandlerList dump:", EngineID);
|
||||||
|
|
||||||
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<OSHttpHandler> l)
|
|
||||||
{
|
|
||||||
_log.DebugFormat("OSHttpHandlerList dump: {0}", msg);
|
|
||||||
foreach (OSHttpHandler h in l)
|
foreach (OSHttpHandler h in l)
|
||||||
_LogDumpOSHttpHandler("OSHttpHandler", h);
|
_log.DebugFormat(" ", h.ToString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,42 +44,6 @@ namespace OpenSim.Framework.Servers
|
||||||
{
|
{
|
||||||
private static readonly ILog _log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
private static readonly ILog _log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 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 '^$'
|
|
||||||
/// </summary>
|
|
||||||
public Regex Path
|
|
||||||
{
|
|
||||||
get { return _pathsRegex; }
|
|
||||||
}
|
|
||||||
private Regex _pathsRegex;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Dictionary of (header name, regular expression) tuples,
|
|
||||||
/// allowing us to match on HTTP header fields.
|
|
||||||
/// </summary>
|
|
||||||
public Dictionary<string, Regex> Headers
|
|
||||||
{
|
|
||||||
get { return _headers; }
|
|
||||||
}
|
|
||||||
private Dictionary<string, Regex> _headers;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Regex to whitelist IP end points. A null value disables
|
|
||||||
/// checking of IP end points.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// This feature is currently not implemented as it requires
|
|
||||||
/// (trivial) changes to HttpServer.HttpListener that have not
|
|
||||||
/// been implemented.
|
|
||||||
/// </remarks>
|
|
||||||
public Regex IPEndPointWhitelist
|
|
||||||
{
|
|
||||||
get { return _ipEndPointRegex; }
|
|
||||||
}
|
|
||||||
private Regex _ipEndPointRegex;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// An OSHttpHandler that matches on the "content-type" header can
|
/// An OSHttpHandler that matches on the "content-type" header can
|
||||||
/// supply an OSHttpContentTypeChecker delegate which will be
|
/// supply an OSHttpContentTypeChecker delegate which will be
|
||||||
|
@ -87,7 +51,7 @@ 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>
|
||||||
public OSHttpContentTypeChecker ContentTypeChecker
|
internal override OSHttpContentTypeChecker ContentTypeChecker
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
|
@ -132,7 +96,7 @@ namespace OpenSim.Framework.Servers
|
||||||
}
|
}
|
||||||
|
|
||||||
// contains handler for processing XmlRpc Request
|
// contains handler for processing XmlRpc Request
|
||||||
private OSHttpXmlRpcProcessor _handler;
|
private XmlRpcMethod _handler;
|
||||||
|
|
||||||
// contains XmlRpc method name
|
// contains XmlRpc method name
|
||||||
private string _methodName;
|
private string _methodName;
|
||||||
|
@ -141,7 +105,7 @@ namespace OpenSim.Framework.Servers
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Instantiate an XmlRpc handler.
|
/// Instantiate an XmlRpc handler.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="handler">OSHttpXmlRpcProcessor
|
/// <param name="handler">XmlRpcMethod
|
||||||
/// delegate</param>
|
/// delegate</param>
|
||||||
/// <param name="methodName">XmlRpc method name</param>
|
/// <param name="methodName">XmlRpc method name</param>
|
||||||
/// <param name="path">XmlRpc path prefix (regular expression)</param>
|
/// <param name="path">XmlRpc path prefix (regular expression)</param>
|
||||||
|
@ -154,28 +118,24 @@ namespace OpenSim.Framework.Servers
|
||||||
/// can be null, in which case they are not taken into account
|
/// can be null, in which case they are not taken into account
|
||||||
/// when the handler is being looked up.
|
/// when the handler is being looked up.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
public OSHttpXmlRpcHandler(OSHttpXmlRpcProcessor handler, string methodName, Regex path,
|
public OSHttpXmlRpcHandler(XmlRpcMethod handler, string methodName, Regex path,
|
||||||
Dictionary<string, Regex> headers, Regex whitelist)
|
Dictionary<string, Regex> 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;
|
_handler = handler;
|
||||||
_pathsRegex = path;
|
|
||||||
_methodName = methodName;
|
_methodName = methodName;
|
||||||
|
|
||||||
if (null == _headers) _headers = new Dictionary<string, Regex>();
|
|
||||||
_headers.Add("content-type", new Regex(@"^(text|application)/xml", RegexOptions.IgnoreCase |
|
|
||||||
RegexOptions.Compiled));
|
|
||||||
|
|
||||||
_ipEndPointRegex = whitelist;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Instantiate an XmlRpc handler.
|
/// Instantiate an XmlRpc handler.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="handler">OSHttpXmlRpcProcessor
|
/// <param name="handler">XmlRpcMethod
|
||||||
/// delegate</param>
|
/// delegate</param>
|
||||||
/// <param name="methodName">XmlRpc method name</param>
|
/// <param name="methodName">XmlRpc method name</param>
|
||||||
public OSHttpXmlRpcHandler(OSHttpXmlRpcProcessor handler, string methodName)
|
public OSHttpXmlRpcHandler(XmlRpcMethod handler, string methodName)
|
||||||
: this(handler, methodName, null, null, null)
|
: this(handler, methodName, null, null, null)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -184,7 +144,7 @@ namespace OpenSim.Framework.Servers
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Invoked by OSHttpRequestPump.
|
/// Invoked by OSHttpRequestPump.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public OSHttpHandlerResult Process(OSHttpRequest request)
|
public override OSHttpHandlerResult Process(OSHttpRequest request)
|
||||||
{
|
{
|
||||||
XmlRpcResponse xmlRpcResponse;
|
XmlRpcResponse xmlRpcResponse;
|
||||||
string responseString;
|
string responseString;
|
||||||
|
|
Loading…
Reference in New Issue