Exemple #1
0
        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);
            }
        }