#54 - Throw if anyone tries to modify the response headers after they are sent.
This commit is contained in:
parent
281ef61e8c
commit
56483cb0ed
|
|
@ -47,7 +47,7 @@ namespace SelfHostServer
|
|||
else
|
||||
{
|
||||
context.Response.ContentType = "text/plain";
|
||||
await context.Response.WriteAsync("Hello world");
|
||||
await context.Response.WriteAsync("Hello world from " + context.Request.Host + " at " + DateTime.Now);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,11 +21,15 @@ namespace Microsoft.Net.Http.Server
|
|||
|
||||
private IDictionary<string, string[]> Store { get; set; }
|
||||
|
||||
// Readonly after the response has been sent.
|
||||
internal bool Sent { get; set; }
|
||||
|
||||
public string this[string key]
|
||||
{
|
||||
get { return Get(key); }
|
||||
set
|
||||
{
|
||||
ThrowIfSent();
|
||||
if (string.IsNullOrEmpty(value))
|
||||
{
|
||||
Remove(key);
|
||||
|
|
@ -40,7 +44,11 @@ namespace Microsoft.Net.Http.Server
|
|||
string[] IDictionary<string, string[]>.this[string key]
|
||||
{
|
||||
get { return Store[key]; }
|
||||
set { Store[key] = value; }
|
||||
set
|
||||
{
|
||||
ThrowIfSent();
|
||||
Store[key] = value;
|
||||
}
|
||||
}
|
||||
|
||||
public int Count
|
||||
|
|
@ -50,7 +58,7 @@ namespace Microsoft.Net.Http.Server
|
|||
|
||||
public bool IsReadOnly
|
||||
{
|
||||
get { return false; }
|
||||
get { return Sent; }
|
||||
}
|
||||
|
||||
public ICollection<string> Keys
|
||||
|
|
@ -65,16 +73,19 @@ namespace Microsoft.Net.Http.Server
|
|||
|
||||
public void Add(KeyValuePair<string, string[]> item)
|
||||
{
|
||||
ThrowIfSent();
|
||||
Store.Add(item);
|
||||
}
|
||||
|
||||
public void Add(string key, string[] value)
|
||||
{
|
||||
ThrowIfSent();
|
||||
Store.Add(key, value);
|
||||
}
|
||||
|
||||
public void Append(string key, string value)
|
||||
{
|
||||
ThrowIfSent();
|
||||
string[] values;
|
||||
if (Store.TryGetValue(key, out values))
|
||||
{
|
||||
|
|
@ -91,6 +102,7 @@ namespace Microsoft.Net.Http.Server
|
|||
|
||||
public void AppendValues(string key, params string[] values)
|
||||
{
|
||||
ThrowIfSent();
|
||||
string[] oldValues;
|
||||
if (Store.TryGetValue(key, out oldValues))
|
||||
{
|
||||
|
|
@ -107,6 +119,7 @@ namespace Microsoft.Net.Http.Server
|
|||
|
||||
public void Clear()
|
||||
{
|
||||
ThrowIfSent();
|
||||
Store.Clear();
|
||||
}
|
||||
|
||||
|
|
@ -152,21 +165,25 @@ namespace Microsoft.Net.Http.Server
|
|||
|
||||
public bool Remove(KeyValuePair<string, string[]> item)
|
||||
{
|
||||
ThrowIfSent();
|
||||
return Store.Remove(item);
|
||||
}
|
||||
|
||||
public bool Remove(string key)
|
||||
{
|
||||
ThrowIfSent();
|
||||
return Store.Remove(key);
|
||||
}
|
||||
|
||||
public void Set(string key, string value)
|
||||
{
|
||||
ThrowIfSent();
|
||||
Store[key] = new[] { value };
|
||||
}
|
||||
|
||||
public void SetValues(string key, params string[] values)
|
||||
{
|
||||
ThrowIfSent();
|
||||
Store[key] = values;
|
||||
}
|
||||
|
||||
|
|
@ -179,5 +196,13 @@ namespace Microsoft.Net.Http.Server
|
|||
{
|
||||
return GetEnumerator();
|
||||
}
|
||||
|
||||
private void ThrowIfSent()
|
||||
{
|
||||
if (Sent)
|
||||
{
|
||||
throw new InvalidOperationException("The response headers cannot be modified because they have already been sent.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -583,6 +583,7 @@ namespace Microsoft.Net.Http.Server
|
|||
|
||||
private List<GCHandle> SerializeHeaders(bool isOpaqueUpgrade)
|
||||
{
|
||||
Headers.Sent = true; // Prohibit further modifications.
|
||||
UnsafeNclNativeMethods.HttpApi.HTTP_UNKNOWN_HEADER[] unknownHeaders = null;
|
||||
UnsafeNclNativeMethods.HttpApi.HTTP_RESPONSE_INFO[] knownHeaderInfo = null;
|
||||
List<GCHandle> pinnedHeaders;
|
||||
|
|
|
|||
|
|
@ -247,7 +247,7 @@ namespace Microsoft.AspNet.Server.WebListener
|
|||
var body = responseInfo.Body;
|
||||
body.Flush();
|
||||
Assert.Throws<InvalidOperationException>(() => responseInfo.StatusCode = 404);
|
||||
responseHeaders.Add("Custom3", new string[] { "value3a, value3b", "value3c" }); // Ignored
|
||||
Assert.Throws<InvalidOperationException>(() => responseHeaders.Add("Custom3", new string[] { "value3a, value3b", "value3c" }));
|
||||
return Task.FromResult(0);
|
||||
}))
|
||||
{
|
||||
|
|
@ -277,7 +277,7 @@ namespace Microsoft.AspNet.Server.WebListener
|
|||
var body = responseInfo.Body;
|
||||
await body.FlushAsync();
|
||||
Assert.Throws<InvalidOperationException>(() => responseInfo.StatusCode = 404);
|
||||
responseHeaders.Add("Custom3", new string[] { "value3a, value3b", "value3c" }); // Ignored
|
||||
Assert.Throws<InvalidOperationException>(() => responseHeaders.Add("Custom3", new string[] { "value3a, value3b", "value3c" }));
|
||||
}))
|
||||
{
|
||||
HttpResponseMessage response = await SendRequestAsync(address);
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ namespace Microsoft.Net.Http.Server
|
|||
byte[] body = Encoding.UTF8.GetBytes("Hello World");
|
||||
context.Response.Body.Write(body, 0, body.Length);
|
||||
|
||||
context.Response.Headers["Upgrade"] = "WebSocket"; // Win8.1 blocks anything but WebSocket
|
||||
Assert.Throws<InvalidOperationException>(() => context.Response.Headers["Upgrade"] = "WebSocket"); // Win8.1 blocks anything but WebSocket
|
||||
await Assert.ThrowsAsync<InvalidOperationException>(async () => await context.UpgradeAsync());
|
||||
context.Dispose();
|
||||
HttpResponseMessage response = await clientTask;
|
||||
|
|
|
|||
|
|
@ -233,8 +233,10 @@ namespace Microsoft.Net.Http.Server
|
|||
responseHeaders.SetValues("Custom2", "value2a, value2b");
|
||||
var body = context.Response.Body;
|
||||
body.Flush();
|
||||
Assert.Throws<InvalidOperationException>(() => context.Response.StatusCode = 404);
|
||||
responseHeaders.Add("Custom3", new string[] { "value3a, value3b", "value3c" }); // Ignored
|
||||
var ex = Assert.Throws<InvalidOperationException>(() => context.Response.StatusCode = 404);
|
||||
Assert.Equal("Headers already sent.", ex.Message);
|
||||
ex = Assert.Throws<InvalidOperationException>(() => responseHeaders.Add("Custom3", new string[] { "value3a, value3b", "value3c" }));
|
||||
Assert.Equal("The response headers cannot be modified because they have already been sent.", ex.Message);
|
||||
|
||||
context.Dispose();
|
||||
|
||||
|
|
@ -265,8 +267,10 @@ namespace Microsoft.Net.Http.Server
|
|||
responseHeaders.SetValues("Custom2", "value2a, value2b");
|
||||
var body = context.Response.Body;
|
||||
await body.FlushAsync();
|
||||
Assert.Throws<InvalidOperationException>(() => context.Response.StatusCode = 404);
|
||||
responseHeaders.SetValues("Custom3", "value3a, value3b", "value3c"); // Ignored
|
||||
var ex = Assert.Throws<InvalidOperationException>(() => context.Response.StatusCode = 404);
|
||||
Assert.Equal("Headers already sent.", ex.Message);
|
||||
ex = Assert.Throws<InvalidOperationException>(() => responseHeaders.Add("Custom3", new string[] { "value3a, value3b", "value3c" }));
|
||||
Assert.Equal("The response headers cannot be modified because they have already been sent.", ex.Message);
|
||||
|
||||
context.Dispose();
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue