Throw InvalidOperationException from IHttpUpgradeFeature.UpgradeAsync when request is not upgradable

This commit is contained in:
Nate McMaster 2017-05-17 10:47:38 -07:00
parent 10f88aeafc
commit 7f0319f5dd
6 changed files with 61 additions and 1 deletions

View File

@ -306,4 +306,7 @@
<data name="RequestProcessingEndError" xml:space="preserve"> <data name="RequestProcessingEndError" xml:space="preserve">
<value>Connection processing ended abnormally.</value> <value>Connection processing ended abnormally.</value>
</data> </data>
<data name="CannotUpgradeNonUpgradableRequest" xml:space="preserve">
<value>Cannot upgrade a non-upgradable request. Check IHttpUpgradeFeature.IsUpgradableRequest to determine if a request can be upgraded.</value>
</data>
</root> </root>

View File

@ -230,6 +230,11 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
async Task<Stream> IHttpUpgradeFeature.UpgradeAsync() async Task<Stream> IHttpUpgradeFeature.UpgradeAsync()
{ {
if (!((IHttpUpgradeFeature)this).IsUpgradableRequest)
{
throw new InvalidOperationException(CoreStrings.CannotUpgradeNonUpgradableRequest);
}
StatusCode = StatusCodes.Status101SwitchingProtocols; StatusCode = StatusCodes.Status101SwitchingProtocols;
ReasonPhrase = "Switching Protocols"; ReasonPhrase = "Switching Protocols";
ResponseHeaders["Connection"] = "Upgrade"; ResponseHeaders["Connection"] = "Upgrade";

View File

@ -892,6 +892,20 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core
internal static string FormatRequestProcessingEndError() internal static string FormatRequestProcessingEndError()
=> GetString("RequestProcessingEndError"); => GetString("RequestProcessingEndError");
/// <summary>
/// Cannot upgrade a non-upgradable request. Check IHttpUpgradeFeature.IsUpgradableRequest to determine if a request can be upgraded.
/// </summary>
internal static string CannotUpgradeNonUpgradableRequest
{
get => GetString("CannotUpgradeNonUpgradableRequest");
}
/// <summary>
/// Cannot upgrade a non-upgradable request. Check IHttpUpgradeFeature.IsUpgradableRequest to determine if a request can be upgraded.
/// </summary>
internal static string FormatCannotUpgradeNonUpgradableRequest()
=> GetString("CannotUpgradeNonUpgradableRequest");
private static string GetString(string name, params string[] formatterNames) private static string GetString(string name, params string[] formatterNames)
{ {
var value = _resourceManager.GetString(name); var value = _resourceManager.GetString(name);

View File

@ -162,6 +162,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
await connection.Send( await connection.Send(
"GET /upgrade HTTP/1.1", "GET /upgrade HTTP/1.1",
"Host:", "Host:",
"Connection: Upgrade",
"", "",
""); "");
await connection.Receive( await connection.Receive(

View File

@ -1775,6 +1775,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
await connection.Send( await connection.Send(
"GET / HTTP/1.1", "GET / HTTP/1.1",
"Host:", "Host:",
"Connection: Upgrade",
"", "",
""); "");
await connection.ReceiveForcedEnd( await connection.ReceiveForcedEnd(
@ -1789,7 +1790,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
{ {
await connection.Send( await connection.Send(
"GET / HTTP/1.0", "GET / HTTP/1.0",
"Connection: keep-alive", "Connection: keep-alive, Upgrade",
"", "",
""); "");
await connection.ReceiveForcedEnd( await connection.ReceiveForcedEnd(

View File

@ -182,5 +182,41 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
""); "");
} }
} }
[Fact]
public async Task ThrowsWhenUpgradingNonUpgradableRequest()
{
var upgradeTcs = new TaskCompletionSource<bool>();
using (var server = new TestServer(async context =>
{
var feature = context.Features.Get<IHttpUpgradeFeature>();
Assert.False(feature.IsUpgradableRequest);
try
{
var stream = await feature.UpgradeAsync();
}
catch (Exception e)
{
upgradeTcs.TrySetException(e);
}
finally
{
upgradeTcs.TrySetResult(false);
}
}))
{
using (var connection = server.CreateConnection())
{
await connection.Send("GET / HTTP/1.1",
"Host:",
"",
"");
await connection.Receive("HTTP/1.1 200 OK");
}
}
var ex = await Assert.ThrowsAsync<InvalidOperationException>(async () => await upgradeTcs.Task).TimeoutAfter(TimeSpan.FromSeconds(15));
Assert.Equal(CoreStrings.CannotUpgradeNonUpgradableRequest, ex.Message);
}
} }
} }