public void HandleRequest(string uri, HttpRequest request, HttpResponse response, HttpContext context) { if (request.Method != HttpMethod.Get) throw new HttpMethodNotAllowedException(); // Replace '/' with '.' to generate the resource name string resourceName = uri.Replace('/', '.'); if (resourceName.StartsWith(".")) resourceName = m_prefix + resourceName; else resourceName = string.Format("{0}.{1}", m_prefix, resourceName); Stream resource = null; // If we are not expecting a directory, try and load the stream if (!resourceName.EndsWith(".")) resource = m_assembly.GetManifestResourceStream(resourceName); else resourceName = resourceName.Substring(0, resourceName.Length - 1); // If nothing found try and load the default filename instead if ((resource == null) && (m_defaultFile != null)) { // Try the default file resourceName = string.Format("{0}.{1}", resourceName, m_defaultFile); resource = m_assembly.GetManifestResourceStream(resourceName); } if (resource == null) throw new HttpNotFoundException(); // Get the mime type and send the file response.Headers[HttpHeaders.ContentType] = MimeType.FromExtension(resourceName); resource.CopyTo(response.Content); }
/// <summary> /// Handle the request /// </summary> /// <param name="uri"></param> /// <param name="request"></param> /// <param name="response"></param> /// <param name="context"></param> public void HandleRequest(string uri, HttpRequest request, HttpResponse response, HttpContext context) { // Split into path and filename int index = uri.LastIndexOf('/'); string path = (index < 0) ? "" : uri.Substring(0, index); string filename = (index < 0) ? uri : uri.Substring(index + 1); // Use default filename if applicable if (filename.Length == 0) filename = m_defaultFile; // Strip leading separators from URI if (path.StartsWith("/")) path = path.Substring(1); // Now look for the file IFolder folder = m_basePath.OpenChild(path); if (folder == null) throw new HttpNotFoundException(); if (!folder.FileExists(filename)) throw new HttpNotFoundException(); // Get the content type response.ResponseCode = HttpResponseCode.Ok; response.ContentType = MimeType.FromExtension(filename); using(Stream input = folder.CreateFile(filename, FileAccessMode.Read, CreationOptions.OpenIfExists)) input.CopyTo(response.Content); }
/// <summary> /// Handle the HTTP connection /// /// This implementation doesn't support keep alive so each HTTP session /// consists of parsing the request, dispatching to a handler and then /// sending the response before closing the connection. /// </summary> /// <param name="server"></param> /// <param name="input"></param> /// <param name="output"></param> public void ProcessHttpRequest(Stream input, Stream output) { // Set up state HttpRequest request = null; HttpResponse response = null; HttpException parseError = null; // Process the request try { request = ParseRequest(input); if ((request == null) || !m_connected) return; // Nothing we can do, just drop the connection // Do we have any content in the body ? if (request.Headers.ContainsKey(HttpHeaders.ContentType)) { if (!request.Headers.ContainsKey(HttpHeaders.ContentLength)) throw new HttpLengthRequiredException(); int length; if (!int.TryParse(request.Headers[HttpHeaders.ContentLength], out length)) throw new HttpLengthRequiredException(); request.ContentLength = length; if (length > MaxRequestBody) throw new HttpRequestEntityTooLargeException(); // Read the data in MemoryStream content = new MemoryStream(); while (m_connected && (content.Length != length)) { ReadData(input); content.Write(m_buffer, 0, m_index); ExtractBytes(m_index); } // Did the connection drop while reading? if (!m_connected) return; // Reset the stream location and attach it to the request content.Seek(0, SeekOrigin.Begin); request.Content = content; } // Process the cookies if (request.Headers.ContainsKey(HttpHeaders.Cookie)) { string[] cookies = request.Headers[HttpHeaders.Cookie].Split(CookieSeparator); foreach (string cookie in cookies) { string[] parts = cookie.Split(CookieValueSeparator); Cookie c = new Cookie(); c.Name = parts[0].Trim(); if (parts.Length > 1) c.Value = parts[1].Trim(); request.Cookies.Add(c); } } // We have at least a partial request, create the matching response HttpContext context = new HttpContext(); response = new HttpResponse(); // Apply filters m_server.ApplyFilters(request, response, context); // TODO: Check for WebSocket upgrade IWebSocketRequestHandler wsHandler = UpgradeToWebsocket(request, response); if (wsHandler!=null) { // Write the response back to accept the connection response.Send(output); output.Flush(); // Now we can process the websocket WebSocket ws = new WebSocket(input, output); wsHandler.Connected(ws); ws.Run(); // Once the websocket connection is finished we don't need to do anything else return; } // Dispatch to the handler string partialUri; IHttpRequestHandler handler = m_server.GetHandlerForUri(request.URI, out partialUri); if (handler == null) throw new HttpNotFoundException(); handler.HandleRequest(partialUri, request, response, context); } catch (HttpException ex) { parseError = ex; } catch (Exception) { parseError = new HttpInternalServerErrorException(); } // Do we need to send back an error response ? if (parseError != null) { // TODO: Clear any content that might already be added response.ResponseCode = parseError.ResponseCode; response.ResponseMessage = parseError.Message; } // Write the response response.Send(output); output.Flush(); }
/// <summary> /// Check for an upgrade to a web socket connection. /// </summary> /// <param name="request"></param> /// <param name="response"></param> /// <returns></returns> private IWebSocketRequestHandler UpgradeToWebsocket(HttpRequest request, HttpResponse response) { // Check for required headers if (!(request.Headers.ContainsKey(HttpHeaders.Connection) && request.Headers[HttpHeaders.Connection].Contains("Upgrade"))) return null; if (!(request.Headers.ContainsKey(HttpHeaders.Upgrade) && request.Headers[HttpHeaders.Upgrade].Contains("websocket"))) return null; if (!request.Headers.ContainsKey(SecWebSocketVersion)) return null; int version; if (!(int.TryParse(request.Headers[SecWebSocketVersion], out version) && (version == 13))) return null; if (!request.Headers.ContainsKey(SecWebSocketKey)) return null; // Make sure we have a handler for the URI string partial; IWebSocketRequestHandler handler = m_server.GetHandlerForWebSocket(request.URI, out partial); if (handler == null) return null; // Do we support the protocols requested? string protocol = null; if (request.Headers.ContainsKey(SecWebSocketProtocol)) { foreach (string proto in request.Headers[SecWebSocketProtocol].Split(WebSocketProtocolSeparator)) { if (handler.WillAcceptRequest(partial, proto.Trim())) { protocol = proto.Trim(); break; } } } else if (handler.WillAcceptRequest(partial, "")) protocol = ""; if (protocol == null) return null; // Finish the handshake byte[] security = Encoding.UTF8.GetBytes(request.Headers[SecWebSocketKey].Trim() + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"); SHA1CryptoServiceProvider sha1 = new SHA1CryptoServiceProvider(); sha1.Initialize(); sha1.HashCore(security, 0, security.Length); security = sha1.HashFinal(); response.Headers[SecWebSocketAccept] = Convert.ToBase64String(security); response.Headers[HttpHeaders.Upgrade] = "websocket"; response.Headers[HttpHeaders.Connection] = "Upgrade"; response.ResponseCode = HttpResponseCode.SwitchingProtocols; if (protocol.Length > 0) response.Headers[SecWebSocketProtocol] = protocol; // And we are done return handler; }
/// <summary> /// Apply all the filters to the current request /// </summary> /// <param name="request"></param> /// <param name="response"></param> /// <param name="context"></param> internal void ApplyFilters(HttpRequest request, HttpResponse response, HttpContext context) { lock (m_filters) { foreach (IHttpFilter filter in m_filters) filter.ApplyFilter(request, response, context); } }
/// <summary> /// Apply all the filters to the current request /// </summary> /// <param name="request"></param> /// <param name="response"></param> /// <param name="context"></param> internal void ApplyAfterFilters(HttpRequest request, HttpResponse response, HttpContext context) { lock (m_filters) { foreach (IHttpFilter filter in m_filters) { try { filter.After(request, response, context); } catch (Exception) { // Just silently ignore it } } } }
/// <summary> /// Apply all the filters to the current request /// </summary> /// <param name="request"></param> /// <param name="response"></param> /// <param name="context"></param> internal bool ApplyBeforeFilters(HttpRequest request, HttpResponse response, HttpContext context) { bool allowHandling = true; lock (m_filters) { foreach (IHttpFilter filter in m_filters) { try { allowHandling = allowHandling && filter.Before(request, response, context); } catch (Exception) { // Just silently ignore it } } } return allowHandling; }