Beispiel #1
0
        /// <summary>
        /// Try add the specified bytes to the request.
        /// Returns the number of bytes read from the buffer.
        /// </summary>
        internal unsafe int TryAdd(byte[] buffer, int index, int count)
        {
            // is the request complete?
            if (_complete)
            {
                return(0);
            }

            // has the header been completely read?
            if (_section == Section.Body)
            {
                // does the current buffer contain the required bytes?
                if (_contentLength <= count)
                {
                    // yes, write the remaining content length to the stream
                    _stream.Write(buffer, index, _contentLength);
                    count          = _contentLength;
                    _contentLength = 0;

                    // the request is complete
                    _complete = true;

                    // move back to the start of the content body - this flushes the byte stream
                    _stream.Position = _bodyIndex;

                    // TODO : Auto decompression

                    return(count);
                }

                // no, write the buffer
                _stream.Write(buffer, index, count);
                // decrement the remaining content length
                _contentLength -= count;

                return(count);
            }

            // persist the starting index of the stream
            long startIndex = _stream.WriteEnd;

            // write the buffer to the request
            _stream.Write(buffer, index, count);

            // return to the start of the buffer
            _stream.Position = startIndex;

            char c;

            // while characters can be read from the stream
            while ((c = _stream.ReadChar()) != Chars.Null)
            {
                // should the character be skipped? yes, continue reading
                if (c == Chars.CarriageReturn)
                {
                    continue;
                }

                // determine the state of the request method
                switch (_section)
                {
                case Section.Method:

                    // read until a space is encountered
                    if (c == Chars.Space)
                    {
                        // try determine the type of web request
                        if (_chars.EndsWith(Chars.G, Chars.E, Chars.T))
                        {
                            Method = HttpMethod.Get;
                        }
                        else if (_chars.EndsWith(Chars.P, Chars.O, Chars.S, Chars.T))
                        {
                            Method = HttpMethod.Post;
                        }
                        else if (_chars.EndsWith(Chars.P, Chars.U, Chars.T, Chars.Space))
                        {
                            Method = HttpMethod.Put;
                        }
                        else if (_chars.EndsWith(Chars.D, Chars.E, Chars.L, Chars.E, Chars.T, Chars.E))
                        {
                            Method = HttpMethod.Delete;
                        }
                        else if (_chars.EndsWith(Chars.U, Chars.P, Chars.D, Chars.A, Chars.T, Chars.E))
                        {
                            Method = HttpMethod.Update;
                        }
                        _section = Section.Path;
                        _chars.Reset();
                    }
                    else
                    {
                        // add the current character to the collection
                        _chars.Add(c);
                    }

                    break;

                case Section.Path:

                    // yes, does the current character equal a new line?
                    if (c == Chars.NewLine)
                    {
                        // yes, derive the request path and the http version
                        index = _chars.Count;
                        bool versionFound = false;

                        // while the indices haven't been explored
                        while (--index >= 0)
                        {
                            // does the current character equal a space?
                            if (_chars[index] == Chars.Space)
                            {
                                // no, derive the request version
                                Headers[HttpRequestHeader.HttpVersion] = new string(_chars.Array, index + 1, _chars.Count - index - 1);
                                versionFound = true;
                                break;
                            }
                        }

                        // yes, has the version been derived? yes, derive the request path
                        if (versionFound)
                        {
                            RequestPath = new string(_chars.Array, 0, index);
                        }
                        else
                        {
                            RequestPath = "/";
                        }

                        _section = Section.HeaderKey;
                        _chars.Reset();
                    }
                    else
                    {
                        // add the current character to the collection
                        _chars.Add(c);
                    }

                    break;

                case Section.HeaderKey:

                    // is the current character a separator between header names and values?
                    if (c == Chars.Colon)
                    {
                        // get the name of the chracter header
                        _headerKey = new string(_chars.Array, 0, _chars.Count);
                        // read the header value
                        _section = Section.HeaderValue;
                        // clear the characters
                        _chars.Reset();
                    }
                    else if (c == Chars.NewLine && _chars.Count == 0)
                    {
                        // yes, the request header has been completed
                        _chars.Dispose();

                        // determine whether to continue the request
                        switch (Method)
                        {
                        case HttpMethod.Put:
                        case HttpMethod.Post:
                        case HttpMethod.Update:

                            // set the start of the body index
                            _bodyIndex = (int)_stream.Position;

                            // get the content length - was it able to be parsed?
                            if (!int.TryParse(Headers[HttpRequestHeader.ContentLength], out _contentLength))
                            {
                                // the content length wasn't able to be parsed
                                Log.Warning("Invalid content length parameter.");
                                // set the content length to '0'.
                                _contentLength = 0;
                                _complete      = true;
                                return(count);
                            }

                            // the request contains a body
                            // should this request claim the remaining bytes written to the stream?
                            if (_stream.WriteEnd - _stream.Position >= _contentLength)
                            {
                                // no, get the excess number of bytes from the request
                                count          = (int)(_stream.WriteEnd - startIndex);
                                _contentLength = 0;
                                _complete      = true;
                            }
                            else
                            {
                                // decrement the content length
                                _contentLength -= (int)(_stream.WriteEnd - _stream.Position);
                                // flag the header as complete
                                _section = Section.Body;
                                // move the stream to the end of the written section
                                _stream.Position = _stream.WriteEnd;
                            }

                            // return the number of bytes that contribute to the request
                            return(count);

                        default:

                            // the request doesn't contain a body, end reading the request
                            _complete = true;
                            // return the number of bytes read from the buffer
                            return((int)(_stream.Position - startIndex));
                        }
                    }
                    else
                    {
                        // add the current character to the collection
                        _chars.Add(c);
                    }

                    break;

                case Section.HeaderValue:

                    // is the current character a new line?
                    if (c == Chars.NewLine)
                    {
                        // add the header to the collection
                        Headers[_headerKey] = new string(_chars.Array, 0, _chars.Count);
                        _chars.Reset();
                        _section = Section.HeaderKey;
                    }
                    else if (c != Chars.Space || _chars.Count != 0)
                    {
                        // add the current character to the collection
                        _chars.Add(c);
                    }
                    break;
                }
            }

            // return the number of bytes read from the buffer
            return(count);
        }