Example #1
0
        /// <summary>
        ///   Called to scan the bytes of a potential line for invalid characters
        /// </summary>
        /// <param name="buffer">
        ///   Array containing the bytes that to can for invalid characters
        /// </param>
        /// <param name="start">Index in the array at which to begin reading</param>
        /// <param name="count">Number of bytes from the array to scan</param>
        protected override void VerifyPotentialLine(byte[] buffer, int start, int count)
        {
            // Make sure the line does not contain any characters which are considered
            // invalid by the RFC
            for (int index = start; index < count; ++index)
            {
                // First, find out whether this is a control character. All but 2 control
                // characters are disallowed by the RFC
                bool isControlCharacter =
                    (buffer[index] < 32) ||
                    (buffer[index] == DEL);

                // If it Is a control character, we need to do another check to see whether
                // the characters is one of the two allowed control characters
                if (isControlCharacter)
                {
                    bool isValidControlCharacter =
                        (buffer[index] == SP) ||
                        (buffer[index] == HT);

                    // It's not one of the two allowed control characters, let's complain
                    if (!isValidControlCharacter)
                    {
                        throw Errors.BadRequest("Invalid character in request header");
                    }
                }
            }
        }
        /// <summary>Parses a request header line sent from the client</summary>
        /// <param name="headerLine">String containing the received header line</param>
        private void parseHeaderLine(string headerLine)
        {
            // Find out whether this header line begins with whitespace. According to the
            // RFC, a message header can be broken into multiple lines by beginning the
            // next line with one or more whitespace characters (SP and HT)
            char firstCharacter       = headerLine[0];
            bool startsWithWhitespace =
                (firstCharacter == ' ') ||
                (firstCharacter == '\t');

            // If the line starts with a whitespace, it is either a continuation of the
            // previous line or simply a broken request (or there is no previous line)
            if (startsWithWhitespace)
            {
                // If this is the first header field, the request is broken
                if (this.currentFieldName == null)
                {
                    throw Errors.BadRequest("First message header is preceded by whitespace");
                }

                // Alright, this actually seems to be a valid field continuation
                parseHeaderFieldValue(headerLine, 1);
            }
            else // Line doesn't begin with a whitespace

            // Look for the delimiter character that ends the field name
            {
                int valueDelimiterIndex = headerLine.IndexOf(':');
                if (valueDelimiterIndex == -1) // No delimiter? Invalid request!
                {
                    throw Errors.BadRequest("Message header field omits value");
                }

                // Extract the field name from the line
                string fieldName = headerLine.Substring(0, valueDelimiterIndex);
                if (fieldName == string.Empty) // Empty field name? Request broken!
                {
                    throw Errors.BadRequest("Message header contains unnamed field");
                }

                // There is no mention in the RFC that whitespace is allowed between the
                // header field name and the delimiter character, so we don't allow it.
                bool fieldNameEndsInWhitespace =
                    (fieldName[fieldName.Length - 1] == ' ') ||
                    (fieldName[fieldName.Length - 1] == '\t');

                if (fieldNameEndsInWhitespace)
                {
                    throw Errors.BadRequest(
                              "Message header field name is followed by whitespace"
                              );
                }

                // Now that we know where the value begins, parse it!
                this.currentFieldName = fieldName;
                parseHeaderFieldValue(headerLine, valueDelimiterIndex + 1);
            }
        }
        /// <summary>Parses the request line sent from the client</summary>
        /// <param name="requestLine">String containing the received request line</param>
        private void parseRequestLine(string requestLine)
        {
            // The RFC doesn't say that the request line must not contain any additional
            // spaces, so in the we will assume the first space terminates the method and the
            // last space terminates the URI.
            int uriDelimiterIndex = requestLine.IndexOf(' ');

            if (uriDelimiterIndex == -1)
            {
                throw Errors.BadRequest("Request-line is missing an URI");
            }

            // If there's only one space character, then the request is missing the version
            // of the HTTP protocol used.
            int versionDelimiterIndex = requestLine.LastIndexOf(' ');

            if (versionDelimiterIndex == uriDelimiterIndex)
            {
                throw Errors.BadRequest("Request-line does not specify HTTP version");
            }

            // Request seems to be at least be in the right layout. Extract the individual
            // components and pass them to the request container builder (validation of
            // the actual settings takes place once we have a complete request).
            requestBuilder.Method = requestLine.Substring(0, uriDelimiterIndex);
            requestBuilder.Uri    = requestLine.Substring(
                uriDelimiterIndex + 1, versionDelimiterIndex - uriDelimiterIndex - 1
                );
            requestBuilder.Version = requestLine.Substring(versionDelimiterIndex + 1);

            // We expect HTTP/1.* to stay compatible with the general format of the request.
            // Any other version of the protocol may include major changes to the request
            // format, thus we only accept HTTP/1.*.
            if (!requestBuilder.Version.StartsWith("HTTP/1."))
            {
                throw Errors.UnsupportedProtocolVersion();
            }
        }
Example #4
0
 /// <summary>
 ///   Called when the message contains a carriage return without a line feed
 /// </summary>
 protected override void HandleLoneCarriageReturn()
 {
     throw Errors.BadRequest("Invalid character in request header");
 }