diff --git a/OpenSim/Framework/Servers/BaseHttpServer.cs b/OpenSim/Framework/Servers/BaseHttpServer.cs
index 22698d0e3c..9d2a804aec 100644
--- a/OpenSim/Framework/Servers/BaseHttpServer.cs
+++ b/OpenSim/Framework/Servers/BaseHttpServer.cs
@@ -416,7 +416,7 @@ namespace OpenSim.Framework.Servers
{
try
{
- response.OutputStream.Close();
+ response.Send();
}
catch (SocketException e)
{
diff --git a/OpenSim/Framework/Servers/OSHttpHandler.cs b/OpenSim/Framework/Servers/OSHttpHandler.cs
index da96cca577..a9f42f3e92 100644
--- a/OpenSim/Framework/Servers/OSHttpHandler.cs
+++ b/OpenSim/Framework/Servers/OSHttpHandler.cs
@@ -59,10 +59,18 @@ namespace OpenSim.Framework.Servers
{
Unprocessed,
Pass,
- Handled,
- Detached,
+ Done,
}
+ ///
+ /// 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
+ public delegate bool OSHttpContentTypeChecker(OSHttpRequest req);
+
public interface OSHttpHandler
{
///
@@ -98,6 +106,19 @@ namespace OpenSim.Framework.Servers
get;
}
+
+ ///
+ /// 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
+ OSHttpContentTypeChecker ContentTypeChecker
+ {
+ get;
+ }
+
OSHttpHandlerResult Process(OSHttpRequest request);
}
}
\ No newline at end of file
diff --git a/OpenSim/Framework/Servers/OSHttpRequest.cs b/OpenSim/Framework/Servers/OSHttpRequest.cs
index c5231431ab..7549f08142 100644
--- a/OpenSim/Framework/Servers/OSHttpRequest.cs
+++ b/OpenSim/Framework/Servers/OSHttpRequest.cs
@@ -59,7 +59,7 @@ namespace OpenSim.Framework.Servers
private IPEndPoint _ipEndPoint;
private HttpRequest _request;
- // private HttpClientContext _context;
+ private HttpClientContext _context;
public string[] AcceptTypes
{
@@ -152,11 +152,28 @@ namespace OpenSim.Framework.Servers
get { return _ipEndPoint; }
}
- public HttpRequest HttpRequest
+
+ internal HttpRequest HttpRequest
{
get { return _request; }
}
+ internal HttpClientContext HttpClientContext
+ {
+ get { return _context; }
+ }
+
+ ///
+ /// Internal whiteboard for handlers to store temporary stuff
+ /// into.
+ ///
+ internal Dictionary Whiteboard
+ {
+ get { return _whiteboard; }
+ }
+ private Dictionary _whiteboard = new Dictionary();
+
+
public OSHttpRequest()
{
}
@@ -185,7 +202,7 @@ namespace OpenSim.Framework.Servers
public OSHttpRequest(HttpClientContext context, HttpRequest req)
{
- // _context = context;
+ _context = context;
_request = req;
_acceptTypes = req.AcceptTypes;
@@ -215,5 +232,21 @@ namespace OpenSim.Framework.Servers
// _isSecureConnection = req.IsSecureConnection;
// _isAuthenticated = req.IsAuthenticated;
}
+
+ public override string ToString()
+ {
+ StringBuilder me = new StringBuilder();
+ me.Append(String.Format("OSHttpRequest: {0} {1}\n", HttpMethod, RawUrl));
+ foreach (string k in Headers.AllKeys)
+ {
+ me.Append(String.Format(" {0}: {1}\n", k, Headers[k]));
+ }
+ if (null != RemoteIPEndPoint)
+ {
+ me.Append(String.Format(" IP: {0}\n", RemoteIPEndPoint.ToString()));
+ }
+
+ return me.ToString();
+ }
}
}
diff --git a/OpenSim/Framework/Servers/OSHttpRequestPump.cs b/OpenSim/Framework/Servers/OSHttpRequestPump.cs
index 4218be582c..56714fad36 100644
--- a/OpenSim/Framework/Servers/OSHttpRequestPump.cs
+++ b/OpenSim/Framework/Servers/OSHttpRequestPump.cs
@@ -28,6 +28,7 @@
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
+using System.IO;
using System.Net;
using System.Reflection;
using System.Text.RegularExpressions;
@@ -114,7 +115,7 @@ namespace OpenSim.Framework.Servers
// process req: we try each handler in turn until
// we are either out of handlers or get back a
- // Handled or Detached
+ // Pass or Done
OSHttpHandlerResult rc = OSHttpHandlerResult.Unprocessed;
foreach (OSHttpHandler h in handlers)
{
@@ -123,22 +124,35 @@ namespace OpenSim.Framework.Servers
// Pass: handler did not process the request,
// try next handler
if (OSHttpHandlerResult.Pass == rc) continue;
- // Detached: handler is taking over processing
- // of request, we are done
- if (OSHttpHandlerResult.Detached == rc) break;
-
- if (OSHttpHandlerResult.Handled != rc)
- {
- // something went wrong
- throw new Exception(String.Format("[{0}] got unexpected OSHttpHandlerResult {1}", EngineID, rc));
- }
-
- // Handled: clean up now
- req.HttpRequest.AddHeader("keep-alive", "false");
- break;
+ // Handled: handler has processed the request
+ if (OSHttpHandlerResult.Done == rc) break;
+
+ // hmm, something went wrong
+ throw new Exception(String.Format("[{0}] got unexpected OSHttpHandlerResult {1}", EngineID, rc));
+ }
+
+ if (OSHttpHandlerResult.Unprocessed == rc)
+ {
+ _log.InfoFormat("[{0}] OSHttpHandler: no handler registered for {1}", EngineID, req);
+
+ // set up response header
+ OSHttpResponse resp = new OSHttpResponse(req);
+ resp.StatusCode = (int)OSHttpStatusCode.ClientErrorNotFound;
+ resp.StatusDescription = String.Format("no handler on call for {0}", req);
+ resp.ContentType = "text/html";
+
+ // add explanatory message
+ StreamWriter body = new StreamWriter(resp.Body);
+ body.WriteLine("");
+ body.WriteLine("Ooops...");
+ body.WriteLine(String.Format("{0}
", resp.StatusDescription));
+ body.WriteLine("");
+ body.Flush();
+
+ // and ship it back
+ resp.HttpResponse.Send();
}
-
}
catch (Exception e)
{
@@ -199,17 +213,37 @@ namespace OpenSim.Framework.Servers
NameValueCollection headers = req.HttpRequest.Headers;
foreach (string tag in headerRegexs.Keys)
{
- if (null != headers[tag])
+ // do we have a header "tag"?
+ if (null == headers[tag])
{
- Match hm = headerRegexs[tag].Match(headers[tag]);
- if (hm.Success) {
- headersMatch++;
- continue;
- }
+ // no: remove the handler if it was added
+ // earlier and on to the next one
+ scoredHandlers.Remove(h);
+ break;
}
-
- 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
+ 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);
+ break;
+ }
+
+ // ok: header matches
+ headersMatch++;
+ continue;
}
// check whether h got kicked out
if (!scoredHandlers.ContainsKey(h)) continue;
diff --git a/OpenSim/Framework/Servers/OSHttpResponse.cs b/OpenSim/Framework/Servers/OSHttpResponse.cs
index e1ab005c97..352c6f6e09 100644
--- a/OpenSim/Framework/Servers/OSHttpResponse.cs
+++ b/OpenSim/Framework/Servers/OSHttpResponse.cs
@@ -25,141 +25,346 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
+using System;
using System.Collections;
using System.IO;
using System.Net;
using System.Text;
+using HttpServer;
namespace OpenSim.Framework.Servers
{
+ ///
+ /// OSHttpResponse is the OpenSim representation of an HTTP
+ /// response.
+ ///
+ ///
+ /// OSHttpResponse is currently dual "homed" in that it support
+ /// both the .NET HttpListenerResponse and the HttpServer
+ /// HttpResponse (similar to OSHttpRequest); this duality is only
+ /// temporary and the .NET usage will disappear once the switch to
+ /// HttpServer is completed.
+ ///
public class OSHttpResponse
{
- private string _contentType;
- private bool _contentTypeSet;
+
+ // property code below is a bit messy, will all resolve to
+ // harmony once we've completed the switch
+
+ ///
+ /// Content type property.
+ ///
+ ///
+ /// Setting this property will also set IsContentTypeSet to
+ /// true.
+ ///
public string ContentType
{
- get { return _contentType; }
+ get
+ {
+ return HttpServer ? _httpResponse.ContentType : _contentType;
+ }
set
{
- _contentType = value;
- _contentTypeSet = true;
+ if (HttpServer)
+ {
+ _httpResponse.ContentType = value;
+ }
+ else
+ {
+ _contentType = value;
+ _contentTypeSet = true;
+ }
}
}
+ private string _contentType;
+
+ ///
+ /// Boolean property indicating whether the content type
+ /// property actively has been set.
+ ///
+ ///
+ /// IsContentTypeSet will go away together with .NET base.
+ ///
public bool IsContentTypeSet
{
get { return _contentTypeSet; }
}
+ private bool _contentTypeSet;
- private long _contentLength64;
+
+ ///
+ /// Length of the body content; 0 if there is no body.
+ ///
+ public long ContentLength
+ {
+ get
+ {
+ return HttpServer ? _httpResponse.ContentLength : _contentLength;
+ }
+ set
+ {
+ if (HttpServer)
+ _httpResponse.ContentLength = value;
+ else
+ _contentLength = value;
+ }
+ }
+ private long _contentLength;
+
+ ///
+ /// Aliases for ContentLength.
+ ///
public long ContentLength64
{
- get { return _contentLength64; }
- set
- {
- _contentLength64 = value;
- if (null != _resp) _resp.ContentLength64 = value;
- }
+ get { return ContentLength; }
+ set { ContentLength = value; }
}
- private Encoding _contentEncoding;
+ ///
+ /// Encoding of the body content.
+ ///
public Encoding ContentEncoding
{
- get { return _contentEncoding; }
+ get {
+ return HttpServer ? _httpResponse.Encoding : _contentEncoding;
+ }
set
{
- _contentEncoding = value;
- if (null != _resp) _resp.ContentEncoding = value;
+ if (HttpServer)
+ _httpResponse.Encoding = value;
+ else
+ _contentEncoding = value;
}
}
+ private Encoding _contentEncoding;
- public WebHeaderCollection Headers;
- // public CookieCollection Cookies;
+ ///
+ /// Headers of the response.
+ ///
+ public WebHeaderCollection Headers
+ {
+ get
+ {
+ return HttpServer ? null : _headers;
+ }
+ }
+ private WebHeaderCollection _headers;
- private bool _keepAlive;
+ ///
+ /// Get or set the keep alive property.
+ ///
public bool KeepAlive
{
- get { return _keepAlive; }
+ get
+ {
+ if (HttpServer)
+ return _httpResponse.Connection == ConnectionType.KeepAlive;
+ else
+ return _keepAlive;
+ }
set
{
- _keepAlive = value;
- if (null != _resp) _resp.KeepAlive = value;
+ if (HttpServer)
+ _httpResponse.Connection = ConnectionType.KeepAlive;
+ else
+ _keepAlive = value;
+ }
+ }
+ private bool _keepAlive;
+
+ ///
+ /// Return the output stream feeding the body.
+ ///
+ ///
+ /// On its way out...
+ ///
+ public Stream OutputStream
+ {
+ get
+ {
+ return HttpServer ? _httpResponse.Body : _outputStream;
+ }
+ }
+ private Stream _outputStream;
+
+
+ ///
+ /// Return the output stream feeding the body.
+ ///
+ public Stream Body
+ {
+ get
+ {
+ if (HttpServer)
+ return _httpResponse.Body;
+ throw new Exception("[OSHttpResponse] mixed .NET and HttpServer access");
}
}
- public Stream OutputStream;
-
- private string _redirectLocation;
+ ///
+ /// Set a redirct location.
+ ///
public string RedirectLocation
{
- get { return _redirectLocation; }
+ // get { return _redirectLocation; }
set
{
- _redirectLocation = value;
- if (null != _resp) _resp.RedirectLocation = value;
+ if (HttpServer)
+ _httpResponse.Redirect(value);
+ // else
+ // _redirectLocation = value;
}
}
+ // private string _redirectLocation;
- private bool _sendChunked;
+
+
+ ///
+ /// Chunk transfers.
+ ///
public bool SendChunked
{
- get { return _sendChunked; }
+ get
+ {
+ return HttpServer ? _httpResponse.Chunked :_sendChunked;
+ }
+
set
{
- _sendChunked = value;
- if (null != _resp) _resp.SendChunked = value;
+ if (HttpServer)
+ _httpResponse.Chunked = value;
+ else
+ _sendChunked = value;
}
}
+ private bool _sendChunked;
- private int _statusCode;
+
+ ///
+ /// HTTP status code.
+ ///
public int StatusCode
{
- get { return _statusCode; }
+ get
+ {
+ return HttpServer ? (int)_httpResponse.Status : _statusCode;
+ }
+
set
{
- _statusCode = value;
- if (null != _resp) _resp.StatusCode = value;
+ if (HttpServer)
+ _httpResponse.Status = (HttpStatusCode)value;
+ else
+ _statusCode = value;
}
}
+ private int _statusCode;
- private string _statusDescription;
+
+ ///
+ /// HTTP status description.
+ ///
public string StatusDescription
{
- get { return _statusDescription; }
+ get
+ {
+ return HttpServer ? _httpResponse.Reason : _statusDescription;
+ }
+
set
{
- _statusDescription = value;
- if (null != _resp) _resp.StatusDescription = value;
+ if (HttpServer)
+ _httpResponse.Reason = value;
+ else
+ _statusDescription = value;
}
}
+ private string _statusDescription;
- private HttpListenerResponse _resp;
+ private HttpResponse _httpResponse;
+
+ internal bool HttpServer
+ {
+ get { return null != _httpResponse; }
+ }
+
+ internal HttpResponse HttpResponse
+ {
+ get { return _httpResponse; }
+ }
public OSHttpResponse()
{
}
+ ///
+ /// Instantiate an OSHttpResponse object based on an
+ /// underlying .NET HttpListenerResponse.
+ ///
+ ///
+ /// Almost deprecated; will go west to make once HttpServer
+ /// base takes over.
+ ///
public OSHttpResponse(HttpListenerResponse resp)
{
- ContentEncoding = resp.ContentEncoding;
- ContentLength64 = resp.ContentLength64;
+ _contentEncoding = resp.ContentEncoding;
+ _contentLength = resp.ContentLength64;
_contentType = resp.ContentType;
- Headers = resp.Headers;
- // Cookies = resp.Cookies;
- KeepAlive = resp.KeepAlive;
- OutputStream = resp.OutputStream;
- RedirectLocation = resp.RedirectLocation;
- SendChunked = resp.SendChunked;
- StatusCode = resp.StatusCode;
- StatusDescription = resp.StatusDescription;
+ _headers = resp.Headers;
+ // _cookies = resp.Cookies;
+ _keepAlive = resp.KeepAlive;
+ _outputStream = resp.OutputStream;
+ // _redirectLocation = resp.RedirectLocation;
+ _sendChunked = resp.SendChunked;
+ _statusCode = resp.StatusCode;
+ _statusDescription = resp.StatusDescription;
_contentTypeSet = false;
- _resp = resp;
+ // _resp = resp;
}
+ ///
+ /// Instantiate an OSHttpResponse object from an OSHttpRequest
+ /// object.
+ /// Incoming OSHttpRequest to which we are
+ /// replying
+ public OSHttpResponse(OSHttpRequest req)
+ {
+ _httpResponse = new HttpResponse(req.HttpClientContext, req.HttpRequest);
+ }
+
+ ///
+ /// Add a header field and content to the response.
+ ///
+ /// string containing the header field
+ /// name
+ /// string containing the header field
+ /// value
public void AddHeader(string key, string value)
{
- Headers.Add(key, value);
+ if (HttpServer)
+ _headers.Add(key, value);
+ else
+ _httpResponse.AddHeader(key, value);
+ }
+
+ ///
+ /// Send the response back to the remote client
+ ///
+ public void Send()
+ {
+ if (HttpServer)
+ {
+ _httpResponse.Body.Flush();
+ _httpResponse.Send();
+ }
+ else
+ {
+ OutputStream.Close();
+ }
}
}
}
diff --git a/OpenSim/Framework/Servers/OSHttpXmlRpcHandler.cs b/OpenSim/Framework/Servers/OSHttpXmlRpcHandler.cs
new file mode 100644
index 0000000000..420554774e
--- /dev/null
+++ b/OpenSim/Framework/Servers/OSHttpXmlRpcHandler.cs
@@ -0,0 +1,222 @@
+/*
+ * 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;
+using System.Collections.Generic;
+using System.IO;
+using System.Net;
+using System.Reflection;
+using System.Text;
+using System.Text.RegularExpressions;
+using System.Xml;
+using log4net;
+using Nwc.XmlRpc;
+
+namespace OpenSim.Framework.Servers
+{
+ public delegate XmlRpcResponse OSHttpXmlRpcProcessor(XmlRpcRequest request);
+
+ public class OSHttpXmlRpcHandler: OSHttpHandler
+ {
+ 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
+ /// invoked by the request matcher in OSHttpRequestPump.
+ ///
+ /// true if the handler is interested in the content;
+ /// false otherwise
+ public OSHttpContentTypeChecker ContentTypeChecker
+ {
+ get
+ {
+ return delegate(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 = 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
+ private OSHttpXmlRpcProcessor _handler;
+
+ // contains XmlRpc method name
+ private string _methodName;
+
+
+ ///
+ /// Instantiate an XmlRpc handler.
+ ///
+ /// OSHttpXmlRpcProcessor
+ /// delegate
+ /// XmlRpc method name
+ /// XmlRpc path prefix (regular expression)
+ /// Dictionary with header names and
+ /// regular expressions to match content of headers
+ /// IP whitelist of remote end points
+ /// to accept (regular expression)
+ ///
+ /// Except for handler and methodName, all other parameters
+ /// 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,
+ Dictionary headers, Regex 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
+ /// delegate
+ /// XmlRpc method name
+ public OSHttpXmlRpcHandler(OSHttpXmlRpcProcessor handler, string methodName)
+ : this(handler, methodName, null, null, null)
+ {
+ }
+
+
+ ///
+ /// Invoked by OSHttpRequestPump.
+ ///
+ public OSHttpHandlerResult Process(OSHttpRequest request)
+ {
+ XmlRpcResponse xmlRpcResponse;
+ string responseString;
+
+ OSHttpResponse resp = new OSHttpResponse(request);
+
+ try
+ {
+ // reified XmlRpcRequest must still be on the whiteboard
+ XmlRpcRequest xmlRpcRequest = request.Whiteboard["xmlrequest"] as XmlRpcRequest;
+ xmlRpcResponse = _handler(xmlRpcRequest);
+ responseString = XmlRpcResponseSerializer.Singleton.Serialize(xmlRpcResponse);
+
+ resp.ContentType = "text/xml";
+ byte[] buffer = Encoding.UTF8.GetBytes(responseString);
+
+ resp.SendChunked = false;
+ resp.ContentLength = buffer.Length;
+ resp.ContentEncoding = Encoding.UTF8;
+
+ resp.Body.Write(buffer, 0, buffer.Length);
+ resp.Body.Flush();
+
+ resp.Send();
+
+ }
+ catch (Exception ex)
+ {
+ _log.WarnFormat("[OSHttpXmlRpcHandler]: Error: {0}", ex.Message);
+ return OSHttpHandlerResult.Pass;
+ }
+ return OSHttpHandlerResult.Done;
+ }
+ }
+}
\ No newline at end of file