* Fixed a nasty OSD->JSON bug that was producing invalid JSON for empty arrays or dictionaries

* Several fixes in OpenMetaverse.Http.CapsServer and OpenMetaverse.Http.EventQueueServer (this is the first time they've been tested)
[Simian]
* Initial capabilities and EventQueue support (appears to be working)
* HyperGrid is almost working
* More cleanup with how agents are removed from the scene

git-svn-id: http://libopenmetaverse.googlecode.com/svn/libopenmetaverse/trunk@2427 52acb1d6-8a22-11de-b505-999d5b087335
This commit is contained in:
John Hurliman
2009-02-04 23:00:33 +00:00
parent 875aa0b6e8
commit 808b681b83
17 changed files with 689 additions and 138 deletions

View File

@@ -34,19 +34,31 @@ using HttpServer;
namespace OpenMetaverse.Http
{
/// <summary>
/// Delegate for handling incoming HTTP requests through a capability
/// </summary>
/// <param name="context">Client context</param>
/// <param name="request">HTTP request</param>
/// <param name="response">HTTP response</param>
/// <param name="state">User-defined state object</param>
/// <returns>True to send the response and close the connection, false to leave the connection open</returns>
public delegate bool CapsRequestCallback(IHttpClientContext context, IHttpRequest request, IHttpResponse response, object state);
public class CapsServer
{
struct CapsRedirector
{
public HttpRequestCallback LocalCallback;
public CapsRequestCallback LocalCallback;
public Uri RemoteHandler;
public bool ClientCertRequired;
public object State;
public CapsRedirector(HttpRequestCallback localCallback, Uri remoteHandler, bool clientCertRequired)
public CapsRedirector(CapsRequestCallback localCallback, Uri remoteHandler, bool clientCertRequired, object state)
{
LocalCallback = localCallback;
RemoteHandler = remoteHandler;
ClientCertRequired = clientCertRequired;
State = state;
}
}
@@ -60,7 +72,7 @@ namespace OpenMetaverse.Http
public CapsServer(IPAddress address, int port)
{
serverOwned = true;
capsHandler = BuildCapsHandler("^/");
capsHandler = BuildCapsHandler(@"^/caps/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$");
server = new WebServer(address, port);
server.LogWriter = new log4netLogWriter(Logger.Log);
}
@@ -68,7 +80,7 @@ namespace OpenMetaverse.Http
public CapsServer(IPAddress address, int port, X509Certificate sslCertificate, X509Certificate rootCA, bool requireClientCertificate)
{
serverOwned = true;
capsHandler = BuildCapsHandler("^/");
capsHandler = BuildCapsHandler(@"^/caps/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$");
server = new WebServer(address, port, sslCertificate, rootCA, requireClientCertificate);
server.LogWriter = new log4netLogWriter(Logger.Log);
}
@@ -96,10 +108,10 @@ namespace OpenMetaverse.Http
server.RemoveHandler(capsHandler);
}
public UUID CreateCapability(HttpRequestCallback localHandler, bool clientCertRequired)
public UUID CreateCapability(CapsRequestCallback localHandler, bool clientCertRequired, object state)
{
UUID id = UUID.Random();
CapsRedirector redirector = new CapsRedirector(localHandler, null, clientCertRequired);
CapsRedirector redirector = new CapsRedirector(localHandler, null, clientCertRequired, state);
lock (syncRoot)
fixedCaps.Add(id, redirector);
@@ -110,7 +122,7 @@ namespace OpenMetaverse.Http
public UUID CreateCapability(Uri remoteHandler, bool clientCertRequired)
{
UUID id = UUID.Random();
CapsRedirector redirector = new CapsRedirector(null, remoteHandler, clientCertRequired);
CapsRedirector redirector = new CapsRedirector(null, remoteHandler, clientCertRequired, null);
lock (syncRoot)
fixedCaps.Add(id, redirector);
@@ -118,10 +130,10 @@ namespace OpenMetaverse.Http
return id;
}
public UUID CreateCapability(HttpRequestCallback localHandler, bool clientCertRequired, double ttlSeconds)
public UUID CreateCapability(CapsRequestCallback localHandler, bool clientCertRequired, object state, double ttlSeconds)
{
UUID id = UUID.Random();
CapsRedirector redirector = new CapsRedirector(localHandler, null, clientCertRequired);
CapsRedirector redirector = new CapsRedirector(localHandler, null, clientCertRequired, state);
lock (syncRoot)
expiringCaps.Add(id, redirector, DateTime.Now + TimeSpan.FromSeconds(ttlSeconds));
@@ -129,10 +141,10 @@ namespace OpenMetaverse.Http
return id;
}
public UUID CreateCapability(Uri remoteHandler, bool clientCertRequired, double ttlSeconds)
public UUID CreateCapability(Uri remoteHandler, bool clientCertRequired, object state, double ttlSeconds)
{
UUID id = UUID.Random();
CapsRedirector redirector = new CapsRedirector(null, remoteHandler, clientCertRequired);
CapsRedirector redirector = new CapsRedirector(null, remoteHandler, clientCertRequired, state);
lock (syncRoot)
expiringCaps.Add(id, redirector, DateTime.Now + TimeSpan.FromSeconds(ttlSeconds));
@@ -156,9 +168,10 @@ namespace OpenMetaverse.Http
UUID capsID;
CapsRedirector redirector;
bool success;
string uuidString = request.UriParts[request.UriParts.Length - 1];
if (UUID.TryParse(uuidString, out capsID))
string path = request.Uri.PathAndQuery.TrimEnd('/');
if (UUID.TryParse(path.Substring(path.Length - 36), out capsID))
{
lock (syncRoot)
success = (expiringCaps.TryGetValue(capsID, out redirector) || fixedCaps.TryGetValue(capsID, out redirector));
@@ -179,7 +192,7 @@ namespace OpenMetaverse.Http
if (redirector.RemoteHandler != null)
ProxyCapCallback(client, request, response, redirector.RemoteHandler);
else
return redirector.LocalCallback(client, request, response);
return redirector.LocalCallback(client, request, response, redirector.State);
return true;
}
@@ -234,7 +247,7 @@ namespace OpenMetaverse.Http
}
}
HttpServer.HttpRequestHandler BuildCapsHandler(string path)
HttpRequestHandler BuildCapsHandler(string path)
{
HttpRequestSignature signature = new HttpRequestSignature();
signature.ContentType = "application/xml";

View File

@@ -108,15 +108,15 @@ namespace OpenMetaverse.Http
eventQueue.Enqueue(events[i]);
}
public bool EventQueueHandler(ref HttpListenerContext context)
public bool EventQueueHandler(IHttpClientContext context, IHttpRequest request, IHttpResponse response)
{
// Decode the request
OSD request = null;
OSD osdRequest = null;
try { request = OSDParser.DeserializeLLSDXml(context.Request.InputStream); }
try { osdRequest = OSDParser.DeserializeLLSDXml(request.Body); }
catch (Exception) { }
if (request != null && request.Type == OSDType.Map)
if (request != null && osdRequest.Type == OSDType.Map)
{
OSDMap requestMap = (OSDMap)request;
int ack = requestMap["ack"].AsInteger();
@@ -130,7 +130,7 @@ namespace OpenMetaverse.Http
if (!done)
{
StartEventQueueThread(context);
StartEventQueueThread(context, request, response);
// Tell HttpServer to leave the connection open
return false;
@@ -138,25 +138,25 @@ namespace OpenMetaverse.Http
else
{
Logger.Log.InfoFormat("[EventQueue] Shutting down the event queue {0} at the client's request",
context.Request.Url);
request.Uri);
Stop();
context.Response.KeepAlive = context.Request.KeepAlive;
response.Connection = request.Connection;
return true;
}
}
else
{
Logger.Log.WarnFormat("[EventQueue] Received a request with invalid or missing LLSD at {0}, closing the connection",
context.Request.Url);
request.Uri);
context.Response.KeepAlive = context.Request.KeepAlive;
context.Response.StatusCode = (int)HttpStatusCode.BadRequest;
response.Connection = request.Connection;
response.Status = HttpStatusCode.BadRequest;
return true;
}
}
void StartEventQueueThread(HttpListenerContext httpContext)
void StartEventQueueThread(IHttpClientContext context, IHttpRequest request, IHttpResponse response)
{
// Spawn a new thread to hold the connection open and return from our precious IOCP thread
Thread thread = new Thread(new ThreadStart(
@@ -188,7 +188,7 @@ namespace OpenMetaverse.Http
batchMsPassed = (int)(DateTime.Now - start).TotalMilliseconds;
}
SendResponse(httpContext, eventsToSend);
SendResponse(context, request, response, eventsToSend);
return;
}
else
@@ -202,7 +202,7 @@ namespace OpenMetaverse.Http
Logger.Log.DebugFormat(
"[EventQueue] {0}ms passed without an event, timing out the event queue",
totalMsPassed);
SendResponse(httpContext, null);
SendResponse(context, request, response, null);
return;
}
}
@@ -215,9 +215,9 @@ namespace OpenMetaverse.Http
thread.Start();
}
void SendResponse(HttpListenerContext httpContext, List<EventQueueEvent> eventsToSend)
void SendResponse(IHttpClientContext context, IHttpRequest request, IHttpResponse response, List<EventQueueEvent> eventsToSend)
{
httpContext.Response.KeepAlive = httpContext.Request.KeepAlive;
response.Connection = request.Connection;
if (eventsToSend != null)
{
@@ -241,19 +241,19 @@ namespace OpenMetaverse.Http
// Serialize the events and send the response
byte[] buffer = OSDParser.SerializeLLSDXmlBytes(responseMap);
httpContext.Response.ContentType = "application/xml";
httpContext.Response.ContentLength64 = buffer.Length;
httpContext.Response.OutputStream.Write(buffer, 0, buffer.Length);
httpContext.Response.OutputStream.Close();
httpContext.Response.Close();
response.ContentType = "application/xml";
response.ContentLength = buffer.Length;
response.Body.Write(buffer, 0, buffer.Length);
response.Body.Flush();
}
else
{
// The 502 response started as a bug in the LL event queue server implementation,
// but is now hardcoded into the protocol as the code to use for a timeout
httpContext.Response.StatusCode = (int)HttpStatusCode.BadGateway;
httpContext.Response.Close();
response.Status = HttpStatusCode.BadGateway;
}
response.Send();
}
}
}