Do not allow control characters in response headers.
This commit is contained in:
parent
5bcf381604
commit
3061a48a38
|
|
@ -41,6 +41,8 @@ namespace Microsoft.Net.Http.Server
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
ValidateHeaderCharacters(key);
|
||||||
|
ValidateHeaderCharacters(value);
|
||||||
Store[key] = value;
|
Store[key] = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -52,6 +54,8 @@ namespace Microsoft.Net.Http.Server
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
ThrowIfReadOnly();
|
ThrowIfReadOnly();
|
||||||
|
ValidateHeaderCharacters(key);
|
||||||
|
ValidateHeaderCharacters(value);
|
||||||
Store[key] = value;
|
Store[key] = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -74,18 +78,24 @@ namespace Microsoft.Net.Http.Server
|
||||||
public void Add(KeyValuePair<string, StringValues> item)
|
public void Add(KeyValuePair<string, StringValues> item)
|
||||||
{
|
{
|
||||||
ThrowIfReadOnly();
|
ThrowIfReadOnly();
|
||||||
|
ValidateHeaderCharacters(item.Key);
|
||||||
|
ValidateHeaderCharacters(item.Value);
|
||||||
Store.Add(item);
|
Store.Add(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Add(string key, StringValues value)
|
public void Add(string key, StringValues value)
|
||||||
{
|
{
|
||||||
ThrowIfReadOnly();
|
ThrowIfReadOnly();
|
||||||
|
ValidateHeaderCharacters(key);
|
||||||
|
ValidateHeaderCharacters(value);
|
||||||
Store.Add(key, value);
|
Store.Add(key, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Append(string key, string value)
|
public void Append(string key, string value)
|
||||||
{
|
{
|
||||||
ThrowIfReadOnly();
|
ThrowIfReadOnly();
|
||||||
|
ValidateHeaderCharacters(key);
|
||||||
|
ValidateHeaderCharacters(value);
|
||||||
StringValues values;
|
StringValues values;
|
||||||
Store.TryGetValue(key, out values);
|
Store.TryGetValue(key, out values);
|
||||||
Store[key] = StringValues.Concat(values, value);
|
Store[key] = StringValues.Concat(values, value);
|
||||||
|
|
@ -156,5 +166,27 @@ namespace Microsoft.Net.Http.Server
|
||||||
throw new InvalidOperationException("The response headers cannot be modified because the response has already started.");
|
throw new InvalidOperationException("The response headers cannot be modified because the response has already started.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void ValidateHeaderCharacters(StringValues headerValues)
|
||||||
|
{
|
||||||
|
foreach (var value in headerValues)
|
||||||
|
{
|
||||||
|
ValidateHeaderCharacters(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void ValidateHeaderCharacters(string headerCharacters)
|
||||||
|
{
|
||||||
|
if (headerCharacters != null)
|
||||||
|
{
|
||||||
|
foreach (var ch in headerCharacters)
|
||||||
|
{
|
||||||
|
if (ch < 0x20)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException(string.Format("Invalid control character in header: 0x{0:X2}", (byte)ch));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1,11 +1,13 @@
|
||||||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
|
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.Extensions.Primitives;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
namespace Microsoft.Net.Http.Server
|
namespace Microsoft.Net.Http.Server
|
||||||
|
|
@ -415,6 +417,65 @@ namespace Microsoft.Net.Http.Server
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[InlineData("Server", "\r\nData")]
|
||||||
|
[InlineData("Server", "\0Data")]
|
||||||
|
[InlineData("Server", "Data\r")]
|
||||||
|
[InlineData("Server", "Da\0ta")]
|
||||||
|
[InlineData("Server", "Da\u001Fta")]
|
||||||
|
[InlineData("Unknown-Header", "\r\nData")]
|
||||||
|
[InlineData("Unknown-Header", "\0Data")]
|
||||||
|
[InlineData("Unknown-Header", "Data\0")]
|
||||||
|
[InlineData("Unknown-Header", "Da\nta")]
|
||||||
|
[InlineData("\r\nServer", "Data")]
|
||||||
|
[InlineData("Server\r", "Data")]
|
||||||
|
[InlineData("Ser\0ver", "Data")]
|
||||||
|
[InlineData("Server\r\n", "Data")]
|
||||||
|
[InlineData("\u001FServer", "Data")]
|
||||||
|
[InlineData("Unknown-Header\r\n", "Data")]
|
||||||
|
[InlineData("\0Unknown-Header", "Data")]
|
||||||
|
[InlineData("Unknown\r-Header", "Data")]
|
||||||
|
[InlineData("Unk\nown-Header", "Data")]
|
||||||
|
public async Task AddingControlCharactersToHeadersThrows(string key, string value)
|
||||||
|
{
|
||||||
|
string address;
|
||||||
|
using (var server = Utilities.CreateHttpServer(out address))
|
||||||
|
{
|
||||||
|
Task<HttpResponseMessage> responseTask = SendRequestAsync(address);
|
||||||
|
|
||||||
|
var context = await server.GetContextAsync();
|
||||||
|
|
||||||
|
var responseHeaders = context.Response.Headers;
|
||||||
|
|
||||||
|
Assert.Throws<InvalidOperationException>(() => {
|
||||||
|
responseHeaders[key] = value;
|
||||||
|
});
|
||||||
|
|
||||||
|
Assert.Throws<InvalidOperationException>(() => {
|
||||||
|
responseHeaders[key] = new StringValues(new[] { "valid", value });
|
||||||
|
});
|
||||||
|
|
||||||
|
Assert.Throws<InvalidOperationException>(() => {
|
||||||
|
((IDictionary<string, StringValues>)responseHeaders)[key] = value;
|
||||||
|
});
|
||||||
|
|
||||||
|
Assert.Throws<InvalidOperationException>(() => {
|
||||||
|
var kvp = new KeyValuePair<string, StringValues>(key, value);
|
||||||
|
((ICollection<KeyValuePair<string, StringValues>>)responseHeaders).Add(kvp);
|
||||||
|
});
|
||||||
|
|
||||||
|
Assert.Throws<InvalidOperationException>(() => {
|
||||||
|
var kvp = new KeyValuePair<string, StringValues>(key, value);
|
||||||
|
((IDictionary<string, StringValues>)responseHeaders).Add(key, value);
|
||||||
|
});
|
||||||
|
|
||||||
|
context.Dispose();
|
||||||
|
|
||||||
|
HttpResponseMessage response = await responseTask;
|
||||||
|
response.EnsureSuccessStatusCode();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private async Task<HttpResponseMessage> SendRequestAsync(string uri, bool usehttp11 = true, bool sendKeepAlive = false)
|
private async Task<HttpResponseMessage> SendRequestAsync(string uri, bool usehttp11 = true, bool sendKeepAlive = false)
|
||||||
{
|
{
|
||||||
using (HttpClient client = new HttpClient())
|
using (HttpClient client = new HttpClient())
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue