diff options
Diffstat (limited to 'OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs')
-rw-r--r-- | OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs | 230 |
1 files changed, 175 insertions, 55 deletions
diff --git a/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs b/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs index 77fce9e..27af009 100644 --- a/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs +++ b/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs | |||
@@ -54,6 +54,16 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
54 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 54 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
55 | private HttpServerLogWriter httpserverlog = new HttpServerLogWriter(); | 55 | private HttpServerLogWriter httpserverlog = new HttpServerLogWriter(); |
56 | 56 | ||
57 | |||
58 | /// <summary> | ||
59 | /// This is a pending websocket request before it got an sucessful upgrade response. | ||
60 | /// The consumer must call handler.HandshakeAndUpgrade() to signal to the handler to | ||
61 | /// start the connection and optionally provide an origin authentication method. | ||
62 | /// </summary> | ||
63 | /// <param name="servicepath"></param> | ||
64 | /// <param name="handler"></param> | ||
65 | public delegate void WebSocketRequestDelegate(string servicepath, WebSocketHttpServerHandler handler); | ||
66 | |||
57 | /// <summary> | 67 | /// <summary> |
58 | /// Gets or sets the debug level. | 68 | /// Gets or sets the debug level. |
59 | /// </summary> | 69 | /// </summary> |
@@ -77,6 +87,7 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
77 | // protected HttpListener m_httpListener; | 87 | // protected HttpListener m_httpListener; |
78 | protected CoolHTTPListener m_httpListener2; | 88 | protected CoolHTTPListener m_httpListener2; |
79 | protected Dictionary<string, XmlRpcMethod> m_rpcHandlers = new Dictionary<string, XmlRpcMethod>(); | 89 | protected Dictionary<string, XmlRpcMethod> m_rpcHandlers = new Dictionary<string, XmlRpcMethod>(); |
90 | protected Dictionary<string, JsonRPCMethod> jsonRpcHandlers = new Dictionary<string, JsonRPCMethod>(); | ||
80 | protected Dictionary<string, bool> m_rpcHandlersKeepAlive = new Dictionary<string, bool>(); | 91 | 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/ | 92 | 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>(); | 93 | protected Dictionary<string, LLSDMethod> m_llsdHandlers = new Dictionary<string, LLSDMethod>(); |
@@ -86,6 +97,9 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
86 | protected Dictionary<string, PollServiceEventArgs> m_pollHandlers = | 97 | protected Dictionary<string, PollServiceEventArgs> m_pollHandlers = |
87 | new Dictionary<string, PollServiceEventArgs>(); | 98 | new Dictionary<string, PollServiceEventArgs>(); |
88 | 99 | ||
100 | protected Dictionary<string, WebSocketRequestDelegate> m_WebSocketHandlers = | ||
101 | new Dictionary<string, WebSocketRequestDelegate>(); | ||
102 | |||
89 | protected uint m_port; | 103 | protected uint m_port; |
90 | protected uint m_sslport; | 104 | protected uint m_sslport; |
91 | protected bool m_ssl; | 105 | protected bool m_ssl; |
@@ -169,6 +183,22 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
169 | } | 183 | } |
170 | } | 184 | } |
171 | 185 | ||
186 | public void AddWebSocketHandler(string servicepath, WebSocketRequestDelegate handler) | ||
187 | { | ||
188 | lock (m_WebSocketHandlers) | ||
189 | { | ||
190 | if (!m_WebSocketHandlers.ContainsKey(servicepath)) | ||
191 | m_WebSocketHandlers.Add(servicepath, handler); | ||
192 | } | ||
193 | } | ||
194 | |||
195 | public void RemoveWebSocketHandler(string servicepath) | ||
196 | { | ||
197 | lock (m_WebSocketHandlers) | ||
198 | if (m_WebSocketHandlers.ContainsKey(servicepath)) | ||
199 | m_WebSocketHandlers.Remove(servicepath); | ||
200 | } | ||
201 | |||
172 | public List<string> GetStreamHandlerKeys() | 202 | public List<string> GetStreamHandlerKeys() |
173 | { | 203 | { |
174 | lock (m_streamHandlers) | 204 | lock (m_streamHandlers) |
@@ -217,6 +247,37 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
217 | return new List<string>(m_rpcHandlers.Keys); | 247 | return new List<string>(m_rpcHandlers.Keys); |
218 | } | 248 | } |
219 | 249 | ||
250 | // JsonRPC | ||
251 | public bool AddJsonRPCHandler(string method, JsonRPCMethod handler) | ||
252 | { | ||
253 | lock(jsonRpcHandlers) | ||
254 | { | ||
255 | jsonRpcHandlers.Add(method, handler); | ||
256 | } | ||
257 | return true; | ||
258 | } | ||
259 | |||
260 | public JsonRPCMethod GetJsonRPCHandler(string method) | ||
261 | { | ||
262 | lock (jsonRpcHandlers) | ||
263 | { | ||
264 | if (jsonRpcHandlers.ContainsKey(method)) | ||
265 | { | ||
266 | return jsonRpcHandlers[method]; | ||
267 | } | ||
268 | else | ||
269 | { | ||
270 | return null; | ||
271 | } | ||
272 | } | ||
273 | } | ||
274 | |||
275 | public List<string> GetJsonRpcHandlerKeys() | ||
276 | { | ||
277 | lock (jsonRpcHandlers) | ||
278 | return new List<string>(jsonRpcHandlers.Keys); | ||
279 | } | ||
280 | |||
220 | public bool AddHTTPHandler(string methodName, GenericHTTPMethod handler) | 281 | public bool AddHTTPHandler(string methodName, GenericHTTPMethod handler) |
221 | { | 282 | { |
222 | //m_log.DebugFormat("[BASE HTTP SERVER]: Registering {0}", methodName); | 283 | //m_log.DebugFormat("[BASE HTTP SERVER]: Registering {0}", methodName); |
@@ -378,9 +439,24 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
378 | 439 | ||
379 | public void OnHandleRequestIOThread(IHttpClientContext context, IHttpRequest request) | 440 | public void OnHandleRequestIOThread(IHttpClientContext context, IHttpRequest request) |
380 | { | 441 | { |
442 | |||
381 | OSHttpRequest req = new OSHttpRequest(context, request); | 443 | OSHttpRequest req = new OSHttpRequest(context, request); |
444 | WebSocketRequestDelegate dWebSocketRequestDelegate = null; | ||
445 | lock (m_WebSocketHandlers) | ||
446 | { | ||
447 | if (m_WebSocketHandlers.ContainsKey(req.RawUrl)) | ||
448 | dWebSocketRequestDelegate = m_WebSocketHandlers[req.RawUrl]; | ||
449 | } | ||
450 | if (dWebSocketRequestDelegate != null) | ||
451 | { | ||
452 | dWebSocketRequestDelegate(req.Url.AbsolutePath, new WebSocketHttpServerHandler(req, context, 8192)); | ||
453 | return; | ||
454 | } | ||
455 | |||
382 | OSHttpResponse resp = new OSHttpResponse(new HttpResponse(context, request),context); | 456 | OSHttpResponse resp = new OSHttpResponse(new HttpResponse(context, request),context); |
457 | |||
383 | HandleRequest(req, resp); | 458 | HandleRequest(req, resp); |
459 | |||
384 | 460 | ||
385 | // !!!HACK ALERT!!! | 461 | // !!!HACK ALERT!!! |
386 | // There seems to be a bug in the underlying http code that makes subsequent requests | 462 | // There seems to be a bug in the underlying http code that makes subsequent requests |
@@ -437,7 +513,7 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
437 | // reqnum = String.Format("{0}:{1}",request.RemoteIPEndPoint,request.Headers["opensim-request-id"]); | 513 | // reqnum = String.Format("{0}:{1}",request.RemoteIPEndPoint,request.Headers["opensim-request-id"]); |
438 | //m_log.DebugFormat("[BASE HTTP SERVER]: <{0}> handle request for {1}",reqnum,request.RawUrl); | 514 | //m_log.DebugFormat("[BASE HTTP SERVER]: <{0}> handle request for {1}",reqnum,request.RawUrl); |
439 | 515 | ||
440 | Thread.CurrentThread.CurrentCulture = new CultureInfo("en-US", true); | 516 | Culture.SetCurrentCulture(); |
441 | 517 | ||
442 | // // This is the REST agent interface. We require an agent to properly identify | 518 | // // This is the REST agent interface. We require an agent to properly identify |
443 | // // itself. If the REST handler recognizes the prefix it will attempt to | 519 | // // itself. If the REST handler recognizes the prefix it will attempt to |
@@ -469,7 +545,7 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
469 | LogIncomingToStreamHandler(request, requestHandler); | 545 | LogIncomingToStreamHandler(request, requestHandler); |
470 | 546 | ||
471 | response.ContentType = requestHandler.ContentType; // Lets do this defaulting before in case handler has varying content type. | 547 | response.ContentType = requestHandler.ContentType; // Lets do this defaulting before in case handler has varying content type. |
472 | 548 | ||
473 | if (requestHandler is IStreamedRequestHandler) | 549 | if (requestHandler is IStreamedRequestHandler) |
474 | { | 550 | { |
475 | IStreamedRequestHandler streamedRequestHandler = requestHandler as IStreamedRequestHandler; | 551 | IStreamedRequestHandler streamedRequestHandler = requestHandler as IStreamedRequestHandler; |
@@ -557,10 +633,18 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
557 | 633 | ||
558 | buffer = HandleLLSDRequests(request, response); | 634 | buffer = HandleLLSDRequests(request, response); |
559 | break; | 635 | break; |
636 | |||
637 | case "application/json-rpc": | ||
638 | if (DebugLevel >= 3) | ||
639 | LogIncomingToContentTypeHandler(request); | ||
640 | |||
641 | buffer = HandleJsonRpcRequests(request, response); | ||
642 | break; | ||
560 | 643 | ||
561 | case "text/xml": | 644 | case "text/xml": |
562 | case "application/xml": | 645 | case "application/xml": |
563 | case "application/json": | 646 | case "application/json": |
647 | |||
564 | default: | 648 | default: |
565 | //m_log.Info("[Debug BASE HTTP SERVER]: in default handler"); | 649 | //m_log.Info("[Debug BASE HTTP SERVER]: in default handler"); |
566 | // Point of note.. the DoWeHaveA methods check for an EXACT path | 650 | // Point of note.. the DoWeHaveA methods check for an EXACT path |
@@ -986,6 +1070,93 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
986 | return buffer; | 1070 | return buffer; |
987 | } | 1071 | } |
988 | 1072 | ||
1073 | // JsonRpc (v2.0 only) | ||
1074 | // Batch requests not yet supported | ||
1075 | private byte[] HandleJsonRpcRequests(OSHttpRequest request, OSHttpResponse response) | ||
1076 | { | ||
1077 | Stream requestStream = request.InputStream; | ||
1078 | JsonRpcResponse jsonRpcResponse = new JsonRpcResponse(); | ||
1079 | OSDMap jsonRpcRequest = null; | ||
1080 | |||
1081 | try | ||
1082 | { | ||
1083 | jsonRpcRequest = (OSDMap)OSDParser.DeserializeJson(requestStream); | ||
1084 | } | ||
1085 | catch (LitJson.JsonException e) | ||
1086 | { | ||
1087 | jsonRpcResponse.Error.Code = ErrorCode.InternalError; | ||
1088 | jsonRpcResponse.Error.Message = e.Message; | ||
1089 | } | ||
1090 | |||
1091 | requestStream.Close(); | ||
1092 | |||
1093 | if (jsonRpcRequest != null) | ||
1094 | { | ||
1095 | if (jsonRpcRequest.ContainsKey("jsonrpc") || jsonRpcRequest["jsonrpc"].AsString() == "2.0") | ||
1096 | { | ||
1097 | jsonRpcResponse.JsonRpc = "2.0"; | ||
1098 | |||
1099 | // If we have no id, then it's a "notification" | ||
1100 | if (jsonRpcRequest.ContainsKey("id")) | ||
1101 | { | ||
1102 | jsonRpcResponse.Id = jsonRpcRequest["id"].AsString(); | ||
1103 | } | ||
1104 | |||
1105 | string methodname = jsonRpcRequest["method"]; | ||
1106 | JsonRPCMethod method; | ||
1107 | |||
1108 | if (jsonRpcHandlers.ContainsKey(methodname)) | ||
1109 | { | ||
1110 | lock(jsonRpcHandlers) | ||
1111 | { | ||
1112 | jsonRpcHandlers.TryGetValue(methodname, out method); | ||
1113 | } | ||
1114 | bool res = false; | ||
1115 | try | ||
1116 | { | ||
1117 | res = method(jsonRpcRequest, ref jsonRpcResponse); | ||
1118 | if(!res) | ||
1119 | { | ||
1120 | // The handler sent back an unspecified error | ||
1121 | if(jsonRpcResponse.Error.Code == 0) | ||
1122 | { | ||
1123 | jsonRpcResponse.Error.Code = ErrorCode.InternalError; | ||
1124 | } | ||
1125 | } | ||
1126 | } | ||
1127 | catch (Exception e) | ||
1128 | { | ||
1129 | string ErrorMessage = string.Format("[BASE HTTP SERVER]: Json-Rpc Handler Error method {0} - {1}", methodname, e.Message); | ||
1130 | m_log.Error(ErrorMessage); | ||
1131 | jsonRpcResponse.Error.Code = ErrorCode.InternalError; | ||
1132 | jsonRpcResponse.Error.Message = ErrorMessage; | ||
1133 | } | ||
1134 | } | ||
1135 | else // Error no hanlder defined for requested method | ||
1136 | { | ||
1137 | jsonRpcResponse.Error.Code = ErrorCode.InvalidRequest; | ||
1138 | jsonRpcResponse.Error.Message = string.Format ("No handler defined for {0}", methodname); | ||
1139 | } | ||
1140 | } | ||
1141 | else // not json-rpc 2.0 could be v1 | ||
1142 | { | ||
1143 | jsonRpcResponse.Error.Code = ErrorCode.InvalidRequest; | ||
1144 | jsonRpcResponse.Error.Message = "Must be valid json-rpc 2.0 see: http://www.jsonrpc.org/specification"; | ||
1145 | |||
1146 | if (jsonRpcRequest.ContainsKey("id")) | ||
1147 | jsonRpcResponse.Id = jsonRpcRequest["id"].AsString(); | ||
1148 | } | ||
1149 | } | ||
1150 | |||
1151 | response.KeepAlive = true; | ||
1152 | string responseData = string.Empty; | ||
1153 | |||
1154 | responseData = jsonRpcResponse.Serialize(); | ||
1155 | |||
1156 | byte[] buffer = Encoding.UTF8.GetBytes(responseData); | ||
1157 | return buffer; | ||
1158 | } | ||
1159 | |||
989 | private byte[] HandleLLSDRequests(OSHttpRequest request, OSHttpResponse response) | 1160 | private byte[] HandleLLSDRequests(OSHttpRequest request, OSHttpResponse response) |
990 | { | 1161 | { |
991 | //m_log.Warn("[BASE HTTP SERVER]: We've figured out it's a LLSD Request"); | 1162 | //m_log.Warn("[BASE HTTP SERVER]: We've figured out it's a LLSD Request"); |
@@ -1283,59 +1454,6 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
1283 | map["login"] = OSD.FromString("false"); | 1454 | map["login"] = OSD.FromString("false"); |
1284 | return map; | 1455 | return map; |
1285 | } | 1456 | } |
1286 | /// <summary> | ||
1287 | /// A specific agent handler was provided. Such a handler is expecetd to have an | ||
1288 | /// intimate, and highly specific relationship with the client. Consequently, | ||
1289 | /// nothing is done here. | ||
1290 | /// </summary> | ||
1291 | /// <param name="handler"></param> | ||
1292 | /// <param name="request"></param> | ||
1293 | /// <param name="response"></param> | ||
1294 | |||
1295 | private bool HandleAgentRequest(IHttpAgentHandler handler, OSHttpRequest request, OSHttpResponse response) | ||
1296 | { | ||
1297 | // In the case of REST, then handler is responsible for ALL aspects of | ||
1298 | // the request/response handling. Nothing is done here, not even encoding. | ||
1299 | |||
1300 | try | ||
1301 | { | ||
1302 | return handler.Handle(request, response); | ||
1303 | } | ||
1304 | catch (Exception e) | ||
1305 | { | ||
1306 | // If the handler did in fact close the stream, then this will blow | ||
1307 | // chunks. So that that doesn't disturb anybody we throw away any | ||
1308 | // and all exceptions raised. We've done our best to release the | ||
1309 | // client. | ||
1310 | try | ||
1311 | { | ||
1312 | m_log.Warn("[HTTP-AGENT]: Error - " + e.Message); | ||
1313 | response.SendChunked = false; | ||
1314 | response.KeepAlive = true; | ||
1315 | response.StatusCode = (int)OSHttpStatusCode.ServerErrorInternalError; | ||
1316 | //response.OutputStream.Close(); | ||
1317 | try | ||
1318 | { | ||
1319 | response.Send(); | ||
1320 | //response.FreeContext(); | ||
1321 | } | ||
1322 | catch (SocketException f) | ||
1323 | { | ||
1324 | // This has to be here to prevent a Linux/Mono crash | ||
1325 | m_log.Warn( | ||
1326 | String.Format("[BASE HTTP SERVER]: XmlRpcRequest issue {0}.\nNOTE: this may be spurious on Linux. ", f.Message), f); | ||
1327 | } | ||
1328 | } | ||
1329 | catch(Exception) | ||
1330 | { | ||
1331 | } | ||
1332 | } | ||
1333 | |||
1334 | // Indicate that the request has been "handled" | ||
1335 | |||
1336 | return true; | ||
1337 | |||
1338 | } | ||
1339 | 1457 | ||
1340 | public byte[] HandleHTTPRequest(OSHttpRequest request, OSHttpResponse response) | 1458 | public byte[] HandleHTTPRequest(OSHttpRequest request, OSHttpResponse response) |
1341 | { | 1459 | { |
@@ -1775,6 +1893,8 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
1775 | HTTPDRunning = false; | 1893 | HTTPDRunning = false; |
1776 | try | 1894 | try |
1777 | { | 1895 | { |
1896 | // m_PollServiceManager.Stop(); | ||
1897 | |||
1778 | m_httpListener2.ExceptionThrown -= httpServerException; | 1898 | m_httpListener2.ExceptionThrown -= httpServerException; |
1779 | //m_httpListener2.DisconnectHandler = null; | 1899 | //m_httpListener2.DisconnectHandler = null; |
1780 | 1900 | ||