29 using System.Collections;
30 using System.Collections.Generic;
31 using System.Collections.Specialized;
34 using System.Net.Sockets;
35 using System.Security.Cryptography.X509Certificates;
36 using System.Reflection;
37 using System.Globalization;
39 using System.Threading;
44 using OpenMetaverse.StructuredData;
48 using OpenSim.Framework.Monitoring;
49 using System.IO.Compression;
51 namespace OpenSim.Framework.Servers.HttpServer
55 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
57 private static Encoding UTF8NoBOM =
new System.Text.UTF8Encoding(
false);
74 public int DebugLevel {
get; set; }
83 public int RequestNumber {
get;
private set; }
88 private Stat m_requestsProcessedStat;
90 private volatile int NotSocketErrors = 0;
91 public volatile bool HTTPDRunning =
false;
95 protected Dictionary<string, XmlRpcMethod> m_rpcHandlers =
new Dictionary<string, XmlRpcMethod>();
96 protected Dictionary<string, JsonRPCMethod> jsonRpcHandlers =
new Dictionary<string, JsonRPCMethod>();
97 protected Dictionary<string, bool> m_rpcHandlersKeepAlive =
new Dictionary<string, bool>();
99 protected Dictionary<string, LLSDMethod> m_llsdHandlers =
new Dictionary<string, LLSDMethod>();
100 protected Dictionary<string, IRequestHandler> m_streamHandlers =
new Dictionary<string, IRequestHandler>();
101 protected Dictionary<string, GenericHTTPMethod> m_HTTPHandlers =
new Dictionary<string, GenericHTTPMethod>();
103 protected Dictionary<string, PollServiceEventArgs> m_pollHandlers =
104 new Dictionary<string, PollServiceEventArgs>();
106 protected Dictionary<string, WebSocketRequestDelegate> m_WebSocketHandlers =
107 new Dictionary<string, WebSocketRequestDelegate>();
112 private X509Certificate2 m_cert;
113 protected bool m_firstcaps =
true;
114 protected string m_SSLCommonName =
"";
116 protected IPAddress m_listenIPAddress = IPAddress.Any;
122 get {
return m_sslport; }
125 public string SSLCommonName
127 get {
return m_SSLCommonName; }
132 get {
return m_port; }
137 get {
return m_ssl; }
140 public IPAddress ListenIPAddress
142 get {
return m_listenIPAddress; }
143 set { m_listenIPAddress = value; }
156 public BaseHttpServer(uint port,
bool ssl, uint sslport,
string CN) : this (port, ssl)
164 public BaseHttpServer(uint port,
bool ssl,
string CPath,
string CPass) : this (port, ssl)
168 m_cert =
new X509Certificate2(CPath, CPass);
178 string httpMethod = handler.HttpMethod;
179 string path = handler.Path;
180 string handlerKey = GetHandlerKey(httpMethod, path);
182 lock (m_streamHandlers)
184 if (!m_streamHandlers.ContainsKey(handlerKey))
187 m_streamHandlers.Add(handlerKey, handler);
194 lock (m_WebSocketHandlers)
196 if (!m_WebSocketHandlers.ContainsKey(servicepath))
197 m_WebSocketHandlers.Add(servicepath, handler);
203 lock (m_WebSocketHandlers)
204 if (m_WebSocketHandlers.ContainsKey(servicepath))
205 m_WebSocketHandlers.Remove(servicepath);
210 lock (m_streamHandlers)
211 return new List<string>(m_streamHandlers.Keys);
214 private static string GetHandlerKey(
string httpMethod,
string path)
216 return httpMethod +
":" + path;
221 return AddXmlRPCHandler(method, handler,
true);
228 m_rpcHandlers[method] = handler;
229 m_rpcHandlersKeepAlive[method] = keepAlive;
239 if (m_rpcHandlers.ContainsKey(method))
241 return m_rpcHandlers[method];
253 return new List<string>(m_rpcHandlers.Keys);
259 lock(jsonRpcHandlers)
261 jsonRpcHandlers.Add(method, handler);
268 lock (jsonRpcHandlers)
270 if (jsonRpcHandlers.ContainsKey(method))
272 return jsonRpcHandlers[method];
283 lock (jsonRpcHandlers)
284 return new List<string>(jsonRpcHandlers.Keys);
291 lock (m_HTTPHandlers)
293 if (!m_HTTPHandlers.ContainsKey(methodName))
295 m_HTTPHandlers.Add(methodName, handler);
306 lock (m_HTTPHandlers)
307 return new List<string>(m_HTTPHandlers.Keys);
312 lock (m_pollHandlers)
314 if (!m_pollHandlers.ContainsKey(methodName))
316 m_pollHandlers.Add(methodName, args);
326 lock (m_pollHandlers)
327 return new List<string>(m_pollHandlers.Keys);
356 lock (m_llsdHandlers)
358 if (!m_llsdHandlers.ContainsKey(path))
360 m_llsdHandlers.Add(path, handler);
369 lock (m_llsdHandlers)
370 return new List<string>(m_llsdHandlers.Keys);
375 m_defaultLlsdHandler = handler;
379 public void OnRequest(
object source, RequestEventArgs args)
385 IHttpClientContext context = (IHttpClientContext)source;
386 IHttpRequest request = args.Request;
390 if (TryGetPollServiceHTTPHandler(request.UriPath.ToString(), out psEvArgs))
392 psEvArgs.RequestsReceived++;
400 Stream requestStream = req.InputStream;
402 Encoding encoding = Encoding.UTF8;
403 StreamReader reader =
new StreamReader(requestStream, encoding);
405 string requestBody = reader.ReadToEnd();
408 Hashtable keysvals =
new Hashtable();
409 Hashtable headervals =
new Hashtable();
411 string[] querystringkeys = req.QueryString.AllKeys;
412 string[] rHeaders = req.Headers.AllKeys;
414 keysvals.Add(
"body", requestBody);
415 keysvals.Add(
"uri", req.RawUrl);
416 keysvals.Add(
"content-type", req.ContentType);
417 keysvals.Add(
"http-method", req.HttpMethod);
419 foreach (
string queryname
in querystringkeys)
421 keysvals.Add(queryname, req.QueryString[queryname]);
424 foreach (
string headername
in rHeaders)
426 headervals[headername] = req.Headers[headername];
429 keysvals.Add(
"headers", headervals);
430 keysvals.Add(
"querystringkeys", querystringkeys);
432 psEvArgs.Request(psreq.RequestID, keysvals);
435 PollServiceRequestManager.Enqueue(psreq);
439 OnHandleRequestIOThread(context, request);
444 m_log.Error(String.Format(
"[BASE HTTP SERVER]: OnRequest() failed: {0} ", e.Message), e);
448 private void OnHandleRequestIOThread(IHttpClientContext context, IHttpRequest request)
451 WebSocketRequestDelegate dWebSocketRequestDelegate = null;
452 lock (m_WebSocketHandlers)
454 if (m_WebSocketHandlers.ContainsKey(req.
RawUrl))
455 dWebSocketRequestDelegate = m_WebSocketHandlers[req.
RawUrl];
457 if (dWebSocketRequestDelegate != null)
459 dWebSocketRequestDelegate(req.
Url.AbsolutePath,
new WebSocketHttpServerHandler(req, context, 8192));
463 OSHttpResponse resp =
new OSHttpResponse(
new HttpResponse(context, request),context);
464 resp.ReuseContext =
false;
465 HandleRequest(req, resp);
470 if (request.AcceptTypes != null)
471 for (
int i = 0; i < request.AcceptTypes.Length; i++)
472 request.AcceptTypes[i] =
string.Empty;
496 byte[] buffer500 = SendHTML500(response);
497 response.OutputStream.Write(buffer500, 0, buffer500.Length);
507 string requestMethod = request.HttpMethod;
508 string uriString = request.RawUrl;
510 int requestStartTick = Environment.TickCount;
513 int requestEndTick = requestStartTick;
524 Culture.SetCurrentCulture();
544 response.SendChunked =
false;
546 string path = request.RawUrl;
547 string handlerKey = GetHandlerKey(request.
HttpMethod, path);
548 byte[] buffer = null;
550 if (TryGetStreamHandler(handlerKey, out requestHandler))
553 LogIncomingToStreamHandler(request, requestHandler);
555 response.ContentType = requestHandler.ContentType;
559 IStreamedRequestHandler streamedRequestHandler = requestHandler as IStreamedRequestHandler;
561 buffer = streamedRequestHandler.Handle(path, request.InputStream, request, response);
566 IGenericHTTPHandler HTTPRequestHandler = requestHandler as IGenericHTTPHandler;
567 Stream requestStream = request.InputStream;
569 Encoding encoding = Encoding.UTF8;
570 StreamReader reader =
new StreamReader(requestStream, encoding);
572 string requestBody = reader.ReadToEnd();
577 Hashtable keysvals =
new Hashtable();
578 Hashtable headervals =
new Hashtable();
581 string[] querystringkeys = request.QueryString.AllKeys;
582 string[] rHeaders = request.Headers.AllKeys;
584 foreach (
string queryname
in querystringkeys)
586 keysvals.Add(queryname, request.QueryString[queryname]);
589 foreach (
string headername
in rHeaders)
592 headervals[headername] = request.Headers[headername];
600 keysvals.Add(
"requestbody", requestBody);
601 keysvals.Add(
"headers",headervals);
602 if (keysvals.Contains(
"method"))
610 buffer = DoHTTPGruntWork(HTTPRequestHandler.Handle(path, keysvals), response);
616 using (MemoryStream memoryStream =
new MemoryStream())
618 streamHandler.Handle(path, request.InputStream, memoryStream, request, response);
619 memoryStream.Flush();
620 buffer = memoryStream.ToArray();
631 LogIncomingToContentTypeHandler(request);
633 buffer = HandleHTTPRequest(request, response);
636 case "application/llsd+xml":
637 case "application/xml+llsd":
638 case "application/llsd+json":
640 LogIncomingToContentTypeHandler(request);
642 buffer = HandleLLSDRequests(request, response);
645 case "application/json-rpc":
647 LogIncomingToContentTypeHandler(request);
649 buffer = HandleJsonRpcRequests(request, response);
653 case "application/xml":
654 case "application/json":
664 if (DoWeHaveALLSDHandler(request.
RawUrl))
667 LogIncomingToContentTypeHandler(request);
669 buffer = HandleLLSDRequests(request, response);
672 else if (DoWeHaveAHTTPHandler(request.
RawUrl))
675 LogIncomingToContentTypeHandler(request);
677 buffer = HandleHTTPRequest(request, response);
682 LogIncomingToXmlRpcHandler(request);
685 buffer = HandleXmlRpcRequests(request, response);
692 request.InputStream.Close();
696 if (WebUtil.DebugLevel >= 5)
698 string output = System.Text.Encoding.UTF8.GetString(buffer);
700 if (WebUtil.DebugLevel >= 6)
703 if ((requestHandler != null && requestHandler.Name ==
"GetMesh"))
705 if (output.Length > WebUtil.MaxRequestDiagLength)
706 output = output.Substring(0, WebUtil.MaxRequestDiagLength) +
"...";
710 WebUtil.LogResponseDetail(RequestNumber, output);
714 response.ContentLength64 = buffer.LongLength;
716 response.OutputStream.Write(buffer, 0, buffer.Length);
722 requestEndTick = Environment.TickCount;
730 catch (SocketException e)
739 m_log.Warn(String.Format(
"[BASE HTTP SERVER]: HandleRequest threw {0}.\nNOTE: this may be spurious on Linux ", e.Message), e);
741 catch (IOException e)
743 m_log.Error(
"[BASE HTTP SERVER]: HandleRequest() threw exception ", e);
747 m_log.Error(
"[BASE HTTP SERVER]: HandleRequest() threw exception ", e);
750 byte[] buffer500 = SendHTML500(response);
751 response.OutputStream.Write(buffer500, 0, buffer500.Length);
762 int tickdiff = requestEndTick - requestStartTick;
763 if (tickdiff > 3000 && (requestHandler == null || requestHandler.
Name == null || requestHandler.
Name !=
"GetTexture"))
766 "[LOGHTTP] Slow handling of {0} {1} {2} {3} {4} from {5} took {6}ms",
770 requestHandler != null ? requestHandler.Name :
"",
771 requestHandler != null ? requestHandler.Description :
"",
772 request.RemoteIPEndPoint,
775 else if (DebugLevel >= 4)
778 "[LOGHTTP] HTTP IN {0} :{1} took {2}ms",
789 "[LOGHTTP] HTTP IN {0} :{1} stream handler {2} {3} {4} {5} from {6}",
793 request.Url.PathAndQuery,
795 requestHandler.Description,
796 request.RemoteIPEndPoint);
799 LogIncomingInDetail(request);
802 private void LogIncomingToContentTypeHandler(OSHttpRequest request)
805 "[LOGHTTP] HTTP IN {0} :{1} {2} content type handler {3} {4} from {5}",
808 string.IsNullOrEmpty(request.ContentType) ?
"not set" : request.ContentType,
810 request.Url.PathAndQuery,
811 request.RemoteIPEndPoint);
814 LogIncomingInDetail(request);
817 private void LogIncomingToXmlRpcHandler(OSHttpRequest request)
820 "[LOGHTTP] HTTP IN {0} :{1} assumed generic XMLRPC request {2} {3} from {4}",
824 request.Url.PathAndQuery,
825 request.RemoteIPEndPoint);
828 LogIncomingInDetail(request);
831 private void LogIncomingInDetail(OSHttpRequest request)
833 if (request.ContentType ==
"application/octet-stream")
836 Stream inputStream = Util.Copy(request.InputStream);
837 Stream innerStream = null;
840 if ((request.Headers[
"Content-Encoding"] ==
"gzip") || (request.Headers[
"X-Content-Encoding"] ==
"gzip"))
842 innerStream = inputStream;
843 inputStream =
new GZipStream(innerStream, System.IO.Compression.CompressionMode.Decompress);
846 using (StreamReader reader =
new StreamReader(inputStream, Encoding.UTF8))
852 char[] chars =
new char[WebUtil.MaxRequestDiagLength + 1];
853 int len = reader.Read(chars, 0, WebUtil.MaxRequestDiagLength + 1);
854 output =
new string(chars, 0, Math.Min(len, WebUtil.MaxRequestDiagLength));
855 if (len > WebUtil.MaxRequestDiagLength)
860 output = reader.ReadToEnd();
863 m_log.DebugFormat(
"[LOGHTTP] {0}", Util.BinaryToASCII(output));
868 if (innerStream != null)
869 innerStream.Dispose();
870 inputStream.Dispose();
874 private readonly
string HANDLER_SEPARATORS =
"/?&#-";
876 private bool TryGetStreamHandler(
string handlerKey, out IRequestHandler streamHandler)
878 string bestMatch = null;
880 lock (m_streamHandlers)
882 foreach (
string pattern
in m_streamHandlers.Keys)
884 if ((handlerKey == pattern)
885 || (handlerKey.StartsWith(pattern) && (HANDLER_SEPARATORS.IndexOf(handlerKey[pattern.Length]) >= 0)))
887 if (
String.IsNullOrEmpty(bestMatch) || pattern.Length > bestMatch.Length)
894 if (
String.IsNullOrEmpty(bestMatch))
896 streamHandler = null;
901 streamHandler = m_streamHandlers[bestMatch];
907 private bool TryGetPollServiceHTTPHandler(
string handlerKey, out PollServiceEventArgs oServiceEventArgs)
909 string bestMatch = null;
911 lock (m_pollHandlers)
913 foreach (
string pattern
in m_pollHandlers.Keys)
915 if ((handlerKey == pattern)
916 || (handlerKey.StartsWith(pattern) && (HANDLER_SEPARATORS.IndexOf(handlerKey[pattern.Length]) >= 0)))
918 if (
String.IsNullOrEmpty(bestMatch) || pattern.Length > bestMatch.Length)
925 if (
String.IsNullOrEmpty(bestMatch))
927 oServiceEventArgs = null;
932 oServiceEventArgs = m_pollHandlers[bestMatch];
938 private bool TryGetHTTPHandler(
string handlerKey, out
GenericHTTPMethod HTTPHandler)
942 string bestMatch = null;
944 lock (m_HTTPHandlers)
946 foreach (
string pattern
in m_HTTPHandlers.Keys)
948 if ((handlerKey == pattern)
949 || (handlerKey.StartsWith(pattern) && (HANDLER_SEPARATORS.IndexOf(handlerKey[pattern.Length]) >= 0)))
951 if (
String.IsNullOrEmpty(bestMatch) || pattern.Length > bestMatch.Length)
958 if (
String.IsNullOrEmpty(bestMatch))
965 HTTPHandler = m_HTTPHandlers[bestMatch];
996 private byte[] HandleXmlRpcRequests(OSHttpRequest request, OSHttpResponse response)
1000 Stream requestStream = request.InputStream;
1001 Stream innerStream = null;
1004 if ((request.Headers[
"Content-Encoding"] ==
"gzip") || (request.Headers[
"X-Content-Encoding"] ==
"gzip"))
1006 innerStream = requestStream;
1007 requestStream =
new GZipStream(innerStream, System.IO.Compression.CompressionMode.Decompress);
1010 using (StreamReader reader =
new StreamReader(requestStream, Encoding.UTF8))
1012 requestBody = reader.ReadToEnd();
1017 if (innerStream != null)
1018 innerStream.Dispose();
1019 requestStream.Dispose();
1023 requestBody = requestBody.Replace(
"<base64></base64>",
"");
1025 string responseString = String.Empty;
1026 XmlRpcRequest xmlRprcRequest = null;
1028 bool gridproxy =
false;
1029 if (requestBody.Contains(
"encoding=\"utf-8"))
1031 int channelindx = -1;
1032 int optionsindx = requestBody.IndexOf(
">options<");
1035 channelindx = requestBody.IndexOf(
">channel<");
1036 if (optionsindx < channelindx)
1043 xmlRprcRequest = (XmlRpcRequest) (
new XmlRpcRequestDeserializer()).Deserialize(requestBody);
1045 catch (XmlException e)
1047 if (DebugLevel >= 1)
1049 if (DebugLevel >= 2)
1052 "[BASE HTTP SERVER]: Got XMLRPC request with invalid XML from {0}. XML was '{1}'. Sending blank response. Exception ",
1053 request.RemoteIPEndPoint, requestBody),
1058 "[BASE HTTP SERVER]: Got XMLRPC request with invalid XML from {0}, length {1}. Sending blank response.",
1059 request.RemoteIPEndPoint, requestBody.Length);
1064 if (xmlRprcRequest != null)
1066 string methodName = xmlRprcRequest.MethodName;
1067 if (methodName != null)
1069 xmlRprcRequest.Params.Add(request.RemoteIPEndPoint);
1070 XmlRpcResponse xmlRpcResponse;
1073 bool methodWasFound;
1074 bool keepAlive =
false;
1075 lock (m_rpcHandlers)
1077 methodWasFound = m_rpcHandlers.TryGetValue(methodName, out method);
1079 keepAlive = m_rpcHandlersKeepAlive[methodName];
1084 xmlRprcRequest.Params.Add(request.Url);
1086 string xff =
"X-Forwarded-For";
1087 string xfflower = xff.ToLower();
1088 foreach (
string s
in request.Headers.AllKeys)
1090 if (s != null && s.Equals(xfflower))
1096 xmlRprcRequest.Params.Add(request.Headers.Get(xff));
1099 xmlRprcRequest.Params.Add(
"gridproxy");
1102 xmlRpcResponse = method(xmlRprcRequest, request.RemoteIPEndPoint);
1108 "Requested method [{0}] from {1} threw exception: {2} {3}",
1109 methodName, request.RemoteIPEndPoint.Address, e.Message, e.StackTrace);
1111 m_log.ErrorFormat(
"[BASE HTTP SERVER]: {0}", errorMessage);
1114 xmlRpcResponse =
new XmlRpcResponse();
1117 xmlRpcResponse.SetFault(-32603, errorMessage);
1121 response.KeepAlive = keepAlive;
1125 xmlRpcResponse =
new XmlRpcResponse();
1128 xmlRpcResponse.SetFault(
1129 XmlRpcErrorCodes.SERVER_ERROR_METHOD,
1130 String.Format(
"Requested method [{0}] not found", methodName));
1133 response.ContentType =
"text/xml";
1134 using (MemoryStream outs =
new MemoryStream())
1135 using (XmlTextWriter writer =
new XmlTextWriter(outs, UTF8NoBOM))
1137 writer.Formatting = Formatting.None;
1138 XmlRpcResponseSerializer.Singleton.Serialize(writer, xmlRpcResponse);
1142 using (StreamReader sr =
new StreamReader(outs))
1144 responseString = sr.ReadToEnd();
1151 response.ContentType =
"text/plain";
1152 response.StatusCode = 404;
1153 response.StatusDescription =
"Not Found";
1154 response.ProtocolVersion =
"HTTP/1.0";
1155 responseString =
"Not found";
1156 response.KeepAlive =
false;
1159 "[BASE HTTP SERVER]: Handler not found for http request {0} {1}",
1160 request.HttpMethod, request.Url.PathAndQuery);
1164 byte[] buffer = Encoding.UTF8.GetBytes(responseString);
1166 response.SendChunked =
false;
1167 response.ContentLength64 = buffer.Length;
1168 response.ContentEncoding = Encoding.UTF8;
1175 private byte[] HandleJsonRpcRequests(OSHttpRequest request, OSHttpResponse response)
1177 Stream requestStream = request.InputStream;
1178 JsonRpcResponse jsonRpcResponse =
new JsonRpcResponse();
1179 OSDMap jsonRpcRequest = null;
1183 jsonRpcRequest = (
OSDMap)OSDParser.DeserializeJson(requestStream);
1185 catch (LitJson.JsonException e)
1187 jsonRpcResponse.Error.Code = ErrorCode.InternalError;
1188 jsonRpcResponse.Error.Message = e.Message;
1191 requestStream.Close();
1193 if (jsonRpcRequest != null)
1195 if (jsonRpcRequest.ContainsKey(
"jsonrpc") || jsonRpcRequest[
"jsonrpc"].AsString() ==
"2.0")
1197 jsonRpcResponse.JsonRpc =
"2.0";
1200 if (jsonRpcRequest.ContainsKey(
"id"))
1202 jsonRpcResponse.Id = jsonRpcRequest[
"id"].AsString();
1205 string methodname = jsonRpcRequest[
"method"];
1208 if (jsonRpcHandlers.ContainsKey(methodname))
1210 lock(jsonRpcHandlers)
1212 jsonRpcHandlers.TryGetValue(methodname, out method);
1217 res = method(jsonRpcRequest, ref jsonRpcResponse);
1221 if(jsonRpcResponse.Error.Code == 0)
1223 jsonRpcResponse.Error.Code = ErrorCode.InternalError;
1229 string ErrorMessage = string.Format(
"[BASE HTTP SERVER]: Json-Rpc Handler Error method {0} - {1}", methodname, e.Message);
1230 m_log.Error(ErrorMessage);
1231 jsonRpcResponse.Error.Code = ErrorCode.InternalError;
1232 jsonRpcResponse.Error.Message = ErrorMessage;
1237 jsonRpcResponse.Error.Code = ErrorCode.InvalidRequest;
1238 jsonRpcResponse.Error.Message = string.Format (
"No handler defined for {0}", methodname);
1243 jsonRpcResponse.Error.Code = ErrorCode.InvalidRequest;
1244 jsonRpcResponse.Error.Message =
"Must be valid json-rpc 2.0 see: http://www.jsonrpc.org/specification";
1246 if (jsonRpcRequest.ContainsKey(
"id"))
1247 jsonRpcResponse.Id = jsonRpcRequest[
"id"].AsString();
1251 response.KeepAlive =
true;
1252 string responseData = string.Empty;
1254 responseData = jsonRpcResponse.Serialize();
1256 byte[] buffer = Encoding.UTF8.GetBytes(responseData);
1260 private byte[] HandleLLSDRequests(OSHttpRequest request, OSHttpResponse response)
1263 Stream requestStream = request.InputStream;
1265 Encoding encoding = Encoding.UTF8;
1266 StreamReader reader =
new StreamReader(requestStream, encoding);
1268 string requestBody = reader.ReadToEnd();
1270 requestStream.Close();
1274 response.KeepAlive =
false;
1276 OSD llsdRequest = null;
1277 OSD llsdResponse = null;
1279 bool LegacyLLSDLoginLibOMV = (requestBody.Contains(
"passwd") && requestBody.Contains(
"mac") && requestBody.Contains(
"viewer_digest"));
1281 if (requestBody.Length == 0)
1284 requestBody =
"<?xml version=\"1.0\" encoding=\"UTF-8\"?><llsd><map><key>request</key><string>get</string></map></llsd>";
1288 llsdRequest = OSDParser.Deserialize(requestBody);
1290 catch (Exception ex)
1292 m_log.Warn(
"[BASE HTTP SERVER]: Error - " + ex.Message);
1295 if (llsdRequest != null)
1299 if (TryGetLLSDHandler(request.RawUrl, out llsdhandler) && !LegacyLLSDLoginLibOMV)
1302 llsdResponse = llsdhandler(request.RawUrl, llsdRequest, request.RemoteIPEndPoint.ToString());
1309 if (m_defaultLlsdHandler != null)
1312 llsdResponse = m_defaultLlsdHandler(llsdRequest, request.RemoteIPEndPoint);
1317 llsdResponse = GenerateNoLLSDHandlerResponse();
1323 llsdResponse = GenerateNoLLSDHandlerResponse();
1326 byte[] buffer =
new byte[0];
1328 if (llsdResponse.ToString() ==
"shutdown404!")
1330 response.ContentType =
"text/plain";
1331 response.StatusCode = 404;
1332 response.StatusDescription =
"Not Found";
1333 response.ProtocolVersion =
"HTTP/1.0";
1334 buffer = Encoding.UTF8.GetBytes(
"Not found");
1339 buffer = BuildLLSDResponse(request, response, llsdResponse);
1342 response.SendChunked =
false;
1343 response.ContentLength64 = buffer.Length;
1344 response.ContentEncoding = Encoding.UTF8;
1345 response.KeepAlive =
true;
1350 private byte[] BuildLLSDResponse(OSHttpRequest request, OSHttpResponse response,
OSD llsdResponse)
1352 if (request.AcceptTypes != null && request.AcceptTypes.Length > 0)
1354 foreach (
string strAccept
in request.AcceptTypes)
1358 case "application/llsd+xml":
1359 case "application/xml":
1361 response.ContentType = strAccept;
1362 return OSDParser.SerializeLLSDXmlBytes(llsdResponse);
1363 case "application/llsd+json":
1364 case "application/json":
1365 response.ContentType = strAccept;
1366 return Encoding.UTF8.GetBytes(OSDParser.SerializeJsonString(llsdResponse));
1371 if (!
String.IsNullOrEmpty(request.ContentType))
1373 switch (request.ContentType)
1375 case "application/llsd+xml":
1376 case "application/xml":
1378 response.ContentType = request.ContentType;
1379 return OSDParser.SerializeLLSDXmlBytes(llsdResponse);
1380 case "application/llsd+json":
1381 case "application/json":
1382 response.ContentType = request.ContentType;
1383 return Encoding.UTF8.GetBytes(OSDParser.SerializeJsonString(llsdResponse));
1389 response.ContentType =
"application/llsd+xml";
1390 return OSDParser.SerializeLLSDXmlBytes(llsdResponse);
1398 private bool DoWeHaveALLSDHandler(
string path)
1400 string[] pathbase = path.Split(
'/');
1401 string searchquery =
"/";
1403 if (pathbase.Length < 1)
1406 for (
int i = 1; i < pathbase.Length; i++)
1408 searchquery += pathbase[i];
1409 if (pathbase.Length - 1 != i)
1413 string bestMatch = null;
1415 lock (m_llsdHandlers)
1417 foreach (
string pattern
in m_llsdHandlers.Keys)
1419 if (searchquery.StartsWith(pattern) && searchquery.Length >= pattern.Length)
1420 bestMatch = pattern;
1425 if (path !=
"/" && bestMatch ==
"/" && searchquery !=
"/")
1431 if (
String.IsNullOrEmpty(bestMatch))
1446 private bool DoWeHaveAHTTPHandler(
string path)
1448 string[] pathbase = path.Split(
'/');
1449 string searchquery =
"/";
1451 if (pathbase.Length < 1)
1454 for (
int i = 1; i < pathbase.Length; i++)
1456 searchquery += pathbase[i];
1457 if (pathbase.Length - 1 != i)
1461 string bestMatch = null;
1465 lock (m_HTTPHandlers)
1467 foreach (
string pattern
in m_HTTPHandlers.Keys)
1469 if (searchquery.StartsWith(pattern) && searchquery.Length >= pattern.Length)
1471 bestMatch = pattern;
1479 if (
String.IsNullOrEmpty(bestMatch))
1490 private bool TryGetLLSDHandler(
string path, out
LLSDMethod llsdHandler)
1498 string[] pathbase = path.Split(
'/');
1499 string searchquery =
"/";
1501 if (pathbase.Length < 1)
1504 for (
int i=1; i<pathbase.Length; i++)
1506 searchquery += pathbase[i];
1507 if (pathbase.Length-1 != i)
1519 string bestMatch = null;
1521 lock (m_llsdHandlers)
1523 foreach (
string pattern
in m_llsdHandlers.Keys)
1525 if (searchquery.ToLower().StartsWith(pattern.ToLower()))
1527 if (
String.IsNullOrEmpty(bestMatch) || searchquery.Length > bestMatch.Length)
1531 if (pattern ==
"/" && searchquery ==
"/" || pattern !=
"/")
1532 bestMatch = pattern;
1537 if (
String.IsNullOrEmpty(bestMatch))
1544 llsdHandler = m_llsdHandlers[bestMatch];
1550 private OSDMap GenerateNoLLSDHandlerResponse()
1553 map[
"reason"] = OSD.FromString(
"LLSDRequest");
1554 map[
"message"] = OSD.FromString(
"No handler registered for LLSD Requests");
1555 map[
"login"] = OSD.FromString(
"false");
1572 return HandleContentVerbs(request, response);
1594 Stream requestStream = request.InputStream;
1596 Encoding encoding = Encoding.UTF8;
1597 StreamReader reader =
new StreamReader(requestStream, encoding);
1599 string requestBody = reader.ReadToEnd();
1603 requestStream.Close();
1605 Hashtable keysvals =
new Hashtable();
1606 Hashtable headervals =
new Hashtable();
1608 Hashtable requestVars =
new Hashtable();
1610 string host = String.Empty;
1612 string[] querystringkeys = request.QueryString.AllKeys;
1613 string[] rHeaders = request.Headers.AllKeys;
1615 keysvals.Add(
"body", requestBody);
1616 keysvals.Add(
"uri", request.RawUrl);
1617 keysvals.Add(
"content-type", request.ContentType);
1618 keysvals.Add(
"http-method", request.HttpMethod);
1620 foreach (
string queryname
in querystringkeys)
1624 keysvals.Add(queryname, request.QueryString[queryname]);
1625 requestVars.Add(queryname, keysvals[queryname]);
1628 foreach (
string headername
in rHeaders)
1631 headervals[headername] = request.Headers[headername];
1634 if (headervals.Contains(
"Host"))
1636 host = (string)headervals[
"Host"];
1639 keysvals.Add(
"headers", headervals);
1640 keysvals.Add(
"querystringkeys", querystringkeys);
1641 keysvals.Add(
"requestvars", requestVars);
1644 if (keysvals.Contains(
"method"))
1647 string method = (string) keysvals[
"method"];
1650 bool foundHandler = TryGetHTTPHandler(method, out requestprocessor);
1653 Hashtable responsedata1 = requestprocessor(keysvals);
1654 buffer = DoHTTPGruntWork(responsedata1,response);
1661 buffer = SendHTML404(response, host);
1667 bool foundHandler = TryGetHTTPHandlerPathBased(request.
RawUrl, out requestprocessor);
1670 Hashtable responsedata2 = requestprocessor(keysvals);
1671 buffer = DoHTTPGruntWork(responsedata2, response);
1678 buffer = SendHTML404(response, host);
1685 private bool TryGetHTTPHandlerPathBased(
string path, out
GenericHTTPMethod httpHandler)
1693 string[] pathbase = path.Split(
'/');
1694 string searchquery =
"/";
1696 if (pathbase.Length < 1)
1699 for (
int i = 1; i < pathbase.Length; i++)
1701 searchquery += pathbase[i];
1702 if (pathbase.Length - 1 != i)
1714 string bestMatch = null;
1719 lock (m_HTTPHandlers)
1721 foreach (
string pattern
in m_HTTPHandlers.Keys)
1723 if (searchquery.ToLower().StartsWith(pattern.ToLower()))
1725 if (
String.IsNullOrEmpty(bestMatch) || searchquery.Length > bestMatch.Length)
1728 if (pattern ==
"/" && searchquery ==
"/" || pattern !=
"/")
1729 bestMatch = pattern;
1734 if (
String.IsNullOrEmpty(bestMatch))
1741 if (bestMatch ==
"/" && searchquery !=
"/")
1744 httpHandler = m_HTTPHandlers[bestMatch];
1750 internal byte[] DoHTTPGruntWork(Hashtable responsedata, OSHttpResponse response)
1753 string responseString = String.Empty;
1754 byte[] responseData = null;
1757 if (responsedata == null)
1760 responseString =
"No response could be obtained";
1761 contentType =
"text/plain";
1762 responsedata =
new Hashtable();
1769 responsecode = (int)responsedata[
"int_response_code"];
1770 if (responsedata[
"bin_response_data"] != null)
1771 responseData = (byte[])responsedata[
"bin_response_data"];
1773 responseString = (string)responsedata[
"str_response_string"];
1774 contentType = (string)responsedata[
"content_type"];
1775 if (responseString == null)
1776 responseString = String.Empty;
1781 responseString =
"No response could be obtained";
1782 contentType =
"text/plain";
1783 responsedata =
new Hashtable();
1787 if (responsedata.ContainsKey(
"error_status_text"))
1789 response.StatusDescription = (string)responsedata[
"error_status_text"];
1791 if (responsedata.ContainsKey(
"http_protocol_version"))
1793 response.ProtocolVersion = (string)responsedata[
"http_protocol_version"];
1806 response.KeepAlive =
false;
1807 response.ReuseContext =
false;
1810 if (responsedata.ContainsKey(
"access_control_allow_origin"))
1811 response.AddHeader(
"Access-Control-Allow-Origin", (
string)responsedata[
"access_control_allow_origin"]);
1816 if (
string.IsNullOrEmpty(contentType))
1818 contentType =
"text/html";
1826 response.StatusCode = responsecode;
1830 response.RedirectLocation = (string)responsedata[
"str_redirect_location"];
1831 response.StatusCode = responsecode;
1834 response.AddHeader(
"Content-Type", contentType);
1836 if (responsedata.ContainsKey(
"headers"))
1838 Hashtable headerdata = (Hashtable)responsedata[
"headers"];
1840 foreach (
string header
in headerdata.Keys)
1841 response.AddHeader(header, (string)headerdata[header]);
1846 if (responseData != null)
1848 buffer = responseData;
1852 if (!(contentType.Contains(
"image")
1853 || contentType.Contains(
"x-shockwave-flash")
1854 || contentType.Contains(
"application/x-oar")
1855 || contentType.Contains(
"application/vnd.ll.mesh")))
1858 buffer = Encoding.UTF8.GetBytes(responseString);
1863 buffer = Convert.FromBase64String(responseString);
1866 response.SendChunked =
false;
1867 response.ContentLength64 = buffer.Length;
1868 response.ContentEncoding = Encoding.UTF8;
1877 response.StatusCode = 404;
1878 response.AddHeader(
"Content-type",
"text/html");
1880 string responseString = GetHTTP404(host);
1881 byte[] buffer = Encoding.UTF8.GetBytes(responseString);
1883 response.SendChunked =
false;
1884 response.ContentLength64 = buffer.Length;
1885 response.ContentEncoding = Encoding.UTF8;
1894 response.
AddHeader(
"Content-type",
"text/html");
1896 string responseString = GetHTTP500();
1897 byte[] buffer = Encoding.UTF8.GetBytes(responseString);
1899 response.SendChunked =
false;
1900 response.ContentLength64 = buffer.Length;
1901 response.ContentEncoding = Encoding.UTF8;
1919 public void Start(
bool performPollResponsesAsync)
1922 "[BASE HTTP SERVER]: Starting {0} server on port {1}", UseSSL ?
"HTTPS" :
"HTTP", Port);
1928 NotSocketErrors = 0;
1933 m_httpListener2 = CoolHTTPListener.Create(m_listenIPAddress, (int)m_port);
1934 m_httpListener2.ExceptionThrown += httpServerException;
1935 m_httpListener2.LogWriter = httpserverlog;
1947 m_httpListener2 = CoolHTTPListener.Create(IPAddress.Any, (int)m_port, m_cert);
1948 m_httpListener2.ExceptionThrown += httpServerException;
1949 m_httpListener2.LogWriter = httpserverlog;
1952 m_httpListener2.RequestReceived += OnRequest;
1954 m_httpListener2.Start(64);
1959 PollServiceRequestManager.Start();
1961 HTTPDRunning =
true;
1972 m_log.Error(
"[BASE HTTP SERVER]: Error - " + e.Message);
1973 m_log.Error(
"[BASE HTTP SERVER]: Tip: Do you have permission to listen on port " + m_port +
", " + m_sslport +
"?");
1980 m_requestsProcessedStat
1982 "HTTPRequestsServed",
1983 "Number of inbound HTTP requests processed",
1989 MeasuresOfInterest.AverageChangeOverTime,
1990 stat => stat.Value = RequestNumber,
1991 StatVerbosity.Debug);
1993 StatsManager.RegisterStat(m_requestsProcessedStat);
2000 case SocketError.NotSocket:
2009 if (source.ToString() ==
"HttpServer.HttpListener" && exception.ToString().StartsWith(
"Mono.Security.Protocol.Tls.TlsException"))
2011 m_log.ErrorFormat(
"[BASE HTTP SERVER]: {0} had an exception {1}", source.ToString(), exception.ToString());
2025 HTTPDRunning =
false;
2027 StatsManager.DeregisterStat(m_requestsProcessedStat);
2031 PollServiceRequestManager.Stop();
2033 m_httpListener2.ExceptionThrown -= httpServerException;
2036 m_httpListener2.LogWriter = null;
2037 m_httpListener2.RequestReceived -= OnRequest;
2038 m_httpListener2.Stop();
2040 catch (NullReferenceException)
2042 m_log.Warn(
"[BASE HTTP SERVER]: Null Reference when stopping HttpServer.");
2048 string handlerKey = GetHandlerKey(httpMethod, path);
2052 lock (m_streamHandlers)
2053 m_streamHandlers.Remove(handlerKey);
2058 if (path == null)
return;
2059 lock (m_HTTPHandlers)
2061 if (httpMethod != null && httpMethod.Length == 0)
2063 m_HTTPHandlers.Remove(path);
2067 m_HTTPHandlers.Remove(GetHandlerKey(httpMethod, path));
2073 lock (m_pollHandlers)
2074 m_pollHandlers.Remove(path);
2095 lock (m_rpcHandlers)
2096 m_rpcHandlers.Remove(method);
2101 lock(jsonRpcHandlers)
2102 jsonRpcHandlers.Remove(method);
2107 lock (m_llsdHandlers)
2111 if (m_llsdHandlers.TryGetValue(path, out foundHandler) && foundHandler == handler)
2113 m_llsdHandlers.Remove(path);
2123 string file = Path.Combine(
".",
"http_404.html");
2124 if (!
File.Exists(file))
2125 return getDefaultHTTP404(host);
2127 StreamReader sr = File.OpenText(file);
2128 string result = sr.ReadToEnd();
2135 string file = Path.Combine(
".",
"http_500.html");
2136 if (!
File.Exists(file))
2137 return getDefaultHTTP500();
2139 StreamReader sr = File.OpenText(file);
2140 string result = sr.ReadToEnd();
2146 private static string getDefaultHTTP404(
string host)
2148 return "<HTML><HEAD><TITLE>404 Page not found</TITLE><BODY><BR /><H1>Ooops!</H1><P>The page you requested has been obsconded with by knomes. Find hippos quick!</P><P>If you are trying to log-in, your link parameters should have: "-loginpage http://" + host +
"/?method=login -loginuri http://" + host +
"/" in your link </P></BODY></HTML>";
2151 private static string getDefaultHTTP500()
2153 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>";
2159 public IHttpClientContext context = null;
2160 public IHttpRequest req = null;
bool RemoveLLSDHandler(string path, LLSDMethod handler)
bool AddHTTPHandler(string methodName, GenericHTTPMethod handler)
Add a handler for an HTTP request.
long ContentLength64
Alias for ContentLength.
bool AddLLSDHandler(string path, LLSDMethod handler)
Adds a LLSD handler, yay.
string Name
Name for this handler.
HttpServer.LogPrio LogPrio
string GetHTTP404(string host)
void RemovePollServiceHTTPHandler(string httpMethod, string path)
List< string > GetXmlRpcHandlerKeys()
void Write(object source, LogPrio priority, string message)
byte[] SendHTML404(OSHttpResponse response, string host)
delegate OSD DefaultLLSDMethod(OSD request, IPEndPoint client)
List< string > GetJsonRpcHandlerKeys()
List< string > GetHTTPHandlerKeys()
delegate bool JsonRPCMethod(OSDMap jsonRpcRequest, ref JsonRpcResponse response)
HttpServer.HttpListener CoolHTTPListener
XmlRpcMethod GetXmlRPCHandler(string method)
Gets the XML RPC handler for given method name
void RemoveXmlRPCHandler(string method)
This class implements websockets. It grabs the network context from C::Webserver and utilizes it dire...
OSHttpResponse is the OpenSim representation of an HTTP response.
byte[] HandleHTTPRequest(OSHttpRequest request, OSHttpResponse response)
void httpServerException(object source, Exception exception)
OpenMetaverse.StructuredData.OSDMap OSDMap
byte[] SendHTML500(OSHttpResponse response)
void Start(bool performPollResponsesAsync)
Start the http server
List< string > GetLLSDHandlerKeys()
List< string > GetStreamHandlerKeys()
Holds individual statistic details
HttpServerContextObj(OSHttpRequest osreq, OSHttpResponse osresp)
bool AddXmlRPCHandler(string method, XmlRpcMethod handler, bool keepAlive)
Ionic.Zlib.GZipStream GZipStream
void RemoveHTTPHandler(string httpMethod, string path)
Remove an HTTP handler
bool AddJsonRPCHandler(string method, JsonRPCMethod handler)
Interface to OpenSimulator's built in HTTP server. Use this to register handlers (http, llsd, xmlrpc, etc.) for given URLs.
Relays HttpServer log messages to our own logging mechanism.
bool AddXmlRPCHandler(string method, XmlRpcMethod handler)
List< string > GetPollServiceHandlerKeys()
BaseHttpServer(uint port)
bool SetDefaultLLSDHandler(DefaultLLSDMethod handler)
BaseHttpServer(uint port, bool ssl, uint sslport, string CN)
CoolHTTPListener m_httpListener2
void AddStreamHandler(IRequestHandler handler)
Add a stream handler to the http server. If the handler already exists, then nothing happens...
bool AddPollServiceHTTPHandler(string methodName, PollServiceEventArgs args)
delegate XmlRpcResponse XmlRpcMethod(XmlRpcRequest request, IPEndPoint client)
OpenMetaverse.StructuredData.OSD OSD
BaseHttpServer(uint port, bool ssl, string CPath, string CPass)
void OnRequest(object source, RequestEventArgs args)
BaseHttpServer(uint port, bool ssl)
void RemoveStreamHandler(string httpMethod, string path)
delegate Hashtable GenericHTTPMethod(Hashtable request)
bool SendChunked
Chunk transfers.
HttpServerContextObj(IHttpClientContext contxt, IHttpRequest reqs)
void AddWebSocketHandler(string servicepath, WebSocketRequestDelegate handler)
JsonRPCMethod GetJsonRPCHandler(string method)
virtual void HandleRequest(OSHttpRequest request, OSHttpResponse response)
This methods is the start of incoming HTTP request handling.
void AddHeader(string key, string value)
Add a header field and content to the response.
System.Net.HttpListener HttpListener
delegate OSD LLSDMethod(string path, OSD request, string endpoint)
void RemoveWebSocketHandler(string servicepath)
void httpServerDisconnectMonitor(IHttpClientContext source, SocketError err)
OSHttpStatusCode
HTTP status codes (almost) as defined by W3C in http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html and IETF in http://tools.ietf.org/html/rfc6585
void RemoveJsonRPCHandler(string method)