/// <summary> /// Invoked by OSHttpRequestPump. /// </summary> public override OSHttpHandlerResult Process(OSHttpRequest request) { // call handler method Hashtable responseData = _handler(request.Query); int responseCode = (int)responseData["int_response_code"]; string responseString = (string)responseData["str_response_string"]; string contentType = (string)responseData["content_type"]; //Even though only one other part of the entire code uses HTTPHandlers, we shouldn't expect this //and should check for NullReferenceExceptions if (string.IsNullOrEmpty(contentType)) { contentType = "text/html"; } OSHttpResponse response = new OSHttpResponse(request); // We're forgoing the usual error status codes here because the client // ignores anything but 200 and 301 response.StatusCode = (int)OSHttpStatusCode.SuccessOk; if (responseCode == (int)OSHttpStatusCode.RedirectMovedPermanently) { response.RedirectLocation = (string)responseData["str_redirect_location"]; response.StatusCode = responseCode; } response.AddHeader("Content-type", contentType); byte[] buffer; if (!contentType.Contains("image")) { buffer = Encoding.UTF8.GetBytes(responseString); } else { buffer = Convert.FromBase64String(responseString); } response.SendChunked = false; response.ContentLength64 = buffer.Length; response.ContentEncoding = Encoding.UTF8; try { response.Body.Write(buffer, 0, buffer.Length); } catch (Exception ex) { _log.ErrorFormat("[OSHttp Http Handler]: Error: {0}", ex.Message); } finally { response.Send(); } return(OSHttpHandlerResult.Done); }
internal void DoHTTPstop(BaseHttpServer server) { OSHttpResponse response = new OSHttpResponse(new HttpResponse(HttpContext, Request), HttpContext); if (Request.Body.CanRead) { Request.Body.Dispose(); } response.SendChunked = false; response.ContentLength64 = 0; response.ContentEncoding = Encoding.UTF8; response.ReuseContext = false; response.KeepAlive = false; response.SendChunked = false; response.StatusCode = 503; try { response.OutputStream.Flush(); response.Send(); } catch (Exception e) { } }
internal void DoHTTPGruntWork(BaseHttpServer server, Hashtable responsedata) { OSHttpResponse response = new OSHttpResponse(new HttpResponse(HttpContext, Request), HttpContext); byte[] buffer = server.DoHTTPGruntWork(responsedata, response); if (Request.Body.CanRead) { Request.Body.Dispose(); } response.SendChunked = false; response.ContentLength64 = buffer.Length; response.ContentEncoding = Encoding.UTF8; response.ReuseContext = false; try { response.OutputStream.Write(buffer, 0, buffer.Length); response.OutputStream.Flush(); response.Send(); buffer = null; } catch (Exception ex) { m_log.Warn("[POLL SERVICE WORKER THREAD]: Error ", ex); } PollServiceArgs.RequestsHandled++; }
internal void SendNoContentError(OSHttpResponse response) { response.ContentLength64 = 0; response.ContentEncoding = Encoding.UTF8; response.StatusCode = 500; try { response.Send(); } catch { } return; }
/// <summary> /// Invoked by OSHttpRequestPump. /// </summary> public override OSHttpHandlerResult Process(OSHttpRequest request) { XmlRpcResponse xmlRpcResponse; string responseString; // check whether we are interested in this request if (!XmlRpcMethodMatch(request)) { return(OSHttpHandlerResult.Pass); } OSHttpResponse resp = new OSHttpResponse(request); try { // reified XmlRpcRequest must still be on the whiteboard XmlRpcRequest xmlRpcRequest = request.Whiteboard["xmlrequest"] as XmlRpcRequest; xmlRpcResponse = _handler(xmlRpcRequest); responseString = XmlRpcResponseSerializer.Singleton.Serialize(xmlRpcResponse); resp.ContentType = "text/xml"; byte[] buffer = Encoding.UTF8.GetBytes(responseString); resp.SendChunked = false; resp.ContentLength = buffer.Length; resp.ContentEncoding = Encoding.UTF8; resp.Body.Write(buffer, 0, buffer.Length); resp.Body.Flush(); resp.Send(); } catch (Exception ex) { _log.WarnFormat("[OSHttpXmlRpcHandler]: Error: {0}", ex.Message); return(OSHttpHandlerResult.Pass); } return(OSHttpHandlerResult.Done); }
internal void DoHTTPGruntWork(BaseHttpServer server, Hashtable responsedata) { OSHttpResponse response = new OSHttpResponse(new HttpResponse(HttpContext, Request), HttpContext); byte[] buffer = server.DoHTTPGruntWork(responsedata, response); if (Request.Body.CanRead) { Request.Body.Dispose(); } response.SendChunked = false; response.ContentLength64 = buffer.Length; response.ContentEncoding = Encoding.UTF8; try { response.OutputStream.Write(buffer, 0, buffer.Length); response.Send(); buffer = null; } catch (Exception ex) { if (ex is System.Net.Sockets.SocketException) { // only mute connection reset by peer so we are not totally blind for now if (((System.Net.Sockets.SocketException)ex).SocketErrorCode != System.Net.Sockets.SocketError.ConnectionReset) { m_log.Warn("[POLL SERVICE WORKER THREAD]: Error ", ex); } } else { m_log.Warn("[POLL SERVICE WORKER THREAD]: Error ", ex); } } PollServiceArgs.RequestsHandled++; }
internal void DoHTTPstop() { OSHttpResponse response = new OSHttpResponse(new HttpResponse(Request)); if (Request.Body.CanRead) { Request.Body.Dispose(); } response.ContentLength64 = 0; response.ContentEncoding = Encoding.UTF8; response.KeepAlive = false; response.StatusCode = 503; try { response.Send(); } catch { } }
internal void DoHTTPGruntWork(BaseHttpServer server, Hashtable responsedata) { OSHttpResponse response = new OSHttpResponse(new HttpResponse(HttpContext, Request), HttpContext); byte[] buffer = server.DoHTTPGruntWork(responsedata, response); response.SendChunked = false; response.ContentLength64 = buffer.Length; response.ContentEncoding = Encoding.UTF8; try { response.OutputStream.Write(buffer, 0, buffer.Length); } catch (Exception ex) { m_log.Warn(string.Format("[POLL SERVICE WORKER THREAD]: Error ", ex)); } finally { //response.OutputStream.Close(); try { response.OutputStream.Flush(); response.Send(); //if (!response.KeepAlive && response.ReuseContext) // response.FreeContext(); } catch (Exception e) { m_log.Warn(String.Format("[POLL SERVICE WORKER THREAD]: Error ", e)); } PollServiceArgs.RequestsHandled++; } }
internal void DoHTTPGruntWork(Hashtable responsedata, OSHttpResponse response) { //m_log.Info("[BASE HTTP SERVER]: Doing HTTP Grunt work with response"); int responsecode = (int)responsedata["int_response_code"]; string responseString = (string)responsedata["str_response_string"]; string contentType = (string)responsedata["content_type"]; 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")) { bool keepalive = (bool)responsedata["keepalive"]; response.KeepAlive = keepalive; } if (responsedata.ContainsKey("reusecontext")) response.ReuseContext = (bool) responsedata["reusecontext"]; // Cross-Origin Resource Sharing with simple requests if (responsedata.ContainsKey("access_control_allow_origin")) response.AddHeader("Access-Control-Allow-Origin", (string)responsedata["access_control_allow_origin"]); //Even though only one other part of the entire code uses HTTPHandlers, we shouldn't expect this //and should check for NullReferenceExceptions if (string.IsNullOrEmpty(contentType)) { contentType = "text/html"; } // The client ignores anything but 200 here for web login, so ensure that this is 200 for that response.StatusCode = responsecode; if (responsecode == (int)OSHttpStatusCode.RedirectMovedPermanently) { response.RedirectLocation = (string)responsedata["str_redirect_location"]; response.StatusCode = responsecode; } response.AddHeader("Content-Type", contentType); byte[] buffer; if (!(contentType.Contains("image") || contentType.Contains("x-shockwave-flash") || contentType.Contains("application/x-oar") || contentType.Contains("application/vnd.ll.mesh"))) { // Text buffer = Encoding.UTF8.GetBytes(responseString); } else { // Binary! buffer = Convert.FromBase64String(responseString); } response.SendChunked = false; response.ContentLength64 = buffer.Length; response.ContentEncoding = Encoding.UTF8; try { response.OutputStream.Write(buffer, 0, buffer.Length); } catch (Exception ex) { m_log.Warn("[HTTPD]: Error - " + ex.Message); } finally { //response.OutputStream.Close(); try { response.OutputStream.Flush(); response.Send(); //if (!response.KeepAlive && response.ReuseContext) // response.FreeContext(); } catch (SocketException e) { // This has to be here to prevent a Linux/Mono crash m_log.WarnFormat("[BASE HTTP SERVER]: XmlRpcRequest issue {0}.\nNOTE: this may be spurious on Linux.", e); } catch (IOException e) { m_log.Warn("[BASE HTTP SERVER]: XmlRpcRequest issue: " + e.Message); } } }
/// <summary> /// Get the user's display name, currently not used? /// </summary> /// <param name = "mDhttpMethod"></param> /// <param name = "agentID"></param> /// <returns></returns> private byte[] ProcessGetDisplayName(string path, Stream request, OSHttpRequest httpRequest, OSHttpResponse httpResponse) { //I've never seen this come in, so for now... do nothing NameValueCollection query = HttpUtility.ParseQueryString(httpRequest.Url.Query); string[] ids = query.GetValues("ids"); string username = query.GetOne("username"); OSDMap map = new OSDMap(); OSDArray agents = new OSDArray(); OSDArray bad_ids = new OSDArray(); OSDArray bad_usernames = new OSDArray(); if (ids != null) { foreach (string id in ids) { UserAccount account = m_userService.GetUserAccount(UUID.Zero, UUID.Parse(id)); if (account != null) { IUserProfileInfo info = DataManager.RequestPlugin<IProfileConnector>().GetUserProfile(account.PrincipalID); if (info != null) PackUserInfo(info, account, ref agents); else PackUserInfo(info, account, ref agents); //else //Technically is right, but needs to be packed no matter what for OS based grids // bad_ids.Add (id); } } } else if (username != null) { UserAccount account = m_userService.GetUserAccount(UUID.Zero, username.Replace('.', ' ')); if (account != null) { IUserProfileInfo info = DataManager.RequestPlugin<IProfileConnector>().GetUserProfile(account.PrincipalID); if (info != null) PackUserInfo(info, account, ref agents); else bad_usernames.Add(username); } } map["agents"] = agents; map["bad_ids"] = bad_ids; map["bad_usernames"] = bad_usernames; byte[] m = OSDParser.SerializeLLSDXmlBytes(map); httpResponse.Body.Write(m, 0, m.Length); httpResponse.StatusCode = (int) HttpStatusCode.OK; httpResponse.Send(); return null; }
/// <summary> /// A specific agent handler was provided. Such a handler is expecetd to have an /// intimate, and highly specific relationship with the client. Consequently, /// nothing is done here. /// </summary> /// <param name="handler"></param> /// <param name="request"></param> /// <param name="response"></param> private bool HandleAgentRequest(IHttpAgentHandler handler, OSHttpRequest request, OSHttpResponse response) { // In the case of REST, then handler is responsible for ALL aspects of // the request/response handling. Nothing is done here, not even encoding. try { return handler.Handle(request, response); } catch (Exception e) { // If the handler did in fact close the stream, then this will blow // chunks. So that that doesn't disturb anybody we throw away any // and all exceptions raised. We've done our best to release the // client. try { m_log.Warn("[HTTP-AGENT]: Error - " + e.Message); response.SendChunked = false; response.KeepAlive = true; response.StatusCode = (int)OSHttpStatusCode.ServerErrorInternalError; //response.OutputStream.Close(); try { response.Send(); //response.FreeContext(); } catch (SocketException f) { // This has to be here to prevent a Linux/Mono crash m_log.WarnFormat( "[BASE HTTP SERVER]: XmlRpcRequest issue {0}.\nNOTE: this may be spurious on Linux.", f); } } catch(Exception) { } } // Indicate that the request has been "handled" return true; }
public void Engine() { OSHttpRequest req = null; while (true) { try { // dequeue an OSHttpRequest from OSHttpServer's // request queue req = _queue.Dequeue(); // get a copy of the list of registered handlers List<OSHttpHandler> handlers = _server.OSHttpHandlers; // prune list and have it sorted from most // specific to least specific handlers = MatchHandlers(req, handlers); // process req: we try each handler in turn until // we are either out of handlers or get back a // Pass or Done OSHttpHandlerResult rc = OSHttpHandlerResult.Unprocessed; foreach (OSHttpHandler h in handlers) { rc = h.Process(req); // Pass: handler did not process the request, // try next handler if (OSHttpHandlerResult.Pass == rc) continue; // Handled: handler has processed the request if (OSHttpHandlerResult.Done == rc) break; // hmm, something went wrong throw new Exception(String.Format("[{0}] got unexpected OSHttpHandlerResult {1}", EngineID, rc)); } if (OSHttpHandlerResult.Unprocessed == rc) { _log.InfoFormat("[{0}] OSHttpHandler: no handler registered for {1}", EngineID, req); // set up response header OSHttpResponse resp = new OSHttpResponse(req); resp.StatusCode = (int)OSHttpStatusCode.ClientErrorNotFound; resp.StatusDescription = String.Format("no handler on call for {0}", req); resp.ContentType = "text/html"; // add explanatory message StreamWriter body = new StreamWriter(resp.Body); body.WriteLine("<html>"); body.WriteLine("<header><title>Ooops...</title><header>"); body.WriteLine(String.Format("<body><p>{0}</p></body>", resp.StatusDescription)); body.WriteLine("</html>"); body.Flush(); // and ship it back resp.Send(); } } catch (Exception e) { _log.DebugFormat("[{0}] OSHttpHandler problem: {1}", EngineID, e.ToString()); _log.ErrorFormat("[{0}] OSHttpHandler problem: {1}", EngineID, e.Message); } } }
// public void ConvertIHttpClientContextToOSHttp(object stateinfo) // { // HttpServerContextObj objstate = (HttpServerContextObj)stateinfo; // OSHttpRequest request = objstate.oreq; // OSHttpResponse resp = objstate.oresp; // HandleRequest(request,resp); // } /// <summary> /// This methods is the start of incoming HTTP request handling. /// </summary> /// <param name="request"></param> /// <param name="response"></param> public virtual void HandleRequest(OSHttpRequest request, OSHttpResponse response) { if (request.HttpMethod == String.Empty) // Can't handle empty requests, not wasting a thread { try { byte[] buffer500 = SendHTML500(response); response.Body.Write(buffer500,0,buffer500.Length); response.Body.Close(); } catch { } return; } string requestMethod = request.HttpMethod; string uriString = request.RawUrl; int requestStartTick = Environment.TickCount; // Will be adjusted later on. int requestEndTick = requestStartTick; IRequestHandler requestHandler = 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); Culture.SetCurrentCulture(); // // This is the REST agent interface. We require an agent to properly identify // // itself. If the REST handler recognizes the prefix it will attempt to // // satisfy the request. If it is not recognizable, and no damage has occurred // // the request can be passed through to the other handlers. This is a low // // probability event; if a request is matched it is normally expected to be // // handled // IHttpAgentHandler agentHandler; // // if (TryGetAgentHandler(request, response, out agentHandler)) // { // if (HandleAgentRequest(agentHandler, request, response)) // { // requestEndTick = Environment.TickCount; // return; // } // } //response.KeepAlive = true; response.SendChunked = false; string path = request.RawUrl; string handlerKey = GetHandlerKey(request.HttpMethod, path); byte[] buffer = null; if (TryGetStreamHandler(handlerKey, out requestHandler)) { if (DebugLevel >= 3) LogIncomingToStreamHandler(request, requestHandler); response.ContentType = requestHandler.ContentType; // Lets do this defaulting before in case handler has varying content type. if (requestHandler is IStreamedRequestHandler) { IStreamedRequestHandler streamedRequestHandler = requestHandler as IStreamedRequestHandler; buffer = streamedRequestHandler.Handle(path, request.InputStream, request, response); } else if (requestHandler is IGenericHTTPHandler) { //m_log.Debug("[BASE HTTP SERVER]: Found Caps based HTTP Handler"); IGenericHTTPHandler HTTPRequestHandler = requestHandler as IGenericHTTPHandler; Stream requestStream = request.InputStream; Encoding encoding = Encoding.UTF8; StreamReader reader = new StreamReader(requestStream, encoding); string requestBody = reader.ReadToEnd(); reader.Close(); //requestStream.Close(); Hashtable keysvals = new Hashtable(); Hashtable headervals = new Hashtable(); //string host = String.Empty; string[] querystringkeys = request.QueryString.AllKeys; string[] rHeaders = request.Headers.AllKeys; foreach (string queryname in querystringkeys) { keysvals.Add(queryname, request.QueryString[queryname]); } foreach (string headername in rHeaders) { //m_log.Warn("[HEADER]: " + headername + "=" + request.Headers[headername]); headervals[headername] = request.Headers[headername]; } // if (headervals.Contains("Host")) // { // host = (string)headervals["Host"]; // } keysvals.Add("requestbody", requestBody); keysvals.Add("headers",headervals); if (keysvals.Contains("method")) { //m_log.Warn("[HTTP]: Contains Method"); //string method = (string)keysvals["method"]; //m_log.Warn("[HTTP]: " + requestBody); } buffer = DoHTTPGruntWork(HTTPRequestHandler.Handle(path, keysvals), response); } else { IStreamHandler streamHandler = (IStreamHandler)requestHandler; using (MemoryStream memoryStream = new MemoryStream()) { streamHandler.Handle(path, request.InputStream, memoryStream, request, response); memoryStream.Flush(); buffer = memoryStream.ToArray(); } } } else { switch (request.ContentType) { case null: case "text/html": if (DebugLevel >= 3) LogIncomingToContentTypeHandler(request); buffer = HandleHTTPRequest(request, response); break; case "application/llsd+xml": case "application/xml+llsd": case "application/llsd+json": if (DebugLevel >= 3) LogIncomingToContentTypeHandler(request); buffer = HandleLLSDRequests(request, response); break; case "application/json-rpc": if (DebugLevel >= 3) LogIncomingToContentTypeHandler(request); buffer = HandleJsonRpcRequests(request, response); break; case "text/xml": case "application/xml": case "application/json": default: //m_log.Info("[Debug BASE HTTP SERVER]: in default handler"); // Point of note.. the DoWeHaveA methods check for an EXACT path // if (request.RawUrl.Contains("/CAPS/EQG")) // { // int i = 1; // } //m_log.Info("[Debug BASE HTTP SERVER]: Checking for LLSD Handler"); if (DoWeHaveALLSDHandler(request.RawUrl)) { if (DebugLevel >= 3) LogIncomingToContentTypeHandler(request); buffer = HandleLLSDRequests(request, response); } // m_log.DebugFormat("[BASE HTTP SERVER]: Checking for HTTP Handler for request {0}", request.RawUrl); else if (DoWeHaveAHTTPHandler(request.RawUrl)) { if (DebugLevel >= 3) LogIncomingToContentTypeHandler(request); buffer = HandleHTTPRequest(request, response); } else { if (DebugLevel >= 3) LogIncomingToXmlRpcHandler(request); // generic login request. buffer = HandleXmlRpcRequests(request, response); } break; } } request.InputStream.Close(); if (buffer != null) { if (!response.SendChunked && response.ContentLength64 <= 0) response.ContentLength64 = buffer.LongLength; response.OutputStream.Write(buffer, 0, buffer.Length); } // Do not include the time taken to actually send the response to the caller in the measurement // time. This is to avoid logging when it's the client that is slow to process rather than the // server requestEndTick = Environment.TickCount; response.Send(); //response.OutputStream.Close(); //response.FreeContext(); } catch (SocketException e) { // At least on linux, it appears that if the client makes a request without requiring the response, // an unconnected socket exception is thrown when we close the response output stream. There's no // obvious way to tell if the client didn't require the response, so instead we'll catch and ignore // the exception instead. // // 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); } catch (IOException e) { m_log.Error(String.Format("[BASE HTTP SERVER]: HandleRequest() threw {0} ", e.StackTrace), e); } catch (Exception e) { m_log.Error(String.Format("[BASE HTTP SERVER]: HandleRequest() threw {0} ", e.StackTrace), e); try { byte[] buffer500 = SendHTML500(response); response.Body.Write(buffer500, 0, buffer500.Length); response.Body.Close(); } catch { } } finally { // Every month or so this will wrap and give bad numbers, not really a problem // since its just for reporting int tickdiff = requestEndTick - requestStartTick; if (tickdiff > 3000 && requestHandler != null && requestHandler.Name != "GetTexture") { m_log.InfoFormat( "[BASE HTTP SERVER]: 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.RemoteIPEndPoint, tickdiff); } else if (DebugLevel >= 4) { m_log.DebugFormat( "[BASE HTTP SERVER]: HTTP IN {0} :{1} took {2}ms", RequestNumber, Port, tickdiff); } } }
private byte[] ProcessGetTexture(string path, Stream request, OSHttpRequest httpRequest, OSHttpResponse httpResponse) { // TODO: Change this to a config option const string REDIRECT_URL = null; // Try to parse the texture ID from the request URL NameValueCollection query = HttpUtility.ParseQueryString(httpRequest.Url.Query); string textureStr = query.GetOne("texture_id"); if (m_assetService == null) { m_log.Error("[GETTEXTURE]: Cannot fetch texture " + textureStr + " without an asset service"); httpResponse.StatusCode = (int)System.Net.HttpStatusCode.NotFound; return null; } UUID textureID; if (!String.IsNullOrEmpty(textureStr) && UUID.TryParse(textureStr, out textureID)) { //m_log.DebugFormat("[GETTEXTURE]: {0}", textureID); AssetBase texture; if (!String.IsNullOrEmpty(REDIRECT_URL)) { // Only try to fetch locally cached textures. Misses are redirected texture = m_assetService.GetCached(textureID.ToString()); if (texture != null) { if (texture.Type != (sbyte)AssetType.Texture) { httpResponse.StatusCode = (int)System.Net.HttpStatusCode.NotFound; httpResponse.Send(); return null; } SendTexture(httpRequest, httpResponse, texture); } else { string textureUrl = REDIRECT_URL + textureID.ToString(); m_log.Debug("[GETTEXTURE]: Redirecting texture request to " + textureUrl); httpResponse.RedirectLocation = textureUrl; } } else { // Fetch locally or remotely. Misses return a 404 texture = m_assetService.Get(textureID.ToString()); if (texture != null) { if (texture.Type != (sbyte)AssetType.Texture) { httpResponse.StatusCode = (int)System.Net.HttpStatusCode.NotFound; httpResponse.Send(); return null; } SendTexture(httpRequest, httpResponse, texture); } else { m_log.Warn("[GETTEXTURE]: Texture " + textureID + " not found"); httpResponse.StatusCode = (int)System.Net.HttpStatusCode.NotFound; } } } else { m_log.Warn("[GETTEXTURE]: Failed to parse a texture_id from GetTexture request: " + httpRequest.Url); } httpResponse.Send(); return null; }
private byte[] ProcessGetTexture(string path, Stream request, OSHttpRequest httpRequest, OSHttpResponse httpResponse) { //m_log.DebugFormat("[GETTEXTURE]: called in {0}", m_scene.RegionInfo.RegionName); // Try to parse the texture ID from the request URL NameValueCollection query = HttpUtility.ParseQueryString(httpRequest.Url.Query); string textureStr = query.GetOne("texture_id"); string format = query.GetOne("format"); if (m_assetService == null) { m_log.Error("[GETTEXTURE]: Cannot fetch texture " + textureStr + " without an asset service"); httpResponse.StatusCode = (int)System.Net.HttpStatusCode.NotFound; return null; } UUID textureID; if (!String.IsNullOrEmpty(textureStr) && UUID.TryParse(textureStr, out textureID)) { string[] formats; if (format != null && format != string.Empty) { formats = new string[1] { format.ToLower() }; } else { formats = WebUtil.GetPreferredImageTypes(httpRequest.Headers.Get("Accept")); if (formats.Length == 0) formats = new string[1] { DefaultFormat }; // default } // OK, we have an array with preferred formats, possibly with only one entry httpResponse.StatusCode = (int)System.Net.HttpStatusCode.NotFound; foreach (string f in formats) { if (FetchTexture(httpRequest, httpResponse, textureID, f)) break; } } else { m_log.Warn("[GETTEXTURE]: Failed to parse a texture_id from GetTexture request: " + httpRequest.Url); } httpResponse.Send(); return null; }
/// <summary> /// Get the user's display name, currently not used? /// </summary> /// <param name="mDhttpMethod"></param> /// <param name="agentID"></param> /// <returns></returns> private byte[] ProcessGetDisplayName(string path, Stream request, OSHttpRequest httpRequest, OSHttpResponse httpResponse) { //I've never seen this come in, so for now... do nothing NameValueCollection query = HttpUtility.ParseQueryString (httpRequest.Url.Query); string[] ids = query.GetValues ("ids"); string username = query.GetOne ("username"); OSDMap map = new OSDMap (); OSDArray agents = new OSDArray (); OSDArray bad_ids = new OSDArray (); OSDArray bad_usernames = new OSDArray (); if (ids != null) { foreach (string id in ids) { UserAccount account = m_userService.GetUserAccount (UUID.Zero, UUID.Parse (id)); if (account != null) { IUserProfileInfo info = Aurora.DataManager.DataManager.RequestPlugin<IProfileConnector> ().GetUserProfile (UUID.Parse (id)); if (info != null) PackUserInfo (info, account, ref agents); else bad_ids.Add (id); } } } //TODO: usernames map["agents"] = agents; map["bad_ids"] = bad_ids; map["bad_usernames"] = bad_usernames; byte[] m = OSDParser.SerializeLLSDXmlBytes (map); httpResponse.Body.Write (m, 0, m.Length); httpResponse.StatusCode = (int)System.Net.HttpStatusCode.OK; httpResponse.Send (); return null; }
internal void DoHTTPGruntWork(Hashtable responsedata) { if (Request.Body.CanRead) { Request.Body.Dispose(); } if (responsedata.Contains("h")) { OSHttpResponse r = (OSHttpResponse)responsedata["h"]; try { r.Send(); } catch { } PollServiceArgs.RequestsHandled++; return; } OSHttpResponse response = new OSHttpResponse(new HttpResponse(Request)); if (responsedata == null) { SendNoContentError(response); return; } int responsecode = 200; string responseString = String.Empty; string contentType; byte[] buffer = null; int rangeStart = 0; int rangeLen = -1; try { //m_log.Info("[BASE HTTP SERVER]: Doing HTTP Grunt work with response"); if (responsedata["int_response_code"] != null) { responsecode = (int)responsedata["int_response_code"]; } if (responsedata["bin_response_data"] != null) { buffer = (byte[])responsedata["bin_response_data"]; responsedata["bin_response_data"] = null; if (responsedata["bin_start"] != null) { rangeStart = (int)responsedata["bin_start"]; } if (responsedata["int_bytes"] != null) { rangeLen = (int)responsedata["int_bytes"]; } } else { responseString = (string)responsedata["str_response_string"]; } contentType = (string)responsedata["content_type"]; if (responseString == null) { responseString = String.Empty; } } catch { SendNoContentError(response); return; } response.StatusCode = responsecode; if (responsecode == (int)HttpStatusCode.Moved) { response.AddHeader("Location", (string)responsedata["str_redirect_location"]); response.KeepAlive = false; PollServiceArgs.RequestsHandled++; response.Send(); return; } if (responsedata.ContainsKey("http_protocol_version")) { response.ProtocolVersion = (string)responsedata["http_protocol_version"]; } if (responsedata.ContainsKey("keepalive")) { response.KeepAlive = (bool)responsedata["keepalive"]; } if (responsedata.ContainsKey("keepaliveTimeout")) { response.KeepAliveTimeout = (int)responsedata["keepaliveTimeout"]; } if (responsedata.ContainsKey("prio")) { response.Priority = (int)responsedata["prio"]; } if (responsedata.ContainsKey("error_status_text")) { response.StatusDescription = (string)responsedata["error_status_text"]; } // Cross-Origin Resource Sharing with simple requests if (responsedata.ContainsKey("access_control_allow_origin")) { response.AddHeader("Access-Control-Allow-Origin", (string)responsedata["access_control_allow_origin"]); } if (string.IsNullOrEmpty(contentType)) { response.AddHeader("Content-Type", "text/html"); } else { response.AddHeader("Content-Type", contentType); } if (responsedata.ContainsKey("headers")) { Hashtable headerdata = (Hashtable)responsedata["headers"]; foreach (string header in headerdata.Keys) { response.AddHeader(header, headerdata[header].ToString()); } } if (buffer == null) { if (contentType != null && (!(contentType.Contains("image") || contentType.Contains("x-shockwave-flash") || contentType.Contains("application/x-oar") || contentType.Contains("application/vnd.ll.mesh")))) { // Text buffer = Encoding.UTF8.GetBytes(responseString); } else { // Binary! buffer = Convert.FromBase64String(responseString); } response.ContentEncoding = Encoding.UTF8; } if (rangeStart < 0 || rangeStart > buffer.Length) { rangeStart = 0; } if (rangeLen < 0) { rangeLen = buffer.Length; } else if (rangeLen + rangeStart > buffer.Length) { rangeLen = buffer.Length - rangeStart; } response.ContentLength64 = rangeLen; try { if (rangeLen > 0) { response.RawBufferStart = rangeStart; response.RawBufferLen = rangeLen; response.RawBuffer = buffer; //response.OutputStream.Write(buffer, rangeStart, rangeLen); } buffer = null; response.Send(); } catch (Exception ex) { if (ex is System.Net.Sockets.SocketException) { // only mute connection reset by peer so we are not totally blind for now if (((System.Net.Sockets.SocketException)ex).SocketErrorCode != System.Net.Sockets.SocketError.ConnectionReset) { m_log.Warn("[POLL SERVICE WORKER THREAD]: Error ", ex); } } else { m_log.Warn("[POLL SERVICE WORKER THREAD]: Error ", ex); } } PollServiceArgs.RequestsHandled++; }
/// <summary> /// Invoked by OSHttpRequestPump. /// </summary> public override OSHttpHandlerResult Process(OSHttpRequest request) { XmlRpcResponse xmlRpcResponse; string responseString; // check whether we are interested in this request if (!XmlRpcMethodMatch(request)) return OSHttpHandlerResult.Pass; OSHttpResponse resp = new OSHttpResponse(request); try { // reified XmlRpcRequest must still be on the whiteboard XmlRpcRequest xmlRpcRequest = request.Whiteboard["xmlrequest"] as XmlRpcRequest; xmlRpcResponse = _handler(xmlRpcRequest); responseString = XmlRpcResponseSerializer.Singleton.Serialize(xmlRpcResponse); resp.ContentType = "text/xml"; byte[] buffer = Encoding.UTF8.GetBytes(responseString); resp.SendChunked = false; resp.ContentLength = buffer.Length; resp.ContentEncoding = Encoding.UTF8; resp.Body.Write(buffer, 0, buffer.Length); resp.Body.Flush(); resp.Send(); } catch (Exception ex) { _log.WarnFormat("[OSHttpXmlRpcHandler]: Error: {0}", ex.Message); return OSHttpHandlerResult.Pass; } return OSHttpHandlerResult.Done; }
public void Engine() { OSHttpRequest req = null; while (true) { try { // dequeue an OSHttpRequest from OSHttpServer's // request queue req = _queue.Dequeue(); // get a copy of the list of registered handlers List <OSHttpHandler> handlers = _server.OSHttpHandlers; // prune list and have it sorted from most // specific to least specific handlers = MatchHandlers(req, handlers); // process req: we try each handler in turn until // we are either out of handlers or get back a // Pass or Done OSHttpHandlerResult rc = OSHttpHandlerResult.Unprocessed; foreach (OSHttpHandler h in handlers) { rc = h.Process(req); // Pass: handler did not process the request, // try next handler if (OSHttpHandlerResult.Pass == rc) { continue; } // Handled: handler has processed the request if (OSHttpHandlerResult.Done == rc) { break; } // hmm, something went wrong throw new Exception(String.Format("[{0}] got unexpected OSHttpHandlerResult {1}", EngineID, rc)); } if (OSHttpHandlerResult.Unprocessed == rc) { _log.InfoFormat("[{0}] OSHttpHandler: no handler registered for {1}", EngineID, req); // set up response header OSHttpResponse resp = new OSHttpResponse(req); resp.StatusCode = (int)OSHttpStatusCode.ClientErrorNotFound; resp.StatusDescription = String.Format("no handler on call for {0}", req); resp.ContentType = "text/html"; // add explanatory message StreamWriter body = new StreamWriter(resp.Body); body.WriteLine("<html>"); body.WriteLine("<header><title>Ooops...</title><header>"); body.WriteLine(String.Format("<body><p>{0}</p></body>", resp.StatusDescription)); body.WriteLine("</html>"); body.Flush(); // and ship it back resp.Send(); } } catch (Exception e) { _log.DebugFormat("[{0}] OSHttpHandler problem: {1}", EngineID, e.ToString()); _log.ErrorFormat("[{0}] OSHttpHandler problem: {1}", EngineID, e.Message); } } }
/// <summary> /// Try all the registered xmlrpc handlers when an xmlrpc request is received. /// Sends back an XMLRPC unknown request response if no handler is registered for the requested method. /// </summary> /// <param name="request"></param> /// <param name="response"></param> private void HandleXmlRpcRequests(OSHttpRequest request, OSHttpResponse response) { Stream requestStream = request.InputStream; Encoding encoding = Encoding.UTF8; StreamReader reader = new StreamReader(requestStream, encoding); string requestBody = reader.ReadToEnd(); reader.Close(); requestStream.Close(); //m_log.Debug(requestBody); requestBody = requestBody.Replace("<base64></base64>", ""); string responseString = String.Empty; XmlRpcRequest xmlRprcRequest = null; try { xmlRprcRequest = (XmlRpcRequest) (new XmlRpcRequestDeserializer()).Deserialize(requestBody); } catch (XmlException) { } if (xmlRprcRequest != null) { string methodName = xmlRprcRequest.MethodName; if (methodName != null) { xmlRprcRequest.Params.Add(request.RemoteIPEndPoint); // Param[1] XmlRpcResponse xmlRpcResponse; XmlRpcMethod method; bool methodWasFound; bool keepAlive = false; lock (m_rpcHandlers) { methodWasFound = m_rpcHandlers.TryGetValue(methodName, out method); if (methodWasFound) keepAlive = m_rpcHandlersKeepAlive[methodName]; } if (methodWasFound) { 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)) { xff = xfflower; break; } } xmlRprcRequest.Params.Add(request.Headers.Get(xff)); // Param[3] try { xmlRpcResponse = method(xmlRprcRequest, request.RemoteIPEndPoint); } 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); // if the registered XmlRpc method threw an exception, we pass a fault-code along xmlRpcResponse = new XmlRpcResponse(); // Code probably set in accordance with http://xmlrpc-epi.sourceforge.net/specs/rfc.fault_codes.php xmlRpcResponse.SetFault(-32603, errorMessage); } // if the method wasn't found, we can't determine KeepAlive state anyway, so lets do it only here response.KeepAlive = keepAlive; } else { xmlRpcResponse = new XmlRpcResponse(); // Code set in accordance with http://xmlrpc-epi.sourceforge.net/specs/rfc.fault_codes.php xmlRpcResponse.SetFault( XmlRpcErrorCodes.SERVER_ERROR_METHOD, String.Format("Requested method [{0}] not found", methodName)); } responseString = XmlRpcResponseSerializer.Singleton.Serialize(xmlRpcResponse); } else { //HandleLLSDRequests(request, response); response.ContentType = "text/plain"; response.StatusCode = 404; response.StatusDescription = "Not Found"; response.ProtocolVersion = "HTTP/1.0"; byte[] buf = Encoding.UTF8.GetBytes("Not found"); response.KeepAlive = false; m_log.ErrorFormat("[BASE HTTP SERVER]: Handler not found for http request {0}", request.RawUrl); response.SendChunked = false; response.ContentLength64 = buf.Length; response.ContentEncoding = Encoding.UTF8; try { response.OutputStream.Write(buf, 0, buf.Length); } catch (Exception ex) { m_log.Warn("[BASE HTTP SERVER]: Error - " + ex.Message); } finally { try { response.Send(); //response.FreeContext(); } catch (SocketException e) { // This has to be here to prevent a Linux/Mono crash m_log.WarnFormat("[BASE HTTP SERVER]: XmlRpcRequest issue {0}.\nNOTE: this may be spurious on Linux.", e); } catch (IOException e) { m_log.Warn("[BASE HTTP SERVER]: XmlRpcRequest issue: " + e.Message); } } return; //responseString = "Error"; } } response.ContentType = "text/xml"; byte[] buffer = Encoding.UTF8.GetBytes(responseString); response.SendChunked = false; response.ContentLength64 = buffer.Length; response.ContentEncoding = Encoding.UTF8; try { response.OutputStream.Write(buffer, 0, buffer.Length); } catch (Exception ex) { m_log.Warn("[BASE HTTP SERVER]: Error - " + ex.Message); } finally { try { response.Send(); //response.FreeContext(); } catch (SocketException e) { // This has to be here to prevent a Linux/Mono crash m_log.WarnFormat("[BASE HTTP SERVER]: XmlRpcRequest issue {0}.\nNOTE: this may be spurious on Linux.", e); } catch (IOException e) { m_log.Warn("[BASE HTTP SERVER]: XmlRpcRequest issue: " + e.Message); } } }
string HandleVoxelChunkReq(string request, string path, string param, OSHttpRequest httpRequest, OSHttpResponse httpResponse) { // Try to parse the texture ID from the request URL NameValueCollection query = HttpUtility.ParseQueryString(httpRequest.Url.Query); int X, Y,Z=0; if (!int.TryParse(query.GetOne("x"), out X) || !int.TryParse(query.GetOne("y"), out Y)) { httpResponse.StatusCode = 404; httpResponse.Send(); return null; } if (X < 0 || X > m_scene.Voxels.Width / VoxelChannel.CHUNK_SIZE_X || Y < 0 || Y > m_scene.Voxels.Length / VoxelChannel.CHUNK_SIZE_Y || Z < 0 || Z > m_scene.Voxels.Height / VoxelChannel.CHUNK_SIZE_Z) { httpResponse.StatusCode = 404; httpResponse.Send(); return null; } SendChunk(httpRequest, httpResponse, X, Y); httpResponse.Send(); return null; }
private byte[] ProcessAvatarPickerSearch(string path, Stream request, OSHttpRequest httpRequest, OSHttpResponse httpResponse) { NameValueCollection query = HttpUtility.ParseQueryString(httpRequest.Url.Query); string amt = query.GetOne("page-size"); string name = query.GetOne("names"); List<UserAccount> accounts = m_service.Registry.RequestModuleInterface<IUserAccountService>().GetUserAccounts(UUID.Zero, name); if (accounts == null) accounts = new List<UserAccount>(0); OSDMap body = new OSDMap(); OSDArray array = new OSDArray(); foreach (UserAccount account in accounts) { OSDMap map = new OSDMap(); map["agent_id"] = account.PrincipalID; IUserProfileInfo profileInfo = Aurora.DataManager.DataManager.RequestPlugin<IProfileConnector>().GetUserProfile(account.PrincipalID); map["display_name"] = (profileInfo == null || profileInfo.DisplayName == "") ? account.Name : profileInfo.DisplayName; map["username"] = account.Name; array.Add(map); } body["agents"] = array; byte[] m = OSDParser.SerializeLLSDXmlBytes(body); httpResponse.Body.Write(m, 0, m.Length); httpResponse.StatusCode = (int)System.Net.HttpStatusCode.OK; httpResponse.Send(); return null; }
public void SendHTML500(OSHttpResponse response) { // I know this statuscode is dumb, but the client doesn't respond to 404s and 500s response.StatusCode = (int)OSHttpStatusCode.SuccessOk; response.AddHeader("Content-type", "text/html"); string responseString = GetHTTP500(); byte[] buffer = Encoding.UTF8.GetBytes(responseString); response.SendChunked = false; response.ContentLength64 = buffer.Length; response.ContentEncoding = Encoding.UTF8; try { response.OutputStream.Write(buffer, 0, buffer.Length); } catch (Exception ex) { m_log.Warn("[BASE HTTP SERVER]: Error - " + ex.Message); } finally { //response.OutputStream.Close(); try { response.Send(); //response.FreeContext(); } catch (SocketException e) { // This has to be here to prevent a Linux/Mono crash m_log.WarnFormat("[BASE HTTP SERVER] XmlRpcRequest issue {0}.\nNOTE: this may be spurious on Linux.", e); } } }
/// <summary> /// Invoked by OSHttpRequestPump. /// </summary> public override OSHttpHandlerResult Process(OSHttpRequest request) { // call handler method Hashtable responseData = _handler(request.Query); int responseCode = (int)responseData["int_response_code"]; string responseString = (string)responseData["str_response_string"]; string contentType = (string)responseData["content_type"]; //Even though only one other part of the entire code uses HTTPHandlers, we shouldn't expect this //and should check for NullReferenceExceptions if (string.IsNullOrEmpty(contentType)) { contentType = "text/html"; } OSHttpResponse response = new OSHttpResponse(request); // We're forgoing the usual error status codes here because the client // ignores anything but 200 and 301 response.StatusCode = (int)OSHttpStatusCode.SuccessOk; if (responseCode == (int)OSHttpStatusCode.RedirectMovedPermanently) { response.RedirectLocation = (string)responseData["str_redirect_location"]; response.StatusCode = responseCode; } response.AddHeader("Content-type", contentType); byte[] buffer; if (!contentType.Contains("image")) { buffer = Encoding.UTF8.GetBytes(responseString); } else { buffer = Convert.FromBase64String(responseString); } response.SendChunked = false; response.ContentLength64 = buffer.Length; response.ContentEncoding = Encoding.UTF8; try { response.Body.Write(buffer, 0, buffer.Length); } catch (Exception ex) { _log.ErrorFormat("[OSHttpHttpHandler]: Error: {0}", ex.Message); } finally { response.Send(); } return OSHttpHandlerResult.Done; }
// public void ConvertIHttpClientContextToOSHttp(object stateinfo) // { // HttpServerContextObj objstate = (HttpServerContextObj)stateinfo; // OSHttpRequest request = objstate.oreq; // OSHttpResponse resp = objstate.oresp; // HandleRequest(request,resp); // } /// <summary> /// This methods is the start of incoming HTTP request handling. /// </summary> /// <param name="request"></param> /// <param name="response"></param> public virtual void HandleRequest(OSHttpRequest request, OSHttpResponse response) { if (request.HttpMethod == String.Empty) // Can't handle empty requests, not wasting a thread { try { SendHTML500(response); } catch { } return; } string requestMethod = request.HttpMethod; string uriString = request.RawUrl; // string reqnum = "unknown"; int tickstart = Environment.TickCount; 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); Thread.CurrentThread.CurrentCulture = new CultureInfo("en-US", true); // This is the REST agent interface. We require an agent to properly identify // itself. If the REST handler recognizes the prefix it will attempt to // satisfy the request. If it is not recognizable, and no damage has occurred // the request can be passed through to the other handlers. This is a low // probability event; if a request is matched it is normally expected to be // handled IHttpAgentHandler agentHandler; if (TryGetAgentHandler(request, response, out agentHandler)) { if (HandleAgentRequest(agentHandler, request, response)) { return; } } //response.KeepAlive = true; response.SendChunked = false; IRequestHandler requestHandler; string path = request.RawUrl; string handlerKey = GetHandlerKey(request.HttpMethod, path); // m_log.DebugFormat("[BASE HTTP SERVER]: Handling {0} request for {1}", request.HttpMethod, path); if (TryGetStreamHandler(handlerKey, out requestHandler)) { //m_log.Debug("[BASE HTTP SERVER]: Found Stream Handler"); // Okay, so this is bad, but should be considered temporary until everything is IStreamHandler. byte[] buffer = null; response.ContentType = requestHandler.ContentType; // Lets do this defaulting before in case handler has varying content type. if (requestHandler is IStreamedRequestHandler) { IStreamedRequestHandler streamedRequestHandler = requestHandler as IStreamedRequestHandler; buffer = streamedRequestHandler.Handle(path, request.InputStream, request, response); } else if (requestHandler is IGenericHTTPHandler) { //m_log.Debug("[BASE HTTP SERVER]: Found Caps based HTTP Handler"); IGenericHTTPHandler HTTPRequestHandler = requestHandler as IGenericHTTPHandler; Stream requestStream = request.InputStream; Encoding encoding = Encoding.UTF8; StreamReader reader = new StreamReader(requestStream, encoding); string requestBody = reader.ReadToEnd(); reader.Close(); //requestStream.Close(); Hashtable keysvals = new Hashtable(); Hashtable headervals = new Hashtable(); //string host = String.Empty; string[] querystringkeys = request.QueryString.AllKeys; string[] rHeaders = request.Headers.AllKeys; foreach (string queryname in querystringkeys) { keysvals.Add(queryname, request.QueryString[queryname]); } foreach (string headername in rHeaders) { //m_log.Warn("[HEADER]: " + headername + "=" + request.Headers[headername]); headervals[headername] = request.Headers[headername]; } // if (headervals.Contains("Host")) // { // host = (string)headervals["Host"]; // } keysvals.Add("requestbody", requestBody); keysvals.Add("headers",headervals); if (keysvals.Contains("method")) { //m_log.Warn("[HTTP]: Contains Method"); //string method = (string)keysvals["method"]; //m_log.Warn("[HTTP]: " + requestBody); } DoHTTPGruntWork(HTTPRequestHandler.Handle(path, keysvals), response); return; } else { IStreamHandler streamHandler = (IStreamHandler)requestHandler; using (MemoryStream memoryStream = new MemoryStream()) { streamHandler.Handle(path, request.InputStream, memoryStream, request, response); memoryStream.Flush(); buffer = memoryStream.ToArray(); } } request.InputStream.Close(); // HTTP IN support. The script engine takes it from here // Nothing to worry about for us. // if (buffer == null) return; if (!response.SendChunked) response.ContentLength64 = buffer.LongLength; try { response.OutputStream.Write(buffer, 0, buffer.Length); //response.OutputStream.Close(); } catch (HttpListenerException) { m_log.WarnFormat("[BASE HTTP SERVER]: HTTP request abnormally terminated."); } //response.OutputStream.Close(); try { response.Send(); //response.FreeContext(); } catch (SocketException e) { // This has to be here to prevent a Linux/Mono crash m_log.WarnFormat("[BASE HTTP SERVER]: XmlRpcRequest issue {0}.\nNOTE: this may be spurious on Linux.", e); } catch (IOException e) { m_log.Warn("[BASE HTTP SERVER]: XmlRpcRequest issue: " + e.Message); } return; } if (request.AcceptTypes != null && request.AcceptTypes.Length > 0) { foreach (string strAccept in request.AcceptTypes) { if (strAccept.Contains("application/llsd+xml") || strAccept.Contains("application/llsd+json")) { //m_log.Info("[Debug BASE HTTP SERVER]: Found an application/llsd+xml accept header"); HandleLLSDRequests(request, response); return; } } } switch (request.ContentType) { case null: case "text/html": // m_log.DebugFormat( // "[BASE HTTP SERVER]: Found a text/html content type for request {0}", request.RawUrl); HandleHTTPRequest(request, response); return; case "application/llsd+xml": case "application/xml+llsd": case "application/llsd+json": //m_log.Info("[Debug BASE HTTP SERVER]: found a application/llsd+xml content type"); HandleLLSDRequests(request, response); return; case "text/xml": case "application/xml": case "application/json": default: //m_log.Info("[Debug BASE HTTP SERVER]: in default handler"); // Point of note.. the DoWeHaveA methods check for an EXACT path // if (request.RawUrl.Contains("/CAPS/EQG")) // { // int i = 1; // } //m_log.Info("[Debug BASE HTTP SERVER]: Checking for LLSD Handler"); if (DoWeHaveALLSDHandler(request.RawUrl)) { //m_log.Info("[Debug BASE HTTP SERVER]: Found LLSD Handler"); HandleLLSDRequests(request, response); return; } // m_log.DebugFormat("[BASE HTTP SERVER]: Checking for HTTP Handler for request {0}", request.RawUrl); if (DoWeHaveAHTTPHandler(request.RawUrl)) { // m_log.DebugFormat("[BASE HTTP SERVER]: Found HTTP Handler for request {0}", request.RawUrl); HandleHTTPRequest(request, response); return; } //m_log.Info("[Debug BASE HTTP SERVER]: Generic XMLRPC"); // generic login request. HandleXmlRpcRequests(request, response); return; } } catch (SocketException e) { // At least on linux, it appears that if the client makes a request without requiring the response, // an unconnected socket exception is thrown when we close the response output stream. There's no // obvious way to tell if the client didn't require the response, so instead we'll catch and ignore // the exception instead. // // An alternative may be to turn off all response write exceptions on the HttpListener, but let's go // with the minimum first m_log.WarnFormat("[BASE HTTP SERVER]: HandleRequest threw {0}.\nNOTE: this may be spurious on Linux", e); } catch (IOException e) { m_log.ErrorFormat("[BASE HTTP SERVER]: HandleRequest() threw ", e); } catch (Exception e) { m_log.ErrorFormat("[BASE HTTP SERVER]: HandleRequest() threw " + e.ToString()); SendHTML500(response); } finally { // Every month or so this will wrap and give bad numbers, not really a problem // since its just for reporting, tickdiff limit can be adjusted int tickdiff = Environment.TickCount - tickstart; if (tickdiff > 3000) m_log.InfoFormat( "[BASE HTTP SERVER]: slow {0} request for {1} from {2} took {3} ms", requestMethod, uriString, request.RemoteIPEndPoint.ToString(), tickdiff); } }
public void SendHTML404(OSHttpResponse response, string host) { // I know this statuscode is dumb, but the client doesn't respond to 404s and 500s //MSIE doesn't allow for 400 pages to show... so we send 200 for now response.StatusCode = 200; //response.StatusCode = 400; response.AddHeader("Content-type", "text/html"); string responseString = GetHTTP404(host); byte[] buffer = Encoding.UTF8.GetBytes(responseString); response.SendChunked = false; response.ContentLength64 = buffer.Length; response.ContentEncoding = Encoding.UTF8; try { response.OutputStream.Write(buffer, 0, buffer.Length); } catch (Exception ex) { m_log.Warn("[BASE HTTP SERVER]: Error - " + ex.ToString()); } finally { //response.OutputStream.Close(); try { response.Send(); //response.FreeContext(); } catch (SocketException e) { // This has to be here to prevent a Linux/Mono crash m_log.WarnFormat("[BASE HTTP SERVER]: XmlRpcRequest issue {0}.\nNOTE: this may be spurious on Linux.", e); } } }
private void HandleLLSDRequests(OSHttpRequest request, OSHttpResponse response) { //m_log.Warn("[BASE HTTP SERVER]: We've figured out it's a LLSD Request"); Stream requestStream = request.InputStream; Encoding encoding = Encoding.UTF8; StreamReader reader = new StreamReader(requestStream, encoding); string requestBody = reader.ReadToEnd(); reader.Close(); requestStream.Close(); //m_log.DebugFormat("[OGP]: {0}:{1}", request.RawUrl, requestBody); response.KeepAlive = true; OSD llsdRequest = null; OSD llsdResponse = null; bool LegacyLLSDLoginLibOMV = (requestBody.Contains("passwd") && requestBody.Contains("mac") && requestBody.Contains("viewer_digest")); if (requestBody.Length == 0) // Get Request { requestBody = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><llsd><map><key>request</key><string>get</string></map></llsd>"; } try { llsdRequest = OSDParser.Deserialize(requestBody); } catch (Exception ex) { m_log.Warn("[BASE HTTP SERVER]: Error - " + ex.Message); } if (llsdRequest != null)// && m_defaultLlsdHandler != null) { LLSDMethod llsdhandler = null; if (TryGetLLSDHandler(request.RawUrl, out llsdhandler) && !LegacyLLSDLoginLibOMV) { // we found a registered llsd handler to service this request llsdResponse = llsdhandler(request.RawUrl, llsdRequest, request.RemoteIPEndPoint.ToString()); } else { // we didn't find a registered llsd handler to service this request // check if we have a default llsd handler if (m_defaultLlsdHandler != null) { // LibOMV path llsdResponse = m_defaultLlsdHandler(llsdRequest, request.RemoteIPEndPoint); } else { // Oops, no handler for this.. give em the failed message llsdResponse = GenerateNoLLSDHandlerResponse(); } } } else { llsdResponse = GenerateNoLLSDHandlerResponse(); } byte[] buffer = new byte[0]; if (llsdResponse.ToString() == "shutdown404!") { response.ContentType = "text/plain"; response.StatusCode = 404; response.StatusDescription = "Not Found"; response.ProtocolVersion = "HTTP/1.0"; buffer = Encoding.UTF8.GetBytes("Not found"); } else { // Select an appropriate response format buffer = BuildLLSDResponse(request, response, llsdResponse); } response.SendChunked = false; response.ContentLength64 = buffer.Length; response.ContentEncoding = Encoding.UTF8; response.KeepAlive = true; try { response.OutputStream.Write(buffer, 0, buffer.Length); } catch (Exception ex) { m_log.Warn("[BASE HTTP SERVER]: Error - " + ex.Message); } finally { //response.OutputStream.Close(); try { response.Send(); response.OutputStream.Flush(); //response.FreeContext(); //response.OutputStream.Close(); } catch (IOException e) { m_log.WarnFormat("[BASE HTTP SERVER]: LLSD IOException {0}.", e); } catch (SocketException e) { // This has to be here to prevent a Linux/Mono crash m_log.WarnFormat("[BASE HTTP SERVER]: LLSD issue {0}.\nNOTE: this may be spurious on Linux.", e); } } }
// public void ConvertIHttpClientContextToOSHttp(object stateinfo) // { // HttpServerContextObj objstate = (HttpServerContextObj)stateinfo; // OSHttpRequest request = objstate.oreq; // OSHttpResponse resp = objstate.oresp; // HandleRequest(request,resp); // } /// <summary> /// This methods is the start of incoming HTTP request handling. /// </summary> /// <param name="request"></param> /// <param name="response"></param> public virtual void HandleRequest(OSHttpRequest request, OSHttpResponse response) { if (request.HttpMethod == String.Empty) // Can't handle empty requests, not wasting a thread { try { SendHTML500(response); } catch { } return; } string reqnum = "unknown"; int tickstart = Environment.TickCount; string RawUrl = request.RawUrl; string HTTPMethod = request.HttpMethod; try { if (request.Headers["opensim-request-id"] != null) reqnum = String.Format("{0}:{1}", request.RemoteIPEndPoint, request.Headers["opensim-request-id"]); // MainConsole.Instance.DebugFormat("[BASE HTTP SERVER]: <{0}> handle request for {1}",reqnum,request.RawUrl); //Fix the current Culture Culture.SetCurrentCulture(); //response.KeepAlive = true; response.SendChunked = false; IRequestHandler requestHandler; string path = request.RawUrl; string handlerKey = GetHandlerKey(request.HttpMethod, path); // MainConsole.Instance.DebugFormat("[BASE HTTP SERVER]: Handling {0} request for {1}", request.HttpMethod, path); if (TryGetStreamHandler(handlerKey, out requestHandler)) { //MainConsole.Instance.Debug("[BASE HTTP SERVER]: Found Stream Handler"); // Okay, so this is bad, but should be considered temporary until everything is IStreamHandler. byte[] buffer; response.ContentType = requestHandler.ContentType; // Lets do this defaulting before in case handler has varying content type. if (requestHandler is IStreamedRequestHandler) { IStreamedRequestHandler streamedRequestHandler = requestHandler as IStreamedRequestHandler; buffer = streamedRequestHandler.Handle(path, request.InputStream, request, response); } else if (requestHandler is IGenericHTTPHandler) { //MainConsole.Instance.Debug("[BASE HTTP SERVER]: Found Caps based HTTP Handler"); IGenericHTTPHandler HTTPRequestHandler = requestHandler as IGenericHTTPHandler; Stream requestStream = request.InputStream; Encoding encoding = Encoding.UTF8; StreamReader reader = new StreamReader(requestStream, encoding); string requestBody = reader.ReadToEnd(); reader.Close(); //requestStream.Close(); Hashtable keysvals = new Hashtable(); Hashtable headervals = new Hashtable(); //string host = String.Empty; string[] querystringkeys = request.QueryString.AllKeys; string[] rHeaders = request.Headers.AllKeys; foreach (string queryname in querystringkeys) { keysvals.Add(queryname, request.QueryString[queryname]); } foreach (string headername in rHeaders) { //MainConsole.Instance.Warn("[HEADER]: " + headername + "=" + request.Headers[headername]); headervals[headername] = request.Headers[headername]; } // if (headervals.Contains("Host")) // { // host = (string)headervals["Host"]; // } keysvals.Add("requestbody", requestBody); keysvals.Add("headers", headervals); if (keysvals.Contains("method")) { //MainConsole.Instance.Warn("[HTTP]: Contains Method"); //string method = (string)keysvals["method"]; //MainConsole.Instance.Warn("[HTTP]: " + requestBody); } DoHTTPGruntWork(HTTPRequestHandler.Handle(path, keysvals), response); return; } else { IStreamHandler streamHandler = (IStreamHandler)requestHandler; using (MemoryStream memoryStream = new MemoryStream()) { streamHandler.Handle(path, request.InputStream, memoryStream, request, response); memoryStream.Flush(); buffer = memoryStream.ToArray(); } } request.InputStream.Close(); // HTTP IN support. The script engine takes it from here // Nothing to worry about for us. // if (buffer == null) return; if (!response.SendChunked) response.ContentLength64 = buffer.LongLength; try { response.OutputStream.Write(buffer, 0, buffer.Length); } catch (HttpListenerException) { MainConsole.Instance.WarnFormat("[BASE HTTP SERVER]: HTTP request abnormally terminated."); } // try { response.Send(); } catch (SocketException e) { // This has to be here to prevent a Linux/Mono crash MainConsole.Instance.WarnFormat("[BASE HTTP SERVER]: XmlRpcRequest issue {0}.\nNOTE: this may be spurious on Linux.", e); } catch (IOException e) { MainConsole.Instance.Warn("[BASE HTTP SERVER]: XmlRpcRequest issue: " + e); } response = null; //This makes timeouts VERY bad if enabled /*try { //Clean up after ourselves response.OutputStream.Close(); response.FreeContext(); } catch(Exception ex) { MainConsole.Instance.ErrorFormat("[BASE HTTP SERVER]: ISSUE WITH CLEANUP {0}", ex.ToString()); }*/ return; } if (request.AcceptTypes != null && request.AcceptTypes.Length > 0) { #if (!ISWIN) foreach (string strAccept in request.AcceptTypes) { if (strAccept.Contains("application/llsd+xml") || strAccept.Contains("application/llsd+json")) { HandleLLSDRequests(request, response); return; } } #else if (request.AcceptTypes.Any(strAccept => strAccept.Contains("application/llsd+xml") || strAccept.Contains("application/llsd+json"))) { HandleLLSDRequests(request, response); return; } #endif } switch (request.ContentType) { case null: case "text/html": case "application/x-www-form-urlencoded": // MainConsole.Instance.DebugFormat( // "[BASE HTTP SERVER]: Found a text/html content type for request {0}", request.RawUrl); HandleHTTPRequest(request, response); return; case "application/llsd+xml": case "application/xml+llsd": case "application/llsd+json": //MainConsole.Instance.Info("[Debug BASE HTTP SERVER]: found a application/llsd+xml content type"); HandleLLSDRequests(request, response); return; case "text/xml": case "application/xml": case "application/json": default: //MainConsole.Instance.Info("[Debug BASE HTTP SERVER]: in default handler"); // Point of note.. the DoWeHaveA methods check for an EXACT path // if (request.RawUrl.Contains("/CAPS/EQG")) // { // int i = 1; // } //MainConsole.Instance.Info("[Debug BASE HTTP SERVER]: Checking for LLSD Handler"); if (DoWeHaveALLSDHandler(request.RawUrl)) { //MainConsole.Instance.Info("[Debug BASE HTTP SERVER]: Found LLSD Handler"); HandleLLSDRequests(request, response); return; } // MainConsole.Instance.DebugFormat("[BASE HTTP SERVER]: Checking for HTTP Handler for request {0}", request.RawUrl); if (DoWeHaveAHTTPHandler(request.RawUrl)) { // MainConsole.Instance.DebugFormat("[BASE HTTP SERVER]: Found HTTP Handler for request {0}", request.RawUrl); HandleHTTPRequest(request, response); return; } //MainConsole.Instance.Info("[Debug BASE HTTP SERVER]: Generic XMLRPC"); // generic login request. if (!HandleXmlRpcRequests(request, response)) { SendHTML404(response, ""); } return; } } catch (SocketException e) { // At least on linux, it appears that if the client makes a request without requiring the response, // an unconnected socket exception is thrown when we close the response output stream. There's no // obvious way to tell if the client didn't require the response, so instead we'll catch and ignore // the exception instead. // // An alternative may be to turn off all response write exceptions on the HttpListener, but let's go // with the minimum first MainConsole.Instance.WarnFormat("[BASE HTTP SERVER]: HandleRequest threw {0}.\nNOTE: this may be spurious on Linux", e); } catch (IOException) { MainConsole.Instance.ErrorFormat("[BASE HTTP SERVER]: HandleRequest() threw "); } catch (Exception e) { MainConsole.Instance.ErrorFormat("[BASE HTTP SERVER]: HandleRequest() threw {0}", e); SendHTML500(response); } finally { int tickdiff = Environment.TickCount - tickstart; if (MainConsole.Instance.IsEnabled(log4net.Core.Level.Trace)) MainConsole.Instance.TraceFormat("[BASE HTTP SERVER]: request for {0} on port {3}, {2} took {1} ms", RawUrl, tickdiff, HTTPMethod, Port); // Every month or so this will wrap and give bad numbers, not really a problem // since its just for reporting, 500ms limit can be adjusted if (tickdiff > 500) MainConsole.Instance.InfoFormat("[BASE HTTP SERVER]: slow request <{0}> for {1},{3} took {2} ms", reqnum, RawUrl, tickdiff, HTTPMethod); } }