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("[HTTPD]: 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("[HTTPD]: Error - " + ex.Message); } finally { //response.OutputStream.Close(); try { response.Send(); response.OutputStream.Flush(); response.FreeContext(); //response.OutputStream.Close(); } catch (IOException e) { m_log.DebugFormat("[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 virtual void HandleRequest(OSHttpRequest request, OSHttpResponse response) { try { 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 //m_log.Debug("[BASE HTTP SERVER]: Handling Request" + request.RawUrl); IHttpAgentHandler agentHandler; if (TryGetAgentHandler(request, response, out agentHandler)) { if (HandleAgentRequest(agentHandler, request, response)) { return; } } IRequestHandler requestHandler; //response.KeepAlive = true; response.SendChunked = false; 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); 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 taes 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.Info("[Debug BASE HTTP SERVER]: found a text/html content type"); 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.Info("[Debug BASE HTTP SERVER]: Checking for HTTP Handler"); if (DoWeHaveAHTTPHandler(request.RawUrl)) { //m_log.Info("[Debug BASE HTTP SERVER]: found HTTP Handler"); 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 (InvalidOperationException e) { m_log.ErrorFormat("[BASE HTTP SERVER]: HandleRequest() threw {0}", e); SendHTML500(response); } }
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"]; //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"))) { // 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); } } }
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("[HTTPD]: 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> /// 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; }