void Header() { string region_1 = "GET / HTTP/1.1\r\n" + "Host: blog.lunaixsky.com\r\n" + "Connection: keep-alive\r\n" + "Cache-Control: max-age=0\r\n" + "Upgrade-Insecure-Requests: 1\r\n" + "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.83 Safari/537.36"; string region_2 = "\r\nAccept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9\r\n" + "Sec-Fetch-Site: none\r\n" + "Sec-Fetch-Mode: navigate\r\nSec-Fetch-User: ?1\r\nSec-Fetch-Dest: document\r\n" + "Accept-Encoding: gzip, deflate, br\r\n" + "Accept-Language: en-GB,en;q=0.9,zh-CN;q=0.8,zh;q=0.7,ru-RU;q=0.6,ru;q=0.5,en-US;q=0.4\r\n" + "Cookie: _ga=GA1.2.1727535589.1597313386; _gid=GA1.2.1552299765.1598851724; _gat_gtag_UA_175290221_1=1\r\n\r\n" + "<html>some html tags</html>"; byte[] r1 = Encoding.ASCII.GetBytes(region_1); byte[] r2 = Encoding.ASCII.GetBytes(region_2); HeaderParser headerParser = new HeaderParser(); ParserStatus status1 = headerParser.ProcessBuffer(r1, r1.Length); Console.WriteLine("Region 1 : {0}", status1); if (status1 == ParserStatus.REQUIRE_MORE) { status1 = headerParser.ProcessBuffer(r2, r2.Length); Console.WriteLine("Region 2 : {0}", status1); } if (status1 == ParserStatus.MOVE_NEXT_NEW_BUFFER || status1 == ParserStatus.MOVE_NEXT_SAME_BUFFER) { Console.WriteLine("Next State start pointer={0}", headerParser.BufferOffset); Console.WriteLine("Hint: {0}", region_2[headerParser.BufferOffset]); Console.WriteLine(headerParser.Content); } }
public void ReadCallback(IAsyncResult result) { HttpConnection conn = (HttpConnection)result.AsyncState; conn.MarkActiveOnce(); try { int byteReceived = conn.ActiveSocket.EndReceive(result); // Remote Client Close Connection if (byteReceived == 0) { conn.NaturalClose(); return; } ParserStatus status = ParserStatus.MOVE_NEXT_SAME_BUFFER; do { switch (currentState) { case HTTP_HEADER: status = headerParser.ProcessBuffer(conn.ConnectionBuffer, byteReceived); if (status == ParserStatus.ERROR) { conn.Response.SendError(HttpStatusCode.BadRequest); return; } else if (status.HasFlag(ParserStatus.MOVE_NEXT)) { HeaderStatus header = CreateAndCheckHeader(headerParser.Content, conn, out maxContentLength); if (header == HeaderStatus.ERROR) { conn.Response.SendError(HttpStatusCode.BadRequest); } else if (header == HeaderStatus.NO_CONTENT) { currentState = ACCEPT; } else if (header == HeaderStatus.CONTINUE) { //TODO Add 100/417 response } else { currentState = CONTENT; } contentParser.BufferOffset = headerParser.BufferOffset; } conn.ActiveSocket.BeginReceive( conn.ConnectionBuffer, 0, HttpConnection.BUFFER_SIZE, 0, new AsyncCallback(ReadCallback), conn); break; case CONTENT: if (maxContentLength > conn.ServerContext.ServerConfig.MaxContentSizeByte) { conn.Response.SendError(HttpStatusCode.RequestEntityTooLarge); } // IMPORTANT Identify chunked data and try to process it. // ================================================= // The illustration of such process. // We will handle it to a IChunkedRequestStream (yet to implement) // This will have a built in chunk parse state machine, invoking each time // when user calls method IChunkedRequestStream::ReadData. // // This connection will be blocked until all chunked data to be read // The control will be moved to the IChunkedRequestStream, this current thread // will be blocked according to "chunk parse state machine" return value: // 1. ParserStatus.REQUIRE_MORE: // Thread resume, BeginReceive will be invoke to get more data. // 2. ParserStatus.MOVE_NEXT: // Thread resume, Goto ACCEPT state, wait for next request. // 3. ParserStatus.ERROR: // Thread resume, Send BAD_REQUEST, close the current socket. status = contentParser.ProcessBuffer(conn.ConnectionBuffer, byteReceived, maxContentLength); if (status.HasFlag(ParserStatus.MOVE_NEXT)) { currentState = ACCEPT; } // Put the socket on recieving mode for further incoming requests conn.ActiveSocket.BeginReceive( conn.ConnectionBuffer, 0, HttpConnection.BUFFER_SIZE, 0, new AsyncCallback(ReadCallback), conn); break; case ACCEPT: currentState = HTTP_HEADER; maxContentLength = 0; headerParser.ResetParser(); contentParser.ResetParser(); CurrentRequest.RequestContentStream = new RequestStream(); CurrentRequest.RequestContentStream.CopyFrom(contentParser.Content); conn.ServerContext.RequestDispatcher.Dispatch( CurrentRequest, new Response.HttpResponse(conn)); break; } }while (status.HasFlag(ParserStatus.SAME_BUFFER) || currentState == ACCEPT); } catch (SocketException se) { //TODO May need logger here Console.WriteLine("{0}\r\n{1}", se.Message, se.StackTrace); conn.NaturalClose(); } catch (Exception ex) { Console.WriteLine("{0}\r\n{1}", ex.Message, ex.StackTrace); conn.Response.SendError(HttpStatusCode.InternalServerError); } }