Example #1
0
        public static HeaderSection CreateNew(HttpHeaders headers)
        {
            var hs = new HeaderSection();

            foreach (var header in headers)
            {
                hs.Fields.Add(new HeaderField(header.Key, string.Join(",", header.Value)));
            }

            // -- Start [SECTION] Crazy VS2017/.NET Core 1.1 bug ---
            // The following if branch is needed as is to avoid the craziest VS2017/.NET Core 1.1 bug I have ever seen!
            // If this section is not added the Content-Length header will not be set unless...
            // - I put a break point at the start of the function
            // - And I explicitly expand the "headers" variable
            if (headers is HttpContentHeaders)
            {
                if (((HttpContentHeaders)headers).ContentLength != null)
                {
                    if (hs.Fields.All(x => x.Name != "Content-Length"))
                    {
                        hs.Fields.Add(new HeaderField("Content-Length", ((HttpContentHeaders)headers).ContentLength.ToString()));
                    }
                }
            }
            // -- End [SECTION] Crazy VS2017/.NET Core 1.1 bug ---

            return(hs);
        }
Example #2
0
        public static HeaderSection CreateNew(string headersString)
        {
            headersString = HeaderField.CorrectObsFolding(headersString);

            var hs = new HeaderSection();

            if (headersString.EndsWith(CRLF + CRLF))
            {
                headersString = headersString.TrimEnd(CRLF, StringComparison.Ordinal);
            }

            using (var reader = new StringReader(headersString))
            {
                while (true)
                {
                    var field = reader.ReadLine(strictCRLF: true);
                    if (field is null)
                    {
                        break;
                    }
                    hs.Fields.Add(HeaderField.CreateNew(field));
                }

                ValidateAndCorrectHeaders(hs);

                return(hs);
            }
        }
Example #3
0
        public static async Task <HeaderSection> CreateNewAsync(string headersString)
        {
            headersString = HeaderField.CorrectObsFolding(headersString);

            var hs = new HeaderSection();

            if (headersString.EndsWith(CRLF + CRLF))
            {
                headersString = headersString.TrimEnd(CRLF, StringComparison.Ordinal);
            }

            using var reader = new StringReader(headersString);
            while (true)
            {
                var field = reader.ReadLine(strictCRLF: true);
                if (field is null)
                {
                    break;
                }
                hs.Fields.Add(await HeaderField.CreateNewAsync(field).ConfigureAwait(false));
            }

            ValidateAndCorrectHeaders(hs);

            return(hs);
        }
Example #4
0
        private static void ValidateAndCorrectHeaders(HeaderSection hs)
        {
            // https://tools.ietf.org/html/rfc7230#section-5.4
            // Since the Host field - value is critical information for handling a
            // request, a user agent SHOULD generate Host as the first header field
            // following the request - line.
            HeaderField hostToCorrect = null;

            foreach (var f in hs.Fields)
            {
                // if we find host
                if (f.Name == "Host")
                {
                    // if host is not first
                    if (hs.Fields.First().Name != "Host")
                    {
                        // then correct host
                        hostToCorrect = f;
                        break;
                    }
                }
            }

            if (hostToCorrect != null)
            {
                hs.Fields.Remove(hostToCorrect);
                hs.Fields.Insert(0, hostToCorrect);
            }

            // https://tools.ietf.org/html/rfc7230#section-3.3.2
            // If a message is received that has multiple Content-Length header
            // fields with field-values consisting of the same decimal value, or a
            // single Content-Length header field with a field value containing a
            // list of identical decimal values(e.g., "Content-Length: 42, 42"),
            // indicating that duplicate Content-Length header fields have been
            // generated or combined by an upstream message processor, then the
            // recipient MUST either reject the message as invalid or replace the
            // duplicated field - values with a single valid Content - Length field
            // containing that decimal value prior to determining the message body
            // length or forwarding the message.

            var allParts = new HashSet <string>();

            foreach (var field in hs.Fields)
            {
                if (field.Name == "Content-Length")
                {
                    var parts = field.Value.Trim().Split(',');
                    foreach (var part in parts)
                    {
                        allParts.Add(part.Trim());
                    }
                }
            }
            if (allParts.Count > 0)             // then has Content-Length field
            {
                if (allParts.Count > 1)
                {
                    throw new InvalidDataException("Invalid Content-Length.");
                }
                hs.Fields.RemoveAll(x => x.Name == "Content-Length");
                hs.Fields.Add(new HeaderField("Content-Length", allParts.First()));
            }
        }