Пример #1
0
        private static (string PrevHeaderValue, string NextHeaderValue) GetHeaderValues(HttpRequestHeaders headers, string prevName, string nextName, string prevValue, string nextValue)
        {
            headers.Reset();
            var headerName = Encoding.ASCII.GetBytes(prevName).AsSpan();
            var prevSpan   = Encoding.UTF8.GetBytes(prevValue).AsSpan();

            headers.Append(headerName, prevSpan);
            headers.OnHeadersComplete();
            var prevHeaderValue = ((IHeaderDictionary)headers)[prevName].ToString();

            headers.Reset();

            if (nextValue != null)
            {
                headerName = Encoding.ASCII.GetBytes(prevName).AsSpan();
                var nextSpan = Encoding.UTF8.GetBytes(nextValue).AsSpan();
                headers.Append(headerName, nextSpan);
            }

            headers.OnHeadersComplete();

            var newHeaderValue = ((IHeaderDictionary)headers)[nextName].ToString();

            return(prevHeaderValue, newHeaderValue);
        }
Пример #2
0
        public void Latin1ValuesAcceptedInLatin1ModeButNotReused(bool reuseValue, KnownHeader header)
        {
            var headers = new HttpRequestHeaders(reuseHeaderValues: reuseValue, _ => Encoding.Latin1);

            var headerValue = new char[127]; // 64 + 32 + 16 + 8 + 4 + 2 + 1

            for (var i = 0; i < headerValue.Length; i++)
            {
                headerValue[i] = 'a';
            }

            for (var i = 0; i < headerValue.Length; i++)
            {
                // Set non-ascii Latin char that is valid Utf16 when widened; but not a valid utf8 -> utf16 conversion.
                headerValue[i] = '\u00a3';

                for (var mode = 0; mode <= 1; mode++)
                {
                    string headerValueUtf16Latin1CrossOver;
                    if (mode == 0)
                    {
                        // Full length
                        headerValueUtf16Latin1CrossOver = new string(headerValue);
                    }
                    else
                    {
                        // Truncated length (to ensure different paths from changing lengths in matching)
                        headerValueUtf16Latin1CrossOver = new string(headerValue.AsSpan().Slice(0, i + 1));
                    }

                    var headerName     = Encoding.ASCII.GetBytes(header.Name).AsSpan();
                    var latinValueSpan = Encoding.Latin1.GetBytes(headerValueUtf16Latin1CrossOver).AsSpan();

                    Assert.False(latinValueSpan.SequenceEqual(Encoding.ASCII.GetBytes(headerValueUtf16Latin1CrossOver)));

                    headers.Reset();
                    headers.Append(headerName, latinValueSpan);
                    headers.OnHeadersComplete();
                    var parsedHeaderValue1 = ((IHeaderDictionary)headers)[header.Name].ToString();

                    headers.Reset();
                    headers.Append(headerName, latinValueSpan);
                    headers.OnHeadersComplete();
                    var parsedHeaderValue2 = ((IHeaderDictionary)headers)[header.Name].ToString();

                    Assert.Equal(headerValueUtf16Latin1CrossOver, parsedHeaderValue1);
                    Assert.Equal(parsedHeaderValue1, parsedHeaderValue2);
                    Assert.NotSame(parsedHeaderValue1, parsedHeaderValue2);
                }

                // Reset back to Ascii
                headerValue[i] = 'a';
            }
        }
Пример #3
0
        public void CanSpecifyEncodingBasedOnHeaderName()
        {
            const string headerValue      = "Hello \u03a0";
            var          acceptNameBytes  = Encoding.ASCII.GetBytes(HeaderNames.Accept);
            var          cookieNameBytes  = Encoding.ASCII.GetBytes(HeaderNames.Cookie);
            var          headerValueBytes = Encoding.UTF8.GetBytes(headerValue);

            var headers = new HttpRequestHeaders(encodingSelector: headerName =>
            {
                // For known headers, the HeaderNames value is passed in.
                if (ReferenceEquals(headerName, HeaderNames.Accept))
                {
                    return(Encoding.GetEncoding("ASCII", EncoderFallback.ExceptionFallback, DecoderFallback.ExceptionFallback));
                }

                return(Encoding.UTF8);
            });

            Assert.Throws <InvalidOperationException>(() => headers.Append(acceptNameBytes, headerValueBytes));
            headers.Append(cookieNameBytes, headerValueBytes);
            headers.OnHeadersComplete();

            var parsedAcceptHeaderValue = ((IHeaderDictionary)headers)[HeaderNames.Accept].ToString();
            var parsedCookieHeaderValue = ((IHeaderDictionary)headers)[HeaderNames.Cookie].ToString();

            Assert.Empty(parsedAcceptHeaderValue);
            Assert.Equal(headerValue, parsedCookieHeaderValue);
        }
Пример #4
0
        public void ValueReuseLatin1NotConfusedForUtf16AndStillRejected(bool reuseValue, KnownHeader header)
        {
            var headers = new HttpRequestHeaders(reuseHeaderValues: reuseValue);

            var headerValue = new char[127]; // 64 + 32 + 16 + 8 + 4 + 2 + 1

            for (var i = 0; i < headerValue.Length; i++)
            {
                headerValue[i] = 'a';
            }

            for (var i = 0; i < headerValue.Length; i++)
            {
                // Set non-ascii Latin char that is valid Utf16 when widened; but not a valid utf8 -> utf16 conversion.
                headerValue[i] = '\u00a3';

                for (var mode = 0; mode <= 1; mode++)
                {
                    string headerValueUtf16Latin1CrossOver;
                    if (mode == 0)
                    {
                        // Full length
                        headerValueUtf16Latin1CrossOver = new string(headerValue);
                    }
                    else
                    {
                        // Truncated length (to ensure different paths from changing lengths in matching)
                        headerValueUtf16Latin1CrossOver = new string(headerValue.AsSpan().Slice(0, i + 1));
                    }

                    headers.Reset();

                    var headerName = Encoding.ASCII.GetBytes(header.Name).AsSpan();
                    var prevSpan   = Encoding.UTF8.GetBytes(headerValueUtf16Latin1CrossOver).AsSpan();

                    headers.Append(headerName, prevSpan);
                    headers.OnHeadersComplete();
                    var prevHeaderValue = ((IHeaderDictionary)headers)[header.Name].ToString();

                    Assert.Equal(headerValueUtf16Latin1CrossOver, prevHeaderValue);
                    Assert.NotSame(headerValueUtf16Latin1CrossOver, prevHeaderValue);

                    headers.Reset();

                    Assert.Throws <InvalidOperationException>(() =>
                    {
                        var headerName = Encoding.ASCII.GetBytes(header.Name).AsSpan();
                        var nextSpan   = Encoding.Latin1.GetBytes(headerValueUtf16Latin1CrossOver).AsSpan();

                        Assert.False(nextSpan.SequenceEqual(Encoding.ASCII.GetBytes(headerValueUtf16Latin1CrossOver)));

                        headers.Append(headerName, nextSpan);
                    });
                }

                // Reset back to Ascii
                headerValue[i] = 'a';
            }
        }
Пример #5
0
        public void MultiValueReuseEmptyAfterReset(bool reuseValue, KnownHeader header)
        {
            const string HeaderValue1 = "Hello1";
            const string HeaderValue2 = "Hello2";

            var headers    = new HttpRequestHeaders(reuseHeaderValues: reuseValue);
            var headerName = Encoding.ASCII.GetBytes(header.Name).AsSpan();
            var prevSpan1  = Encoding.UTF8.GetBytes(HeaderValue1).AsSpan();
            var prevSpan2  = Encoding.UTF8.GetBytes(HeaderValue2).AsSpan();

            headers.Append(headerName, prevSpan1);
            headers.Append(headerName, prevSpan2);
            headers.OnHeadersComplete();
            var prevHeaderValue = ((IHeaderDictionary)headers)[header.Name];

            Assert.Equal(2, prevHeaderValue.Count);

            Assert.NotEqual(string.Empty, prevHeaderValue.ToString());
            Assert.Single(headers);
            var count = headers.Count;

            Assert.Equal(1, count);

            headers.Reset();

            // Empty after reset
            var nextHeaderValue = ((IHeaderDictionary)headers)[header.Name].ToString();

            Assert.NotNull(nextHeaderValue);
            Assert.Equal(string.Empty, nextHeaderValue);
            Assert.Empty(headers);
            count = headers.Count;
            Assert.Equal(0, count);

            headers.OnHeadersComplete();

            // Still empty after complete
            nextHeaderValue = ((IHeaderDictionary)headers)[header.Name].ToString();

            Assert.NotNull(nextHeaderValue);
            Assert.Equal(string.Empty, nextHeaderValue);
            Assert.Empty(headers);
            count = headers.Count;
            Assert.Equal(0, count);
        }
Пример #6
0
        public void ValueReuseEmptyAfterReset(bool reuseValue, KnownHeader header)
        {
            const string HeaderValue = "Hello";

            var headers    = new HttpRequestHeaders(reuseHeaderValues: reuseValue);
            var headerName = Encoding.ASCII.GetBytes(header.Name).AsSpan();
            var prevSpan   = Encoding.UTF8.GetBytes(HeaderValue).AsSpan();

            headers.Append(headerName, prevSpan, checkForNewlineChars: false);
            headers.OnHeadersComplete();
            var prevHeaderValue = ((IHeaderDictionary)headers)[header.Name].ToString();

            Assert.NotNull(prevHeaderValue);
            Assert.NotEqual(string.Empty, prevHeaderValue);
            Assert.Equal(HeaderValue, prevHeaderValue);
            Assert.NotSame(HeaderValue, prevHeaderValue);
            Assert.Single(headers);
            var count = headers.Count;

            Assert.Equal(1, count);

            headers.Reset();

            // Empty after reset
            var nextHeaderValue = ((IHeaderDictionary)headers)[header.Name].ToString();

            Assert.NotNull(nextHeaderValue);
            Assert.Equal(string.Empty, nextHeaderValue);
            Assert.NotEqual(HeaderValue, nextHeaderValue);
            Assert.Empty(headers);
            count = headers.Count;
            Assert.Equal(0, count);

            headers.OnHeadersComplete();

            // Still empty after complete
            nextHeaderValue = ((IHeaderDictionary)headers)[header.Name].ToString();

            Assert.NotNull(nextHeaderValue);
            Assert.Equal(string.Empty, nextHeaderValue);
            Assert.NotEqual(HeaderValue, nextHeaderValue);
            Assert.Empty(headers);
            count = headers.Count;
            Assert.Equal(0, count);
        }
Пример #7
0
        public void CanSpecifyEncodingForContentLength()
        {
            var contentLengthNameBytes = Encoding.ASCII.GetBytes(HeaderNames.ContentLength);
            // Always 32 bits per code point, so not a superset of ASCII
            var contentLengthValueBytes = Encoding.UTF32.GetBytes("1337");

            var headers = new HttpRequestHeaders(encodingSelector: _ => Encoding.UTF32);

            headers.Append(contentLengthNameBytes, contentLengthValueBytes);
            headers.OnHeadersComplete();

            Assert.Equal(1337, headers.ContentLength);

            Assert.Throws <InvalidOperationException>(() =>
                                                      new HttpRequestHeaders().Append(contentLengthNameBytes, contentLengthValueBytes));
        }