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); }
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'; } }
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); }
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'; } }
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); }
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); }
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)); }