Example #1
0
        /// <summary>
        /// Constructor
        /// </summary>
        internal HttpResponseParser()
        {
            // initialize parser state
            this.state     = HttpResponseParserState.ResponseLine;
            this.lineState = HttpResponseLineState.Idle;
#if !MF_FRAMEWORK_VERSION_V4_1
            this.lineBuilder = new StringBuilder();
#else
            this.lineBuilder = String.Empty;
#endif

            // create HTTP response object and assign read method for body response
            this.response           = new HttpResponse();
            this.response.Body.Read = this.ReadBody;
        }
Example #2
0
        /// <summary>
        /// Called for reading response body by client
        /// </summary>
        /// <param name="buffer">Destination client buffer</param>
        /// <param name="offset">Offset to start reading</param>
        /// <param name="count">Number of bytes to read</param>
        /// <returns>Number of bytes read</returns>
        private int ReadBody(byte[] buffer, int offset, int count)
        {
            int readBytes = 0;

            // we can read at most bytes inside buffer (remaining)
            readBytes = (this.bodyRemaining <= this.remaining) ? this.bodyRemaining : this.remaining;

            // if client want to read less then remaining bytes
            if (count < readBytes)
            {
                readBytes = count;
            }

            // copy bytes to client buffer
            Array.Copy(this.buffer, this.parsed, buffer, offset, readBytes);

            this.parsed += readBytes;

            // body chunked
            if (this.isChunked)
            {
                // if read all chunk, consider CR LF ending chunk
                if (readBytes == this.bodyRemaining)
                {
                    this.parsed += HttpBase.CRLF.Length;
                    // waiting for another chunk
                    this.bodyRemaining = 0;
                }
                // not read entire current chunk
                else
                {
                    this.bodyRemaining -= readBytes;
                }
            }
            else
            {
                this.bodyRemaining -= readBytes;

                // body and parsing end
                if (this.bodyRemaining == 0)
                {
                    this.result = HttpResponseParserResult.Completed;
                    this.state  = HttpResponseParserState.ResponseLine;
                }
            }

            return(readBytes);
        }
Example #3
0
        /// <summary>
        /// Execute HTTP response parsing
        /// </summary>
        /// <param name="buffer">Buffer with HTTP response bytes</param>
        /// <param name="size">Number of bytes</param>
        /// <returns>Parsing result</returns>
        internal HttpResponseParserResult Parse(byte[] buffer, int size)
        {
            this.result    = HttpResponseParserResult.NotCompleted;
            this.parsed    = 0;
            this.remaining = 0;
            this.buffer    = buffer;
            this.size      = size;

            // entire size is remaining bytes to parser
            this.remaining = this.size;

            while (this.remaining > 0)
            {
                switch (this.state)
                {
                // waiting for response line, start of HTTP response
                case HttpResponseParserState.ResponseLine:

                    this.parsed += this.ExtractLine(this.buffer, this.parsed, this.size);
                    // response line extracted
                    if (this.lineState == HttpResponseLineState.End)
                    {
                        try
                        {
                            string[] token = this.lineBuilder.ToString().Split(HttpBase.RESPONSE_LINE_SEPARATOR);

                            // set HTTP protocol, status code and reason phrase
                            this.response.HttpProtocol = token[0];
                            this.response.StatusCode   = (HttpStatusCode)Convert.ToInt32(token[1]);
                            if (token.Length == 3)
                            {
                                this.response.ReasonPhrase = token[2];
                            }
                            else
                            {
                                this.response.ReasonPhrase = string.Empty;
                                for (int i = 2; i < token.Length; i++)
                                {
                                    this.response.ReasonPhrase += token[i];
                                }
                            }

                            // change parser state for waiting headers
                            this.state = HttpResponseParserState.Headers;
                            // reset extract line parser state
                            this.lineState = HttpResponseLineState.Idle;
#if !MF_FRAMEWORK_VERSION_V4_1
                            this.lineBuilder.Clear();
#else
                            this.lineBuilder = String.Empty;
#endif
                        }
                        catch
                        {
                            this.result = HttpResponseParserResult.Malformed;
                        }
                    }
                    this.remaining = (this.size - this.parsed);
                    break;

                // receiving HTTP headers
                case HttpResponseParserState.Headers:

                    this.parsed += this.ExtractLine(this.buffer, this.parsed, this.size);
                    // line extracted
                    if (this.lineState == HttpResponseLineState.End)
                    {
                        // header line
                        if (this.lineBuilder.Length > 0)
                        {
                            string headerLine = this.lineBuilder.ToString();

                            // add header to response (key and value)
                            this.response.Headers.Add(
                                headerLine.Substring(0, headerLine.IndexOf(HttpBase.HEADER_VALUE_SEPARATOR)).Trim(),
                                headerLine.Substring(headerLine.IndexOf(HttpBase.HEADER_VALUE_SEPARATOR) + 1).Trim()
                                );
                        }
                        // empty line, headers end
                        else
                        {
                            // body chunked or not
                            if ((this.response.ContentLength > 0) || (this.response.TransferEncoding != null))
                            {
                                this.bodyRemaining = (this.response.ContentLength > 0) ? this.response.ContentLength : 0;

                                if (this.response.TransferEncoding != null)
                                {
                                    this.isChunked = (this.response.TransferEncoding.Equals(HttpBase.TRANSFER_ENCODING_CHUNKED));
                                }

                                this.state = HttpResponseParserState.Body;
                            }
                            // no body, HTTP response end
                            else
                            {
                                this.result = HttpResponseParserResult.Completed;
                                this.state  = HttpResponseParserState.ResponseLine;
                            }
                        }

                        // reset extract line parser state
                        this.lineState = HttpResponseLineState.Idle;
#if !MF_FRAMEWORK_VERSION_V4_1
                        this.lineBuilder.Clear();
#else
                        this.lineBuilder = String.Empty;
#endif
                    }
                    this.remaining = (this.size - this.parsed);
                    break;

                // receiving body
                case HttpResponseParserState.Body:

                    // body chunked and no chunk size already found
                    if ((this.isChunked) && (this.bodyRemaining == 0))
                    {
                        this.parsed += this.ExtractLine(this.buffer, this.parsed, this.size);
                        // line extracted
                        if (this.lineState == HttpResponseLineState.End)
                        {
                            // line contains chunk size
                            if (this.lineBuilder.Length > 0)
                            {
                                this.bodyRemaining = Convert.ToInt32(this.lineBuilder.ToString(), 16);
                            }
                            // empty line, body chunked end
                            else
                            {
                                this.result = HttpResponseParserResult.Completed;
                                this.state  = HttpResponseParserState.ResponseLine;
                            }

                            // reset extract line parser state
                            this.lineState = HttpResponseLineState.Idle;
#if !MF_FRAMEWORK_VERSION_V4_1
                            this.lineBuilder.Clear();
#else
                            this.lineBuilder = String.Empty;
#endif
                        }

                        this.remaining = (this.size - this.parsed);
                    }
                    // read body or chunk
                    else
                    {
                        // raise event for allow client to read body response
                        this.OnReceivingBody(this.response);

                        this.remaining = (this.size - this.parsed);
                    }

                    break;

                default:
                    break;
                }

                // HTTP response malfomerd, break
                if (this.result == HttpResponseParserResult.Malformed)
                {
                    this.response = null;
                    break;
                }
            }

            return(this.result);
        }
        /// <summary>
        /// Called for reading response body by client
        /// </summary>
        /// <param name="buffer">Destination client buffer</param>
        /// <param name="offset">Offset to start reading</param>
        /// <param name="count">Number of bytes to read</param>
        /// <returns>Number of bytes read</returns>
        private int ReadBody(byte[] buffer, int offset, int count)
        {
            int readBytes = 0;

            // we can read at most bytes inside buffer (remaining)
            readBytes = (this.bodyRemaining <= this.remaining) ? this.bodyRemaining : this.remaining;

            // if client want to read less then remaining bytes
            if (count < readBytes)
                readBytes = count;

            // copy bytes to client buffer
            Array.Copy(this.buffer, this.parsed, buffer, offset, readBytes);

            this.parsed += readBytes;

            // body chunked
            if (this.isChunked)
            {
                // if read all chunk, consider CR LF ending chunk
                if (readBytes == this.bodyRemaining)
                {
                    this.parsed += HttpBase.CRLF.Length;
                    // waiting for another chunk
                    this.bodyRemaining = 0;
                }
                // not read entire current chunk
                else
                {
                    this.bodyRemaining -= readBytes;
                }
            }
            else
            {
                this.bodyRemaining -= readBytes;

                // body and parsing end
                if (this.bodyRemaining == 0)
                {
                    this.result = HttpResponseParserResult.Completed;
                    this.state = HttpResponseParserState.ResponseLine;
                }
            }

            return readBytes;
        }
        /// <summary>
        /// Execute HTTP response parsing
        /// </summary>
        /// <param name="buffer">Buffer with HTTP response bytes</param>
        /// <param name="size">Number of bytes</param>
        /// <returns>Parsing result</returns>
        internal HttpResponseParserResult Parse(byte[] buffer, int size)
        {
            this.result = HttpResponseParserResult.NotCompleted;
            this.parsed = 0;
            this.remaining = 0;
            this.buffer = buffer;
            this.size = size;

            // entire size is remaining bytes to parser
            this.remaining = this.size;

            while (this.remaining > 0)
            {
                switch (this.state)
                {
                    // waiting for response line, start of HTTP response
                    case HttpResponseParserState.ResponseLine:

                        this.parsed += this.ExtractLine(this.buffer, this.parsed, this.size);
                        // response line extracted
                        if (this.lineState == HttpResponseLineState.End)
                        {
                            try
                            {
                                string[] token = this.lineBuilder.ToString().Split(HttpBase.RESPONSE_LINE_SEPARATOR);

                                // set HTTP protocol, status code and reason phrase
                                this.response.HttpProtocol = token[0];
                                this.response.StatusCode = (HttpStatusCode)Convert.ToInt32(token[1]);
                                if (token.Length == 3)
                                    this.response.ReasonPhrase = token[2];
                                else
                                {
                                    this.response.ReasonPhrase = string.Empty;
                                    for (int i = 2; i < token.Length; i++)
                                        this.response.ReasonPhrase += token[i];
                                }

                                // change parser state for waiting headers
                                this.state = HttpResponseParserState.Headers;
                                // reset extract line parser state
                                this.lineState = HttpResponseLineState.Idle;
            #if !MF_FRAMEWORK_VERSION_V4_1
                                this.lineBuilder.Clear();
            #else
                                this.lineBuilder = String.Empty;
            #endif
                            }
                            catch
                            {
                                this.result = HttpResponseParserResult.Malformed;
                            }
                        }
                        this.remaining = (this.size - this.parsed);
                        break;

                    // receiving HTTP headers
                    case HttpResponseParserState.Headers:

                        this.parsed += this.ExtractLine(this.buffer, this.parsed, this.size);
                        // line extracted
                        if (this.lineState == HttpResponseLineState.End)
                        {
                            // header line
                            if (this.lineBuilder.Length > 0)
                            {
                                string headerLine = this.lineBuilder.ToString();

                                // add header to response (key and value)
                                this.response.Headers.Add(
                                    headerLine.Substring(0, headerLine.IndexOf(HttpBase.HEADER_VALUE_SEPARATOR)).Trim(),
                                    headerLine.Substring(headerLine.IndexOf(HttpBase.HEADER_VALUE_SEPARATOR) + 1).Trim()
                                    );
                            }
                            // empty line, headers end
                            else
                            {
                                // body chunked or not
                                if ((this.response.ContentLength > 0) || (this.response.TransferEncoding != null))
                                {
                                    this.bodyRemaining = (this.response.ContentLength > 0) ? this.response.ContentLength : 0;

                                    if (this.response.TransferEncoding != null)
                                        this.isChunked = (this.response.TransferEncoding.Equals(HttpBase.TRANSFER_ENCODING_CHUNKED));

                                    this.state = HttpResponseParserState.Body;
                                }
                                // no body, HTTP response end
                                else
                                {
                                    this.result = HttpResponseParserResult.Completed;
                                    this.state = HttpResponseParserState.ResponseLine;
                                }
                            }

                            // reset extract line parser state
                            this.lineState = HttpResponseLineState.Idle;
            #if !MF_FRAMEWORK_VERSION_V4_1
                            this.lineBuilder.Clear();
            #else
                            this.lineBuilder = String.Empty;
            #endif
                        }
                        this.remaining = (this.size - this.parsed);
                        break;

                    // receiving body
                    case HttpResponseParserState.Body:

                        // body chunked and no chunk size already found
                        if ((this.isChunked) && (this.bodyRemaining == 0))
                        {

                            this.parsed += this.ExtractLine(this.buffer, this.parsed, this.size);
                            // line extracted
                            if (this.lineState == HttpResponseLineState.End)
                            {
                                // line contains chunk size
                                if (this.lineBuilder.Length > 0)
                                {
                                    this.bodyRemaining = Convert.ToInt32(this.lineBuilder.ToString(), 16);
                                }
                                // empty line, body chunked end
                                else
                                {
                                    this.result = HttpResponseParserResult.Completed;
                                    this.state = HttpResponseParserState.ResponseLine;
                                }

                                // reset extract line parser state
                                this.lineState = HttpResponseLineState.Idle;
            #if !MF_FRAMEWORK_VERSION_V4_1
                                this.lineBuilder.Clear();
            #else
                                this.lineBuilder = String.Empty;
            #endif
                            }

                            this.remaining = (this.size - this.parsed);
                        }
                        // read body or chunk
                        else
                        {
                            // raise event for allow client to read body response
                            this.OnReceivingBody(this.response);

                            this.remaining = (this.size - this.parsed);
                        }

                        break;
                    default:
                        break;
                }

                // HTTP response malfomerd, break
                if (this.result == HttpResponseParserResult.Malformed)
                {
                    this.response = null;
                    break;
                }
            }

            return this.result;
        }
        /// <summary>
        /// Constructor
        /// </summary>
        internal HttpResponseParser()
        {
            // initialize parser state
            this.state = HttpResponseParserState.ResponseLine;
            this.lineState = HttpResponseLineState.Idle;
            #if !MF_FRAMEWORK_VERSION_V4_1
            this.lineBuilder = new StringBuilder();
            #else
            this.lineBuilder = String.Empty;
            #endif

            // create HTTP response object and assign read method for body response
            this.response = new HttpResponse();
            this.response.Body.Read = this.ReadBody;
        }