Skip to content
This repository was archived by the owner on Mar 19, 2019. It is now read-only.

Commit cd9952c

Browse files
committed
Merge branch 'release' into dev
2 parents a811eaf + 3061a48 commit cd9952c

File tree

2 files changed

+93
-0
lines changed

2 files changed

+93
-0
lines changed

src/Microsoft.Net.Http.Server/RequestProcessing/HeaderCollection.cs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@ public StringValues this[string key]
4141
}
4242
else
4343
{
44+
ValidateHeaderCharacters(key);
45+
ValidateHeaderCharacters(value);
4446
Store[key] = value;
4547
}
4648
}
@@ -52,6 +54,8 @@ StringValues IDictionary<string, StringValues>.this[string key]
5254
set
5355
{
5456
ThrowIfReadOnly();
57+
ValidateHeaderCharacters(key);
58+
ValidateHeaderCharacters(value);
5559
Store[key] = value;
5660
}
5761
}
@@ -74,18 +78,24 @@ public ICollection<StringValues> Values
7478
public void Add(KeyValuePair<string, StringValues> item)
7579
{
7680
ThrowIfReadOnly();
81+
ValidateHeaderCharacters(item.Key);
82+
ValidateHeaderCharacters(item.Value);
7783
Store.Add(item);
7884
}
7985

8086
public void Add(string key, StringValues value)
8187
{
8288
ThrowIfReadOnly();
89+
ValidateHeaderCharacters(key);
90+
ValidateHeaderCharacters(value);
8391
Store.Add(key, value);
8492
}
8593

8694
public void Append(string key, string value)
8795
{
8896
ThrowIfReadOnly();
97+
ValidateHeaderCharacters(key);
98+
ValidateHeaderCharacters(value);
8999
StringValues values;
90100
Store.TryGetValue(key, out values);
91101
Store[key] = StringValues.Concat(values, value);
@@ -156,5 +166,27 @@ private void ThrowIfReadOnly()
156166
throw new InvalidOperationException("The response headers cannot be modified because the response has already started.");
157167
}
158168
}
169+
170+
public static void ValidateHeaderCharacters(StringValues headerValues)
171+
{
172+
foreach (var value in headerValues)
173+
{
174+
ValidateHeaderCharacters(value);
175+
}
176+
}
177+
178+
public static void ValidateHeaderCharacters(string headerCharacters)
179+
{
180+
if (headerCharacters != null)
181+
{
182+
foreach (var ch in headerCharacters)
183+
{
184+
if (ch < 0x20)
185+
{
186+
throw new InvalidOperationException(string.Format("Invalid control character in header: 0x{0:X2}", (byte)ch));
187+
}
188+
}
189+
}
190+
}
159191
}
160192
}

test/Microsoft.Net.Http.Server.FunctionalTests/ResponseHeaderTests.cs

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
22

33
using System;
4+
using System.Collections.Generic;
45
using System.Linq;
56
using System.Net;
67
using System.Net.Http;
78
using System.Text;
89
using System.Threading.Tasks;
10+
using Microsoft.Extensions.Primitives;
911
using Xunit;
1012

1113
namespace Microsoft.Net.Http.Server
@@ -415,6 +417,65 @@ public async Task Headers_FlushAsyncSendsHeaders_Success()
415417
}
416418
}
417419

420+
[Theory]
421+
[InlineData("Server", "\r\nData")]
422+
[InlineData("Server", "\0Data")]
423+
[InlineData("Server", "Data\r")]
424+
[InlineData("Server", "Da\0ta")]
425+
[InlineData("Server", "Da\u001Fta")]
426+
[InlineData("Unknown-Header", "\r\nData")]
427+
[InlineData("Unknown-Header", "\0Data")]
428+
[InlineData("Unknown-Header", "Data\0")]
429+
[InlineData("Unknown-Header", "Da\nta")]
430+
[InlineData("\r\nServer", "Data")]
431+
[InlineData("Server\r", "Data")]
432+
[InlineData("Ser\0ver", "Data")]
433+
[InlineData("Server\r\n", "Data")]
434+
[InlineData("\u001FServer", "Data")]
435+
[InlineData("Unknown-Header\r\n", "Data")]
436+
[InlineData("\0Unknown-Header", "Data")]
437+
[InlineData("Unknown\r-Header", "Data")]
438+
[InlineData("Unk\nown-Header", "Data")]
439+
public async Task AddingControlCharactersToHeadersThrows(string key, string value)
440+
{
441+
string address;
442+
using (var server = Utilities.CreateHttpServer(out address))
443+
{
444+
Task<HttpResponseMessage> responseTask = SendRequestAsync(address);
445+
446+
var context = await server.GetContextAsync();
447+
448+
var responseHeaders = context.Response.Headers;
449+
450+
Assert.Throws<InvalidOperationException>(() => {
451+
responseHeaders[key] = value;
452+
});
453+
454+
Assert.Throws<InvalidOperationException>(() => {
455+
responseHeaders[key] = new StringValues(new[] { "valid", value });
456+
});
457+
458+
Assert.Throws<InvalidOperationException>(() => {
459+
((IDictionary<string, StringValues>)responseHeaders)[key] = value;
460+
});
461+
462+
Assert.Throws<InvalidOperationException>(() => {
463+
var kvp = new KeyValuePair<string, StringValues>(key, value);
464+
((ICollection<KeyValuePair<string, StringValues>>)responseHeaders).Add(kvp);
465+
});
466+
467+
Assert.Throws<InvalidOperationException>(() => {
468+
var kvp = new KeyValuePair<string, StringValues>(key, value);
469+
((IDictionary<string, StringValues>)responseHeaders).Add(key, value);
470+
});
471+
472+
context.Dispose();
473+
474+
HttpResponseMessage response = await responseTask;
475+
response.EnsureSuccessStatusCode();
476+
}
477+
}
478+
418479
private async Task<HttpResponseMessage> SendRequestAsync(string uri, bool usehttp11 = true, bool sendKeepAlive = false)
419480
{
420481
using (HttpClient client = new HttpClient())

0 commit comments

Comments
 (0)