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
|
||||
{
|
||||
ValidateHeaderCharacters(key);
|
||||
ValidateHeaderCharacters(value);
|
||||
Store[key] = value;
|
||||
}
|
||||
}
|
||||
|
|
@ -52,6 +54,8 @@ namespace Microsoft.Net.Http.Server
|
|||
set
|
||||
{
|
||||
ThrowIfReadOnly();
|
||||
ValidateHeaderCharacters(key);
|
||||
ValidateHeaderCharacters(value);
|
||||
Store[key] = value;
|
||||
}
|
||||
}
|
||||
|
|
@ -74,18 +78,24 @@ namespace Microsoft.Net.Http.Server
|
|||
public void Add(KeyValuePair<string, StringValues> item)
|
||||
{
|
||||
ThrowIfReadOnly();
|
||||
ValidateHeaderCharacters(item.Key);
|
||||
ValidateHeaderCharacters(item.Value);
|
||||
Store.Add(item);
|
||||
}
|
||||
|
||||
public void Add(string key, StringValues value)
|
||||
{
|
||||
ThrowIfReadOnly();
|
||||
ValidateHeaderCharacters(key);
|
||||
ValidateHeaderCharacters(value);
|
||||
Store.Add(key, value);
|
||||
}
|
||||
|
||||
public void Append(string key, string value)
|
||||
{
|
||||
ThrowIfReadOnly();
|
||||
ValidateHeaderCharacters(key);
|
||||
ValidateHeaderCharacters(value);
|
||||
StringValues values;
|
||||
Store.TryGetValue(key, out values);
|
||||
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.");
|
||||
}
|
||||
}
|
||||
|
||||
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.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Extensions.Primitives;
|
||||
using Xunit;
|
||||
|
||||
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)
|
||||
{
|
||||
using (HttpClient client = new HttpClient())
|
||||
|
|
|
|||
Loading…
Reference in New Issue