diff options
Diffstat (limited to '')
-rw-r--r-- | OpenSim/Framework/Servers/BaseHttpServer.cs | 272 |
1 files changed, 234 insertions, 38 deletions
diff --git a/OpenSim/Framework/Servers/BaseHttpServer.cs b/OpenSim/Framework/Servers/BaseHttpServer.cs index 707f621..6090d1f 100644 --- a/OpenSim/Framework/Servers/BaseHttpServer.cs +++ b/OpenSim/Framework/Servers/BaseHttpServer.cs | |||
@@ -40,7 +40,9 @@ using System.Xml; | |||
40 | using OpenMetaverse.StructuredData; | 40 | using OpenMetaverse.StructuredData; |
41 | using log4net; | 41 | using log4net; |
42 | using Nwc.XmlRpc; | 42 | using Nwc.XmlRpc; |
43 | 43 | using CoolHTTPListener = HttpServer.HttpListener; | |
44 | using IHttpClientContext = HttpServer.IHttpClientContext; | ||
45 | using IHttpRequest = HttpServer.IHttpRequest; | ||
44 | 46 | ||
45 | namespace OpenSim.Framework.Servers | 47 | namespace OpenSim.Framework.Servers |
46 | { | 48 | { |
@@ -50,6 +52,7 @@ namespace OpenSim.Framework.Servers | |||
50 | 52 | ||
51 | protected Thread m_workerThread; | 53 | protected Thread m_workerThread; |
52 | protected HttpListener m_httpListener; | 54 | protected HttpListener m_httpListener; |
55 | protected CoolHTTPListener m_httpListener2; | ||
53 | protected Dictionary<string, XmlRpcMethod> m_rpcHandlers = new Dictionary<string, XmlRpcMethod>(); | 56 | protected Dictionary<string, XmlRpcMethod> m_rpcHandlers = new Dictionary<string, XmlRpcMethod>(); |
54 | protected DefaultLLSDMethod m_defaultLlsdHandler = null; // <-- Moving away from the monolithic.. and going to /registered/ | 57 | protected DefaultLLSDMethod m_defaultLlsdHandler = null; // <-- Moving away from the monolithic.. and going to /registered/ |
55 | protected Dictionary<string, LLSDMethod> m_llsdHandlers = new Dictionary<string, LLSDMethod>(); | 58 | protected Dictionary<string, LLSDMethod> m_llsdHandlers = new Dictionary<string, LLSDMethod>(); |
@@ -102,13 +105,14 @@ namespace OpenSim.Framework.Servers | |||
102 | m_port = port; | 105 | m_port = port; |
103 | if (m_ssl) | 106 | if (m_ssl) |
104 | { | 107 | { |
105 | SetupSsl((int)sslport, CN); | 108 | //SetupSsl((int)sslport, CN); |
106 | m_sslport = sslport; | 109 | m_sslport = sslport; |
107 | } | 110 | } |
108 | } | 111 | } |
109 | 112 | ||
110 | 113 | ||
111 | 114 | /* | |
115 | * | ||
112 | public bool SetupSsl(int port, string CN) | 116 | public bool SetupSsl(int port, string CN) |
113 | { | 117 | { |
114 | string searchCN = Environment.MachineName.ToUpper(); | 118 | string searchCN = Environment.MachineName.ToUpper(); |
@@ -211,7 +215,7 @@ namespace OpenSim.Framework.Servers | |||
211 | } | 215 | } |
212 | 216 | ||
213 | } | 217 | } |
214 | 218 | */ | |
215 | 219 | ||
216 | /// <summary> | 220 | /// <summary> |
217 | /// Add a stream handler to the http server. If the handler already exists, then nothing happens. | 221 | /// Add a stream handler to the http server. If the handler already exists, then nothing happens. |
@@ -308,23 +312,135 @@ namespace OpenSim.Framework.Servers | |||
308 | } | 312 | } |
309 | 313 | ||
310 | /// <summary> | 314 | /// <summary> |
311 | /// Handle an individual http request. This method is given to a worker in the thread pool. | 315 | /// HttpListener Handle an individual http request. This method is given to a worker in the thread pool. |
312 | /// </summary> | 316 | /// </summary> |
313 | /// <param name="stateinfo"></param> | 317 | /// <param name="stateinfo"></param> |
314 | public virtual void HandleRequest(Object stateinfo) | 318 | public virtual void HandleRequest(Object stateinfo) |
315 | { | 319 | { |
316 | // force the culture to en-US | 320 | // force the culture to en-US |
317 | Culture.SetCurrentCulture(); | 321 | |
318 | 322 | ||
319 | // If we don't catch the exception here it will just disappear into the thread pool and we'll be none the wiser | 323 | // If we don't catch the exception here it will just disappear into the thread pool and we'll be none the wiser |
320 | try | 324 | try |
321 | { | 325 | { |
322 | HttpListenerContext context = (HttpListenerContext) stateinfo; | 326 | HttpListenerContext context = (HttpListenerContext)stateinfo; |
323 | 327 | ||
324 | OSHttpRequest request = new OSHttpRequest(context.Request); | 328 | OSHttpRequest request = new OSHttpRequest(context.Request); |
325 | OSHttpResponse response = new OSHttpResponse(context.Response); | 329 | OSHttpResponse response = new OSHttpResponse(context.Response); |
326 | context.Response.ProtocolVersion = new Version("1.0"); | 330 | |
327 | context.Response.KeepAlive = false; | 331 | HandleRequest(request, response); |
332 | |||
333 | } | ||
334 | catch (SocketException e) | ||
335 | { | ||
336 | // At least on linux, it appears that if the client makes a request without requiring the response, | ||
337 | // an unconnected socket exception is thrown when we close the response output stream. There's no | ||
338 | // obvious way to tell if the client didn't require the response, so instead we'll catch and ignore | ||
339 | // the exception instead. | ||
340 | // | ||
341 | // An alternative may be to turn off all response write exceptions on the HttpListener, but let's go | ||
342 | // with the minimum first | ||
343 | m_log.WarnFormat("[BASE HTTP SERVER]: HandleRequest threw {0}.\nNOTE: this may be spurious on Linux", e); | ||
344 | } | ||
345 | catch (Exception e) | ||
346 | { | ||
347 | m_log.ErrorFormat("[BASE HTTP SERVER]: HandleRequest() threw {0}", e); | ||
348 | } | ||
349 | } | ||
350 | |||
351 | /* | ||
352 | /// <summary> | ||
353 | /// HttpListener Handle an individual http request. This method is given to a worker in the thread pool. | ||
354 | /// </summary> | ||
355 | /// <param name="stateinfo"></param> | ||
356 | public virtual void HandleRequestHttpServer(Object stateinfo) | ||
357 | { | ||
358 | // force the culture to en-US | ||
359 | |||
360 | |||
361 | // If we don't catch the exception here it will just disappear into the thread pool and we'll be none the wiser | ||
362 | try | ||
363 | { | ||
364 | HttpServerContextObj context = (HttpServerContextObj)stateinfo; | ||
365 | |||
366 | OSHttpRequest request = new OSHttpRequest(context.Request); | ||
367 | OSHttpResponse response = new OSHttpResponse(context.Response); | ||
368 | |||
369 | HandleRequest(request, response); | ||
370 | |||
371 | } | ||
372 | catch (SocketException e) | ||
373 | { | ||
374 | // At least on linux, it appears that if the client makes a request without requiring the response, | ||
375 | // an unconnected socket exception is thrown when we close the response output stream. There's no | ||
376 | // obvious way to tell if the client didn't require the response, so instead we'll catch and ignore | ||
377 | // the exception instead. | ||
378 | // | ||
379 | // An alternative may be to turn off all response write exceptions on the HttpListener, but let's go | ||
380 | // with the minimum first | ||
381 | m_log.WarnFormat("[BASE HTTP SERVER]: HandleRequest threw {0}.\nNOTE: this may be spurious on Linux", e); | ||
382 | } | ||
383 | catch (Exception e) | ||
384 | { | ||
385 | m_log.ErrorFormat("[BASE HTTP SERVER]: HandleRequest() threw {0}", e); | ||
386 | } | ||
387 | } | ||
388 | */ | ||
389 | public void OnHandleRequestIOThread(IHttpClientContext context, IHttpRequest request) | ||
390 | { | ||
391 | OSHttpRequest req = new OSHttpRequest(context, request); | ||
392 | OSHttpResponse resp = new OSHttpResponse(new HttpServer.HttpResponse(context, request)); | ||
393 | |||
394 | //HttpServerContextObj objstate= new HttpServerContextObj(req,resp); | ||
395 | //ThreadPool.QueueUserWorkItem(new WaitCallback(ConvertIHttpClientContextToOSHttp), (object)objstate); | ||
396 | HandleRequest(req, resp); | ||
397 | } | ||
398 | |||
399 | public void ConvertIHttpClientContextToOSHttp(object stateinfo) | ||
400 | { | ||
401 | HttpServerContextObj objstate = (HttpServerContextObj)stateinfo; | ||
402 | //OSHttpRequest request = new OSHttpRequest(objstate.context,objstate.req); | ||
403 | //OSHttpResponse resp = new OSHttpResponse(new HttpServer.HttpResponse(objstate.context, objstate.req)); | ||
404 | |||
405 | OSHttpRequest request = objstate.oreq; | ||
406 | OSHttpResponse resp = objstate.oresp; | ||
407 | //OSHttpResponse resp = new OSHttpResponse(new HttpServer.HttpResponse(objstate.context, objstate.req)); | ||
408 | |||
409 | /* | ||
410 | request.AcceptTypes = objstate.req.AcceptTypes; | ||
411 | request.ContentLength = (long)objstate.req.ContentLength; | ||
412 | request.Headers = objstate.req.Headers; | ||
413 | request.HttpMethod = objstate.req.Method; | ||
414 | request.InputStream = objstate.req.Body; | ||
415 | foreach (string str in request.Headers) | ||
416 | { | ||
417 | if (str.ToLower().Contains("content-type: ")) | ||
418 | { | ||
419 | request.ContentType = str.Substring(13, str.Length - 13); | ||
420 | break; | ||
421 | } | ||
422 | } | ||
423 | //request.KeepAlive = objstate.req. | ||
424 | foreach (HttpServer.HttpInput httpinput in objstate.req.QueryString) | ||
425 | { | ||
426 | request.QueryString.Add(httpinput.Name, httpinput[httpinput.Name]); | ||
427 | } | ||
428 | |||
429 | //request.Query = objstate.req.//objstate.req.QueryString; | ||
430 | //foreach ( | ||
431 | //request.QueryString = objstate.req.QueryString; | ||
432 | |||
433 | */ | ||
434 | HandleRequest(request,resp); | ||
435 | |||
436 | |||
437 | } | ||
438 | |||
439 | public virtual void HandleRequest(OSHttpRequest request, OSHttpResponse response) | ||
440 | { | ||
441 | try | ||
442 | { | ||
443 | Culture.SetCurrentCulture(); | ||
328 | // This is the REST agent interface. We require an agent to properly identify | 444 | // This is the REST agent interface. We require an agent to properly identify |
329 | // itself. If the REST handler recognizes the prefix it will attempt to | 445 | // itself. If the REST handler recognizes the prefix it will attempt to |
330 | // satisfy the request. If it is not recognizable, and no damage has occurred | 446 | // satisfy the request. If it is not recognizable, and no damage has occurred |
@@ -431,12 +547,22 @@ namespace OpenSim.Framework.Servers | |||
431 | try | 547 | try |
432 | { | 548 | { |
433 | response.OutputStream.Write(buffer, 0, buffer.Length); | 549 | response.OutputStream.Write(buffer, 0, buffer.Length); |
434 | response.OutputStream.Close(); | 550 | //response.OutputStream.Close(); |
435 | } | 551 | } |
436 | catch (HttpListenerException) | 552 | catch (HttpListenerException) |
437 | { | 553 | { |
438 | m_log.WarnFormat("[BASE HTTP SERVER]: HTTP request abnormally terminated."); | 554 | m_log.WarnFormat("[BASE HTTP SERVER]: HTTP request abnormally terminated."); |
439 | } | 555 | } |
556 | //response.OutputStream.Close(); | ||
557 | try | ||
558 | { | ||
559 | response.Send(); | ||
560 | } | ||
561 | catch (SocketException e) | ||
562 | { | ||
563 | // This has to be here to prevent a Linux/Mono crash | ||
564 | m_log.WarnFormat("[BASE HTTP SERVER] XmlRpcRequest issue {0}.\nNOTE: this may be spurious on Linux.", e); | ||
565 | } | ||
440 | return; | 566 | return; |
441 | } | 567 | } |
442 | 568 | ||
@@ -489,7 +615,7 @@ namespace OpenSim.Framework.Servers | |||
489 | // with the minimum first | 615 | // with the minimum first |
490 | m_log.WarnFormat("[BASE HTTP SERVER]: HandleRequest threw {0}.\nNOTE: this may be spurious on Linux", e); | 616 | m_log.WarnFormat("[BASE HTTP SERVER]: HandleRequest threw {0}.\nNOTE: this may be spurious on Linux", e); |
491 | } | 617 | } |
492 | catch (Exception e) | 618 | catch (EndOfStreamException e) |
493 | { | 619 | { |
494 | m_log.ErrorFormat("[BASE HTTP SERVER]: HandleRequest() threw {0}", e); | 620 | m_log.ErrorFormat("[BASE HTTP SERVER]: HandleRequest() threw {0}", e); |
495 | } | 621 | } |
@@ -739,7 +865,16 @@ namespace OpenSim.Framework.Servers | |||
739 | } | 865 | } |
740 | finally | 866 | finally |
741 | { | 867 | { |
742 | response.OutputStream.Close(); | 868 | //response.OutputStream.Close(); |
869 | try | ||
870 | { | ||
871 | response.Send(); | ||
872 | } | ||
873 | catch (SocketException e) | ||
874 | { | ||
875 | // This has to be here to prevent a Linux/Mono crash | ||
876 | m_log.WarnFormat("[BASE HTTP SERVER] XmlRpcRequest issue {0}.\nNOTE: this may be spurious on Linux.", e); | ||
877 | } | ||
743 | } | 878 | } |
744 | } | 879 | } |
745 | 880 | ||
@@ -883,7 +1018,16 @@ namespace OpenSim.Framework.Servers | |||
883 | response.SendChunked = false; | 1018 | response.SendChunked = false; |
884 | response.KeepAlive = false; | 1019 | response.KeepAlive = false; |
885 | response.StatusCode = (int)OSHttpStatusCode.ServerErrorInternalError; | 1020 | response.StatusCode = (int)OSHttpStatusCode.ServerErrorInternalError; |
886 | response.OutputStream.Close(); | 1021 | //response.OutputStream.Close(); |
1022 | try | ||
1023 | { | ||
1024 | response.Send(); | ||
1025 | } | ||
1026 | catch (SocketException f) | ||
1027 | { | ||
1028 | // This has to be here to prevent a Linux/Mono crash | ||
1029 | m_log.WarnFormat("[BASE HTTP SERVER] XmlRpcRequest issue {0}.\nNOTE: this may be spurious on Linux.", f); | ||
1030 | } | ||
887 | } | 1031 | } |
888 | catch(Exception) | 1032 | catch(Exception) |
889 | { | 1033 | { |
@@ -996,6 +1140,10 @@ namespace OpenSim.Framework.Servers | |||
996 | { | 1140 | { |
997 | response.StatusDescription = (string)responsedata["error_status_text"]; | 1141 | response.StatusDescription = (string)responsedata["error_status_text"]; |
998 | } | 1142 | } |
1143 | if (responsedata.ContainsKey("http_protocol_version")) | ||
1144 | { | ||
1145 | response.ProtocolVersion = (string)responsedata["http_protocol_version"]; | ||
1146 | } | ||
999 | 1147 | ||
1000 | if (responsedata.ContainsKey("keepalive")) | 1148 | if (responsedata.ContainsKey("keepalive")) |
1001 | { | 1149 | { |
@@ -1049,7 +1197,16 @@ namespace OpenSim.Framework.Servers | |||
1049 | } | 1197 | } |
1050 | finally | 1198 | finally |
1051 | { | 1199 | { |
1052 | response.OutputStream.Close(); | 1200 | //response.OutputStream.Close(); |
1201 | try | ||
1202 | { | ||
1203 | response.Send(); | ||
1204 | } | ||
1205 | catch (SocketException e) | ||
1206 | { | ||
1207 | // This has to be here to prevent a Linux/Mono crash | ||
1208 | m_log.WarnFormat("[BASE HTTP SERVER] XmlRpcRequest issue {0}.\nNOTE: this may be spurious on Linux.", e); | ||
1209 | } | ||
1053 | } | 1210 | } |
1054 | 1211 | ||
1055 | } | 1212 | } |
@@ -1077,7 +1234,16 @@ namespace OpenSim.Framework.Servers | |||
1077 | } | 1234 | } |
1078 | finally | 1235 | finally |
1079 | { | 1236 | { |
1080 | response.OutputStream.Close(); | 1237 | //response.OutputStream.Close(); |
1238 | try | ||
1239 | { | ||
1240 | response.Send(); | ||
1241 | } | ||
1242 | catch (SocketException e) | ||
1243 | { | ||
1244 | // This has to be here to prevent a Linux/Mono crash | ||
1245 | m_log.WarnFormat("[BASE HTTP SERVER] XmlRpcRequest issue {0}.\nNOTE: this may be spurious on Linux.", e); | ||
1246 | } | ||
1081 | } | 1247 | } |
1082 | } | 1248 | } |
1083 | 1249 | ||
@@ -1103,7 +1269,16 @@ namespace OpenSim.Framework.Servers | |||
1103 | } | 1269 | } |
1104 | finally | 1270 | finally |
1105 | { | 1271 | { |
1106 | response.OutputStream.Close(); | 1272 | //response.OutputStream.Close(); |
1273 | try | ||
1274 | { | ||
1275 | response.Send(); | ||
1276 | } | ||
1277 | catch (SocketException e) | ||
1278 | { | ||
1279 | // This has to be here to prevent a Linux/Mono crash | ||
1280 | m_log.WarnFormat("[BASE HTTP SERVER] XmlRpcRequest issue {0}.\nNOTE: this may be spurious on Linux.", e); | ||
1281 | } | ||
1107 | } | 1282 | } |
1108 | } | 1283 | } |
1109 | 1284 | ||
@@ -1111,11 +1286,12 @@ namespace OpenSim.Framework.Servers | |||
1111 | { | 1286 | { |
1112 | m_log.Info("[HTTPD]: Starting up HTTP Server"); | 1287 | m_log.Info("[HTTPD]: Starting up HTTP Server"); |
1113 | 1288 | ||
1114 | m_workerThread = new Thread(new ThreadStart(StartHTTP)); | 1289 | //m_workerThread = new Thread(new ThreadStart(StartHTTP)); |
1115 | m_workerThread.Name = "HttpThread"; | 1290 | //m_workerThread.Name = "HttpThread"; |
1116 | m_workerThread.IsBackground = true; | 1291 | //m_workerThread.IsBackground = true; |
1117 | m_workerThread.Start(); | 1292 | //m_workerThread.Start(); |
1118 | ThreadTracker.Add(m_workerThread); | 1293 | //ThreadTracker.Add(m_workerThread); |
1294 | StartHTTP(); | ||
1119 | } | 1295 | } |
1120 | 1296 | ||
1121 | private void StartHTTP() | 1297 | private void StartHTTP() |
@@ -1123,31 +1299,30 @@ namespace OpenSim.Framework.Servers | |||
1123 | try | 1299 | try |
1124 | { | 1300 | { |
1125 | m_log.Info("[HTTPD]: Spawned main thread OK"); | 1301 | m_log.Info("[HTTPD]: Spawned main thread OK"); |
1126 | m_httpListener = new HttpListener(); | 1302 | //m_httpListener = new HttpListener(); |
1127 | 1303 | ||
1128 | if (!m_ssl) | 1304 | if (!m_ssl) |
1129 | { | 1305 | { |
1130 | m_httpListener.Prefixes.Add("http://+:" + m_port + "/"); | 1306 | //m_httpListener.Prefixes.Add("http://+:" + m_port + "/"); |
1131 | //m_httpListener.Prefixes.Add("http://10.1.1.5:" + m_port + "/"); | 1307 | //m_httpListener.Prefixes.Add("http://10.1.1.5:" + m_port + "/"); |
1308 | m_httpListener2 = new HttpServer.HttpListener(IPAddress.Any, (int)m_port); | ||
1132 | } | 1309 | } |
1133 | else | 1310 | else |
1134 | { | 1311 | { |
1135 | m_httpListener.Prefixes.Add("https://+:" + (m_sslport) + "/"); | 1312 | //m_httpListener.Prefixes.Add("https://+:" + (m_sslport) + "/"); |
1136 | m_httpListener.Prefixes.Add("http://+:" + m_port + "/"); | 1313 | //m_httpListener.Prefixes.Add("http://+:" + m_port + "/"); |
1137 | } | 1314 | } |
1138 | HttpListenerPrefixCollection prefixs = m_httpListener.Prefixes; | ||
1139 | 1315 | ||
1140 | foreach (string prefix in prefixs) | 1316 | m_httpListener2.RequestHandler += OnHandleRequestIOThread; |
1141 | System.Console.WriteLine("Listening on: " + prefix); | 1317 | //m_httpListener.Start(); |
1142 | 1318 | m_httpListener2.Start(5); | |
1143 | m_httpListener.Start(); | ||
1144 | 1319 | ||
1145 | HttpListenerContext context; | 1320 | //HttpListenerContext context; |
1146 | while (true) | 1321 | //while (true) |
1147 | { | 1322 | //{ |
1148 | context = m_httpListener.GetContext(); | 1323 | // context = m_httpListener.GetContext(); |
1149 | ThreadPool.QueueUserWorkItem(new WaitCallback(HandleRequest), context); | 1324 | // ThreadPool.QueueUserWorkItem(new WaitCallback(HandleRequest), context); |
1150 | } | 1325 | // } |
1151 | } | 1326 | } |
1152 | catch (Exception e) | 1327 | catch (Exception e) |
1153 | { | 1328 | { |
@@ -1244,4 +1419,25 @@ namespace OpenSim.Framework.Servers | |||
1244 | return "<HTML><HEAD><TITLE>500 Internal Server Error</TITLE><BODY><BR /><H1>Ooops!</H1><P>The server you requested is overun by knomes! Find hippos quick!</P></BODY></HTML>"; | 1419 | return "<HTML><HEAD><TITLE>500 Internal Server Error</TITLE><BODY><BR /><H1>Ooops!</H1><P>The server you requested is overun by knomes! Find hippos quick!</P></BODY></HTML>"; |
1245 | } | 1420 | } |
1246 | } | 1421 | } |
1422 | |||
1423 | public class HttpServerContextObj | ||
1424 | { | ||
1425 | public IHttpClientContext context = null; | ||
1426 | public IHttpRequest req = null; | ||
1427 | public OSHttpRequest oreq = null; | ||
1428 | public OSHttpResponse oresp = null; | ||
1429 | |||
1430 | public HttpServerContextObj(IHttpClientContext contxt, IHttpRequest reqs) | ||
1431 | { | ||
1432 | context = contxt; | ||
1433 | req = reqs; | ||
1434 | } | ||
1435 | |||
1436 | public HttpServerContextObj(OSHttpRequest osreq, OSHttpResponse osresp) | ||
1437 | { | ||
1438 | oreq = osreq; | ||
1439 | oresp = osresp; | ||
1440 | } | ||
1441 | |||
1442 | } | ||
1247 | } | 1443 | } |