/// <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; HttpContext context = null; SessionHandler sessionHandler = 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(); //23.08.2016 - Changes for supporting POST Method int contentCopyCounter = 0; int bodyReadCount = 0; while (m_connected && (content.Length != length)) { if (contentCopyCounter > 0) { int bytesToRead = ((length - bodyReadCount) > InputBufferSize) ? InputBufferSize : (length - bodyReadCount); ReadData(input, bytesToRead); } bodyReadCount += m_index; content.Write(m_buffer, 0, m_index); ExtractBytes(m_index); contentCopyCounter++; } //23.08.2016 - End of Changes for supporting POST Method // 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 context = new HttpContext(); response = new HttpResponse(); //Get session id from cookies var sessionId = GetSessionIdentifier(request.Cookies); var isNewRequest = string.IsNullOrEmpty(sessionId); if (isNewRequest) { sessionId = Utilities.GetNewSessionIdentifier(); } sessionHandler = new SessionHandler(sessionId, m_server.SessionStorageHandler); context.SessionHandler = sessionHandler; sessionHandler.DestroyExpiredSessions(); //Update session data if (isNewRequest) { sessionHandler.SaveSessionData(); response.Cookies.Add(new Cookie(SessionName, sessionHandler.SessionId)); } else { sessionHandler.UpdateSessionTimeOut(); var isRetrieved = sessionHandler.GetSessionData(); if (!isRetrieved) { sessionId = Utilities.GetNewSessionIdentifier(); sessionHandler = new SessionHandler(sessionId, m_server.SessionStorageHandler); context.SessionHandler = sessionHandler; sessionHandler.SaveSessionData(); response.Cookies.Add(new Cookie(SessionName, sessionHandler.SessionId)); } } // Apply filters if (m_server.ApplyBeforeFilters(request, response, context)) { // Check for WebSocket upgrade IWebSocketRequestHandler wsHandler = UpgradeToWebsocket(request, response); if (wsHandler != null) { // Apply the after filters here m_server.ApplyAfterFilters(request, response, context); // Write the response back to accept the connection /////////////////////////////////Changes done locally to fix HTTP 1.1 on Safari 10 websocket error on 22.11.2016///////////////////// response.Send(output, HttpVersion.Ver1_1); 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; } // Apply the after filters here m_server.ApplyAfterFilters(request, response, context); //Update the session before sending the response if (sessionHandler != null) { if (sessionHandler.IsChanged) { sessionHandler.SaveSessionData(); } if (sessionHandler.IsSessionDestroyed) { sessionHandler.IsSessionDestroyed = false; response.Cookies.Add(new Cookie(SessionName, sessionHandler.SessionId)); } } // Write the response response.Send(output); output.Flush(); }