Add regression test for http inventory fetch.
Involved some restructuring to allow regression tests to dequeue inventory requests and perform poll responses synchronously rather than async0.8.0.3
parent
873eee5431
commit
f3e177814a
|
@ -50,8 +50,7 @@ namespace OpenSim.Framework.Capabilities
|
||||||
|
|
||||||
public class Caps
|
public class Caps
|
||||||
{
|
{
|
||||||
// private static readonly ILog m_log =
|
// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
||||||
// LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
|
||||||
|
|
||||||
private string m_httpListenerHostName;
|
private string m_httpListenerHostName;
|
||||||
private uint m_httpListenPort;
|
private uint m_httpListenPort;
|
||||||
|
@ -152,6 +151,10 @@ namespace OpenSim.Framework.Capabilities
|
||||||
|
|
||||||
public void RegisterPollHandler(string capName, PollServiceEventArgs pollServiceHandler)
|
public void RegisterPollHandler(string capName, PollServiceEventArgs pollServiceHandler)
|
||||||
{
|
{
|
||||||
|
// m_log.DebugFormat(
|
||||||
|
// "[CAPS]: Registering handler with name {0}, url {1} for {2}",
|
||||||
|
// capName, pollServiceHandler.Url, m_agentID, m_regionName);
|
||||||
|
|
||||||
m_pollServiceHandlers.Add(capName, pollServiceHandler);
|
m_pollServiceHandlers.Add(capName, pollServiceHandler);
|
||||||
|
|
||||||
m_httpListener.AddPollServiceHTTPHandler(pollServiceHandler.Url, pollServiceHandler);
|
m_httpListener.AddPollServiceHTTPHandler(pollServiceHandler.Url, pollServiceHandler);
|
||||||
|
|
|
@ -113,7 +113,7 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||||
|
|
||||||
protected IPAddress m_listenIPAddress = IPAddress.Any;
|
protected IPAddress m_listenIPAddress = IPAddress.Any;
|
||||||
|
|
||||||
private PollServiceRequestManager m_PollServiceManager;
|
public PollServiceRequestManager PollServiceRequestManager { get; private set; }
|
||||||
|
|
||||||
public uint SSLPort
|
public uint SSLPort
|
||||||
{
|
{
|
||||||
|
@ -374,7 +374,7 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnRequest(object source, RequestEventArgs args)
|
public void OnRequest(object source, RequestEventArgs args)
|
||||||
{
|
{
|
||||||
RequestNumber++;
|
RequestNumber++;
|
||||||
|
|
||||||
|
@ -429,7 +429,7 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||||
psEvArgs.Request(psreq.RequestID, keysvals);
|
psEvArgs.Request(psreq.RequestID, keysvals);
|
||||||
}
|
}
|
||||||
|
|
||||||
m_PollServiceManager.Enqueue(psreq);
|
PollServiceRequestManager.Enqueue(psreq);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -1781,10 +1781,17 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||||
|
|
||||||
public void Start()
|
public void Start()
|
||||||
{
|
{
|
||||||
StartHTTP();
|
Start(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void StartHTTP()
|
/// <summary>
|
||||||
|
/// Start the http server
|
||||||
|
/// </summary>
|
||||||
|
/// <param name='processPollRequestsAsync'>
|
||||||
|
/// If true then poll responses are performed asynchronsly.
|
||||||
|
/// Option exists to allow regression tests to perform processing synchronously.
|
||||||
|
/// </param>
|
||||||
|
public void Start(bool performPollResponsesAsync)
|
||||||
{
|
{
|
||||||
m_log.InfoFormat(
|
m_log.InfoFormat(
|
||||||
"[BASE HTTP SERVER]: Starting {0} server on port {1}", UseSSL ? "HTTPS" : "HTTP", Port);
|
"[BASE HTTP SERVER]: Starting {0} server on port {1}", UseSSL ? "HTTPS" : "HTTP", Port);
|
||||||
|
@ -1822,8 +1829,9 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||||
m_httpListener2.Start(64);
|
m_httpListener2.Start(64);
|
||||||
|
|
||||||
// Long Poll Service Manager with 3 worker threads a 25 second timeout for no events
|
// Long Poll Service Manager with 3 worker threads a 25 second timeout for no events
|
||||||
m_PollServiceManager = new PollServiceRequestManager(this, 3, 25000);
|
PollServiceRequestManager = new PollServiceRequestManager(this, performPollResponsesAsync, 3, 25000);
|
||||||
m_PollServiceManager.Start();
|
PollServiceRequestManager.Start();
|
||||||
|
|
||||||
HTTPDRunning = true;
|
HTTPDRunning = true;
|
||||||
|
|
||||||
//HttpListenerContext context;
|
//HttpListenerContext context;
|
||||||
|
@ -1892,7 +1900,7 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
m_PollServiceManager.Stop();
|
PollServiceRequestManager.Stop();
|
||||||
|
|
||||||
m_httpListener2.ExceptionThrown -= httpServerException;
|
m_httpListener2.ExceptionThrown -= httpServerException;
|
||||||
//m_httpListener2.DisconnectHandler = null;
|
//m_httpListener2.DisconnectHandler = null;
|
||||||
|
|
|
@ -44,6 +44,20 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||||
{
|
{
|
||||||
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Is the poll service request manager running?
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// Can be running either synchronously or asynchronously
|
||||||
|
/// </remarks>
|
||||||
|
public bool IsRunning { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Is the poll service performing responses asynchronously (with its own threads) or synchronously (via
|
||||||
|
/// external calls)?
|
||||||
|
/// </summary>
|
||||||
|
public bool PerformResponsesAsync { get; private set; }
|
||||||
|
|
||||||
private readonly BaseHttpServer m_server;
|
private readonly BaseHttpServer m_server;
|
||||||
|
|
||||||
private BlockingQueue<PollServiceHttpRequest> m_requests = new BlockingQueue<PollServiceHttpRequest>();
|
private BlockingQueue<PollServiceHttpRequest> m_requests = new BlockingQueue<PollServiceHttpRequest>();
|
||||||
|
@ -52,48 +66,53 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||||
private uint m_WorkerThreadCount = 0;
|
private uint m_WorkerThreadCount = 0;
|
||||||
private Thread[] m_workerThreads;
|
private Thread[] m_workerThreads;
|
||||||
|
|
||||||
private bool m_running = true;
|
|
||||||
|
|
||||||
private SmartThreadPool m_threadPool = new SmartThreadPool(20000, 12, 2);
|
private SmartThreadPool m_threadPool = new SmartThreadPool(20000, 12, 2);
|
||||||
|
|
||||||
// private int m_timeout = 1000; // increase timeout 250; now use the event one
|
// private int m_timeout = 1000; // increase timeout 250; now use the event one
|
||||||
|
|
||||||
public PollServiceRequestManager(BaseHttpServer pSrv, uint pWorkerThreadCount, int pTimeout)
|
public PollServiceRequestManager(
|
||||||
|
BaseHttpServer pSrv, bool performResponsesAsync, uint pWorkerThreadCount, int pTimeout)
|
||||||
{
|
{
|
||||||
m_server = pSrv;
|
m_server = pSrv;
|
||||||
|
PerformResponsesAsync = performResponsesAsync;
|
||||||
m_WorkerThreadCount = pWorkerThreadCount;
|
m_WorkerThreadCount = pWorkerThreadCount;
|
||||||
m_workerThreads = new Thread[m_WorkerThreadCount];
|
m_workerThreads = new Thread[m_WorkerThreadCount];
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Start()
|
public void Start()
|
||||||
{
|
{
|
||||||
//startup worker threads
|
IsRunning = true;
|
||||||
for (uint i = 0; i < m_WorkerThreadCount; i++)
|
|
||||||
{
|
|
||||||
m_workerThreads[i]
|
|
||||||
= Watchdog.StartThread(
|
|
||||||
PoolWorkerJob,
|
|
||||||
string.Format("PollServiceWorkerThread{0}:{1}", i, m_server.Port),
|
|
||||||
ThreadPriority.Normal,
|
|
||||||
false,
|
|
||||||
false,
|
|
||||||
null,
|
|
||||||
int.MaxValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
Watchdog.StartThread(
|
if (PerformResponsesAsync)
|
||||||
this.CheckLongPollThreads,
|
{
|
||||||
string.Format("LongPollServiceWatcherThread:{0}", m_server.Port),
|
//startup worker threads
|
||||||
ThreadPriority.Normal,
|
for (uint i = 0; i < m_WorkerThreadCount; i++)
|
||||||
false,
|
{
|
||||||
true,
|
m_workerThreads[i]
|
||||||
null,
|
= Watchdog.StartThread(
|
||||||
1000 * 60 * 10);
|
PoolWorkerJob,
|
||||||
|
string.Format("PollServiceWorkerThread{0}:{1}", i, m_server.Port),
|
||||||
|
ThreadPriority.Normal,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
null,
|
||||||
|
int.MaxValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
Watchdog.StartThread(
|
||||||
|
this.CheckLongPollThreads,
|
||||||
|
string.Format("LongPollServiceWatcherThread:{0}", m_server.Port),
|
||||||
|
ThreadPriority.Normal,
|
||||||
|
false,
|
||||||
|
true,
|
||||||
|
null,
|
||||||
|
1000 * 60 * 10);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ReQueueEvent(PollServiceHttpRequest req)
|
private void ReQueueEvent(PollServiceHttpRequest req)
|
||||||
{
|
{
|
||||||
if (m_running)
|
if (IsRunning)
|
||||||
{
|
{
|
||||||
// delay the enqueueing for 100ms. There's no need to have the event
|
// delay the enqueueing for 100ms. There's no need to have the event
|
||||||
// actively on the queue
|
// actively on the queue
|
||||||
|
@ -109,7 +128,7 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||||
|
|
||||||
public void Enqueue(PollServiceHttpRequest req)
|
public void Enqueue(PollServiceHttpRequest req)
|
||||||
{
|
{
|
||||||
if (m_running)
|
if (IsRunning)
|
||||||
{
|
{
|
||||||
if (req.PollServiceArgs.Type == PollServiceEventArgs.EventType.LongPoll)
|
if (req.PollServiceArgs.Type == PollServiceEventArgs.EventType.LongPoll)
|
||||||
{
|
{
|
||||||
|
@ -129,7 +148,7 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||||
// All other types of tasks (Inventory handlers, http-in, etc) don't have the long-poll nature,
|
// All other types of tasks (Inventory handlers, http-in, etc) don't have the long-poll nature,
|
||||||
// so if they aren't ready to be served by a worker thread (no events), they are placed
|
// so if they aren't ready to be served by a worker thread (no events), they are placed
|
||||||
// directly back in the "ready-to-serve" queue by the worker thread.
|
// directly back in the "ready-to-serve" queue by the worker thread.
|
||||||
while (m_running)
|
while (IsRunning)
|
||||||
{
|
{
|
||||||
Thread.Sleep(500);
|
Thread.Sleep(500);
|
||||||
Watchdog.UpdateThread();
|
Watchdog.UpdateThread();
|
||||||
|
@ -137,7 +156,7 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||||
// List<PollServiceHttpRequest> not_ready = new List<PollServiceHttpRequest>();
|
// List<PollServiceHttpRequest> not_ready = new List<PollServiceHttpRequest>();
|
||||||
lock (m_longPollRequests)
|
lock (m_longPollRequests)
|
||||||
{
|
{
|
||||||
if (m_longPollRequests.Count > 0 && m_running)
|
if (m_longPollRequests.Count > 0 && IsRunning)
|
||||||
{
|
{
|
||||||
List<PollServiceHttpRequest> ready = m_longPollRequests.FindAll(req =>
|
List<PollServiceHttpRequest> ready = m_longPollRequests.FindAll(req =>
|
||||||
(req.PollServiceArgs.HasEvents(req.RequestID, req.PollServiceArgs.Id) || // there are events in this EQ
|
(req.PollServiceArgs.HasEvents(req.RequestID, req.PollServiceArgs.Id) || // there are events in this EQ
|
||||||
|
@ -158,7 +177,7 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||||
|
|
||||||
public void Stop()
|
public void Stop()
|
||||||
{
|
{
|
||||||
m_running = false;
|
IsRunning = false;
|
||||||
// m_timeout = -10000; // cause all to expire
|
// m_timeout = -10000; // cause all to expire
|
||||||
Thread.Sleep(1000); // let the world move
|
Thread.Sleep(1000); // let the world move
|
||||||
|
|
||||||
|
@ -169,7 +188,7 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||||
|
|
||||||
lock (m_longPollRequests)
|
lock (m_longPollRequests)
|
||||||
{
|
{
|
||||||
if (m_longPollRequests.Count > 0 && m_running)
|
if (m_longPollRequests.Count > 0 && IsRunning)
|
||||||
m_longPollRequests.ForEach(req => m_requests.Enqueue(req));
|
m_longPollRequests.ForEach(req => m_requests.Enqueue(req));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -194,68 +213,82 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||||
|
|
||||||
private void PoolWorkerJob()
|
private void PoolWorkerJob()
|
||||||
{
|
{
|
||||||
while (m_running)
|
while (IsRunning)
|
||||||
{
|
{
|
||||||
PollServiceHttpRequest req = m_requests.Dequeue(5000);
|
|
||||||
//m_log.WarnFormat("[YYY]: Dequeued {0}", (req == null ? "null" : req.PollServiceArgs.Type.ToString()));
|
|
||||||
|
|
||||||
Watchdog.UpdateThread();
|
Watchdog.UpdateThread();
|
||||||
if (req != null)
|
WaitPerformResponse();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void WaitPerformResponse()
|
||||||
|
{
|
||||||
|
PollServiceHttpRequest req = m_requests.Dequeue(5000);
|
||||||
|
// m_log.DebugFormat("[YYY]: Dequeued {0}", (req == null ? "null" : req.PollServiceArgs.Type.ToString()));
|
||||||
|
|
||||||
|
if (req != null)
|
||||||
|
{
|
||||||
|
try
|
||||||
{
|
{
|
||||||
try
|
if (req.PollServiceArgs.HasEvents(req.RequestID, req.PollServiceArgs.Id))
|
||||||
{
|
{
|
||||||
if (req.PollServiceArgs.HasEvents(req.RequestID, req.PollServiceArgs.Id))
|
Hashtable responsedata = req.PollServiceArgs.GetEvents(req.RequestID, req.PollServiceArgs.Id);
|
||||||
|
|
||||||
|
if (responsedata == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// This is the event queue.
|
||||||
|
// Even if we're not running we can still perform responses by explicit request.
|
||||||
|
if (req.PollServiceArgs.Type == PollServiceEventArgs.EventType.LongPoll
|
||||||
|
|| !PerformResponsesAsync)
|
||||||
{
|
{
|
||||||
Hashtable responsedata = req.PollServiceArgs.GetEvents(req.RequestID, req.PollServiceArgs.Id);
|
try
|
||||||
|
{
|
||||||
if (responsedata == null)
|
req.DoHTTPGruntWork(m_server, responsedata);
|
||||||
continue;
|
}
|
||||||
|
catch (ObjectDisposedException e) // Browser aborted before we could read body, server closed the stream
|
||||||
if (req.PollServiceArgs.Type == PollServiceEventArgs.EventType.LongPoll) // This is the event queue
|
{
|
||||||
|
// Ignore it, no need to reply
|
||||||
|
m_log.Error(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_threadPool.QueueWorkItem(x =>
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
req.DoHTTPGruntWork(m_server, responsedata);
|
req.DoHTTPGruntWork(m_server, responsedata);
|
||||||
}
|
}
|
||||||
catch (ObjectDisposedException) // Browser aborted before we could read body, server closed the stream
|
catch (ObjectDisposedException e) // Browser aborted before we could read body, server closed the stream
|
||||||
{
|
{
|
||||||
// Ignore it, no need to reply
|
// Ignore it, no need to reply
|
||||||
|
m_log.Error(e);
|
||||||
}
|
}
|
||||||
}
|
catch (Exception e)
|
||||||
else
|
|
||||||
{
|
|
||||||
m_threadPool.QueueWorkItem(x =>
|
|
||||||
{
|
{
|
||||||
try
|
m_log.Error(e);
|
||||||
{
|
}
|
||||||
req.DoHTTPGruntWork(m_server, responsedata);
|
|
||||||
}
|
|
||||||
catch (ObjectDisposedException) // Browser aborted before we could read body, server closed the stream
|
|
||||||
{
|
|
||||||
// Ignore it, no need to reply
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}, null);
|
}, null);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if ((Environment.TickCount - req.RequestTime) > req.PollServiceArgs.TimeOutms)
|
||||||
|
{
|
||||||
|
req.DoHTTPGruntWork(
|
||||||
|
m_server, req.PollServiceArgs.NoEvents(req.RequestID, req.PollServiceArgs.Id));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if ((Environment.TickCount - req.RequestTime) > req.PollServiceArgs.TimeOutms)
|
ReQueueEvent(req);
|
||||||
{
|
|
||||||
req.DoHTTPGruntWork(
|
|
||||||
m_server, req.PollServiceArgs.NoEvents(req.RequestID, req.PollServiceArgs.Id));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ReQueueEvent(req);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
}
|
||||||
{
|
catch (Exception e)
|
||||||
m_log.ErrorFormat("Exception in poll service thread: " + e.ToString());
|
{
|
||||||
}
|
m_log.ErrorFormat("Exception in poll service thread: " + e.ToString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,323 +41,7 @@ namespace OpenSim.Framework.Servers.Tests
|
||||||
{
|
{
|
||||||
[TestFixture]
|
[TestFixture]
|
||||||
public class OSHttpTests : OpenSimTestCase
|
public class OSHttpTests : OpenSimTestCase
|
||||||
{
|
{
|
||||||
// we need an IHttpClientContext for our tests
|
|
||||||
public class TestHttpClientContext: IHttpClientContext
|
|
||||||
{
|
|
||||||
private bool _secured;
|
|
||||||
public bool IsSecured
|
|
||||||
{
|
|
||||||
get { return _secured; }
|
|
||||||
}
|
|
||||||
public bool Secured
|
|
||||||
{
|
|
||||||
get { return _secured; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public TestHttpClientContext(bool secured)
|
|
||||||
{
|
|
||||||
_secured = secured;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Disconnect(SocketError error) {}
|
|
||||||
public void Respond(string httpVersion, HttpStatusCode statusCode, string reason, string body) {}
|
|
||||||
public void Respond(string httpVersion, HttpStatusCode statusCode, string reason) {}
|
|
||||||
public void Respond(string body) {}
|
|
||||||
public void Send(byte[] buffer) {}
|
|
||||||
public void Send(byte[] buffer, int offset, int size) {}
|
|
||||||
public void Respond(string httpVersion, HttpStatusCode statusCode, string reason, string body, string contentType) {}
|
|
||||||
public void Close() { }
|
|
||||||
public bool EndWhenDone { get { return false;} set { return;}}
|
|
||||||
|
|
||||||
public HTTPNetworkContext GiveMeTheNetworkStreamIKnowWhatImDoing()
|
|
||||||
{
|
|
||||||
return new HTTPNetworkContext();
|
|
||||||
}
|
|
||||||
|
|
||||||
public event EventHandler<DisconnectedEventArgs> Disconnected = delegate { };
|
|
||||||
/// <summary>
|
|
||||||
/// A request have been received in the context.
|
|
||||||
/// </summary>
|
|
||||||
public event EventHandler<RequestEventArgs> RequestReceived = delegate { };
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public class TestHttpRequest: IHttpRequest
|
|
||||||
{
|
|
||||||
private string _uriPath;
|
|
||||||
public bool BodyIsComplete
|
|
||||||
{
|
|
||||||
get { return true; }
|
|
||||||
}
|
|
||||||
public string[] AcceptTypes
|
|
||||||
{
|
|
||||||
get {return _acceptTypes; }
|
|
||||||
}
|
|
||||||
private string[] _acceptTypes;
|
|
||||||
public Stream Body
|
|
||||||
{
|
|
||||||
get { return _body; }
|
|
||||||
set { _body = value;}
|
|
||||||
}
|
|
||||||
private Stream _body;
|
|
||||||
public ConnectionType Connection
|
|
||||||
{
|
|
||||||
get { return _connection; }
|
|
||||||
set { _connection = value; }
|
|
||||||
}
|
|
||||||
private ConnectionType _connection;
|
|
||||||
public int ContentLength
|
|
||||||
{
|
|
||||||
get { return _contentLength; }
|
|
||||||
set { _contentLength = value; }
|
|
||||||
}
|
|
||||||
private int _contentLength;
|
|
||||||
public NameValueCollection Headers
|
|
||||||
{
|
|
||||||
get { return _headers; }
|
|
||||||
}
|
|
||||||
private NameValueCollection _headers = new NameValueCollection();
|
|
||||||
public string HttpVersion
|
|
||||||
{
|
|
||||||
get { return _httpVersion; }
|
|
||||||
set { _httpVersion = value; }
|
|
||||||
}
|
|
||||||
private string _httpVersion = null;
|
|
||||||
public string Method
|
|
||||||
{
|
|
||||||
get { return _method; }
|
|
||||||
set { _method = value; }
|
|
||||||
}
|
|
||||||
private string _method = null;
|
|
||||||
public HttpInput QueryString
|
|
||||||
{
|
|
||||||
get { return _queryString; }
|
|
||||||
}
|
|
||||||
private HttpInput _queryString = null;
|
|
||||||
public Uri Uri
|
|
||||||
{
|
|
||||||
get { return _uri; }
|
|
||||||
set { _uri = value; }
|
|
||||||
}
|
|
||||||
private Uri _uri = null;
|
|
||||||
public string[] UriParts
|
|
||||||
{
|
|
||||||
get { return _uri.Segments; }
|
|
||||||
}
|
|
||||||
public HttpParam Param
|
|
||||||
{
|
|
||||||
get { return null; }
|
|
||||||
}
|
|
||||||
public HttpForm Form
|
|
||||||
{
|
|
||||||
get { return null; }
|
|
||||||
}
|
|
||||||
public bool IsAjax
|
|
||||||
{
|
|
||||||
get { return false; }
|
|
||||||
}
|
|
||||||
public RequestCookies Cookies
|
|
||||||
{
|
|
||||||
get { return null; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public TestHttpRequest() {}
|
|
||||||
|
|
||||||
public TestHttpRequest(string contentEncoding, string contentType, string userAgent,
|
|
||||||
string remoteAddr, string remotePort, string[] acceptTypes,
|
|
||||||
ConnectionType connectionType, int contentLength, Uri uri)
|
|
||||||
{
|
|
||||||
_headers["content-encoding"] = contentEncoding;
|
|
||||||
_headers["content-type"] = contentType;
|
|
||||||
_headers["user-agent"] = userAgent;
|
|
||||||
_headers["remote_addr"] = remoteAddr;
|
|
||||||
_headers["remote_port"] = remotePort;
|
|
||||||
|
|
||||||
_acceptTypes = acceptTypes;
|
|
||||||
_connection = connectionType;
|
|
||||||
_contentLength = contentLength;
|
|
||||||
_uri = uri;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void DecodeBody(FormDecoderProvider providers) {}
|
|
||||||
public void SetCookies(RequestCookies cookies) {}
|
|
||||||
public void AddHeader(string name, string value)
|
|
||||||
{
|
|
||||||
_headers.Add(name, value);
|
|
||||||
}
|
|
||||||
public int AddToBody(byte[] bytes, int offset, int length)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
public void Clear() {}
|
|
||||||
|
|
||||||
public object Clone()
|
|
||||||
{
|
|
||||||
TestHttpRequest clone = new TestHttpRequest();
|
|
||||||
clone._acceptTypes = _acceptTypes;
|
|
||||||
clone._connection = _connection;
|
|
||||||
clone._contentLength = _contentLength;
|
|
||||||
clone._uri = _uri;
|
|
||||||
clone._headers = new NameValueCollection(_headers);
|
|
||||||
|
|
||||||
return clone;
|
|
||||||
}
|
|
||||||
public IHttpResponse CreateResponse(IHttpClientContext context)
|
|
||||||
{
|
|
||||||
return new HttpResponse(context, this);
|
|
||||||
}
|
|
||||||
/// <summary>
|
|
||||||
/// Path and query (will be merged with the host header) and put in Uri
|
|
||||||
/// </summary>
|
|
||||||
/// <see cref="Uri"/>
|
|
||||||
public string UriPath
|
|
||||||
{
|
|
||||||
get { return _uriPath; }
|
|
||||||
set
|
|
||||||
{
|
|
||||||
_uriPath = value;
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public class TestHttpResponse: IHttpResponse
|
|
||||||
{
|
|
||||||
public Stream Body
|
|
||||||
{
|
|
||||||
get { return _body; }
|
|
||||||
|
|
||||||
set { _body = value; }
|
|
||||||
}
|
|
||||||
private Stream _body;
|
|
||||||
|
|
||||||
public string ProtocolVersion
|
|
||||||
{
|
|
||||||
get { return _protocolVersion; }
|
|
||||||
set { _protocolVersion = value; }
|
|
||||||
}
|
|
||||||
private string _protocolVersion;
|
|
||||||
|
|
||||||
public bool Chunked
|
|
||||||
{
|
|
||||||
get { return _chunked; }
|
|
||||||
|
|
||||||
set { _chunked = value; }
|
|
||||||
}
|
|
||||||
private bool _chunked;
|
|
||||||
|
|
||||||
public ConnectionType Connection
|
|
||||||
{
|
|
||||||
get { return _connection; }
|
|
||||||
|
|
||||||
set { _connection = value; }
|
|
||||||
}
|
|
||||||
private ConnectionType _connection;
|
|
||||||
|
|
||||||
public Encoding Encoding
|
|
||||||
{
|
|
||||||
get { return _encoding; }
|
|
||||||
|
|
||||||
set { _encoding = value; }
|
|
||||||
}
|
|
||||||
private Encoding _encoding;
|
|
||||||
|
|
||||||
public int KeepAlive
|
|
||||||
{
|
|
||||||
get { return _keepAlive; }
|
|
||||||
|
|
||||||
set { _keepAlive = value; }
|
|
||||||
}
|
|
||||||
private int _keepAlive;
|
|
||||||
|
|
||||||
public HttpStatusCode Status
|
|
||||||
{
|
|
||||||
get { return _status; }
|
|
||||||
|
|
||||||
set { _status = value; }
|
|
||||||
}
|
|
||||||
private HttpStatusCode _status;
|
|
||||||
|
|
||||||
public string Reason
|
|
||||||
{
|
|
||||||
get { return _reason; }
|
|
||||||
|
|
||||||
set { _reason = value; }
|
|
||||||
}
|
|
||||||
private string _reason;
|
|
||||||
|
|
||||||
public long ContentLength
|
|
||||||
{
|
|
||||||
get { return _contentLength; }
|
|
||||||
|
|
||||||
set { _contentLength = value; }
|
|
||||||
}
|
|
||||||
private long _contentLength;
|
|
||||||
|
|
||||||
public string ContentType
|
|
||||||
{
|
|
||||||
get { return _contentType; }
|
|
||||||
|
|
||||||
set { _contentType = value; }
|
|
||||||
}
|
|
||||||
private string _contentType;
|
|
||||||
|
|
||||||
public bool HeadersSent
|
|
||||||
{
|
|
||||||
get { return _headersSent; }
|
|
||||||
}
|
|
||||||
private bool _headersSent;
|
|
||||||
|
|
||||||
public bool Sent
|
|
||||||
{
|
|
||||||
get { return _sent; }
|
|
||||||
}
|
|
||||||
private bool _sent;
|
|
||||||
|
|
||||||
public ResponseCookies Cookies
|
|
||||||
{
|
|
||||||
get { return _cookies; }
|
|
||||||
}
|
|
||||||
private ResponseCookies _cookies = null;
|
|
||||||
|
|
||||||
public TestHttpResponse()
|
|
||||||
{
|
|
||||||
_headersSent = false;
|
|
||||||
_sent = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void AddHeader(string name, string value) {}
|
|
||||||
public void Send()
|
|
||||||
{
|
|
||||||
if (!_headersSent) SendHeaders();
|
|
||||||
if (_sent) throw new InvalidOperationException("stuff already sent");
|
|
||||||
_sent = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SendBody(byte[] buffer, int offset, int count)
|
|
||||||
{
|
|
||||||
if (!_headersSent) SendHeaders();
|
|
||||||
_sent = true;
|
|
||||||
}
|
|
||||||
public void SendBody(byte[] buffer)
|
|
||||||
{
|
|
||||||
if (!_headersSent) SendHeaders();
|
|
||||||
_sent = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SendHeaders()
|
|
||||||
{
|
|
||||||
if (_headersSent) throw new InvalidOperationException("headers already sent");
|
|
||||||
_headersSent = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Redirect(Uri uri) {}
|
|
||||||
public void Redirect(string url) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public OSHttpRequest req0;
|
public OSHttpRequest req0;
|
||||||
public OSHttpRequest req1;
|
public OSHttpRequest req1;
|
||||||
|
|
||||||
|
@ -429,4 +113,4 @@ namespace OpenSim.Framework.Servers.Tests
|
||||||
Assert.That(rsp0.ContentType, Is.EqualTo("text/xml"));
|
Assert.That(rsp0.ContentType, Is.EqualTo("text/xml"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,158 @@
|
||||||
|
/*
|
||||||
|
* 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 OpenSimulator 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;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Net;
|
||||||
|
using System.Text;
|
||||||
|
using HttpServer;
|
||||||
|
using log4net.Config;
|
||||||
|
using Nini.Config;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using OpenMetaverse;
|
||||||
|
using OpenMetaverse.Packets;
|
||||||
|
using OpenMetaverse.StructuredData;
|
||||||
|
using OpenSim.Framework;
|
||||||
|
using OpenSim.Framework.Capabilities;
|
||||||
|
using OpenSim.Framework.Servers;
|
||||||
|
using OpenSim.Framework.Servers.HttpServer;
|
||||||
|
using OpenSim.Region.ClientStack.Linden;
|
||||||
|
using OpenSim.Region.CoreModules.Framework;
|
||||||
|
using OpenSim.Region.Framework.Scenes;
|
||||||
|
using OpenSim.Services.Interfaces;
|
||||||
|
using OpenSim.Tests.Common;
|
||||||
|
using OpenSim.Tests.Common.Mock;
|
||||||
|
using OSDArray = OpenMetaverse.StructuredData.OSDArray;
|
||||||
|
using OSDMap = OpenMetaverse.StructuredData.OSDMap;
|
||||||
|
|
||||||
|
namespace OpenSim.Region.ClientStack.Linden.Caps.Tests
|
||||||
|
{
|
||||||
|
[TestFixture]
|
||||||
|
public class WebFetchInvDescModuleTests : OpenSimTestCase
|
||||||
|
{
|
||||||
|
[TestFixtureSetUp]
|
||||||
|
public void TestFixtureSetUp()
|
||||||
|
{
|
||||||
|
// Don't allow tests to be bamboozled by asynchronous events. Execute everything on the same thread.
|
||||||
|
Util.FireAndForgetMethod = FireAndForgetMethod.RegressionTest;
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestFixtureTearDown]
|
||||||
|
public void TestFixureTearDown()
|
||||||
|
{
|
||||||
|
// We must set this back afterwards, otherwise later tests will fail since they're expecting multiple
|
||||||
|
// threads. Possibly, later tests should be rewritten so none of them require async stuff (which regression
|
||||||
|
// tests really shouldn't).
|
||||||
|
Util.FireAndForgetMethod = Util.DefaultFireAndForgetMethod;
|
||||||
|
}
|
||||||
|
|
||||||
|
[SetUp]
|
||||||
|
public override void SetUp()
|
||||||
|
{
|
||||||
|
base.SetUp();
|
||||||
|
|
||||||
|
// This is an unfortunate bit of clean up we have to do because MainServer manages things through static
|
||||||
|
// variables and the VM is not restarted between tests.
|
||||||
|
uint port = 9999;
|
||||||
|
MainServer.RemoveHttpServer(port);
|
||||||
|
|
||||||
|
BaseHttpServer server = new BaseHttpServer(port, false, 0, "");
|
||||||
|
MainServer.AddHttpServer(server);
|
||||||
|
MainServer.Instance = server;
|
||||||
|
|
||||||
|
server.Start(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestInventoryDescendentsFetch()
|
||||||
|
{
|
||||||
|
TestHelpers.InMethod();
|
||||||
|
TestHelpers.EnableLogging();
|
||||||
|
|
||||||
|
BaseHttpServer httpServer = MainServer.Instance;
|
||||||
|
Scene scene = new SceneHelpers().SetupScene();
|
||||||
|
|
||||||
|
CapabilitiesModule capsModule = new CapabilitiesModule();
|
||||||
|
WebFetchInvDescModule wfidModule = new WebFetchInvDescModule(false);
|
||||||
|
|
||||||
|
IConfigSource config = new IniConfigSource();
|
||||||
|
config.AddConfig("ClientStack.LindenCaps");
|
||||||
|
config.Configs["ClientStack.LindenCaps"].Set("Cap_FetchInventoryDescendents2", "localhost");
|
||||||
|
|
||||||
|
SceneHelpers.SetupSceneModules(scene, config, capsModule, wfidModule);
|
||||||
|
|
||||||
|
UserAccount ua = UserAccountHelpers.CreateUserWithInventory(scene, TestHelpers.ParseTail(0x1));
|
||||||
|
|
||||||
|
// We need a user present to have any capabilities set up
|
||||||
|
SceneHelpers.AddScenePresence(scene, ua.PrincipalID);
|
||||||
|
|
||||||
|
TestHttpRequest req = new TestHttpRequest();
|
||||||
|
OpenSim.Framework.Capabilities.Caps userCaps = capsModule.GetCapsForUser(ua.PrincipalID);
|
||||||
|
PollServiceEventArgs pseArgs;
|
||||||
|
userCaps.TryGetPollHandler("FetchInventoryDescendents2", out pseArgs);
|
||||||
|
req.UriPath = pseArgs.Url;
|
||||||
|
req.Uri = new Uri(req.UriPath);
|
||||||
|
|
||||||
|
// Retrieve root folder details directly so that we can request
|
||||||
|
InventoryFolderBase folder = scene.InventoryService.GetRootFolder(ua.PrincipalID);
|
||||||
|
|
||||||
|
OSDMap osdFolder = new OSDMap();
|
||||||
|
osdFolder["folder_id"] = folder.ID;
|
||||||
|
osdFolder["owner_id"] = ua.PrincipalID;
|
||||||
|
osdFolder["fetch_folders"] = true;
|
||||||
|
osdFolder["fetch_items"] = true;
|
||||||
|
osdFolder["sort_order"] = 0;
|
||||||
|
|
||||||
|
OSDArray osdFoldersArray = new OSDArray();
|
||||||
|
osdFoldersArray.Add(osdFolder);
|
||||||
|
|
||||||
|
OSDMap osdReqMap = new OSDMap();
|
||||||
|
osdReqMap["folders"] = osdFoldersArray;
|
||||||
|
|
||||||
|
req.Body = new MemoryStream(OSDParser.SerializeLLSDXmlBytes(osdReqMap));
|
||||||
|
|
||||||
|
TestHttpClientContext context = new TestHttpClientContext(false);
|
||||||
|
MainServer.Instance.OnRequest(context, new RequestEventArgs(req));
|
||||||
|
|
||||||
|
// Drive processing of the queued inventory request synchronously.
|
||||||
|
wfidModule.WaitProcessQueuedInventoryRequest();
|
||||||
|
MainServer.Instance.PollServiceRequestManager.WaitPerformResponse();
|
||||||
|
|
||||||
|
// System.Threading.Thread.Sleep(10000);
|
||||||
|
|
||||||
|
OSDMap responseOsd = (OSDMap)OSDParser.DeserializeLLSDXml(context.ResponseBody);
|
||||||
|
OSDArray foldersOsd = (OSDArray)responseOsd["folders"];
|
||||||
|
OSDMap folderOsd = (OSDMap)foldersOsd[0];
|
||||||
|
|
||||||
|
// A sanity check that the response has the expected number of descendents for a default inventory
|
||||||
|
// TODO: Need a more thorough check.
|
||||||
|
Assert.That((int)folderOsd["descendents"], Is.EqualTo(14));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -65,6 +65,15 @@ namespace OpenSim.Region.ClientStack.Linden
|
||||||
|
|
||||||
// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Control whether requests will be processed asynchronously.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// Defaults to true. Can currently not be changed once a region has been added to the module.
|
||||||
|
/// </remarks>
|
||||||
|
public bool ProcessQueuedRequestsAsync { get; private set; }
|
||||||
|
|
||||||
private Scene m_scene;
|
private Scene m_scene;
|
||||||
|
|
||||||
private IInventoryService m_InventoryService;
|
private IInventoryService m_InventoryService;
|
||||||
|
@ -84,6 +93,13 @@ namespace OpenSim.Region.ClientStack.Linden
|
||||||
|
|
||||||
#region ISharedRegionModule Members
|
#region ISharedRegionModule Members
|
||||||
|
|
||||||
|
public WebFetchInvDescModule() : this(true) {}
|
||||||
|
|
||||||
|
public WebFetchInvDescModule(bool processQueuedResultsAsync)
|
||||||
|
{
|
||||||
|
ProcessQueuedRequestsAsync = processQueuedResultsAsync;
|
||||||
|
}
|
||||||
|
|
||||||
public void Initialise(IConfigSource source)
|
public void Initialise(IConfigSource source)
|
||||||
{
|
{
|
||||||
IConfig config = source.Configs["ClientStack.LindenCaps"];
|
IConfig config = source.Configs["ClientStack.LindenCaps"];
|
||||||
|
@ -114,8 +130,16 @@ namespace OpenSim.Region.ClientStack.Linden
|
||||||
|
|
||||||
m_scene.EventManager.OnRegisterCaps -= RegisterCaps;
|
m_scene.EventManager.OnRegisterCaps -= RegisterCaps;
|
||||||
|
|
||||||
foreach (Thread t in m_workerThreads)
|
if (ProcessQueuedRequestsAsync)
|
||||||
Watchdog.AbortThread(t.ManagedThreadId);
|
{
|
||||||
|
if (m_workerThreads != null)
|
||||||
|
{
|
||||||
|
foreach (Thread t in m_workerThreads)
|
||||||
|
Watchdog.AbortThread(t.ManagedThreadId);
|
||||||
|
|
||||||
|
m_workerThreads = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
m_scene = null;
|
m_scene = null;
|
||||||
}
|
}
|
||||||
|
@ -133,7 +157,7 @@ namespace OpenSim.Region.ClientStack.Linden
|
||||||
|
|
||||||
m_scene.EventManager.OnRegisterCaps += RegisterCaps;
|
m_scene.EventManager.OnRegisterCaps += RegisterCaps;
|
||||||
|
|
||||||
if (m_workerThreads == null)
|
if (ProcessQueuedRequestsAsync && m_workerThreads == null)
|
||||||
{
|
{
|
||||||
m_workerThreads = new Thread[2];
|
m_workerThreads = new Thread[2];
|
||||||
|
|
||||||
|
@ -358,11 +382,16 @@ namespace OpenSim.Region.ClientStack.Linden
|
||||||
{
|
{
|
||||||
Watchdog.UpdateThread();
|
Watchdog.UpdateThread();
|
||||||
|
|
||||||
aPollRequest poolreq = m_queue.Dequeue();
|
WaitProcessQueuedInventoryRequest();
|
||||||
|
|
||||||
if (poolreq != null && poolreq.thepoll != null)
|
|
||||||
poolreq.thepoll.Process(poolreq);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void WaitProcessQueuedInventoryRequest()
|
||||||
|
{
|
||||||
|
aPollRequest poolreq = m_queue.Dequeue();
|
||||||
|
|
||||||
|
if (poolreq != null && poolreq.thepoll != null)
|
||||||
|
poolreq.thepoll.Process(poolreq);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -137,6 +137,10 @@ namespace OpenSim.Region.CoreModules.Framework
|
||||||
// agentId, m_scene.RegionInfo.RegionName, oldCaps.CapsObjectPath, capsObjectPath);
|
// agentId, m_scene.RegionInfo.RegionName, oldCaps.CapsObjectPath, capsObjectPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// m_log.DebugFormat(
|
||||||
|
// "[CAPS]: Adding capabilities for agent {0} in {1} with path {2}",
|
||||||
|
// agentId, m_scene.RegionInfo.RegionName, capsObjectPath);
|
||||||
|
|
||||||
caps = new Caps(MainServer.Instance, m_scene.RegionInfo.ExternalHostName,
|
caps = new Caps(MainServer.Instance, m_scene.RegionInfo.ExternalHostName,
|
||||||
(MainServer.Instance == null) ? 0: MainServer.Instance.Port,
|
(MainServer.Instance == null) ? 0: MainServer.Instance.Port,
|
||||||
capsObjectPath, agentId, m_scene.RegionInfo.RegionName);
|
capsObjectPath, agentId, m_scene.RegionInfo.RegionName);
|
||||||
|
|
|
@ -0,0 +1,110 @@
|
||||||
|
/*
|
||||||
|
* 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 OpenSimulator 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.Net.Sockets;
|
||||||
|
using System.Text;
|
||||||
|
using HttpServer;
|
||||||
|
using OpenSim.Framework;
|
||||||
|
|
||||||
|
namespace OpenSim.Tests.Common
|
||||||
|
{
|
||||||
|
public class TestHttpClientContext: IHttpClientContext
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Bodies of responses from the server.
|
||||||
|
/// </summary>
|
||||||
|
public string ResponseBody
|
||||||
|
{
|
||||||
|
get { return Encoding.UTF8.GetString(m_responseStream.ToArray()); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public Byte[] ResponseBodyBytes
|
||||||
|
{
|
||||||
|
get{ return m_responseStream.ToArray(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
private MemoryStream m_responseStream = new MemoryStream();
|
||||||
|
|
||||||
|
public bool IsSecured { get; set; }
|
||||||
|
|
||||||
|
public bool Secured
|
||||||
|
{
|
||||||
|
get { return IsSecured; }
|
||||||
|
set { IsSecured = value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public TestHttpClientContext(bool secured)
|
||||||
|
{
|
||||||
|
Secured = secured;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Disconnect(SocketError error)
|
||||||
|
{
|
||||||
|
// Console.WriteLine("TestHttpClientContext.Disconnect Received disconnect with status {0}", error);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Respond(string httpVersion, HttpStatusCode statusCode, string reason, string body) {Console.WriteLine("x");}
|
||||||
|
public void Respond(string httpVersion, HttpStatusCode statusCode, string reason) {Console.WriteLine("xx");}
|
||||||
|
public void Respond(string body) { Console.WriteLine("xxx");}
|
||||||
|
|
||||||
|
public void Send(byte[] buffer)
|
||||||
|
{
|
||||||
|
// Getting header data here
|
||||||
|
// Console.WriteLine("xxxx: Got {0}", Encoding.UTF8.GetString(buffer));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Send(byte[] buffer, int offset, int size)
|
||||||
|
{
|
||||||
|
// Util.PrintCallStack();
|
||||||
|
//
|
||||||
|
// Console.WriteLine(
|
||||||
|
// "TestHttpClientContext.Send(byte[], int, int) got offset={0}, size={1}, buffer={2}",
|
||||||
|
// offset, size, Encoding.UTF8.GetString(buffer));
|
||||||
|
|
||||||
|
m_responseStream.Write(buffer, offset, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Respond(string httpVersion, HttpStatusCode statusCode, string reason, string body, string contentType) {Console.WriteLine("xxxxxx");}
|
||||||
|
public void Close() { }
|
||||||
|
public bool EndWhenDone { get { return false;} set { return;}}
|
||||||
|
|
||||||
|
public HTTPNetworkContext GiveMeTheNetworkStreamIKnowWhatImDoing()
|
||||||
|
{
|
||||||
|
return new HTTPNetworkContext();
|
||||||
|
}
|
||||||
|
|
||||||
|
public event EventHandler<DisconnectedEventArgs> Disconnected = delegate { };
|
||||||
|
/// <summary>
|
||||||
|
/// A request have been received in the context.
|
||||||
|
/// </summary>
|
||||||
|
public event EventHandler<RequestEventArgs> RequestReceived = delegate { };
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,174 @@
|
||||||
|
/*
|
||||||
|
* 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 OpenSimulator 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.Specialized;
|
||||||
|
using System.IO;
|
||||||
|
using HttpServer;
|
||||||
|
using HttpServer.FormDecoders;
|
||||||
|
|
||||||
|
namespace OpenSim.Tests.Common
|
||||||
|
{
|
||||||
|
public class TestHttpRequest: IHttpRequest
|
||||||
|
{
|
||||||
|
private string _uriPath;
|
||||||
|
public bool BodyIsComplete
|
||||||
|
{
|
||||||
|
get { return true; }
|
||||||
|
}
|
||||||
|
public string[] AcceptTypes
|
||||||
|
{
|
||||||
|
get {return _acceptTypes; }
|
||||||
|
}
|
||||||
|
private string[] _acceptTypes;
|
||||||
|
public Stream Body
|
||||||
|
{
|
||||||
|
get { return _body; }
|
||||||
|
set { _body = value;}
|
||||||
|
}
|
||||||
|
private Stream _body;
|
||||||
|
public ConnectionType Connection
|
||||||
|
{
|
||||||
|
get { return _connection; }
|
||||||
|
set { _connection = value; }
|
||||||
|
}
|
||||||
|
private ConnectionType _connection;
|
||||||
|
public int ContentLength
|
||||||
|
{
|
||||||
|
get { return _contentLength; }
|
||||||
|
set { _contentLength = value; }
|
||||||
|
}
|
||||||
|
private int _contentLength;
|
||||||
|
public NameValueCollection Headers
|
||||||
|
{
|
||||||
|
get { return _headers; }
|
||||||
|
}
|
||||||
|
private NameValueCollection _headers = new NameValueCollection();
|
||||||
|
|
||||||
|
public string HttpVersion { get; set; }
|
||||||
|
|
||||||
|
public string Method
|
||||||
|
{
|
||||||
|
get { return _method; }
|
||||||
|
set { _method = value; }
|
||||||
|
}
|
||||||
|
private string _method = null;
|
||||||
|
public HttpInput QueryString
|
||||||
|
{
|
||||||
|
get { return _queryString; }
|
||||||
|
}
|
||||||
|
private HttpInput _queryString = null;
|
||||||
|
public Uri Uri
|
||||||
|
{
|
||||||
|
get { return _uri; }
|
||||||
|
set { _uri = value; }
|
||||||
|
}
|
||||||
|
private Uri _uri = null;
|
||||||
|
public string[] UriParts
|
||||||
|
{
|
||||||
|
get { return _uri.Segments; }
|
||||||
|
}
|
||||||
|
public HttpParam Param
|
||||||
|
{
|
||||||
|
get { return null; }
|
||||||
|
}
|
||||||
|
public HttpForm Form
|
||||||
|
{
|
||||||
|
get { return null; }
|
||||||
|
}
|
||||||
|
public bool IsAjax
|
||||||
|
{
|
||||||
|
get { return false; }
|
||||||
|
}
|
||||||
|
public RequestCookies Cookies
|
||||||
|
{
|
||||||
|
get { return null; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public TestHttpRequest()
|
||||||
|
{
|
||||||
|
HttpVersion = "HTTP/1.1";
|
||||||
|
}
|
||||||
|
|
||||||
|
public TestHttpRequest(string contentEncoding, string contentType, string userAgent,
|
||||||
|
string remoteAddr, string remotePort, string[] acceptTypes,
|
||||||
|
ConnectionType connectionType, int contentLength, Uri uri) : base()
|
||||||
|
{
|
||||||
|
_headers["content-encoding"] = contentEncoding;
|
||||||
|
_headers["content-type"] = contentType;
|
||||||
|
_headers["user-agent"] = userAgent;
|
||||||
|
_headers["remote_addr"] = remoteAddr;
|
||||||
|
_headers["remote_port"] = remotePort;
|
||||||
|
|
||||||
|
_acceptTypes = acceptTypes;
|
||||||
|
_connection = connectionType;
|
||||||
|
_contentLength = contentLength;
|
||||||
|
_uri = uri;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void DecodeBody(FormDecoderProvider providers) {}
|
||||||
|
public void SetCookies(RequestCookies cookies) {}
|
||||||
|
public void AddHeader(string name, string value)
|
||||||
|
{
|
||||||
|
_headers.Add(name, value);
|
||||||
|
}
|
||||||
|
public int AddToBody(byte[] bytes, int offset, int length)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
public void Clear() {}
|
||||||
|
|
||||||
|
public object Clone()
|
||||||
|
{
|
||||||
|
TestHttpRequest clone = new TestHttpRequest();
|
||||||
|
clone._acceptTypes = _acceptTypes;
|
||||||
|
clone._connection = _connection;
|
||||||
|
clone._contentLength = _contentLength;
|
||||||
|
clone._uri = _uri;
|
||||||
|
clone._headers = new NameValueCollection(_headers);
|
||||||
|
|
||||||
|
return clone;
|
||||||
|
}
|
||||||
|
public IHttpResponse CreateResponse(IHttpClientContext context)
|
||||||
|
{
|
||||||
|
return new HttpResponse(context, this);
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// Path and query (will be merged with the host header) and put in Uri
|
||||||
|
/// </summary>
|
||||||
|
/// <see cref="Uri"/>
|
||||||
|
public string UriPath
|
||||||
|
{
|
||||||
|
get { return _uriPath; }
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_uriPath = value;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,171 @@
|
||||||
|
/*
|
||||||
|
* 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 OpenSimulator 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.IO;
|
||||||
|
using System.Net;
|
||||||
|
using System.Text;
|
||||||
|
using HttpServer;
|
||||||
|
|
||||||
|
namespace OpenSim.Tests.Common
|
||||||
|
{
|
||||||
|
public class TestHttpResponse: IHttpResponse
|
||||||
|
{
|
||||||
|
public Stream Body
|
||||||
|
{
|
||||||
|
get { return _body; }
|
||||||
|
|
||||||
|
set { _body = value; }
|
||||||
|
}
|
||||||
|
private Stream _body;
|
||||||
|
|
||||||
|
public string ProtocolVersion
|
||||||
|
{
|
||||||
|
get { return _protocolVersion; }
|
||||||
|
set { _protocolVersion = value; }
|
||||||
|
}
|
||||||
|
private string _protocolVersion;
|
||||||
|
|
||||||
|
public bool Chunked
|
||||||
|
{
|
||||||
|
get { return _chunked; }
|
||||||
|
|
||||||
|
set { _chunked = value; }
|
||||||
|
}
|
||||||
|
private bool _chunked;
|
||||||
|
|
||||||
|
public ConnectionType Connection
|
||||||
|
{
|
||||||
|
get { return _connection; }
|
||||||
|
|
||||||
|
set { _connection = value; }
|
||||||
|
}
|
||||||
|
private ConnectionType _connection;
|
||||||
|
|
||||||
|
public Encoding Encoding
|
||||||
|
{
|
||||||
|
get { return _encoding; }
|
||||||
|
|
||||||
|
set { _encoding = value; }
|
||||||
|
}
|
||||||
|
private Encoding _encoding;
|
||||||
|
|
||||||
|
public int KeepAlive
|
||||||
|
{
|
||||||
|
get { return _keepAlive; }
|
||||||
|
|
||||||
|
set { _keepAlive = value; }
|
||||||
|
}
|
||||||
|
private int _keepAlive;
|
||||||
|
|
||||||
|
public HttpStatusCode Status
|
||||||
|
{
|
||||||
|
get { return _status; }
|
||||||
|
|
||||||
|
set { _status = value; }
|
||||||
|
}
|
||||||
|
private HttpStatusCode _status;
|
||||||
|
|
||||||
|
public string Reason
|
||||||
|
{
|
||||||
|
get { return _reason; }
|
||||||
|
|
||||||
|
set { _reason = value; }
|
||||||
|
}
|
||||||
|
private string _reason;
|
||||||
|
|
||||||
|
public long ContentLength
|
||||||
|
{
|
||||||
|
get { return _contentLength; }
|
||||||
|
|
||||||
|
set { _contentLength = value; }
|
||||||
|
}
|
||||||
|
private long _contentLength;
|
||||||
|
|
||||||
|
public string ContentType
|
||||||
|
{
|
||||||
|
get { return _contentType; }
|
||||||
|
|
||||||
|
set { _contentType = value; }
|
||||||
|
}
|
||||||
|
private string _contentType;
|
||||||
|
|
||||||
|
public bool HeadersSent
|
||||||
|
{
|
||||||
|
get { return _headersSent; }
|
||||||
|
}
|
||||||
|
private bool _headersSent;
|
||||||
|
|
||||||
|
public bool Sent
|
||||||
|
{
|
||||||
|
get { return _sent; }
|
||||||
|
}
|
||||||
|
private bool _sent;
|
||||||
|
|
||||||
|
public ResponseCookies Cookies
|
||||||
|
{
|
||||||
|
get { return _cookies; }
|
||||||
|
}
|
||||||
|
private ResponseCookies _cookies = null;
|
||||||
|
|
||||||
|
public TestHttpResponse()
|
||||||
|
{
|
||||||
|
_headersSent = false;
|
||||||
|
_sent = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddHeader(string name, string value) {}
|
||||||
|
|
||||||
|
public void Send()
|
||||||
|
{
|
||||||
|
if (!_headersSent) SendHeaders();
|
||||||
|
if (_sent) throw new InvalidOperationException("stuff already sent");
|
||||||
|
_sent = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SendBody(byte[] buffer, int offset, int count)
|
||||||
|
{
|
||||||
|
if (!_headersSent) SendHeaders();
|
||||||
|
_sent = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SendBody(byte[] buffer)
|
||||||
|
{
|
||||||
|
if (!_headersSent) SendHeaders();
|
||||||
|
_sent = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SendHeaders()
|
||||||
|
{
|
||||||
|
if (_headersSent) throw new InvalidOperationException("headers already sent");
|
||||||
|
_headersSent = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Redirect(Uri uri) {}
|
||||||
|
public void Redirect(string url) {}
|
||||||
|
}
|
||||||
|
}
|
|
@ -3321,12 +3321,14 @@
|
||||||
<ReferencePath>../../../../../bin/</ReferencePath>
|
<ReferencePath>../../../../../bin/</ReferencePath>
|
||||||
<Reference name="System"/>
|
<Reference name="System"/>
|
||||||
<Reference name="System.Xml"/>
|
<Reference name="System.Xml"/>
|
||||||
|
<Reference name="HttpServer_OpenSim" path="../../../../../bin/"/>
|
||||||
<Reference name="log4net" path="../../../../../bin/"/>
|
<Reference name="log4net" path="../../../../../bin/"/>
|
||||||
<Reference name="Nini" path="../../../../../bin/"/>
|
<Reference name="Nini" path="../../../../../bin/"/>
|
||||||
<Reference name="nunit.framework" path="../../../../../bin/"/>
|
<Reference name="nunit.framework" path="../../../../../bin/"/>
|
||||||
<Reference name="OpenMetaverse" path="../../../../../bin/"/>
|
<Reference name="OpenMetaverse" path="../../../../../bin/"/>
|
||||||
<Reference name="OpenMetaverseTypes" path="../../../../../bin/"/>
|
<Reference name="OpenMetaverseTypes" path="../../../../../bin/"/>
|
||||||
<Reference name="OpenMetaverse.StructuredData" path="../../../../../bin/"/>
|
<Reference name="OpenMetaverse.StructuredData" path="../../../../../bin/"/>
|
||||||
|
<Reference name="OpenSim.Capabilities"/>
|
||||||
<Reference name="OpenSim.Framework"/>
|
<Reference name="OpenSim.Framework"/>
|
||||||
<Reference name="OpenSim.Framework.Communications"/>
|
<Reference name="OpenSim.Framework.Communications"/>
|
||||||
<Reference name="OpenSim.Framework.Monitoring"/>
|
<Reference name="OpenSim.Framework.Monitoring"/>
|
||||||
|
@ -3341,6 +3343,7 @@
|
||||||
<Reference name="OpenSim.Tests.Common"/>
|
<Reference name="OpenSim.Tests.Common"/>
|
||||||
|
|
||||||
<Files>
|
<Files>
|
||||||
|
<Match path="Tests" pattern="*.cs" recurse="false"/>
|
||||||
<Match path="EventQueue/Tests" pattern="*.cs" recurse="false"/>
|
<Match path="EventQueue/Tests" pattern="*.cs" recurse="false"/>
|
||||||
</Files>
|
</Files>
|
||||||
</Project>
|
</Project>
|
||||||
|
|
Loading…
Reference in New Issue