diff options
Diffstat (limited to 'OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs')
-rw-r--r-- | OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs | 383 |
1 files changed, 336 insertions, 47 deletions
diff --git a/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs b/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs index aa49343..f252bd5 100644 --- a/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs +++ b/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs | |||
@@ -46,6 +46,7 @@ using CoolHTTPListener = HttpServer.HttpListener; | |||
46 | using HttpListener=System.Net.HttpListener; | 46 | using HttpListener=System.Net.HttpListener; |
47 | using LogPrio=HttpServer.LogPrio; | 47 | using LogPrio=HttpServer.LogPrio; |
48 | using OpenSim.Framework.Monitoring; | 48 | using OpenSim.Framework.Monitoring; |
49 | using System.IO.Compression; | ||
49 | 50 | ||
50 | namespace OpenSim.Framework.Servers.HttpServer | 51 | namespace OpenSim.Framework.Servers.HttpServer |
51 | { | 52 | { |
@@ -53,6 +54,16 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
53 | { | 54 | { |
54 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 55 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
55 | private HttpServerLogWriter httpserverlog = new HttpServerLogWriter(); | 56 | private HttpServerLogWriter httpserverlog = new HttpServerLogWriter(); |
57 | private static Encoding UTF8NoBOM = new System.Text.UTF8Encoding(false); | ||
58 | |||
59 | /// <summary> | ||
60 | /// This is a pending websocket request before it got an sucessful upgrade response. | ||
61 | /// The consumer must call handler.HandshakeAndUpgrade() to signal to the handler to | ||
62 | /// start the connection and optionally provide an origin authentication method. | ||
63 | /// </summary> | ||
64 | /// <param name="servicepath"></param> | ||
65 | /// <param name="handler"></param> | ||
66 | public delegate void WebSocketRequestDelegate(string servicepath, WebSocketHttpServerHandler handler); | ||
56 | 67 | ||
57 | /// <summary> | 68 | /// <summary> |
58 | /// Gets or sets the debug level. | 69 | /// Gets or sets the debug level. |
@@ -71,12 +82,18 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
71 | /// </remarks> | 82 | /// </remarks> |
72 | public int RequestNumber { get; private set; } | 83 | public int RequestNumber { get; private set; } |
73 | 84 | ||
85 | /// <summary> | ||
86 | /// Statistic for holding number of requests processed. | ||
87 | /// </summary> | ||
88 | private Stat m_requestsProcessedStat; | ||
89 | |||
74 | private volatile int NotSocketErrors = 0; | 90 | private volatile int NotSocketErrors = 0; |
75 | public volatile bool HTTPDRunning = false; | 91 | public volatile bool HTTPDRunning = false; |
76 | 92 | ||
77 | // protected HttpListener m_httpListener; | 93 | // protected HttpListener m_httpListener; |
78 | protected CoolHTTPListener m_httpListener2; | 94 | protected CoolHTTPListener m_httpListener2; |
79 | protected Dictionary<string, XmlRpcMethod> m_rpcHandlers = new Dictionary<string, XmlRpcMethod>(); | 95 | protected Dictionary<string, XmlRpcMethod> m_rpcHandlers = new Dictionary<string, XmlRpcMethod>(); |
96 | protected Dictionary<string, JsonRPCMethod> jsonRpcHandlers = new Dictionary<string, JsonRPCMethod>(); | ||
80 | protected Dictionary<string, bool> m_rpcHandlersKeepAlive = new Dictionary<string, bool>(); | 97 | protected Dictionary<string, bool> m_rpcHandlersKeepAlive = new Dictionary<string, bool>(); |
81 | protected DefaultLLSDMethod m_defaultLlsdHandler = null; // <-- Moving away from the monolithic.. and going to /registered/ | 98 | protected DefaultLLSDMethod m_defaultLlsdHandler = null; // <-- Moving away from the monolithic.. and going to /registered/ |
82 | protected Dictionary<string, LLSDMethod> m_llsdHandlers = new Dictionary<string, LLSDMethod>(); | 99 | protected Dictionary<string, LLSDMethod> m_llsdHandlers = new Dictionary<string, LLSDMethod>(); |
@@ -86,6 +103,9 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
86 | protected Dictionary<string, PollServiceEventArgs> m_pollHandlers = | 103 | protected Dictionary<string, PollServiceEventArgs> m_pollHandlers = |
87 | new Dictionary<string, PollServiceEventArgs>(); | 104 | new Dictionary<string, PollServiceEventArgs>(); |
88 | 105 | ||
106 | protected Dictionary<string, WebSocketRequestDelegate> m_WebSocketHandlers = | ||
107 | new Dictionary<string, WebSocketRequestDelegate>(); | ||
108 | |||
89 | protected uint m_port; | 109 | protected uint m_port; |
90 | protected uint m_sslport; | 110 | protected uint m_sslport; |
91 | protected bool m_ssl; | 111 | protected bool m_ssl; |
@@ -95,7 +115,7 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
95 | 115 | ||
96 | protected IPAddress m_listenIPAddress = IPAddress.Any; | 116 | protected IPAddress m_listenIPAddress = IPAddress.Any; |
97 | 117 | ||
98 | private PollServiceRequestManager m_PollServiceManager; | 118 | public PollServiceRequestManager PollServiceRequestManager { get; private set; } |
99 | 119 | ||
100 | public uint SSLPort | 120 | public uint SSLPort |
101 | { | 121 | { |
@@ -169,6 +189,22 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
169 | } | 189 | } |
170 | } | 190 | } |
171 | 191 | ||
192 | public void AddWebSocketHandler(string servicepath, WebSocketRequestDelegate handler) | ||
193 | { | ||
194 | lock (m_WebSocketHandlers) | ||
195 | { | ||
196 | if (!m_WebSocketHandlers.ContainsKey(servicepath)) | ||
197 | m_WebSocketHandlers.Add(servicepath, handler); | ||
198 | } | ||
199 | } | ||
200 | |||
201 | public void RemoveWebSocketHandler(string servicepath) | ||
202 | { | ||
203 | lock (m_WebSocketHandlers) | ||
204 | if (m_WebSocketHandlers.ContainsKey(servicepath)) | ||
205 | m_WebSocketHandlers.Remove(servicepath); | ||
206 | } | ||
207 | |||
172 | public List<string> GetStreamHandlerKeys() | 208 | public List<string> GetStreamHandlerKeys() |
173 | { | 209 | { |
174 | lock (m_streamHandlers) | 210 | lock (m_streamHandlers) |
@@ -217,6 +253,37 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
217 | return new List<string>(m_rpcHandlers.Keys); | 253 | return new List<string>(m_rpcHandlers.Keys); |
218 | } | 254 | } |
219 | 255 | ||
256 | // JsonRPC | ||
257 | public bool AddJsonRPCHandler(string method, JsonRPCMethod handler) | ||
258 | { | ||
259 | lock(jsonRpcHandlers) | ||
260 | { | ||
261 | jsonRpcHandlers.Add(method, handler); | ||
262 | } | ||
263 | return true; | ||
264 | } | ||
265 | |||
266 | public JsonRPCMethod GetJsonRPCHandler(string method) | ||
267 | { | ||
268 | lock (jsonRpcHandlers) | ||
269 | { | ||
270 | if (jsonRpcHandlers.ContainsKey(method)) | ||
271 | { | ||
272 | return jsonRpcHandlers[method]; | ||
273 | } | ||
274 | else | ||
275 | { | ||
276 | return null; | ||
277 | } | ||
278 | } | ||
279 | } | ||
280 | |||
281 | public List<string> GetJsonRpcHandlerKeys() | ||
282 | { | ||
283 | lock (jsonRpcHandlers) | ||
284 | return new List<string>(jsonRpcHandlers.Keys); | ||
285 | } | ||
286 | |||
220 | public bool AddHTTPHandler(string methodName, GenericHTTPMethod handler) | 287 | public bool AddHTTPHandler(string methodName, GenericHTTPMethod handler) |
221 | { | 288 | { |
222 | //m_log.DebugFormat("[BASE HTTP SERVER]: Registering {0}", methodName); | 289 | //m_log.DebugFormat("[BASE HTTP SERVER]: Registering {0}", methodName); |
@@ -309,7 +376,7 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
309 | return true; | 376 | return true; |
310 | } | 377 | } |
311 | 378 | ||
312 | private void OnRequest(object source, RequestEventArgs args) | 379 | public void OnRequest(object source, RequestEventArgs args) |
313 | { | 380 | { |
314 | RequestNumber++; | 381 | RequestNumber++; |
315 | 382 | ||
@@ -322,6 +389,8 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
322 | 389 | ||
323 | if (TryGetPollServiceHTTPHandler(request.UriPath.ToString(), out psEvArgs)) | 390 | if (TryGetPollServiceHTTPHandler(request.UriPath.ToString(), out psEvArgs)) |
324 | { | 391 | { |
392 | psEvArgs.RequestsReceived++; | ||
393 | |||
325 | PollServiceHttpRequest psreq = new PollServiceHttpRequest(psEvArgs, context, request); | 394 | PollServiceHttpRequest psreq = new PollServiceHttpRequest(psEvArgs, context, request); |
326 | 395 | ||
327 | if (psEvArgs.Request != null) | 396 | if (psEvArgs.Request != null) |
@@ -362,7 +431,7 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
362 | psEvArgs.Request(psreq.RequestID, keysvals); | 431 | psEvArgs.Request(psreq.RequestID, keysvals); |
363 | } | 432 | } |
364 | 433 | ||
365 | m_PollServiceManager.Enqueue(psreq); | 434 | PollServiceRequestManager.Enqueue(psreq); |
366 | } | 435 | } |
367 | else | 436 | else |
368 | { | 437 | { |
@@ -375,11 +444,24 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
375 | } | 444 | } |
376 | } | 445 | } |
377 | 446 | ||
378 | public void OnHandleRequestIOThread(IHttpClientContext context, IHttpRequest request) | 447 | private void OnHandleRequestIOThread(IHttpClientContext context, IHttpRequest request) |
379 | { | 448 | { |
380 | OSHttpRequest req = new OSHttpRequest(context, request); | 449 | OSHttpRequest req = new OSHttpRequest(context, request); |
450 | WebSocketRequestDelegate dWebSocketRequestDelegate = null; | ||
451 | lock (m_WebSocketHandlers) | ||
452 | { | ||
453 | if (m_WebSocketHandlers.ContainsKey(req.RawUrl)) | ||
454 | dWebSocketRequestDelegate = m_WebSocketHandlers[req.RawUrl]; | ||
455 | } | ||
456 | if (dWebSocketRequestDelegate != null) | ||
457 | { | ||
458 | dWebSocketRequestDelegate(req.Url.AbsolutePath, new WebSocketHttpServerHandler(req, context, 8192)); | ||
459 | return; | ||
460 | } | ||
461 | |||
381 | OSHttpResponse resp = new OSHttpResponse(new HttpResponse(context, request),context); | 462 | OSHttpResponse resp = new OSHttpResponse(new HttpResponse(context, request),context); |
382 | HandleRequest(req, resp); | 463 | resp.ReuseContext = true; |
464 | HandleRequest(req, resp); | ||
383 | 465 | ||
384 | // !!!HACK ALERT!!! | 466 | // !!!HACK ALERT!!! |
385 | // There seems to be a bug in the underlying http code that makes subsequent requests | 467 | // There seems to be a bug in the underlying http code that makes subsequent requests |
@@ -410,7 +492,9 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
410 | { | 492 | { |
411 | try | 493 | try |
412 | { | 494 | { |
413 | SendHTML500(response); | 495 | byte[] buffer500 = SendHTML500(response); |
496 | response.OutputStream.Write(buffer500, 0, buffer500.Length); | ||
497 | response.Send(); | ||
414 | } | 498 | } |
415 | catch | 499 | catch |
416 | { | 500 | { |
@@ -468,7 +552,7 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
468 | LogIncomingToStreamHandler(request, requestHandler); | 552 | LogIncomingToStreamHandler(request, requestHandler); |
469 | 553 | ||
470 | response.ContentType = requestHandler.ContentType; // Lets do this defaulting before in case handler has varying content type. | 554 | response.ContentType = requestHandler.ContentType; // Lets do this defaulting before in case handler has varying content type. |
471 | 555 | ||
472 | if (requestHandler is IStreamedRequestHandler) | 556 | if (requestHandler is IStreamedRequestHandler) |
473 | { | 557 | { |
474 | IStreamedRequestHandler streamedRequestHandler = requestHandler as IStreamedRequestHandler; | 558 | IStreamedRequestHandler streamedRequestHandler = requestHandler as IStreamedRequestHandler; |
@@ -556,10 +640,18 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
556 | 640 | ||
557 | buffer = HandleLLSDRequests(request, response); | 641 | buffer = HandleLLSDRequests(request, response); |
558 | break; | 642 | break; |
643 | |||
644 | case "application/json-rpc": | ||
645 | if (DebugLevel >= 3) | ||
646 | LogIncomingToContentTypeHandler(request); | ||
647 | |||
648 | buffer = HandleJsonRpcRequests(request, response); | ||
649 | break; | ||
559 | 650 | ||
560 | case "text/xml": | 651 | case "text/xml": |
561 | case "application/xml": | 652 | case "application/xml": |
562 | case "application/json": | 653 | case "application/json": |
654 | |||
563 | default: | 655 | default: |
564 | //m_log.Info("[Debug BASE HTTP SERVER]: in default handler"); | 656 | //m_log.Info("[Debug BASE HTTP SERVER]: in default handler"); |
565 | // Point of note.. the DoWeHaveA methods check for an EXACT path | 657 | // Point of note.. the DoWeHaveA methods check for an EXACT path |
@@ -600,7 +692,24 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
600 | 692 | ||
601 | if (buffer != null) | 693 | if (buffer != null) |
602 | { | 694 | { |
603 | if (!response.SendChunked) | 695 | if (WebUtil.DebugLevel >= 5) |
696 | { | ||
697 | string output = System.Text.Encoding.UTF8.GetString(buffer); | ||
698 | |||
699 | if (WebUtil.DebugLevel >= 6) | ||
700 | { | ||
701 | // Always truncate binary blobs. We don't have a ContentType, so detect them using the request name. | ||
702 | if ((requestHandler != null && requestHandler.Name == "GetMesh")) | ||
703 | { | ||
704 | if (output.Length > WebUtil.MaxRequestDiagLength) | ||
705 | output = output.Substring(0, WebUtil.MaxRequestDiagLength) + "..."; | ||
706 | } | ||
707 | } | ||
708 | |||
709 | WebUtil.LogResponseDetail(RequestNumber, output); | ||
710 | } | ||
711 | |||
712 | if (!response.SendChunked && response.ContentLength64 <= 0) | ||
604 | response.ContentLength64 = buffer.LongLength; | 713 | response.ContentLength64 = buffer.LongLength; |
605 | 714 | ||
606 | response.OutputStream.Write(buffer, 0, buffer.Length); | 715 | response.OutputStream.Write(buffer, 0, buffer.Length); |
@@ -630,12 +739,20 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
630 | } | 739 | } |
631 | catch (IOException e) | 740 | catch (IOException e) |
632 | { | 741 | { |
633 | m_log.Error(String.Format("[BASE HTTP SERVER]: HandleRequest() threw {0} ", e.StackTrace), e); | 742 | m_log.Error("[BASE HTTP SERVER]: HandleRequest() threw exception ", e); |
634 | } | 743 | } |
635 | catch (Exception e) | 744 | catch (Exception e) |
636 | { | 745 | { |
637 | m_log.Error(String.Format("[BASE HTTP SERVER]: HandleRequest() threw {0} ", e.StackTrace), e); | 746 | m_log.Error("[BASE HTTP SERVER]: HandleRequest() threw exception ", e); |
638 | SendHTML500(response); | 747 | try |
748 | { | ||
749 | byte[] buffer500 = SendHTML500(response); | ||
750 | response.OutputStream.Write(buffer500, 0, buffer500.Length); | ||
751 | response.Send(); | ||
752 | } | ||
753 | catch | ||
754 | { | ||
755 | } | ||
639 | } | 756 | } |
640 | finally | 757 | finally |
641 | { | 758 | { |
@@ -645,7 +762,7 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
645 | if (tickdiff > 3000 && requestHandler != null && requestHandler.Name != "GetTexture") | 762 | if (tickdiff > 3000 && requestHandler != null && requestHandler.Name != "GetTexture") |
646 | { | 763 | { |
647 | m_log.InfoFormat( | 764 | m_log.InfoFormat( |
648 | "[BASE HTTP SERVER]: Slow handling of {0} {1} {2} {3} {4} from {5} took {6}ms", | 765 | "[LOGHTTP] Slow handling of {0} {1} {2} {3} {4} from {5} took {6}ms", |
649 | RequestNumber, | 766 | RequestNumber, |
650 | requestMethod, | 767 | requestMethod, |
651 | uriString, | 768 | uriString, |
@@ -657,7 +774,7 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
657 | else if (DebugLevel >= 4) | 774 | else if (DebugLevel >= 4) |
658 | { | 775 | { |
659 | m_log.DebugFormat( | 776 | m_log.DebugFormat( |
660 | "[BASE HTTP SERVER]: HTTP IN {0} :{1} took {2}ms", | 777 | "[LOGHTTP] HTTP IN {0} :{1} took {2}ms", |
661 | RequestNumber, | 778 | RequestNumber, |
662 | Port, | 779 | Port, |
663 | tickdiff); | 780 | tickdiff); |
@@ -668,7 +785,7 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
668 | private void LogIncomingToStreamHandler(OSHttpRequest request, IRequestHandler requestHandler) | 785 | private void LogIncomingToStreamHandler(OSHttpRequest request, IRequestHandler requestHandler) |
669 | { | 786 | { |
670 | m_log.DebugFormat( | 787 | m_log.DebugFormat( |
671 | "[BASE HTTP SERVER]: HTTP IN {0} :{1} stream handler {2} {3} {4} {5} from {6}", | 788 | "[LOGHTTP] HTTP IN {0} :{1} stream handler {2} {3} {4} {5} from {6}", |
672 | RequestNumber, | 789 | RequestNumber, |
673 | Port, | 790 | Port, |
674 | request.HttpMethod, | 791 | request.HttpMethod, |
@@ -684,10 +801,10 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
684 | private void LogIncomingToContentTypeHandler(OSHttpRequest request) | 801 | private void LogIncomingToContentTypeHandler(OSHttpRequest request) |
685 | { | 802 | { |
686 | m_log.DebugFormat( | 803 | m_log.DebugFormat( |
687 | "[BASE HTTP SERVER]: HTTP IN {0} :{1} {2} content type handler {3} {4} from {5}", | 804 | "[LOGHTTP] HTTP IN {0} :{1} {2} content type handler {3} {4} from {5}", |
688 | RequestNumber, | 805 | RequestNumber, |
689 | Port, | 806 | Port, |
690 | (request.ContentType == null || request.ContentType == "") ? "not set" : request.ContentType, | 807 | string.IsNullOrEmpty(request.ContentType) ? "not set" : request.ContentType, |
691 | request.HttpMethod, | 808 | request.HttpMethod, |
692 | request.Url.PathAndQuery, | 809 | request.Url.PathAndQuery, |
693 | request.RemoteIPEndPoint); | 810 | request.RemoteIPEndPoint); |
@@ -699,7 +816,7 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
699 | private void LogIncomingToXmlRpcHandler(OSHttpRequest request) | 816 | private void LogIncomingToXmlRpcHandler(OSHttpRequest request) |
700 | { | 817 | { |
701 | m_log.DebugFormat( | 818 | m_log.DebugFormat( |
702 | "[BASE HTTP SERVER]: HTTP IN {0} :{1} assumed generic XMLRPC request {2} {3} from {4}", | 819 | "[LOGHTTP] HTTP IN {0} :{1} assumed generic XMLRPC request {2} {3} from {4}", |
703 | RequestNumber, | 820 | RequestNumber, |
704 | Port, | 821 | Port, |
705 | request.HttpMethod, | 822 | request.HttpMethod, |
@@ -712,29 +829,49 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
712 | 829 | ||
713 | private void LogIncomingInDetail(OSHttpRequest request) | 830 | private void LogIncomingInDetail(OSHttpRequest request) |
714 | { | 831 | { |
715 | using (StreamReader reader = new StreamReader(Util.Copy(request.InputStream), Encoding.UTF8)) | 832 | if (request.ContentType == "application/octet-stream") |
716 | { | 833 | return; // never log these; they're just binary data |
717 | string output; | ||
718 | 834 | ||
719 | if (DebugLevel == 5) | 835 | Stream inputStream = Util.Copy(request.InputStream); |
836 | Stream innerStream = null; | ||
837 | try | ||
838 | { | ||
839 | if ((request.Headers["Content-Encoding"] == "gzip") || (request.Headers["X-Content-Encoding"] == "gzip")) | ||
720 | { | 840 | { |
721 | const int sampleLength = 80; | 841 | innerStream = inputStream; |
722 | char[] sampleChars = new char[sampleLength + 3]; | 842 | inputStream = new GZipStream(innerStream, System.IO.Compression.CompressionMode.Decompress); |
723 | reader.Read(sampleChars, 0, sampleLength); | ||
724 | sampleChars[80] = '.'; | ||
725 | sampleChars[81] = '.'; | ||
726 | sampleChars[82] = '.'; | ||
727 | output = new string(sampleChars); | ||
728 | } | 843 | } |
729 | else | 844 | |
845 | using (StreamReader reader = new StreamReader(inputStream, Encoding.UTF8)) | ||
730 | { | 846 | { |
731 | output = reader.ReadToEnd(); | 847 | string output; |
732 | } | ||
733 | 848 | ||
734 | m_log.DebugFormat("[BASE HTTP SERVER]: {0}", output.Replace("\n", @"\n")); | 849 | if (DebugLevel == 5) |
850 | { | ||
851 | char[] chars = new char[WebUtil.MaxRequestDiagLength + 1]; // +1 so we know to add "..." only if needed | ||
852 | int len = reader.Read(chars, 0, WebUtil.MaxRequestDiagLength + 1); | ||
853 | output = new string(chars, 0, Math.Min(len, WebUtil.MaxRequestDiagLength)); | ||
854 | if (len > WebUtil.MaxRequestDiagLength) | ||
855 | output += "..."; | ||
856 | } | ||
857 | else | ||
858 | { | ||
859 | output = reader.ReadToEnd(); | ||
860 | } | ||
861 | |||
862 | m_log.DebugFormat("[LOGHTTP] {0}", Util.BinaryToASCII(output)); | ||
863 | } | ||
864 | } | ||
865 | finally | ||
866 | { | ||
867 | if (innerStream != null) | ||
868 | innerStream.Dispose(); | ||
869 | inputStream.Dispose(); | ||
735 | } | 870 | } |
736 | } | 871 | } |
737 | 872 | ||
873 | private readonly string HANDLER_SEPARATORS = "/?&#-"; | ||
874 | |||
738 | private bool TryGetStreamHandler(string handlerKey, out IRequestHandler streamHandler) | 875 | private bool TryGetStreamHandler(string handlerKey, out IRequestHandler streamHandler) |
739 | { | 876 | { |
740 | string bestMatch = null; | 877 | string bestMatch = null; |
@@ -743,7 +880,8 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
743 | { | 880 | { |
744 | foreach (string pattern in m_streamHandlers.Keys) | 881 | foreach (string pattern in m_streamHandlers.Keys) |
745 | { | 882 | { |
746 | if (handlerKey.StartsWith(pattern)) | 883 | if ((handlerKey == pattern) |
884 | || (handlerKey.StartsWith(pattern) && (HANDLER_SEPARATORS.IndexOf(handlerKey[pattern.Length]) >= 0))) | ||
747 | { | 885 | { |
748 | if (String.IsNullOrEmpty(bestMatch) || pattern.Length > bestMatch.Length) | 886 | if (String.IsNullOrEmpty(bestMatch) || pattern.Length > bestMatch.Length) |
749 | { | 887 | { |
@@ -773,7 +911,8 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
773 | { | 911 | { |
774 | foreach (string pattern in m_pollHandlers.Keys) | 912 | foreach (string pattern in m_pollHandlers.Keys) |
775 | { | 913 | { |
776 | if (handlerKey.StartsWith(pattern)) | 914 | if ((handlerKey == pattern) |
915 | || (handlerKey.StartsWith(pattern) && (HANDLER_SEPARATORS.IndexOf(handlerKey[pattern.Length]) >= 0))) | ||
777 | { | 916 | { |
778 | if (String.IsNullOrEmpty(bestMatch) || pattern.Length > bestMatch.Length) | 917 | if (String.IsNullOrEmpty(bestMatch) || pattern.Length > bestMatch.Length) |
779 | { | 918 | { |
@@ -805,7 +944,8 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
805 | { | 944 | { |
806 | foreach (string pattern in m_HTTPHandlers.Keys) | 945 | foreach (string pattern in m_HTTPHandlers.Keys) |
807 | { | 946 | { |
808 | if (handlerKey.StartsWith(pattern)) | 947 | if ((handlerKey == pattern) |
948 | || (handlerKey.StartsWith(pattern) && (HANDLER_SEPARATORS.IndexOf(handlerKey[pattern.Length]) >= 0))) | ||
809 | { | 949 | { |
810 | if (String.IsNullOrEmpty(bestMatch) || pattern.Length > bestMatch.Length) | 950 | if (String.IsNullOrEmpty(bestMatch) || pattern.Length > bestMatch.Length) |
811 | { | 951 | { |
@@ -854,16 +994,33 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
854 | /// <param name="response"></param> | 994 | /// <param name="response"></param> |
855 | private byte[] HandleXmlRpcRequests(OSHttpRequest request, OSHttpResponse response) | 995 | private byte[] HandleXmlRpcRequests(OSHttpRequest request, OSHttpResponse response) |
856 | { | 996 | { |
997 | String requestBody; | ||
998 | |||
857 | Stream requestStream = request.InputStream; | 999 | Stream requestStream = request.InputStream; |
1000 | Stream innerStream = null; | ||
1001 | try | ||
1002 | { | ||
1003 | if ((request.Headers["Content-Encoding"] == "gzip") || (request.Headers["X-Content-Encoding"] == "gzip")) | ||
1004 | { | ||
1005 | innerStream = requestStream; | ||
1006 | requestStream = new GZipStream(innerStream, System.IO.Compression.CompressionMode.Decompress); | ||
1007 | } | ||
858 | 1008 | ||
859 | Encoding encoding = Encoding.UTF8; | 1009 | using (StreamReader reader = new StreamReader(requestStream, Encoding.UTF8)) |
860 | StreamReader reader = new StreamReader(requestStream, encoding); | 1010 | { |
1011 | requestBody = reader.ReadToEnd(); | ||
1012 | } | ||
1013 | } | ||
1014 | finally | ||
1015 | { | ||
1016 | if (innerStream != null) | ||
1017 | innerStream.Dispose(); | ||
1018 | requestStream.Dispose(); | ||
1019 | } | ||
861 | 1020 | ||
862 | string requestBody = reader.ReadToEnd(); | ||
863 | reader.Close(); | ||
864 | requestStream.Close(); | ||
865 | //m_log.Debug(requestBody); | 1021 | //m_log.Debug(requestBody); |
866 | requestBody = requestBody.Replace("<base64></base64>", ""); | 1022 | requestBody = requestBody.Replace("<base64></base64>", ""); |
1023 | |||
867 | string responseString = String.Empty; | 1024 | string responseString = String.Empty; |
868 | XmlRpcRequest xmlRprcRequest = null; | 1025 | XmlRpcRequest xmlRprcRequest = null; |
869 | 1026 | ||
@@ -958,7 +1115,19 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
958 | } | 1115 | } |
959 | 1116 | ||
960 | response.ContentType = "text/xml"; | 1117 | response.ContentType = "text/xml"; |
961 | responseString = XmlRpcResponseSerializer.Singleton.Serialize(xmlRpcResponse); | 1118 | using (MemoryStream outs = new MemoryStream()) |
1119 | using (XmlTextWriter writer = new XmlTextWriter(outs, UTF8NoBOM)) | ||
1120 | { | ||
1121 | writer.Formatting = Formatting.None; | ||
1122 | XmlRpcResponseSerializer.Singleton.Serialize(writer, xmlRpcResponse); | ||
1123 | writer.Flush(); | ||
1124 | outs.Flush(); | ||
1125 | outs.Position = 0; | ||
1126 | using (StreamReader sr = new StreamReader(outs)) | ||
1127 | { | ||
1128 | responseString = sr.ReadToEnd(); | ||
1129 | } | ||
1130 | } | ||
962 | } | 1131 | } |
963 | else | 1132 | else |
964 | { | 1133 | { |
@@ -985,6 +1154,93 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
985 | return buffer; | 1154 | return buffer; |
986 | } | 1155 | } |
987 | 1156 | ||
1157 | // JsonRpc (v2.0 only) | ||
1158 | // Batch requests not yet supported | ||
1159 | private byte[] HandleJsonRpcRequests(OSHttpRequest request, OSHttpResponse response) | ||
1160 | { | ||
1161 | Stream requestStream = request.InputStream; | ||
1162 | JsonRpcResponse jsonRpcResponse = new JsonRpcResponse(); | ||
1163 | OSDMap jsonRpcRequest = null; | ||
1164 | |||
1165 | try | ||
1166 | { | ||
1167 | jsonRpcRequest = (OSDMap)OSDParser.DeserializeJson(requestStream); | ||
1168 | } | ||
1169 | catch (LitJson.JsonException e) | ||
1170 | { | ||
1171 | jsonRpcResponse.Error.Code = ErrorCode.InternalError; | ||
1172 | jsonRpcResponse.Error.Message = e.Message; | ||
1173 | } | ||
1174 | |||
1175 | requestStream.Close(); | ||
1176 | |||
1177 | if (jsonRpcRequest != null) | ||
1178 | { | ||
1179 | if (jsonRpcRequest.ContainsKey("jsonrpc") || jsonRpcRequest["jsonrpc"].AsString() == "2.0") | ||
1180 | { | ||
1181 | jsonRpcResponse.JsonRpc = "2.0"; | ||
1182 | |||
1183 | // If we have no id, then it's a "notification" | ||
1184 | if (jsonRpcRequest.ContainsKey("id")) | ||
1185 | { | ||
1186 | jsonRpcResponse.Id = jsonRpcRequest["id"].AsString(); | ||
1187 | } | ||
1188 | |||
1189 | string methodname = jsonRpcRequest["method"]; | ||
1190 | JsonRPCMethod method; | ||
1191 | |||
1192 | if (jsonRpcHandlers.ContainsKey(methodname)) | ||
1193 | { | ||
1194 | lock(jsonRpcHandlers) | ||
1195 | { | ||
1196 | jsonRpcHandlers.TryGetValue(methodname, out method); | ||
1197 | } | ||
1198 | bool res = false; | ||
1199 | try | ||
1200 | { | ||
1201 | res = method(jsonRpcRequest, ref jsonRpcResponse); | ||
1202 | if(!res) | ||
1203 | { | ||
1204 | // The handler sent back an unspecified error | ||
1205 | if(jsonRpcResponse.Error.Code == 0) | ||
1206 | { | ||
1207 | jsonRpcResponse.Error.Code = ErrorCode.InternalError; | ||
1208 | } | ||
1209 | } | ||
1210 | } | ||
1211 | catch (Exception e) | ||
1212 | { | ||
1213 | string ErrorMessage = string.Format("[BASE HTTP SERVER]: Json-Rpc Handler Error method {0} - {1}", methodname, e.Message); | ||
1214 | m_log.Error(ErrorMessage); | ||
1215 | jsonRpcResponse.Error.Code = ErrorCode.InternalError; | ||
1216 | jsonRpcResponse.Error.Message = ErrorMessage; | ||
1217 | } | ||
1218 | } | ||
1219 | else // Error no hanlder defined for requested method | ||
1220 | { | ||
1221 | jsonRpcResponse.Error.Code = ErrorCode.InvalidRequest; | ||
1222 | jsonRpcResponse.Error.Message = string.Format ("No handler defined for {0}", methodname); | ||
1223 | } | ||
1224 | } | ||
1225 | else // not json-rpc 2.0 could be v1 | ||
1226 | { | ||
1227 | jsonRpcResponse.Error.Code = ErrorCode.InvalidRequest; | ||
1228 | jsonRpcResponse.Error.Message = "Must be valid json-rpc 2.0 see: http://www.jsonrpc.org/specification"; | ||
1229 | |||
1230 | if (jsonRpcRequest.ContainsKey("id")) | ||
1231 | jsonRpcResponse.Id = jsonRpcRequest["id"].AsString(); | ||
1232 | } | ||
1233 | } | ||
1234 | |||
1235 | response.KeepAlive = true; | ||
1236 | string responseData = string.Empty; | ||
1237 | |||
1238 | responseData = jsonRpcResponse.Serialize(); | ||
1239 | |||
1240 | byte[] buffer = Encoding.UTF8.GetBytes(responseData); | ||
1241 | return buffer; | ||
1242 | } | ||
1243 | |||
988 | private byte[] HandleLLSDRequests(OSHttpRequest request, OSHttpResponse response) | 1244 | private byte[] HandleLLSDRequests(OSHttpRequest request, OSHttpResponse response) |
989 | { | 1245 | { |
990 | //m_log.Warn("[BASE HTTP SERVER]: We've figured out it's a LLSD Request"); | 1246 | //m_log.Warn("[BASE HTTP SERVER]: We've figured out it's a LLSD Request"); |
@@ -1575,16 +1831,24 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
1575 | response.SendChunked = false; | 1831 | response.SendChunked = false; |
1576 | response.ContentLength64 = buffer.Length; | 1832 | response.ContentLength64 = buffer.Length; |
1577 | response.ContentEncoding = Encoding.UTF8; | 1833 | response.ContentEncoding = Encoding.UTF8; |
1578 | 1834 | ||
1835 | |||
1579 | return buffer; | 1836 | return buffer; |
1580 | } | 1837 | } |
1581 | 1838 | ||
1582 | public void Start() | 1839 | public void Start() |
1583 | { | 1840 | { |
1584 | StartHTTP(); | 1841 | Start(true); |
1585 | } | 1842 | } |
1586 | 1843 | ||
1587 | private void StartHTTP() | 1844 | /// <summary> |
1845 | /// Start the http server | ||
1846 | /// </summary> | ||
1847 | /// <param name='processPollRequestsAsync'> | ||
1848 | /// If true then poll responses are performed asynchronsly. | ||
1849 | /// Option exists to allow regression tests to perform processing synchronously. | ||
1850 | /// </param> | ||
1851 | public void Start(bool performPollResponsesAsync) | ||
1588 | { | 1852 | { |
1589 | m_log.InfoFormat( | 1853 | m_log.InfoFormat( |
1590 | "[BASE HTTP SERVER]: Starting {0} server on port {1}", UseSSL ? "HTTPS" : "HTTP", Port); | 1854 | "[BASE HTTP SERVER]: Starting {0} server on port {1}", UseSSL ? "HTTPS" : "HTTP", Port); |
@@ -1622,8 +1886,9 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
1622 | m_httpListener2.Start(64); | 1886 | m_httpListener2.Start(64); |
1623 | 1887 | ||
1624 | // Long Poll Service Manager with 3 worker threads a 25 second timeout for no events | 1888 | // Long Poll Service Manager with 3 worker threads a 25 second timeout for no events |
1625 | m_PollServiceManager = new PollServiceRequestManager(this, 3, 25000); | 1889 | PollServiceRequestManager = new PollServiceRequestManager(this, performPollResponsesAsync, 3, 25000); |
1626 | m_PollServiceManager.Start(); | 1890 | PollServiceRequestManager.Start(); |
1891 | |||
1627 | HTTPDRunning = true; | 1892 | HTTPDRunning = true; |
1628 | 1893 | ||
1629 | //HttpListenerContext context; | 1894 | //HttpListenerContext context; |
@@ -1642,6 +1907,21 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
1642 | // useful without inbound HTTP. | 1907 | // useful without inbound HTTP. |
1643 | throw e; | 1908 | throw e; |
1644 | } | 1909 | } |
1910 | |||
1911 | m_requestsProcessedStat | ||
1912 | = new Stat( | ||
1913 | "HTTPRequestsServed", | ||
1914 | "Number of inbound HTTP requests processed", | ||
1915 | "", | ||
1916 | "requests", | ||
1917 | "httpserver", | ||
1918 | Port.ToString(), | ||
1919 | StatType.Pull, | ||
1920 | MeasuresOfInterest.AverageChangeOverTime, | ||
1921 | stat => stat.Value = RequestNumber, | ||
1922 | StatVerbosity.Debug); | ||
1923 | |||
1924 | StatsManager.RegisterStat(m_requestsProcessedStat); | ||
1645 | } | 1925 | } |
1646 | 1926 | ||
1647 | public void httpServerDisconnectMonitor(IHttpClientContext source, SocketError err) | 1927 | public void httpServerDisconnectMonitor(IHttpClientContext source, SocketError err) |
@@ -1672,9 +1952,12 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
1672 | public void Stop() | 1952 | public void Stop() |
1673 | { | 1953 | { |
1674 | HTTPDRunning = false; | 1954 | HTTPDRunning = false; |
1955 | |||
1956 | StatsManager.DeregisterStat(m_requestsProcessedStat); | ||
1957 | |||
1675 | try | 1958 | try |
1676 | { | 1959 | { |
1677 | m_PollServiceManager.Stop(); | 1960 | PollServiceRequestManager.Stop(); |
1678 | 1961 | ||
1679 | m_httpListener2.ExceptionThrown -= httpServerException; | 1962 | m_httpListener2.ExceptionThrown -= httpServerException; |
1680 | //m_httpListener2.DisconnectHandler = null; | 1963 | //m_httpListener2.DisconnectHandler = null; |
@@ -1741,6 +2024,12 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
1741 | m_rpcHandlers.Remove(method); | 2024 | m_rpcHandlers.Remove(method); |
1742 | } | 2025 | } |
1743 | 2026 | ||
2027 | public void RemoveJsonRPCHandler(string method) | ||
2028 | { | ||
2029 | lock(jsonRpcHandlers) | ||
2030 | jsonRpcHandlers.Remove(method); | ||
2031 | } | ||
2032 | |||
1744 | public bool RemoveLLSDHandler(string path, LLSDMethod handler) | 2033 | public bool RemoveLLSDHandler(string path, LLSDMethod handler) |
1745 | { | 2034 | { |
1746 | lock (m_llsdHandlers) | 2035 | lock (m_llsdHandlers) |