diff --git a/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs b/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs index aeb67412d8..40f99ef89c 100644 --- a/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs +++ b/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs @@ -46,17 +46,17 @@ using log4net; using Nwc.XmlRpc; using OpenSim.Framework.Monitoring; using OpenMetaverse.StructuredData; - +using OpenMetaverse; namespace OpenSim.Framework.Servers.HttpServer { public class BaseHttpServer : IHttpServer { private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - private HttpServerLogWriter httpserverlog = new HttpServerLogWriter(); - private static Encoding UTF8NoBOM = new System.Text.UTF8Encoding(false); + private readonly HttpServerLogWriter httpserverlog = new HttpServerLogWriter(); + private static readonly Encoding UTF8NoBOM = new System.Text.UTF8Encoding(false); public static PollServiceRequestManager m_pollServiceManager; - private static object m_generalLock = new object(); + private static readonly object m_generalLock = new object(); private string HTTP404; /// @@ -90,7 +90,6 @@ namespace OpenSim.Framework.Servers.HttpServer /// private Stat m_requestsProcessedStat; - private volatile int NotSocketErrors = 0; public volatile bool HTTPDRunning = false; protected tinyHTTPListener m_httpListener; @@ -218,7 +217,7 @@ namespace OpenSim.Framework.Servers.HttpServer { try { - m_cert = new X509Certificate2(CPath, CPass); + m_cert = new X509Certificate2(CPath, CPass); X509Extension ext = m_cert.Extensions["2.5.29.17"]; if(ext != null) { @@ -283,7 +282,7 @@ namespace OpenSim.Framework.Servers.HttpServer if (indx2 != -1) return false; // there can only be one; - string end = dns.Substring(indx + 1); + string end = dns[(indx + 1)..]; int hostlen = hostname.Length; int endlen = end.Length; int length = hostlen - endlen; @@ -299,7 +298,7 @@ namespace OpenSim.Framework.Servers.HttpServer return ((indx2 == -1) || (indx2 >= length)); } - string start = dns.Substring(0, indx); + string start = dns[..indx]; return (String.Compare(hostname, 0, start, 0, start.Length, true, CultureInfo.InvariantCulture) == 0); } @@ -336,19 +335,15 @@ namespace OpenSim.Framework.Servers.HttpServer /// public void AddStreamHandler(IRequestHandler handler) { - string httpMethod = handler.HttpMethod; - string path = handler.Path; - - if(path == "/") + if(handler.Path.Equals("/")) { - if(httpMethod == "GET") + if(handler.HttpMethod.Equals("GET")) m_RootDefaultGET = handler; return; } - string handlerKey = GetHandlerKey(httpMethod, path); - + string handlerKey = GetHandlerKey(handler.HttpMethod, handler.Path); // m_log.DebugFormat("[BASE HTTP SERVER]: Adding handler key {0}", handlerKey); m_streamHandlers.TryAdd(handlerKey, handler); } @@ -419,7 +414,6 @@ namespace OpenSim.Framework.Servers.HttpServer m_rpcHandlers[method] = handler; m_rpcHandlersKeepAlive[method] = keepAlive; // default } - return true; } @@ -427,7 +421,7 @@ namespace OpenSim.Framework.Servers.HttpServer { lock (m_rpcHandlers) { - return (m_rpcHandlers.TryGetValue(method, out XmlRpcMethod xm)) ? xm : null; + return m_rpcHandlers.TryGetValue(method, out XmlRpcMethod xm) ? xm : null; } } @@ -435,7 +429,7 @@ namespace OpenSim.Framework.Servers.HttpServer { lock (m_rpcHandlers) { - return (m_rpcHandlers.TryGetValue(method, out handler)); + return m_rpcHandlers.TryGetValue(method, out handler); } } @@ -450,9 +444,8 @@ namespace OpenSim.Framework.Servers.HttpServer { lock(jsonRpcHandlers) { - jsonRpcHandlers.Add(method, handler); + return jsonRpcHandlers.TryAdd(method, handler); } - return true; } public JsonRPCMethod GetJsonRPCHandler(string method) @@ -472,18 +465,10 @@ namespace OpenSim.Framework.Servers.HttpServer public bool AddHTTPHandler(string methodName, GenericHTTPMethod handler) { //m_log.DebugFormat("[BASE HTTP SERVER]: Registering {0}", methodName); - lock (m_HTTPHandlers) { - if (!m_HTTPHandlers.ContainsKey(methodName)) - { - m_HTTPHandlers.Add(methodName, handler); - return true; - } + return m_HTTPHandlers.TryAdd(methodName, handler); } - - //must already have a handler for that path so return false - return false; } public List GetHTTPHandlerKeys() @@ -518,13 +503,8 @@ namespace OpenSim.Framework.Servers.HttpServer { lock (m_llsdHandlers) { - if (!m_llsdHandlers.ContainsKey(path)) - { - m_llsdHandlers.Add(path, handler); - return true; - } + return m_llsdHandlers.TryAdd(path, handler); } - return false; } public List GetLLSDHandlerKeys() @@ -594,12 +574,12 @@ namespace OpenSim.Framework.Servers.HttpServer { psEvArgs.RequestsReceived++; PollServiceHttpRequest psreq = new PollServiceHttpRequest(psEvArgs, request); - if(psEvArgs.Request == null) + if(psEvArgs.Request is null) m_pollServiceManager.Enqueue(psreq); else { OSHttpResponse resp = psEvArgs.Request.Invoke(psreq.RequestID, osRequest); - if(resp == null) + if(resp is null) m_pollServiceManager.Enqueue(psreq); else resp.Send(); @@ -613,7 +593,7 @@ namespace OpenSim.Framework.Servers.HttpServer } catch (Exception e) { - m_log.Error(string.Format("[BASE HTTP SERVER]: OnRequest() failed: {0} ", e.Message), e); + m_log.Error($"[BASE HTTP SERVER]: OnRequest() failed: {e.Message}"); } } @@ -624,28 +604,22 @@ namespace OpenSim.Framework.Servers.HttpServer /// public virtual void HandleRequest(OSHttpRequest request, OSHttpResponse response) { - string requestMethod = request.HttpMethod; - string uriString = request.RawUrl; - int requestStartTick = Environment.TickCount; - - // Will be adjusted later on. int requestEndTick = requestStartTick; IRequestHandler requestHandler = null; - byte[] responseData = null; try { // OpenSim.Framework.WebUtil.OSHeaderRequestID -// if (request.Headers["opensim-request-id"] != null) -// reqnum = String.Format("{0}:{1}",request.RemoteIPEndPoint,request.Headers["opensim-request-id"]); - //m_log.DebugFormat("[BASE HTTP SERVER]: <{0}> handle request for {1}",reqnum,request.RawUrl); + // if (request.Headers["opensim-request-id"] != null) + // reqnum = String.Format("{0}:{1}",request.RemoteIPEndPoint,request.Headers["opensim-request-id"]); + // m_log.DebugFormat("[BASE HTTP SERVER]: <{0}> handle request for {1}",reqnum,request.RawUrl); Culture.SetCurrentCulture(); - if (request.HttpMethod == "OPTIONS") + if (request.HttpMethod.Equals("OPTIONS")) { //need to check this response.AddHeader("Access-Control-Allow-Origin", "*"); @@ -653,7 +627,7 @@ namespace OpenSim.Framework.Servers.HttpServer response.AddHeader("Access-Control-Allow-Headers", "Content-Type"); response.StatusCode = (int)HttpStatusCode.OK; - if (request.InputStream != null && request.InputStream.CanRead) + if (request.InputStream is not null && request.InputStream.CanRead) request.InputStream.Dispose(); requestEndTick = Environment.TickCount; @@ -662,20 +636,18 @@ namespace OpenSim.Framework.Servers.HttpServer return; } - string path = request.UriPath; - if (path == "/") + if (request.UriPath.Equals("/")) { response.StatusCode = (int)HttpStatusCode.NotFound; // default - if (m_RootDefaultGET != null && request.HttpMethod == "GET") + if (m_RootDefaultGET is not null && request.HttpMethod.Equals("GET")) { - if(m_RootDefaultGET is IStreamedRequestHandler) + if(m_RootDefaultGET is IStreamedRequestHandler isrh) { - IStreamedRequestHandler isrh = m_RootDefaultGET as IStreamedRequestHandler; - response.RawBuffer = isrh.Handle(path, request.InputStream, request, response); + response.RawBuffer = isrh.Handle(request.UriPath, request.InputStream, request, response); response.StatusCode = (int)HttpStatusCode.OK; } - if (request.InputStream != null && request.InputStream.CanRead) + if (request.InputStream is not null && request.InputStream.CanRead) request.InputStream.Dispose(); requestEndTick = Environment.TickCount; @@ -720,7 +692,7 @@ namespace OpenSim.Framework.Servers.HttpServer } } - if (request.InputStream != null && request.InputStream.CanRead) + if (request.InputStream is not null && request.InputStream.CanRead) request.InputStream.Dispose(); requestEndTick = Environment.TickCount; @@ -729,7 +701,7 @@ namespace OpenSim.Framework.Servers.HttpServer return; } - path = Util.TrimEndSlash(path); + string path = Util.TrimEndSlash(request.UriPath); if (TryGetSimpleStreamHandler(path, out ISimpleStreamHandler hdr)) { @@ -737,7 +709,7 @@ namespace OpenSim.Framework.Servers.HttpServer LogIncomingToStreamHandler(request, hdr); hdr.Handle(request, response); - if (request.InputStream != null && request.InputStream.CanRead) + if (request.InputStream is not null && request.InputStream.CanRead) request.InputStream.Dispose(); requestEndTick = Environment.TickCount; @@ -756,16 +728,13 @@ namespace OpenSim.Framework.Servers.HttpServer response.ContentType = requestHandler.ContentType; // Lets do this defaulting before in case handler has varying content type. - if (requestHandler is IStreamedRequestHandler) + if (requestHandler is IStreamedRequestHandler streamedRequestHandler) { - IStreamedRequestHandler streamedRequestHandler = requestHandler as IStreamedRequestHandler; - buffer = streamedRequestHandler.Handle(path, request.InputStream, request, response); } - else if (requestHandler is IGenericHTTPHandler) + else if (requestHandler is IGenericHTTPHandler HTTPRequestHandler) { //m_log.Debug("[BASE HTTP SERVER]: Found Caps based HTTP Handler"); - IGenericHTTPHandler HTTPRequestHandler = requestHandler as IGenericHTTPHandler; string requestBody; Encoding encoding = Encoding.UTF8; @@ -854,10 +823,10 @@ namespace OpenSim.Framework.Servers.HttpServer } } - if(request.InputStream != null && request.InputStream.CanRead) + if(request.InputStream is not null && request.InputStream.CanRead) request.InputStream.Dispose(); - if (buffer != null) + if (buffer is not null) { if (WebUtil.DebugLevel >= 5) { @@ -866,10 +835,10 @@ namespace OpenSim.Framework.Servers.HttpServer if (WebUtil.DebugLevel >= 6) { // Always truncate binary blobs. We don't have a ContentType, so detect them using the request name. - if ((requestHandler != null && requestHandler.Name == "GetMesh")) + if (requestHandler is not null && requestHandler.Name.Equals("GetMesh")) { if (output.Length > WebUtil.MaxRequestDiagLength) - output = output.Substring(0, WebUtil.MaxRequestDiagLength) + "..."; + output = string.Concat(output.AsSpan(0, WebUtil.MaxRequestDiagLength), "..."); } } @@ -903,7 +872,7 @@ namespace OpenSim.Framework.Servers.HttpServer // // An alternative may be to turn off all response write exceptions on the HttpListener, but let's go // with the minimum first - m_log.Warn(String.Format("[BASE HTTP SERVER]: HandleRequest threw {0}.\nNOTE: this may be spurious on Linux ", e.Message), e); + m_log.Warn($"[BASE HTTP SERVER]: HandleRequest threw {e.Message}.\nNOTE: this may be spurious on Linux"); } catch (IOException e) { @@ -922,7 +891,7 @@ namespace OpenSim.Framework.Servers.HttpServer } finally { - if(request.InputStream != null && request.InputStream.CanRead) + if(request.InputStream is not null && request.InputStream.CanRead) request.InputStream.Close(); int tickdiff = requestEndTick - requestStartTick; @@ -931,10 +900,10 @@ namespace OpenSim.Framework.Servers.HttpServer m_log.InfoFormat( "[LOGHTTP] Slow handling of {0} {1} {2} {3} {4} from {5} took {6}ms", RequestNumber, - requestMethod, - uriString, - requestHandler != null ? requestHandler.Name : "", - requestHandler != null ? requestHandler.Description : "", + request.HttpMethod, + request.RawUrl, + requestHandler is null ? "" : requestHandler.Name, + requestHandler is null ? "" : requestHandler.Description, request.RemoteIPEndPoint, tickdiff); } @@ -953,12 +922,10 @@ namespace OpenSim.Framework.Servers.HttpServer if (DebugLevel == 5) { if (output.Length > WebUtil.MaxRequestDiagLength) - output = output.Substring(0, WebUtil.MaxRequestDiagLength) + "..."; + output = string.Concat(output.AsSpan(0, WebUtil.MaxRequestDiagLength), "..."); } m_log.DebugFormat("[LOGHTTP] RESPONSE {0}: {1}", RequestNumber, output); } - - responseData = null; } } @@ -1101,7 +1068,7 @@ namespace OpenSim.Framework.Servers.HttpServer if(m_pollHandlers.TryGetValue(handlerKey, out oServiceEventArgs)) return true; - if(m_pollHandlersVarPath.Count > 0 && handlerKey.Length >= 45) + if(m_pollHandlersVarPath.IsEmpty && handlerKey.Length >= 45) { // tuned for lsl requests, the only ones that should reach this, so be strict (/lslhttp/uuid.ToString()) int indx = handlerKey.IndexOf('/', 44); @@ -1110,7 +1077,7 @@ namespace OpenSim.Framework.Servers.HttpServer if(m_pollHandlersVarPath.TryGetValue(handlerKey, out oServiceEventArgs)) return true; } - else if(m_pollHandlersVarPath.TryGetValue(handlerKey.Substring(0, indx), out oServiceEventArgs)) + else if(m_pollHandlersVarPath.TryGetValue(handlerKey[..indx], out oServiceEventArgs)) return true; } @@ -1165,7 +1132,7 @@ namespace OpenSim.Framework.Servers.HttpServer if(indx < 0 || indx == uripath.Length - 1) return false; - return m_simpleStreamVarPath.TryGetValue(uripath.Substring(0,indx), out handler); + return m_simpleStreamVarPath.TryGetValue(uripath[..indx], out handler); } /// @@ -1209,7 +1176,7 @@ namespace OpenSim.Framework.Servers.HttpServer { if (requestStream.CanRead) requestStream.Dispose(); - if (innerStream != null && innerStream.CanRead) + if (innerStream is not null && innerStream.CanRead) innerStream.Dispose(); response.StatusCode = (int)HttpStatusCode.BadRequest; @@ -1235,11 +1202,11 @@ namespace OpenSim.Framework.Servers.HttpServer { if (requestStream.CanRead) requestStream.Dispose(); - if (innerStream != null && innerStream.CanRead) + if (innerStream is not null && innerStream.CanRead) innerStream.Dispose(); } - if (xmlRprcRequest == null) + if (xmlRprcRequest is null) return; string methodName = xmlRprcRequest.MethodName; @@ -1267,7 +1234,7 @@ namespace OpenSim.Framework.Servers.HttpServer string xfflower = xff.ToLower(); foreach (string s in request.Headers.AllKeys) { - if (s != null && s.Equals(xfflower)) + if (s is not null && s.Equals(xfflower)) { xff = xfflower; break; @@ -1291,12 +1258,8 @@ namespace OpenSim.Framework.Servers.HttpServer } catch(Exception e) { - string errorMessage - = String.Format( - "Requested method [{0}] from {1} threw exception: {2} {3}", - methodName, request.RemoteIPEndPoint.Address, e.Message, e.StackTrace); - - m_log.ErrorFormat("[BASE HTTP SERVER]: {0}", errorMessage); + string errorMessage = $"Requested method [{methodName}] from {request.RemoteIPEndPoint.Address} threw exception: {e.Message}"; + m_log.Error($"[BASE HTTP SERVER]: {errorMessage}"); // if the registered XmlRpc method threw an exception, we pass a fault-code along xmlRpcResponse = new XmlRpcResponse(); @@ -1349,7 +1312,7 @@ namespace OpenSim.Framework.Servers.HttpServer { if (requestStream.CanRead) requestStream.Dispose(); - if (innerStream != null && innerStream.CanRead) + if (innerStream is not null && innerStream.CanRead) innerStream.Dispose(); response.StatusCode = (int)HttpStatusCode.BadRequest; @@ -1376,11 +1339,11 @@ namespace OpenSim.Framework.Servers.HttpServer { if (requestStream.CanRead) requestStream.Dispose(); - if (innerStream != null && innerStream.CanRead) + if (innerStream is not null && innerStream.CanRead) innerStream.Dispose(); } - if (xmlRprcRequest == null) + if (xmlRprcRequest is null) { response.StatusCode = (int)HttpStatusCode.NotFound; response.KeepAlive = false; @@ -1395,10 +1358,9 @@ namespace OpenSim.Framework.Servers.HttpServer return; } - XmlRpcMethod method; bool methodWasFound; - methodWasFound = rpcHandlers.TryGetValue(methodName, out method); + methodWasFound = rpcHandlers.TryGetValue(methodName, out XmlRpcMethod method); XmlRpcResponse xmlRpcResponse; if (methodWasFound) @@ -1406,27 +1368,20 @@ namespace OpenSim.Framework.Servers.HttpServer xmlRprcRequest.Params.Add(request.RemoteIPEndPoint); // Param[1] xmlRprcRequest.Params.Add(request.Url); // Param[2] - string xff = "X-Forwarded-For"; - string xfflower = xff.ToLower(); foreach (string s in request.Headers.AllKeys) { - if (s != null && s.Equals(xfflower)) + if (s is not null && s.Equals("x-forwarded-for", StringComparison.OrdinalIgnoreCase)) { - xff = xfflower; + xmlRprcRequest.Params.Add(request.Headers.Get(s)); // Param[3] break; } } - xmlRprcRequest.Params.Add(request.Headers.Get(xff)); // Param[3] // reserve this for // ... by Fumi.Iseki for DTLNSLMoneyServer // BUT make its presence possible to detect/parse - string rcn = request.IHttpClientContext.SSLCommonName; - if (!string.IsNullOrWhiteSpace(rcn)) - { - rcn = "SSLCN:" + rcn; - xmlRprcRequest.Params.Add(rcn); // Param[4] or Param[5] - } + if (!string.IsNullOrWhiteSpace(request.IHttpClientContext.SSLCommonName)) + xmlRprcRequest.Params.Add("SSLCN:" + request.IHttpClientContext.SSLCommonName); // Param[4] or Param[5] try { @@ -1435,8 +1390,8 @@ namespace OpenSim.Framework.Servers.HttpServer catch (Exception e) { string errorMessage = string.Format( - "Requested method [{0}] from {1} threw exception: {2} {3}", - methodName, request.RemoteIPEndPoint.Address, e.Message, e.StackTrace); + "Requested method [{0}] from {1} threw exception: {2}", + methodName, request.RemoteIPEndPoint.Address, e.Message); m_log.ErrorFormat("[BASE HTTP SERVER]: {0}", errorMessage); @@ -1492,10 +1447,10 @@ namespace OpenSim.Framework.Servers.HttpServer jsonRpcResponse.Error.Message = e.Message; } - if (request.InputStream != null && request.InputStream.CanRead) + if (request.InputStream is not null && request.InputStream.CanRead) request.InputStream.Dispose(); - if (jsonRpcRequest != null) + if (jsonRpcRequest is not null) { // If we have no id, then it's a "notification" if (jsonRpcRequest.TryGetValue("id", out OSD val)) @@ -1547,7 +1502,7 @@ namespace OpenSim.Framework.Servers.HttpServer private void HandleLLSDLogin(OSHttpRequest request, OSHttpResponse response) { - if (m_defaultLlsdHandler == null) + if (m_defaultLlsdHandler is null) return; response.StatusCode = (int)HttpStatusCode.BadRequest; @@ -1555,11 +1510,11 @@ namespace OpenSim.Framework.Servers.HttpServer try { OSD llsdRequest = OSDParser.DeserializeLLSDXml(request.InputStream); - if (llsdRequest == null || !(llsdRequest is OSDMap)) + if (llsdRequest is not OSDMap) return; OSD llsdResponse = m_defaultLlsdHandler(llsdRequest, request.RemoteIPEndPoint); - if (llsdResponse != null) + if (llsdResponse is not null) { response.ContentType = "application/llsd+xml"; response.RawBuffer = OSDParser.SerializeLLSDXmlBytes(llsdResponse); @@ -1593,7 +1548,7 @@ namespace OpenSim.Framework.Servers.HttpServer m_log.Warn("[BASE HTTP SERVER]: Error - " + ex.Message); } - if (llsdRequest == null) + if (llsdRequest is null) { response.StatusCode = (int)HttpStatusCode.BadRequest; return null; @@ -1609,14 +1564,14 @@ namespace OpenSim.Framework.Servers.HttpServer llsdResponse = null; } - if (llsdResponse == null) + if (llsdResponse is null) { response.StatusCode = (int)HttpStatusCode.BadRequest; return null; } byte[] buffer = Array.Empty(); - if (llsdResponse.ToString() == "shutdown404!") + if (llsdResponse.ToString().Equals("shutdown404!")) { response.ContentType = "text/plain"; response.StatusCode = (int)HttpStatusCode.NotFound; @@ -1634,9 +1589,9 @@ namespace OpenSim.Framework.Servers.HttpServer return buffer; } - private byte[] BuildLLSDResponse(OSHttpRequest request, OSHttpResponse response, OSD llsdResponse) + private static byte[] BuildLLSDResponse(OSHttpRequest request, OSHttpResponse response, OSD llsdResponse) { - if (request.AcceptTypes != null && request.AcceptTypes.Length > 0) + if (request.AcceptTypes is not null && request.AcceptTypes.Length > 0) { foreach (string strAccept in request.AcceptTypes) { @@ -1655,7 +1610,7 @@ namespace OpenSim.Framework.Servers.HttpServer } } - if (!String.IsNullOrEmpty(request.ContentType)) + if (!string.IsNullOrEmpty(request.ContentType)) { switch (request.ContentType) { @@ -1677,6 +1632,14 @@ namespace OpenSim.Framework.Servers.HttpServer return OSDParser.SerializeLLSDXmlBytes(llsdResponse); } + private ReadOnlySpan CleanSearchPath(ReadOnlySpan path) + { + path = path.Trim().TrimEnd('/'); + if (path[0] == '/') + return path; + return ("/" + path.ToString()).AsSpan(); + } + /// /// Checks if we have an Exact path in the LLSD handlers for the path provided /// @@ -1684,38 +1647,22 @@ namespace OpenSim.Framework.Servers.HttpServer /// true if we have one, false if not private bool DoWeHaveALLSDHandler(string path) { - string[] pathbase = path.Split('/'); - string searchquery = "/"; - - if (pathbase.Length < 1) - return false; - - for (int i = 1; i < pathbase.Length; i++) + if(m_llsdHandlers.Count == 0) { - searchquery += pathbase[i]; - if (pathbase.Length - 1 != i) - searchquery += "/"; + return false; } - string bestMatch = null; + var searchquery = CleanSearchPath(path.AsSpan()); lock (m_llsdHandlers) { foreach (string pattern in m_llsdHandlers.Keys) { - if (searchquery.StartsWith(pattern) && searchquery.Length >= pattern.Length) - bestMatch = pattern; + if (searchquery.Length >= pattern.Length && searchquery.StartsWith(pattern)) + return true; } } - - if (String.IsNullOrEmpty(bestMatch)) - { - return false; - } - else - { - return true; - } + return false; } /// @@ -1725,64 +1672,34 @@ namespace OpenSim.Framework.Servers.HttpServer /// true if we have one, false if not private bool DoWeHaveAHTTPHandler(string path) { - string[] pathbase = path.Split('/'); - string searchquery = "/"; - - if (pathbase.Length < 1) - return false; - - for (int i = 1; i < pathbase.Length; i++) - { - searchquery += pathbase[i]; - if (pathbase.Length - 1 != i) - searchquery += "/"; - } - - string bestMatch = null; + var searchquery = CleanSearchPath(path.AsSpan()); //m_log.DebugFormat("[BASE HTTP HANDLER]: Checking if we have an HTTP handler for {0}", searchquery); - lock (m_HTTPHandlers) { foreach (string pattern in m_HTTPHandlers.Keys) { - if (searchquery.StartsWith(pattern) && searchquery.Length >= pattern.Length) - { - bestMatch = pattern; - } - } - - if (String.IsNullOrEmpty(bestMatch)) - { - return false; - } - else - { - return true; + if (searchquery.Length >= pattern.Length && searchquery.StartsWith(pattern)) + return true; } } + return false; } private bool TryGetLLSDHandler(string path, out LLSDMethod llsdHandler) { - llsdHandler = null; + if(m_llsdHandlers.Count == 0) + { + llsdHandler = null; + return false; + } + // Pull out the first part of the path // splitting the path by '/' means we'll get the following return.. // {0}/{1}/{2} // where {0} isn't something we really control 100% - string[] pathbase = path.Split('/'); - string searchquery = "/"; - - if (pathbase.Length < 1) - return false; - - for (int i=1; i bestMatch.Length) + if (nomatch || searchquery.Length > bestMatch.Length) { - // You have to specifically register for '/' and to get it, you must specificaly request it - // - if (pattern == "/" && searchquery == "/" || pattern != "/") - bestMatch = pattern; + bestMatch = pattern; + nomatch = false; } } } - if (String.IsNullOrEmpty(bestMatch)) + if (nomatch) { llsdHandler = null; return false; } - else + if (bestMatch == "/" && searchquery != "/") { - llsdHandler = m_llsdHandlers[bestMatch]; - return true; + llsdHandler = null; + return false; } + + llsdHandler = m_llsdHandlers[bestMatch]; + return true; } } @@ -1848,8 +1766,6 @@ namespace OpenSim.Framework.Servers.HttpServer // to display the form, or process it. // a better way would be nifty. - byte[] buffer; - string requestBody; using(StreamReader reader = new StreamReader(request.InputStream, Encoding.UTF8)) requestBody = reader.ReadToEnd(); @@ -1859,7 +1775,7 @@ namespace OpenSim.Framework.Servers.HttpServer Hashtable requestVars = new Hashtable(); - string host = String.Empty; + string host = string.Empty; string[] querystringkeys = request.QueryString.AllKeys; string[] rHeaders = request.Headers.AllKeys; @@ -1871,8 +1787,8 @@ namespace OpenSim.Framework.Servers.HttpServer foreach (string queryname in querystringkeys) { -// m_log.DebugFormat( -// "[BASE HTTP SERVER]: Got query paremeter {0}={1}", queryname, request.QueryString[queryname]); + //m_log.DebugFormat( + // "[BASE HTTP SERVER]: Got query paremeter {0}={1}", queryname, request.QueryString[queryname]); if(!string.IsNullOrEmpty(queryname)) { keysvals.Add(queryname, request.QueryString[queryname]); @@ -1882,93 +1798,73 @@ namespace OpenSim.Framework.Servers.HttpServer foreach (string headername in rHeaders) { -// m_log.Debug("[BASE HTTP SERVER]: " + headername + "=" + request.Headers[headername]); + //m_log.Debug("[BASE HTTP SERVER]: " + headername + "=" + request.Headers[headername]); headervals[headername] = request.Headers[headername]; } keysvals.Add("headers", headervals); keysvals.Add("querystringkeys", querystringkeys); keysvals.Add("requestvars", requestVars); -// keysvals.Add("form", request.Form); + //keysvals.Add("form", request.Form); Hashtable responsedata2 = requestprocessor(keysvals); - buffer = DoHTTPGruntWork(responsedata2, response); - return buffer; + return DoHTTPGruntWork(responsedata2, response); } private bool TryGetHTTPHandlerPathBased(string path, out GenericHTTPMethod httpHandler) { - httpHandler = null; - // Pull out the first part of the path - // splitting the path by '/' means we'll get the following return.. - // {0}/{1}/{2} - // where {0} isn't something we really control 100% - - string[] pathbase = path.Split('/'); - string searchquery = "/"; - - if (pathbase.Length < 1) - return false; - - for (int i = 1; i < pathbase.Length; i++) + if(m_HTTPHandlers.Count == 0) { - searchquery += pathbase[i]; - if (pathbase.Length - 1 != i) - searchquery += "/"; + httpHandler = null; + return false; } - // while the matching algorithm below doesn't require it, we're expecting a query in the form - // - // [] = optional - // /resource/UUID/action[/action] - // - // now try to get the closest match to the reigstered path - // at least for OGP, registered path would probably only consist of the /resource/ - + var searchquery = CleanSearchPath(path); string bestMatch = null; + bool nomatch = true; -// m_log.DebugFormat( -// "[BASE HTTP HANDLER]: TryGetHTTPHandlerPathBased() looking for HTTP handler to match {0}", searchquery); + //m_log.DebugFormat( + // "[BASE HTTP HANDLER]: TryGetHTTPHandlerPathBased() looking for HTTP handler to match {0}", searchquery); lock (m_HTTPHandlers) { foreach (string pattern in m_HTTPHandlers.Keys) { - if (searchquery.ToLower().StartsWith(pattern.ToLower())) + if (searchquery.StartsWith(pattern, StringComparison.InvariantCultureIgnoreCase)) { - if (String.IsNullOrEmpty(bestMatch) || searchquery.Length > bestMatch.Length) + if (nomatch || searchquery.Length > bestMatch.Length) { - // You have to specifically register for '/' and to get it, you must specifically request it - if (pattern == "/" && searchquery == "/" || pattern != "/") - bestMatch = pattern; + bestMatch = pattern; + nomatch = false; } } } - if (string.IsNullOrEmpty(bestMatch)) + if (nomatch) { httpHandler = null; return false; } - else - { - if (bestMatch == "/" && searchquery != "/") - return false; - httpHandler = m_HTTPHandlers[bestMatch]; - return true; + if (bestMatch == "/" && searchquery != "/") + { + httpHandler = null; + return false; } + + httpHandler = m_HTTPHandlers[bestMatch]; + return true; } } - internal byte[] DoHTTPGruntWork(Hashtable responsedata, OSHttpResponse response) + internal static byte[] DoHTTPGruntWork(Hashtable responsedata, OSHttpResponse response) { int responsecode; - string responseString = String.Empty; + string responseString = string.Empty; byte[] responseData = null; string contentType; - if (responsedata == null) + if (responsedata is null) { responsecode = 500; responseString = "No response could be obtained"; @@ -1981,13 +1877,11 @@ namespace OpenSim.Framework.Servers.HttpServer { //m_log.Info("[BASE HTTP SERVER]: Doing HTTP Grunt work with response"); responsecode = (int)responsedata["int_response_code"]; - if (responsedata["bin_response_data"] != null) - responseData = (byte[])responsedata["bin_response_data"]; + contentType = (string)responsedata["content_type"]; + if (responsedata["bin_response_data"] is byte[] b) + responseData = b; else responseString = (string)responsedata["str_response_string"]; - contentType = (string)responsedata["content_type"]; - if (responseString == null) - responseString = String.Empty; } catch { @@ -1999,13 +1893,10 @@ namespace OpenSim.Framework.Servers.HttpServer } if (responsedata.ContainsKey("error_status_text")) - { response.StatusDescription = (string)responsedata["error_status_text"]; - } + if (responsedata.ContainsKey("http_protocol_version")) - { response.ProtocolVersion = (string)responsedata["http_protocol_version"]; - } if (responsedata.ContainsKey("keepalive")) { @@ -2045,12 +1936,15 @@ namespace OpenSim.Framework.Servers.HttpServer byte[] buffer; - if (responseData != null) + if (responseData is not null) { buffer = responseData; } else { + if(string.IsNullOrEmpty(responseString)) + return null; + if (!(contentType.Contains("image") || contentType.Contains("x-shockwave-flash") || contentType.Contains("application/x-oar") @@ -2064,11 +1958,9 @@ namespace OpenSim.Framework.Servers.HttpServer // Binary! buffer = Convert.FromBase64String(responseString); } - response.ContentLength64 = buffer.Length; response.ContentEncoding = Encoding.UTF8; } - return buffer; } @@ -2100,14 +1992,11 @@ namespace OpenSim.Framework.Servers.HttpServer /// public void Start(bool performPollResponsesAsync, bool runPool) { - m_log.InfoFormat( - "[BASE HTTP SERVER]: Starting {0} server on port {1}", UseSSL ? "HTTPS" : "HTTP", Port); + m_log.Info($"[BASE HTTP SERVER]: Starting HTTP{(UseSSL ? "S" : "")} server on port {Port}"); try { //m_httpListener = new HttpListener(); - - NotSocketErrors = 0; if (!m_ssl) { m_httpListener = tinyHTTPListener.Create(m_listenIPAddress, (int)m_port); @@ -2124,7 +2013,7 @@ namespace OpenSim.Framework.Servers.HttpServer else { m_httpListener = tinyHTTPListener.Create(IPAddress.Any, (int)m_port, m_cert); - if(m_certificateValidationCallback != null) + if(m_certificateValidationCallback is not null) m_httpListener.CertificateValidationCallback = m_certificateValidationCallback; m_httpListener.ExceptionThrown += httpServerException; if (DebugLevel > 0) @@ -2141,8 +2030,7 @@ namespace OpenSim.Framework.Servers.HttpServer { if (runPool) { - if(m_pollServiceManager == null) - m_pollServiceManager = new PollServiceRequestManager(performPollResponsesAsync, 2, 25000); + m_pollServiceManager ??= new PollServiceRequestManager(performPollResponsesAsync, 2, 25000); m_pollServiceManager.Start(); } } @@ -2174,20 +2062,9 @@ namespace OpenSim.Framework.Servers.HttpServer StatsManager.RegisterStat(m_requestsProcessedStat); } - public void httpServerDisconnectMonitor(IHttpClientContext source, SocketError err) + public static void httpServerException(object source, Exception exception) { - switch (err) - { - case SocketError.NotSocket: - NotSocketErrors++; - - break; - } - } - - public void httpServerException(object source, Exception exception) - { - if (source.ToString() == "HttpServer.HttpListener" && exception.ToString().StartsWith("Mono.Security.Protocol.Tls.TlsException")) + if (source.ToString().Equals("HttpServer.HttpListener") && exception.ToString().StartsWith("Mono.Security.Protocol.Tls.TlsException")) return; m_log.ErrorFormat("[BASE HTTP SERVER]: {0} had an exception {1}", source.ToString(), exception.ToString()); } @@ -2221,34 +2098,35 @@ namespace OpenSim.Framework.Servers.HttpServer public void RemoveStreamHandler(string httpMethod, string path) { - if (m_streamHandlers.TryRemove(path, out IRequestHandler dummy)) + if (m_streamHandlers.TryRemove(path, out _)) return; string handlerKey = GetHandlerKey(httpMethod, path); //m_log.DebugFormat("[BASE HTTP SERVER]: Removing handler key {0}", handlerKey); - m_streamHandlers.TryRemove(handlerKey, out dummy); + m_streamHandlers.TryRemove(handlerKey, out _); } public void RemoveStreamHandler(string path) { - m_streamHandlers.TryRemove(path, out IRequestHandler dummy); + m_streamHandlers.TryRemove(path, out IRequestHandler _); } public void RemoveSimpleStreamHandler(string path) { - if(m_simpleStreamHandlers.TryRemove(path, out ISimpleStreamHandler dummy)) + if(m_simpleStreamHandlers.TryRemove(path, out _)) return; - m_simpleStreamVarPath.TryRemove(path, out ISimpleStreamHandler dummy2); + m_simpleStreamVarPath.TryRemove(path, out _); } public void RemoveHTTPHandler(string httpMethod, string path) { - if (path == null) return; // Caps module isn't loaded, tries to remove handler where path = null + if (string.IsNullOrEmpty(path)) + return; // Caps module isn't loaded, tries to remove handler where path = null lock (m_HTTPHandlers) { - if (httpMethod != null && httpMethod.Length == 0) + if (httpMethod is not null && httpMethod.Length == 0) { m_HTTPHandlers.Remove(path); return; @@ -2260,14 +2138,14 @@ namespace OpenSim.Framework.Servers.HttpServer public void RemovePollServiceHTTPHandler(string httpMethod, string path) { - if(!m_pollHandlers.TryRemove(path, out PollServiceEventArgs dummy)) - m_pollHandlersVarPath.TryRemove(path, out PollServiceEventArgs dummy2); + if(!m_pollHandlers.TryRemove(path, out _)) + m_pollHandlersVarPath.TryRemove(path, out _); } public void RemovePollServiceHTTPHandler(string path) { - if(!m_pollHandlers.TryRemove(path, out PollServiceEventArgs dummy)) - m_pollHandlersVarPath.TryRemove(path, out PollServiceEventArgs dummy2); + if(!m_pollHandlers.TryRemove(path, out _)) + m_pollHandlersVarPath.TryRemove(path, out _); } //public bool RemoveAgentHandler(string agent, IHttpAgentHandler handler) @@ -2301,9 +2179,7 @@ namespace OpenSim.Framework.Servers.HttpServer { lock (m_llsdHandlers) { - LLSDMethod foundHandler; - - if (m_llsdHandlers.TryGetValue(path, out foundHandler) && foundHandler == handler) + if (m_llsdHandlers.TryGetValue(path, out LLSDMethod foundHandler) && foundHandler == handler) { m_llsdHandlers.Remove(path); return true; @@ -2410,7 +2286,7 @@ namespace OpenSim.Framework.Servers.HttpServer public class IndexPHPHandler : SimpleStreamHandler { - BaseHttpServer m_server; + readonly BaseHttpServer m_server; public IndexPHPHandler(BaseHttpServer server) : base("/index.php") @@ -2421,7 +2297,7 @@ namespace OpenSim.Framework.Servers.HttpServer protected override void ProcessRequest(IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) { httpResponse.KeepAlive = false; - if (m_server == null || !m_server.HTTPDRunning) + if (m_server is null || !m_server.HTTPDRunning) { httpResponse.StatusCode = (int)HttpStatusCode.NotFound; return; @@ -2437,14 +2313,16 @@ namespace OpenSim.Framework.Servers.HttpServer httpResponse.Redirect("http://opensimulator.org/wiki/0.9.2.2_Release"); return; } - if (!httpRequest.QueryAsDictionary.TryGetValue("method", out string methods) || string.IsNullOrWhiteSpace(methods)) + if (!httpRequest.QueryAsDictionary.TryGetValue("method", out string method) || string.IsNullOrWhiteSpace(method)) { httpResponse.StatusCode = (int)HttpStatusCode.NotFound; ; return; } - string[] splited = methods.Split(Util.SplitCommaArray); - string method = splited[0]; + int indx = method.IndexOf(','); + if(indx > 0) + method = method[..indx]; + if (string.IsNullOrWhiteSpace(method)) { httpResponse.StatusCode = (int)HttpStatusCode.NotFound; @@ -2452,7 +2330,7 @@ namespace OpenSim.Framework.Servers.HttpServer } SimpleStreamMethod sh = m_server.TryGetIndexPHPMethodHandler(method); - if (sh == null) + if (sh is null) { httpResponse.StatusCode = (int)HttpStatusCode.NotFound; return; diff --git a/OpenSim/Framework/Servers/HttpServer/PollServiceHttpRequest.cs b/OpenSim/Framework/Servers/HttpServer/PollServiceHttpRequest.cs index 784e84fa05..10ad353070 100644 --- a/OpenSim/Framework/Servers/HttpServer/PollServiceHttpRequest.cs +++ b/OpenSim/Framework/Servers/HttpServer/PollServiceHttpRequest.cs @@ -73,14 +73,14 @@ namespace OpenSim.Framework.Servers.HttpServer OSHttpResponse response = new OSHttpResponse(new HttpResponse(Request)); - if (responsedata == null) + if (responsedata is null) { SendNoContentError(response); return; } int responsecode = 200; - string responseString = String.Empty; + string responseString = null; string contentType; byte[] buffer = null; int rangeStart = 0; @@ -105,10 +105,7 @@ namespace OpenSim.Framework.Servers.HttpServer } else responseString = (string)responsedata["str_response_string"]; - contentType = (string)responsedata["content_type"]; - if (responseString == null) - responseString = String.Empty; } catch { @@ -158,7 +155,9 @@ namespace OpenSim.Framework.Servers.HttpServer if(buffer == null) { - if (contentType != null && (!(contentType.Contains("image") + if(string.IsNullOrEmpty(responseString)) + buffer = Array.Empty(); + else if (contentType != null && (!(contentType.Contains("image") || contentType.Contains("x-shockwave-flash") || contentType.Contains("application/x-oar") || contentType.Contains("application/vnd.ll.mesh")))) diff --git a/OpenSim/Server/Base/ServerUtils.cs b/OpenSim/Server/Base/ServerUtils.cs index e4878c4420..32b85a8cc2 100644 --- a/OpenSim/Server/Base/ServerUtils.cs +++ b/OpenSim/Server/Base/ServerUtils.cs @@ -400,9 +400,8 @@ namespace OpenSim.Server.Base { if (kvp.Value is List l) { - int llen = l.Count; string nkey = System.Web.HttpUtility.UrlEncode(kvp.Key); - for (int i = 0; i < llen; ++i) + for (int i = 0; i < l.Count; ++i) { if (sb.Length != 0) sb.Append('&'); @@ -414,19 +413,13 @@ namespace OpenSim.Server.Base else if (kvp.Value is Dictionary) { // encode complex structures as JSON - // needed for estate bans with the encoding used on xml - // encode can be here because object does contain the structure information - // but decode needs to be on estateSettings (or other user) string js; try { - // bypass libovm, we dont need even more useless high level maps - // this should only be called once.. but no problem, i hope - // (other uses may need more..) LitJson.JsonMapper.RegisterExporter((uuid, writer) => writer.Write(uuid.ToString())); js = LitJson.JsonMapper.ToJson(kvp.Value); } - // catch(Exception e) + //catch(Exception e) catch { continue; @@ -534,21 +527,29 @@ namespace OpenSim.Server.Base return ret; } + private static readonly XmlReaderSettings ParseXmlStringResponseXmlReaderSettings = new() + { + IgnoreWhitespace = true, + IgnoreComments = true, + ConformanceLevel = ConformanceLevel.Fragment, + CloseInput = true, + MaxCharactersInDocument = 50_000_000 + }; + + private static readonly XmlParserContext ParseXmlResponseXmlParserContext = new(null, null, null, XmlSpace.None) + { + Encoding = Util.UTF8NoBomEncoding + }; + public static Dictionary ParseXmlResponse(string data) { - //m_log.DebugFormat("[XXX]: received xml string: {0}", data); - try { - XmlReaderSettings xset = new XmlReaderSettings() { IgnoreWhitespace = true, IgnoreComments = true, ConformanceLevel = ConformanceLevel.Fragment, CloseInput = true }; - XmlParserContext xpc = new XmlParserContext(null, null, null, XmlSpace.None); - xpc.Encoding = Util.UTF8NoBomEncoding; - using (XmlReader xr = XmlReader.Create(new StringReader(data), xset, xpc)) - { - if (!xr.ReadToFollowing("ServerResponse")) - return new Dictionary(); - return ScanXmlResponse(xr); - } + using XmlReader xr = XmlReader.Create(new StringReader(data), + ParseXmlStringResponseXmlReaderSettings, ParseXmlResponseXmlParserContext); + if (!xr.ReadToFollowing("ServerResponse")) + return new Dictionary(); + return ScanXmlResponse(xr); } catch (Exception e) { @@ -557,26 +558,21 @@ namespace OpenSim.Server.Base return new Dictionary(); } + private static readonly XmlReaderSettings ParseXmlStreamResponseXmlReaderSettings = new() + { + IgnoreWhitespace = true, + IgnoreComments = true, + ConformanceLevel = ConformanceLevel.Fragment, + CloseInput = true, + MaxCharactersInDocument = 50_000_000 + }; + public static Dictionary ParseXmlResponse(Stream src) { - //m_log.DebugFormat("[XXX]: received xml string: {0}", data); - - try - { - XmlReaderSettings xset = new XmlReaderSettings() { IgnoreWhitespace = true, IgnoreComments = true, ConformanceLevel = ConformanceLevel.Fragment, CloseInput = true }; - XmlParserContext xpc = new XmlParserContext(null, null, null, XmlSpace.None); - xpc.Encoding = Util.UTF8NoBomEncoding; - using (XmlReader xr = XmlReader.Create(src, xset, xpc)) - { - if (!xr.ReadToFollowing("ServerResponse")) - return new Dictionary(); - return ScanXmlResponse(xr); - } - } - catch (Exception e) - { - m_log.DebugFormat("[serverUtils.ParseXmlResponse]: failed error: {0}", e.Message); - } + using XmlReader xr = XmlReader.Create(src, + ParseXmlStreamResponseXmlReaderSettings, ParseXmlResponseXmlParserContext); + if (xr.ReadToFollowing("ServerResponse")) + return ScanXmlResponse(xr); return new Dictionary(); }