aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Framework/Servers
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs24
-rw-r--r--OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs175
-rw-r--r--OpenSim/Framework/Servers/Tests/OSHttpTests.cs320
3 files changed, 122 insertions, 397 deletions
diff --git a/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs b/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs
index e1ae74e..e243002 100644
--- a/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs
+++ b/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs
@@ -113,7 +113,7 @@ namespace OpenSim.Framework.Servers.HttpServer
113 113
114 protected IPAddress m_listenIPAddress = IPAddress.Any; 114 protected IPAddress m_listenIPAddress = IPAddress.Any;
115 115
116 private PollServiceRequestManager m_PollServiceManager; 116 public PollServiceRequestManager PollServiceRequestManager { get; private set; }
117 117
118 public uint SSLPort 118 public uint SSLPort
119 { 119 {
@@ -374,7 +374,7 @@ namespace OpenSim.Framework.Servers.HttpServer
374 return true; 374 return true;
375 } 375 }
376 376
377 private void OnRequest(object source, RequestEventArgs args) 377 public void OnRequest(object source, RequestEventArgs args)
378 { 378 {
379 RequestNumber++; 379 RequestNumber++;
380 380
@@ -429,7 +429,7 @@ namespace OpenSim.Framework.Servers.HttpServer
429 psEvArgs.Request(psreq.RequestID, keysvals); 429 psEvArgs.Request(psreq.RequestID, keysvals);
430 } 430 }
431 431
432 m_PollServiceManager.Enqueue(psreq); 432 PollServiceRequestManager.Enqueue(psreq);
433 } 433 }
434 else 434 else
435 { 435 {
@@ -1781,10 +1781,17 @@ namespace OpenSim.Framework.Servers.HttpServer
1781 1781
1782 public void Start() 1782 public void Start()
1783 { 1783 {
1784 StartHTTP(); 1784 Start(true);
1785 } 1785 }
1786 1786
1787 private void StartHTTP() 1787 /// <summary>
1788 /// Start the http server
1789 /// </summary>
1790 /// <param name='processPollRequestsAsync'>
1791 /// If true then poll responses are performed asynchronsly.
1792 /// Option exists to allow regression tests to perform processing synchronously.
1793 /// </param>
1794 public void Start(bool performPollResponsesAsync)
1788 { 1795 {
1789 m_log.InfoFormat( 1796 m_log.InfoFormat(
1790 "[BASE HTTP SERVER]: Starting {0} server on port {1}", UseSSL ? "HTTPS" : "HTTP", Port); 1797 "[BASE HTTP SERVER]: Starting {0} server on port {1}", UseSSL ? "HTTPS" : "HTTP", Port);
@@ -1822,8 +1829,9 @@ namespace OpenSim.Framework.Servers.HttpServer
1822 m_httpListener2.Start(64); 1829 m_httpListener2.Start(64);
1823 1830
1824 // Long Poll Service Manager with 3 worker threads a 25 second timeout for no events 1831 // Long Poll Service Manager with 3 worker threads a 25 second timeout for no events
1825 m_PollServiceManager = new PollServiceRequestManager(this, 3, 25000); 1832 PollServiceRequestManager = new PollServiceRequestManager(this, performPollResponsesAsync, 3, 25000);
1826 m_PollServiceManager.Start(); 1833 PollServiceRequestManager.Start();
1834
1827 HTTPDRunning = true; 1835 HTTPDRunning = true;
1828 1836
1829 //HttpListenerContext context; 1837 //HttpListenerContext context;
@@ -1892,7 +1900,7 @@ namespace OpenSim.Framework.Servers.HttpServer
1892 1900
1893 try 1901 try
1894 { 1902 {
1895 m_PollServiceManager.Stop(); 1903 PollServiceRequestManager.Stop();
1896 1904
1897 m_httpListener2.ExceptionThrown -= httpServerException; 1905 m_httpListener2.ExceptionThrown -= httpServerException;
1898 //m_httpListener2.DisconnectHandler = null; 1906 //m_httpListener2.DisconnectHandler = null;
diff --git a/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs b/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs
index 6aa5907..456acb0 100644
--- a/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs
+++ b/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs
@@ -44,6 +44,20 @@ namespace OpenSim.Framework.Servers.HttpServer
44 { 44 {
45 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 45 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
46 46
47 /// <summary>
48 /// Is the poll service request manager running?
49 /// </summary>
50 /// <remarks>
51 /// Can be running either synchronously or asynchronously
52 /// </remarks>
53 public bool IsRunning { get; private set; }
54
55 /// <summary>
56 /// Is the poll service performing responses asynchronously (with its own threads) or synchronously (via
57 /// external calls)?
58 /// </summary>
59 public bool PerformResponsesAsync { get; private set; }
60
47 private readonly BaseHttpServer m_server; 61 private readonly BaseHttpServer m_server;
48 62
49 private BlockingQueue<PollServiceHttpRequest> m_requests = new BlockingQueue<PollServiceHttpRequest>(); 63 private BlockingQueue<PollServiceHttpRequest> m_requests = new BlockingQueue<PollServiceHttpRequest>();
@@ -52,48 +66,53 @@ namespace OpenSim.Framework.Servers.HttpServer
52 private uint m_WorkerThreadCount = 0; 66 private uint m_WorkerThreadCount = 0;
53 private Thread[] m_workerThreads; 67 private Thread[] m_workerThreads;
54 68
55 private bool m_running = true;
56
57 private SmartThreadPool m_threadPool = new SmartThreadPool(20000, 12, 2); 69 private SmartThreadPool m_threadPool = new SmartThreadPool(20000, 12, 2);
58 70
59// private int m_timeout = 1000; // increase timeout 250; now use the event one 71// private int m_timeout = 1000; // increase timeout 250; now use the event one
60 72
61 public PollServiceRequestManager(BaseHttpServer pSrv, uint pWorkerThreadCount, int pTimeout) 73 public PollServiceRequestManager(
74 BaseHttpServer pSrv, bool performResponsesAsync, uint pWorkerThreadCount, int pTimeout)
62 { 75 {
63 m_server = pSrv; 76 m_server = pSrv;
77 PerformResponsesAsync = performResponsesAsync;
64 m_WorkerThreadCount = pWorkerThreadCount; 78 m_WorkerThreadCount = pWorkerThreadCount;
65 m_workerThreads = new Thread[m_WorkerThreadCount]; 79 m_workerThreads = new Thread[m_WorkerThreadCount];
66 } 80 }
67 81
68 public void Start() 82 public void Start()
69 { 83 {
70 //startup worker threads 84 IsRunning = true;
71 for (uint i = 0; i < m_WorkerThreadCount; i++) 85
86 if (PerformResponsesAsync)
72 { 87 {
73 m_workerThreads[i] 88 //startup worker threads
74 = Watchdog.StartThread( 89 for (uint i = 0; i < m_WorkerThreadCount; i++)
75 PoolWorkerJob, 90 {
76 string.Format("PollServiceWorkerThread{0}:{1}", i, m_server.Port), 91 m_workerThreads[i]
77 ThreadPriority.Normal, 92 = Watchdog.StartThread(
78 false, 93 PoolWorkerJob,
79 false, 94 string.Format("PollServiceWorkerThread{0}:{1}", i, m_server.Port),
80 null, 95 ThreadPriority.Normal,
81 int.MaxValue); 96 false,
82 } 97 false,
98 null,
99 int.MaxValue);
100 }
83 101
84 Watchdog.StartThread( 102 Watchdog.StartThread(
85 this.CheckLongPollThreads, 103 this.CheckLongPollThreads,
86 string.Format("LongPollServiceWatcherThread:{0}", m_server.Port), 104 string.Format("LongPollServiceWatcherThread:{0}", m_server.Port),
87 ThreadPriority.Normal, 105 ThreadPriority.Normal,
88 false, 106 false,
89 true, 107 true,
90 null, 108 null,
91 1000 * 60 * 10); 109 1000 * 60 * 10);
110 }
92 } 111 }
93 112
94 private void ReQueueEvent(PollServiceHttpRequest req) 113 private void ReQueueEvent(PollServiceHttpRequest req)
95 { 114 {
96 if (m_running) 115 if (IsRunning)
97 { 116 {
98 // delay the enqueueing for 100ms. There's no need to have the event 117 // delay the enqueueing for 100ms. There's no need to have the event
99 // actively on the queue 118 // actively on the queue
@@ -109,7 +128,7 @@ namespace OpenSim.Framework.Servers.HttpServer
109 128
110 public void Enqueue(PollServiceHttpRequest req) 129 public void Enqueue(PollServiceHttpRequest req)
111 { 130 {
112 if (m_running) 131 if (IsRunning)
113 { 132 {
114 if (req.PollServiceArgs.Type == PollServiceEventArgs.EventType.LongPoll) 133 if (req.PollServiceArgs.Type == PollServiceEventArgs.EventType.LongPoll)
115 { 134 {
@@ -129,7 +148,7 @@ namespace OpenSim.Framework.Servers.HttpServer
129 // All other types of tasks (Inventory handlers, http-in, etc) don't have the long-poll nature, 148 // All other types of tasks (Inventory handlers, http-in, etc) don't have the long-poll nature,
130 // so if they aren't ready to be served by a worker thread (no events), they are placed 149 // so if they aren't ready to be served by a worker thread (no events), they are placed
131 // directly back in the "ready-to-serve" queue by the worker thread. 150 // directly back in the "ready-to-serve" queue by the worker thread.
132 while (m_running) 151 while (IsRunning)
133 { 152 {
134 Thread.Sleep(500); 153 Thread.Sleep(500);
135 Watchdog.UpdateThread(); 154 Watchdog.UpdateThread();
@@ -137,7 +156,7 @@ namespace OpenSim.Framework.Servers.HttpServer
137// List<PollServiceHttpRequest> not_ready = new List<PollServiceHttpRequest>(); 156// List<PollServiceHttpRequest> not_ready = new List<PollServiceHttpRequest>();
138 lock (m_longPollRequests) 157 lock (m_longPollRequests)
139 { 158 {
140 if (m_longPollRequests.Count > 0 && m_running) 159 if (m_longPollRequests.Count > 0 && IsRunning)
141 { 160 {
142 List<PollServiceHttpRequest> ready = m_longPollRequests.FindAll(req => 161 List<PollServiceHttpRequest> ready = m_longPollRequests.FindAll(req =>
143 (req.PollServiceArgs.HasEvents(req.RequestID, req.PollServiceArgs.Id) || // there are events in this EQ 162 (req.PollServiceArgs.HasEvents(req.RequestID, req.PollServiceArgs.Id) || // there are events in this EQ
@@ -158,7 +177,7 @@ namespace OpenSim.Framework.Servers.HttpServer
158 177
159 public void Stop() 178 public void Stop()
160 { 179 {
161 m_running = false; 180 IsRunning = false;
162// m_timeout = -10000; // cause all to expire 181// m_timeout = -10000; // cause all to expire
163 Thread.Sleep(1000); // let the world move 182 Thread.Sleep(1000); // let the world move
164 183
@@ -169,7 +188,7 @@ namespace OpenSim.Framework.Servers.HttpServer
169 188
170 lock (m_longPollRequests) 189 lock (m_longPollRequests)
171 { 190 {
172 if (m_longPollRequests.Count > 0 && m_running) 191 if (m_longPollRequests.Count > 0 && IsRunning)
173 m_longPollRequests.ForEach(req => m_requests.Enqueue(req)); 192 m_longPollRequests.ForEach(req => m_requests.Enqueue(req));
174 } 193 }
175 194
@@ -194,68 +213,82 @@ namespace OpenSim.Framework.Servers.HttpServer
194 213
195 private void PoolWorkerJob() 214 private void PoolWorkerJob()
196 { 215 {
197 while (m_running) 216 while (IsRunning)
198 { 217 {
199 PollServiceHttpRequest req = m_requests.Dequeue(5000);
200 //m_log.WarnFormat("[YYY]: Dequeued {0}", (req == null ? "null" : req.PollServiceArgs.Type.ToString()));
201
202 Watchdog.UpdateThread(); 218 Watchdog.UpdateThread();
203 if (req != null) 219 WaitPerformResponse();
220 }
221 }
222
223 public void WaitPerformResponse()
224 {
225 PollServiceHttpRequest req = m_requests.Dequeue(5000);
226// m_log.DebugFormat("[YYY]: Dequeued {0}", (req == null ? "null" : req.PollServiceArgs.Type.ToString()));
227
228 if (req != null)
229 {
230 try
204 { 231 {
205 try 232 if (req.PollServiceArgs.HasEvents(req.RequestID, req.PollServiceArgs.Id))
206 { 233 {
207 if (req.PollServiceArgs.HasEvents(req.RequestID, req.PollServiceArgs.Id)) 234 Hashtable responsedata = req.PollServiceArgs.GetEvents(req.RequestID, req.PollServiceArgs.Id);
208 {
209 Hashtable responsedata = req.PollServiceArgs.GetEvents(req.RequestID, req.PollServiceArgs.Id);
210 235
211 if (responsedata == null) 236 if (responsedata == null)
212 continue; 237 return;
213 238
214 if (req.PollServiceArgs.Type == PollServiceEventArgs.EventType.LongPoll) // This is the event queue 239 // This is the event queue.
240 // Even if we're not running we can still perform responses by explicit request.
241 if (req.PollServiceArgs.Type == PollServiceEventArgs.EventType.LongPoll
242 || !PerformResponsesAsync)
243 {
244 try
245 {
246 req.DoHTTPGruntWork(m_server, responsedata);
247 }
248 catch (ObjectDisposedException e) // Browser aborted before we could read body, server closed the stream
249 {
250 // Ignore it, no need to reply
251 m_log.Error(e);
252 }
253 }
254 else
255 {
256 m_threadPool.QueueWorkItem(x =>
215 { 257 {
216 try 258 try
217 { 259 {
218 req.DoHTTPGruntWork(m_server, responsedata); 260 req.DoHTTPGruntWork(m_server, responsedata);
219 } 261 }
220 catch (ObjectDisposedException) // Browser aborted before we could read body, server closed the stream 262 catch (ObjectDisposedException e) // Browser aborted before we could read body, server closed the stream
221 { 263 {
222 // Ignore it, no need to reply 264 // Ignore it, no need to reply
265 m_log.Error(e);
223 } 266 }
224 } 267 catch (Exception e)
225 else
226 {
227 m_threadPool.QueueWorkItem(x =>
228 { 268 {
229 try 269 m_log.Error(e);
230 { 270 }
231 req.DoHTTPGruntWork(m_server, responsedata); 271
232 } 272 return null;
233 catch (ObjectDisposedException) // Browser aborted before we could read body, server closed the stream 273 }, null);
234 { 274 }
235 // Ignore it, no need to reply 275 }
236 } 276 else
237 277 {
238 return null; 278 if ((Environment.TickCount - req.RequestTime) > req.PollServiceArgs.TimeOutms)
239 }, null); 279 {
240 } 280 req.DoHTTPGruntWork(
281 m_server, req.PollServiceArgs.NoEvents(req.RequestID, req.PollServiceArgs.Id));
241 } 282 }
242 else 283 else
243 { 284 {
244 if ((Environment.TickCount - req.RequestTime) > req.PollServiceArgs.TimeOutms) 285 ReQueueEvent(req);
245 {
246 req.DoHTTPGruntWork(
247 m_server, req.PollServiceArgs.NoEvents(req.RequestID, req.PollServiceArgs.Id));
248 }
249 else
250 {
251 ReQueueEvent(req);
252 }
253 } 286 }
254 } 287 }
255 catch (Exception e) 288 }
256 { 289 catch (Exception e)
257 m_log.ErrorFormat("Exception in poll service thread: " + e.ToString()); 290 {
258 } 291 m_log.ErrorFormat("Exception in poll service thread: " + e.ToString());
259 } 292 }
260 } 293 }
261 } 294 }
diff --git a/OpenSim/Framework/Servers/Tests/OSHttpTests.cs b/OpenSim/Framework/Servers/Tests/OSHttpTests.cs
index 5b912b4..5c0e0df 100644
--- a/OpenSim/Framework/Servers/Tests/OSHttpTests.cs
+++ b/OpenSim/Framework/Servers/Tests/OSHttpTests.cs
@@ -41,323 +41,7 @@ namespace OpenSim.Framework.Servers.Tests
41{ 41{
42 [TestFixture] 42 [TestFixture]
43 public class OSHttpTests : OpenSimTestCase 43 public class OSHttpTests : OpenSimTestCase
44 { 44 {
45 // we need an IHttpClientContext for our tests
46 public class TestHttpClientContext: IHttpClientContext
47 {
48 private bool _secured;
49 public bool IsSecured
50 {
51 get { return _secured; }
52 }
53 public bool Secured
54 {
55 get { return _secured; }
56 }
57
58 public TestHttpClientContext(bool secured)
59 {
60 _secured = secured;
61 }
62
63 public void Disconnect(SocketError error) {}
64 public void Respond(string httpVersion, HttpStatusCode statusCode, string reason, string body) {}
65 public void Respond(string httpVersion, HttpStatusCode statusCode, string reason) {}
66 public void Respond(string body) {}
67 public void Send(byte[] buffer) {}
68 public void Send(byte[] buffer, int offset, int size) {}
69 public void Respond(string httpVersion, HttpStatusCode statusCode, string reason, string body, string contentType) {}
70 public void Close() { }
71 public bool EndWhenDone { get { return false;} set { return;}}
72
73 public HTTPNetworkContext GiveMeTheNetworkStreamIKnowWhatImDoing()
74 {
75 return new HTTPNetworkContext();
76 }
77
78 public event EventHandler<DisconnectedEventArgs> Disconnected = delegate { };
79 /// <summary>
80 /// A request have been received in the context.
81 /// </summary>
82 public event EventHandler<RequestEventArgs> RequestReceived = delegate { };
83
84 }
85
86 public class TestHttpRequest: IHttpRequest
87 {
88 private string _uriPath;
89 public bool BodyIsComplete
90 {
91 get { return true; }
92 }
93 public string[] AcceptTypes
94 {
95 get {return _acceptTypes; }
96 }
97 private string[] _acceptTypes;
98 public Stream Body
99 {
100 get { return _body; }
101 set { _body = value;}
102 }
103 private Stream _body;
104 public ConnectionType Connection
105 {
106 get { return _connection; }
107 set { _connection = value; }
108 }
109 private ConnectionType _connection;
110 public int ContentLength
111 {
112 get { return _contentLength; }
113 set { _contentLength = value; }
114 }
115 private int _contentLength;
116 public NameValueCollection Headers
117 {
118 get { return _headers; }
119 }
120 private NameValueCollection _headers = new NameValueCollection();
121 public string HttpVersion
122 {
123 get { return _httpVersion; }
124 set { _httpVersion = value; }
125 }
126 private string _httpVersion = null;
127 public string Method
128 {
129 get { return _method; }
130 set { _method = value; }
131 }
132 private string _method = null;
133 public HttpInput QueryString
134 {
135 get { return _queryString; }
136 }
137 private HttpInput _queryString = null;
138 public Uri Uri
139 {
140 get { return _uri; }
141 set { _uri = value; }
142 }
143 private Uri _uri = null;
144 public string[] UriParts
145 {
146 get { return _uri.Segments; }
147 }
148 public HttpParam Param
149 {
150 get { return null; }
151 }
152 public HttpForm Form
153 {
154 get { return null; }
155 }
156 public bool IsAjax
157 {
158 get { return false; }
159 }
160 public RequestCookies Cookies
161 {
162 get { return null; }
163 }
164
165 public TestHttpRequest() {}
166
167 public TestHttpRequest(string contentEncoding, string contentType, string userAgent,
168 string remoteAddr, string remotePort, string[] acceptTypes,
169 ConnectionType connectionType, int contentLength, Uri uri)
170 {
171 _headers["content-encoding"] = contentEncoding;
172 _headers["content-type"] = contentType;
173 _headers["user-agent"] = userAgent;
174 _headers["remote_addr"] = remoteAddr;
175 _headers["remote_port"] = remotePort;
176
177 _acceptTypes = acceptTypes;
178 _connection = connectionType;
179 _contentLength = contentLength;
180 _uri = uri;
181 }
182
183 public void DecodeBody(FormDecoderProvider providers) {}
184 public void SetCookies(RequestCookies cookies) {}
185 public void AddHeader(string name, string value)
186 {
187 _headers.Add(name, value);
188 }
189 public int AddToBody(byte[] bytes, int offset, int length)
190 {
191 return 0;
192 }
193 public void Clear() {}
194
195 public object Clone()
196 {
197 TestHttpRequest clone = new TestHttpRequest();
198 clone._acceptTypes = _acceptTypes;
199 clone._connection = _connection;
200 clone._contentLength = _contentLength;
201 clone._uri = _uri;
202 clone._headers = new NameValueCollection(_headers);
203
204 return clone;
205 }
206 public IHttpResponse CreateResponse(IHttpClientContext context)
207 {
208 return new HttpResponse(context, this);
209 }
210 /// <summary>
211 /// Path and query (will be merged with the host header) and put in Uri
212 /// </summary>
213 /// <see cref="Uri"/>
214 public string UriPath
215 {
216 get { return _uriPath; }
217 set
218 {
219 _uriPath = value;
220
221 }
222 }
223
224 }
225
226 public class TestHttpResponse: IHttpResponse
227 {
228 public Stream Body
229 {
230 get { return _body; }
231
232 set { _body = value; }
233 }
234 private Stream _body;
235
236 public string ProtocolVersion
237 {
238 get { return _protocolVersion; }
239 set { _protocolVersion = value; }
240 }
241 private string _protocolVersion;
242
243 public bool Chunked
244 {
245 get { return _chunked; }
246
247 set { _chunked = value; }
248 }
249 private bool _chunked;
250
251 public ConnectionType Connection
252 {
253 get { return _connection; }
254
255 set { _connection = value; }
256 }
257 private ConnectionType _connection;
258
259 public Encoding Encoding
260 {
261 get { return _encoding; }
262
263 set { _encoding = value; }
264 }
265 private Encoding _encoding;
266
267 public int KeepAlive
268 {
269 get { return _keepAlive; }
270
271 set { _keepAlive = value; }
272 }
273 private int _keepAlive;
274
275 public HttpStatusCode Status
276 {
277 get { return _status; }
278
279 set { _status = value; }
280 }
281 private HttpStatusCode _status;
282
283 public string Reason
284 {
285 get { return _reason; }
286
287 set { _reason = value; }
288 }
289 private string _reason;
290
291 public long ContentLength
292 {
293 get { return _contentLength; }
294
295 set { _contentLength = value; }
296 }
297 private long _contentLength;
298
299 public string ContentType
300 {
301 get { return _contentType; }
302
303 set { _contentType = value; }
304 }
305 private string _contentType;
306
307 public bool HeadersSent
308 {
309 get { return _headersSent; }
310 }
311 private bool _headersSent;
312
313 public bool Sent
314 {
315 get { return _sent; }
316 }
317 private bool _sent;
318
319 public ResponseCookies Cookies
320 {
321 get { return _cookies; }
322 }
323 private ResponseCookies _cookies = null;
324
325 public TestHttpResponse()
326 {
327 _headersSent = false;
328 _sent = false;
329 }
330
331 public void AddHeader(string name, string value) {}
332 public void Send()
333 {
334 if (!_headersSent) SendHeaders();
335 if (_sent) throw new InvalidOperationException("stuff already sent");
336 _sent = true;
337 }
338
339 public void SendBody(byte[] buffer, int offset, int count)
340 {
341 if (!_headersSent) SendHeaders();
342 _sent = true;
343 }
344 public void SendBody(byte[] buffer)
345 {
346 if (!_headersSent) SendHeaders();
347 _sent = true;
348 }
349
350 public void SendHeaders()
351 {
352 if (_headersSent) throw new InvalidOperationException("headers already sent");
353 _headersSent = true;
354 }
355
356 public void Redirect(Uri uri) {}
357 public void Redirect(string url) {}
358 }
359
360
361 public OSHttpRequest req0; 45 public OSHttpRequest req0;
362 public OSHttpRequest req1; 46 public OSHttpRequest req1;
363 47
@@ -429,4 +113,4 @@ namespace OpenSim.Framework.Servers.Tests
429 Assert.That(rsp0.ContentType, Is.EqualTo("text/xml")); 113 Assert.That(rsp0.ContentType, Is.EqualTo("text/xml"));
430 } 114 }
431 } 115 }
432} 116} \ No newline at end of file