Esempio n. 1
0
        protected virtual void ScanHeaderFieldValue(HeaderBuffer headerBuffer, string decapitalizedFieldName, int startOffset)
        {
            // argument checks
            Debug.Assert(headerBuffer != null);

            string value;

            switch (decapitalizedFieldName)
            {
            case "content-length":
                value = headerBuffer.ReadFieldASCIIValue(decapitalize: false);
                this.ContentLength = HeaderBuffer.ParseHeaderFieldValueAsLong(value);
                break;

            case "transfer-encoding":
                value = headerBuffer.ReadFieldASCIIValue(decapitalize: true);
                if (HeaderBuffer.IsChunkedSpecified(value) == false)
                {
                    throw MessageBuffer.CreateBadRequestException();
                }
                this.ContentLength = -1;                                // -1 means 'chunked'
                break;

            default:
                // just skip
                headerBuffer.SkipField();
                break;
            }
        }
Esempio n. 2
0
        protected override void ScanHeaderFieldValue(HeaderBuffer headerBuffer, string decapitalizedFieldName, int startOffset)
        {
            switch (decapitalizedFieldName)
            {
            case "host":
                // save its value, but its span is unnecessary
                if (this.HostEndPoint == null)
                {
                    string hostValue = HeaderBuffer.TrimHeaderFieldValue(headerBuffer.ReadFieldASCIIValue(false));
                    this.HostEndPoint = Util.ParseEndPoint(hostValue, canOmitPort: true);
                }
                else
                {
                    headerBuffer.SkipField();
                }
                this.HostSpan = new Span(startOffset, headerBuffer.CurrentOffset);
                break;

            case "proxy-authorization":
                // save its span, but its value is unnecessary
                headerBuffer.SkipField();
                this.ProxyAuthorizationSpan = new Span(startOffset, headerBuffer.CurrentOffset);
                break;

            default:
                base.ScanHeaderFieldValue(headerBuffer, decapitalizedFieldName, startOffset);
                break;
            }
        }
Esempio n. 3
0
        protected virtual bool ScanHeaderField(HeaderBuffer headerBuffer)
        {
            // argument checks
            Debug.Assert(headerBuffer != null);

            // read the first byte
            bool emptyLine;
            Func <byte, bool> hasInterest = (b) => {
                char c = Char.ToLower((char)b);
                return(IsInterestingHeaderFieldFirstChar(c));
            };

            byte firstByte = headerBuffer.ReadFieldNameFirstByte();

            if (firstByte == MessageBuffer.CR || hasInterest(firstByte) == false)
            {
                // no interest, just skip this line
                emptyLine = headerBuffer.SkipField(firstByte);
            }
            else
            {
                // scan this field
                int    startOffset            = headerBuffer.CurrentOffset - 1;         // Note we have already read one byte
                string decapitalizedFieldName = headerBuffer.ReadFieldName(firstByte);
                ScanHeaderFieldValue(headerBuffer, decapitalizedFieldName, startOffset);
                emptyLine = false;
            }

            return(emptyLine);
        }
Esempio n. 4
0
        protected override void ScanStartLine(HeaderBuffer headerBuffer)
        {
            // argument checks
            Debug.Assert(headerBuffer != null);

            // read items
            string method = headerBuffer.ReadSpaceSeparatedItem(skipItem: false, decapitalize: false, lastItem: false);

            int    targetStart = headerBuffer.CurrentOffset;
            string target      = headerBuffer.ReadSpaceSeparatedItem(skipItem: false, decapitalize: false, lastItem: false);

            this.RequestTargetSpan = new Span(targetStart, headerBuffer.CurrentOffset - 1);

            string httpVersion = headerBuffer.ReadSpaceSeparatedItem(skipItem: false, decapitalize: false, lastItem: true);

            // set message properties
            this.Method  = method;
            this.Version = HeaderBuffer.ParseVersion(httpVersion);
            if (string.IsNullOrEmpty(target) == false)
            {
                char firstChar = target[0];
                if (firstChar != '/' && firstChar != '*')
                {
                    // absolute-form or authority-form
                    Uri         uri          = null;
                    DnsEndPoint hostEndPoint = null;

                    if (target.Contains("://"))
                    {
                        // maybe absolute-form
                        try {
                            uri          = new Uri(target);
                            hostEndPoint = new DnsEndPoint(uri.Host, uri.Port);
                        } catch {
                            // continue
                        }
                    }
                    else
                    {
                        // maybe authority-form
                        try {
                            // assume https scheme
                            uri          = new Uri($"https://{target}");
                            hostEndPoint = new DnsEndPoint(uri.Host, uri.Port);
                            uri          = null;                    // this.Uri is not set in case of authority-form
                        } catch {
                            // continue
                        }
                    }
                    this.HostEndPoint = hostEndPoint;
                    this.TargetUri    = uri;
                }
            }

            return;
        }
Esempio n. 5
0
        protected virtual void WriteHeader(Stream output, HeaderBuffer headerBuffer, IEnumerable <MessageBuffer.Modification> modifications)
        {
            // argument checks
            Debug.Assert(output != null);
            Debug.Assert(headerBuffer != null);
            // modifications can be null

            // write message header
            headerBuffer.WriteHeader(output, modifications);
        }
Esempio n. 6
0
        protected Message()
        {
            // initialize members
            this.headerBuffer  = new HeaderBuffer();
            this.bodyBuffer    = new BodyBuffer(this.headerBuffer);
            this.modifications = new List <MessageBuffer.Modification>();
            ResetThisClassLevelMessageProperties();
            this.ReadingState = MessageReadingState.Error;

            return;
        }
Esempio n. 7
0
        public void WriteBody(Stream output)
        {
            // argument checks
            if (output == null)
            {
                throw new ArgumentNullException(nameof(output));
            }
            if (output.CanWrite == false)
            {
                throw new ArgumentException("It is not writable", nameof(output));
            }

            // state checks
            if (this.bodyLength == 0)
            {
                // no body
                output.Flush();
                return;
            }

            // write the body
            // Note the media where the body is stored depends on its size.
            if (this.bodyStream != null)
            {
                // the body was stored in the stream (large/medium body or chunked body)
                this.bodyStream.Seek(0, SeekOrigin.Begin);
                this.bodyStream.CopyTo(output);
            }
            else
            {
                Debug.Assert(0 <= this.bodyLength && this.bodyLength <= int.MaxValue);
                int bodyLengthInInt = (int)this.bodyLength;

                if (this.MemoryBlock != null)
                {
                    // the body was stored in the memoryBlock (small body)
                    Debug.Assert(this.Next == 0);
                    Debug.Assert(this.Limit == bodyLengthInInt);
                    WriteTo(output, 0, bodyLengthInInt);
                }
                else
                {
                    // the body was stored in the rest of the header buffer (tiny body)
                    HeaderBuffer headerBuffer = this.headerBuffer;
                    // Be careful not to write bytes of the next message.
                    Debug.Assert(bodyLengthInInt <= headerBuffer.Limit - headerBuffer.Next);
                    WriteTo(headerBuffer, output, headerBuffer.Next, bodyLengthInInt);
                }
            }
            output.Flush();

            return;
        }
Esempio n. 8
0
        public BodyBuffer(HeaderBuffer headerBuffer) : base()
        {
            // argument checks
            if (headerBuffer == null)
            {
                throw new ArgumentNullException(nameof(headerBuffer));
            }

            // initialize members
            this.headerBuffer = headerBuffer;

            return;
        }
Esempio n. 9
0
        protected bool ReadHeader()
        {
            // read header part from the input
            bool read = false;

            try {
                HeaderBuffer headerBuffer = this.headerBuffer;

                // state checks
                switch (this.ReadingState)
                {
                case MessageReadingState.Error:
                    throw CreateNoIOException();

                case MessageReadingState.None:
                    break;

                default:
                    Reset();
                    break;
                }
                Debug.Assert(this.headerBuffer.CanRead);

                // read start line
                ScanStartLine(headerBuffer);

                // read header fields
                bool emptyLine;
                do
                {
                    emptyLine = ScanHeaderField(headerBuffer);
                } while (emptyLine == false);

                // update state
                int endOfHeaderOffset = headerBuffer.CurrentOffset - 2;                  // subtract empty line bytes
                this.EndOfHeaderFields = new Span(endOfHeaderOffset, endOfHeaderOffset);
                this.ReadingState      = MessageReadingState.Header;
                read = true;
            } catch (EndOfStreamException) {
                // no data from input
                // Note that incomplete data results an exception other than EndOfStreamException.
                Debug.Assert(this.ReadingState == MessageReadingState.None);
                Debug.Assert(read == false);
                // continue
            } catch {
                this.ReadingState = MessageReadingState.Error;
                throw;
            }

            return(read);
        }
Esempio n. 10
0
        private void StoreBody(Stream output, long contentLength)
        {
            // argument checks
            Debug.Assert(output != null);
            Debug.Assert(output.CanWrite);
            Debug.Assert(0 <= contentLength);

            // state checks
            HeaderBuffer headerBuffer = this.headerBuffer;

            Debug.Assert(headerBuffer != null);

            // write body bytes in the header buffer to the output
            int bodyBytesInHeaderBufferLength = headerBuffer.Limit - headerBuffer.Next;

            if (bodyBytesInHeaderBufferLength <= contentLength)
            {
                WriteTo(headerBuffer, output, headerBuffer.Next, bodyBytesInHeaderBufferLength);
            }
            else
            {
                // there is data of the next message
                bodyBytesInHeaderBufferLength = (int)contentLength;
                WriteTo(headerBuffer, output, headerBuffer.Next, bodyBytesInHeaderBufferLength);
                headerBuffer.SetPrefetchedBytes(headerBuffer.Next + bodyBytesInHeaderBufferLength);
            }

            // write rest of body bytes to the output
            // the memoryBlock is used as just intermediate buffer instead of storing media
            byte[] memoryBlock = EnsureMemoryBlockAllocated();
            long   remaining   = contentLength - bodyBytesInHeaderBufferLength;

            while (0 < remaining)
            {
                long count     = Math.Min(remaining, memoryBlock.Length);
                int  readCount = ReadBytes(memoryBlock, 0, (int)count);
                Debug.Assert(0 < readCount);                    // ReadBytes() throws an exception on end of stream
                output.Write(memoryBlock, 0, readCount);
                remaining -= readCount;
            }

            return;
        }
Esempio n. 11
0
        protected override void ScanHeaderFieldValue(HeaderBuffer headerBuffer, string decapitalizedFieldName, int startOffset)
        {
            switch (decapitalizedFieldName)
            {
            case "content-length":
            case "transfer-encoding":
                // Do not parse these header fields in response of HEAD method
                // otherwise it will be blocked to try to read body stream after this.
                if (this.Request?.Method != "HEAD")
                {
                    base.ScanHeaderFieldValue(headerBuffer, decapitalizedFieldName, startOffset);
                }
                break;

            case "connection":
                // ToDo: exact parsing
                string value = headerBuffer.ReadFieldASCIIValue(false);
                if (value.Contains("close"))
                {
                    this.KeepAliveEnabled = false;
                }
                else if (value.Contains("keep-alive"))
                {
                    this.KeepAliveEnabled = true;
                }
                break;

            case "proxy-authenticate":
                // save its span and value
                this.ProxyAuthenticateValue = headerBuffer.ReadFieldASCIIValue(false);
                this.ProxyAuthenticateSpan  = new Span(startOffset, headerBuffer.CurrentOffset);
                break;

            default:
                base.ScanHeaderFieldValue(headerBuffer, decapitalizedFieldName, startOffset);
                break;
            }
        }
Esempio n. 12
0
        protected override void ScanStartLine(HeaderBuffer headerBuffer)
        {
            // argument checks
            Debug.Assert(headerBuffer != null);

            // read items
            string version    = headerBuffer.ReadSpaceSeparatedItem(skipItem: false, decapitalize: false, lastItem: false);
            string statusCode = headerBuffer.ReadSpaceSeparatedItem(skipItem: false, decapitalize: false, lastItem: false);

            headerBuffer.ReadSpaceSeparatedItem(skipItem: true, decapitalize: false, lastItem: true);

            // set message properties
            Version httpVersion = HeaderBuffer.ParseVersion(version);

            this.Version    = httpVersion;
            this.StatusCode = HeaderBuffer.ParseStatusCode(statusCode);
            if (httpVersion.Major == 1 && httpVersion.Minor == 0)
            {
                // in HTTP/1.0, keep-alive is disabled by default
                this.KeepAliveEnabled = false;
            }

            return;
        }
Esempio n. 13
0
 protected abstract void ScanStartLine(HeaderBuffer headerBuffer);
Esempio n. 14
0
        public void SkipBody(long contentLength)
        {
            // argument checks
            if (contentLength < 0)
            {
                throw new ArgumentOutOfRangeException(nameof(contentLength));
            }

            // state checks
            HeaderBuffer headerBuffer = this.headerBuffer;

            if (headerBuffer == null)
            {
                throw new InvalidOperationException();
            }
            if (this.bodyLength != 0)
            {
                throw new InvalidOperationException("This buffer has already handled a message body.");
            }
            Debug.Assert(this.bodyStream == null);

            // skip the body storing its bytes
            // The media to store body depends on its length and the current margin.
            Stream bodyStream = null;

            try {
                // Note that the some body bytes may be read into the header buffer.
                // Unread bytes in the header buffer at this point are body bytes.
                // That is, range [headerBuffer.Next - headerBuffer.Limit).
                int  bodyBytesInHeaderBufferLength = headerBuffer.Limit - headerBuffer.Next;
                long restLen = contentLength - bodyBytesInHeaderBufferLength;
                if (restLen <= headerBuffer.Margin)
                {
                    // The body is to be stored in the rest of header buffer. (tiny body)

                    // read body bytes into the rest of the header buffer
                    if (0 <= restLen)
                    {
                        Debug.Assert(restLen <= int.MaxValue);
                        FillBuffer(headerBuffer, (int)restLen);
                        Debug.Assert(contentLength == headerBuffer.Limit - headerBuffer.Next);
                        Debug.Assert(this.MemoryBlock == null);
                    }
                    else
                    {
                        // there is data of the next message
                        Debug.Assert(contentLength <= int.MaxValue);
                        int offset = headerBuffer.Next + (int)contentLength;
                        headerBuffer.SetPrefetchedBytes(offset);
                    }
                }
                else
                {
                    byte[] memoryBlock = EnsureMemoryBlockAllocated();
                    if (contentLength <= memoryBlock.Length)
                    {
                        // The body is to be stored in a memory block. (small body)

                        // copy body bytes in the header buffer to this buffer
                        CopyFrom(headerBuffer, headerBuffer.Next, bodyBytesInHeaderBufferLength);

                        // read rest of body bytes
                        Debug.Assert(restLen <= int.MaxValue);
                        FillBuffer((int)restLen);
                        Debug.Assert(contentLength == (this.Limit - this.Next));
                    }
                    else
                    {
                        // The body is to be stored in a stream.

                        // determine which medium is used to store body, memory or file
                        if (contentLength <= BodyStreamThreshold)
                        {
                            // use memory stream (medium body)
                            Debug.Assert(contentLength <= int.MaxValue);
                            bodyStream = new MemoryStream((int)contentLength);
                        }
                        else
                        {
                            // use temp file stream (large body)
                            bodyStream = Util.CreateTempFileStream();
                        }

                        StoreBody(bodyStream, contentLength);
                    }
                }

                // update state
                this.bodyLength = contentLength;
                this.bodyStream = bodyStream;
            } catch {
                DisposableUtil.DisposeSuppressingErrors(bodyStream);
                throw;
            }

            return;
        }