Exemple #1
0
        static HttpRequest ParseHttpRequest(HttpRequest state)
        {
            var host = state.GetHeader("Host");
            var contentType = state.GetHeaderWithDefault(HttpHeader.ContentType, null);
            var connection = state.GetHeaderWithDefault(HttpHeader.Connection, null);
            var isKeepAlive = false;

            var url = new Uri(string.Format("{0}://{1}{2}", state.IsSecureConnection ? "https" : "http", host, state.Path));

            if (connection != null)
            {
                isKeepAlive = connection.IndexOf("keep-alive", StringComparison.OrdinalIgnoreCase) >= 0;
            }

            state.Host = host;
            state.Url = url;
            state.ContentType = contentType;
            state.IsKeepAlive = isKeepAlive;

            return state;
        }
Exemple #2
0
        //TODO: split to TryParseHttpRequest(out hasBody) + TryParseHttpRequestBody (IF we want to read ahead)
        public static bool TryParseHttpRequest(byte[] buffer,
                                               ref int start,
                                               int end,
                                               HttpRequest state,
                                               out HttpRequest parsedRequest)
        {
            while (true)
            {
                switch (state.State)
                {
                    case State.ReadRequestLine:
                        Method method;
                        string path, query, version;
                        if (TryParseRequestLine(buffer, ref start, end, out method, out path, out query, out version))
                        {
                            state.Method = method;
                            state.Path = path;
                            state.Query = query;
                            state.State = State.ReadHeaders;
                            continue;
                        }
                        else
                        {
                            parsedRequest = null;
                            return false;
                        }

                    case State.ReadHeaders:
                        if (TryParseHeaders(buffer, ref start, end, state.SetHeader))
                        {
                            switch (state.Method)
                            {
                                case Method.GET:
                                case Method.HEAD:
                                case Method.DELETE:
                                case Method.OPTIONS:
                                    state.ContentLength = state.GetHeaderWithDefault<int>(HttpHeader.ContentLength, 0);
                                    if (state.ContentLength > 0) //TODO: or 'Transfer-Encoding: chunked'
                                    {
                                        throw new ParseRequestException("Request body not accepted for [GET|HEAD|DELETE|OPTIONS]", HttpStatusCode.BadRequest);
                                    }
                                    state.Body = EmptyRequestStream.Instance;
                                    parsedRequest = ParseHttpRequest(state);
                                    return true;

                                case Method.POST:
                                case Method.PUT:
                                    // 1) Fully-readahead path
                                    state.ContentLength = state.GetHeaderWithDefault<int>(HttpHeader.ContentLength, -1);
                                    if (state.ContentLength < 0)
                                    {
                                        throw new ParseRequestException("Content-Length required", HttpStatusCode.LengthRequired);
                                    }
                                    state.Body = new MemoryRequestStream(state.ContentLength); //TODO: guard length + support 'Transfer-Encoding: chunked'
                                    state.State = State.ReadBodyToEnd;
                                    // 2) TODO: pass (wrapped) networkstream through to client for reading
                                    continue;

                                default:
                                    throw new ParseRequestException(state.Method + " not supported", HttpStatusCode.MethodNotAllowed); //TODO
                            }
                        }
                        else
                        {
                            parsedRequest = null;
                            return false;
                        }

                    case State.ReadBodyToEnd:
                        var requestBody = (MemoryRequestStream)state.Body;
                        var bytesAvailable = end - start; // may span multiple requests (eg. pipelined)
                        var bytesOutstanding = state.ContentLength - (int)requestBody.Length;
                        var bytesToWrite = Math.Min(bytesAvailable, bytesOutstanding); // only consume enough for the current request
                        requestBody.WriteRequestBody(buffer, start, bytesToWrite);
                        start += bytesToWrite;
                        if (requestBody.Length == state.ContentLength)
                        {
                            requestBody.ResetPosition();
                            parsedRequest = ParseHttpRequest(state);
                            state.State = State.Completed;
                            return true;
                        }
                        else
                        {
                            parsedRequest = null;
                            return false;
                        }
                }
            }
        }