Call Flush With fMoreData=false when response isn't allowed to have body (#4403)
This commit is contained in:
parent
1733aa0c9a
commit
0646bb98b0
|
|
@ -38,7 +38,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "build", "build", "{7E80C58E
|
||||||
build\applicationhost.iis.config = build\applicationhost.iis.config
|
build\applicationhost.iis.config = build\applicationhost.iis.config
|
||||||
build\Build.Settings = build\Build.Settings
|
build\Build.Settings = build\Build.Settings
|
||||||
build\Config.Definitions.Props = build\Config.Definitions.Props
|
build\Config.Definitions.Props = build\Config.Definitions.Props
|
||||||
build\dependencies.props = build\dependencies.props
|
|
||||||
build\functional-test-assets.targets = build\functional-test-assets.targets
|
build\functional-test-assets.targets = build\functional-test-assets.targets
|
||||||
build\Key.snk = build\Key.snk
|
build\Key.snk = build\Key.snk
|
||||||
build\launchSettings.json = build\launchSettings.json
|
build\launchSettings.json = build\launchSettings.json
|
||||||
|
|
@ -116,7 +115,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IIS.BackwardsCompatibility.
|
||||||
EndProject
|
EndProject
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IIS.ForwardsCompatibility.FunctionalTests", "test\IIS.ForwardsCompatibility.FunctionalTests\IIS.ForwardsCompatibility.FunctionalTests.csproj", "{D1EA5D99-28FD-4197-81DE-17098846B38B}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IIS.ForwardsCompatibility.FunctionalTests", "test\IIS.ForwardsCompatibility.FunctionalTests\IIS.ForwardsCompatibility.FunctionalTests.csproj", "{D1EA5D99-28FD-4197-81DE-17098846B38B}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "InProcessForwardsCompatWebSite", "test\WebSites\InProcessForwardsCompatWebSite\InProcessWebSite.csproj", "{BBBC85B2-5D7A-4D09-90B1-8DBCC9059493}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "InProcessWebSite", "test\WebSites\InProcessForwardsCompatWebSite\InProcessWebSite.csproj", "{BBBC85B2-5D7A-4D09-90B1-8DBCC9059493}"
|
||||||
EndProject
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
|
|
|
||||||
|
|
@ -288,13 +288,13 @@ EXTERN_C __MIDL_DECLSPEC_DLLEXPORT
|
||||||
HRESULT
|
HRESULT
|
||||||
http_flush_response_bytes(
|
http_flush_response_bytes(
|
||||||
_In_ IN_PROCESS_HANDLER* pInProcessHandler,
|
_In_ IN_PROCESS_HANDLER* pInProcessHandler,
|
||||||
|
_In_ BOOL fMoreData,
|
||||||
_Out_ BOOL* pfCompletionExpected
|
_Out_ BOOL* pfCompletionExpected
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
IHttpResponse *pHttpResponse = (IHttpResponse*)pInProcessHandler->QueryHttpContext()->GetResponse();
|
IHttpResponse *pHttpResponse = (IHttpResponse*)pInProcessHandler->QueryHttpContext()->GetResponse();
|
||||||
|
|
||||||
BOOL fAsync = TRUE;
|
BOOL fAsync = TRUE;
|
||||||
BOOL fMoreData = TRUE;
|
|
||||||
DWORD dwBytesSent = 0;
|
DWORD dwBytesSent = 0;
|
||||||
|
|
||||||
HRESULT hr = pHttpResponse->Flush(
|
HRESULT hr = pHttpResponse->Flush(
|
||||||
|
|
|
||||||
|
|
@ -158,7 +158,7 @@ namespace Microsoft.AspNetCore.Server.IIS.Core
|
||||||
|
|
||||||
if (flush)
|
if (flush)
|
||||||
{
|
{
|
||||||
await AsyncIO.FlushAsync();
|
await AsyncIO.FlushAsync(moreData: true);
|
||||||
flush = false;
|
flush = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -243,12 +243,12 @@ namespace Microsoft.AspNetCore.Server.IIS.Core
|
||||||
SetResponseHeaders();
|
SetResponseHeaders();
|
||||||
|
|
||||||
EnsureIOInitialized();
|
EnsureIOInitialized();
|
||||||
|
var canHaveNonEmptyBody = StatusCodeCanHaveBody();
|
||||||
if (flushHeaders)
|
if (flushHeaders)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await AsyncIO.FlushAsync();
|
await AsyncIO.FlushAsync(canHaveNonEmptyBody);
|
||||||
}
|
}
|
||||||
// Client might be disconnected at this point
|
// Client might be disconnected at this point
|
||||||
// don't leak the exception
|
// don't leak the exception
|
||||||
|
|
@ -258,7 +258,20 @@ namespace Microsoft.AspNetCore.Server.IIS.Core
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_writeBodyTask = WriteBody(!flushHeaders);
|
if (!canHaveNonEmptyBody)
|
||||||
|
{
|
||||||
|
_bodyOutput.Dispose();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_writeBodyTask = WriteBody(!flushHeaders);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool StatusCodeCanHaveBody()
|
||||||
|
{
|
||||||
|
return StatusCode != 204
|
||||||
|
&& StatusCode != 304;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void InitializeRequestIO()
|
private void InitializeRequestIO()
|
||||||
|
|
|
||||||
|
|
@ -12,21 +12,23 @@ namespace Microsoft.AspNetCore.Server.IIS.Core.IO
|
||||||
private readonly AsyncIOEngine _engine;
|
private readonly AsyncIOEngine _engine;
|
||||||
|
|
||||||
private IntPtr _requestHandler;
|
private IntPtr _requestHandler;
|
||||||
|
private bool _moreData;
|
||||||
|
|
||||||
public AsyncFlushOperation(AsyncIOEngine engine)
|
public AsyncFlushOperation(AsyncIOEngine engine)
|
||||||
{
|
{
|
||||||
_engine = engine;
|
_engine = engine;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Initialize(IntPtr requestHandler)
|
public void Initialize(IntPtr requestHandler, bool moreData)
|
||||||
{
|
{
|
||||||
_requestHandler = requestHandler;
|
_requestHandler = requestHandler;
|
||||||
|
_moreData = moreData;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override bool InvokeOperation(out int hr, out int bytes)
|
protected override bool InvokeOperation(out int hr, out int bytes)
|
||||||
{
|
{
|
||||||
bytes = 0;
|
bytes = 0;
|
||||||
hr = NativeMethods.HttpFlushResponseBytes(_requestHandler, out var fCompletionExpected);
|
hr = NativeMethods.HttpFlushResponseBytes(_requestHandler, _moreData, out var fCompletionExpected);
|
||||||
|
|
||||||
return !fCompletionExpected;
|
return !fCompletionExpected;
|
||||||
}
|
}
|
||||||
|
|
@ -36,6 +38,7 @@ namespace Microsoft.AspNetCore.Server.IIS.Core.IO
|
||||||
base.ResetOperation();
|
base.ResetOperation();
|
||||||
|
|
||||||
_requestHandler = default;
|
_requestHandler = default;
|
||||||
|
_moreData = false;
|
||||||
_engine.ReturnOperation(this);
|
_engine.ReturnOperation(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -90,10 +90,10 @@ namespace Microsoft.AspNetCore.Server.IIS.Core.IO
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public ValueTask FlushAsync()
|
public ValueTask FlushAsync(bool moreData)
|
||||||
{
|
{
|
||||||
var flush = GetFlushOperation();
|
var flush = GetFlushOperation();
|
||||||
flush.Initialize(_handler);
|
flush.Initialize(_handler, moreData);
|
||||||
Run(flush);
|
Run(flush);
|
||||||
return new ValueTask(flush, 0);
|
return new ValueTask(flush, 0);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ namespace Microsoft.AspNetCore.Server.IIS.Core.IO
|
||||||
{
|
{
|
||||||
ValueTask<int> ReadAsync(Memory<byte> memory);
|
ValueTask<int> ReadAsync(Memory<byte> memory);
|
||||||
ValueTask<int> WriteAsync(ReadOnlySequence<byte> data);
|
ValueTask<int> WriteAsync(ReadOnlySequence<byte> data);
|
||||||
ValueTask FlushAsync();
|
ValueTask FlushAsync(bool moreData);
|
||||||
void NotifyCompletion(int hr, int bytes);
|
void NotifyCompletion(int hr, int bytes);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@ namespace Microsoft.AspNetCore.Server.IIS.Core.IO
|
||||||
|
|
||||||
protected override bool InvokeOperation(out int hr, out int bytes)
|
protected override bool InvokeOperation(out int hr, out int bytes)
|
||||||
{
|
{
|
||||||
hr = NativeMethods.HttpFlushResponseBytes(_requestHandler, out var completionExpected);
|
hr = NativeMethods.HttpFlushResponseBytes(_requestHandler, fMoreData: true, out var completionExpected);
|
||||||
bytes = 0;
|
bytes = 0;
|
||||||
return !completionExpected;
|
return !completionExpected;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -56,7 +56,7 @@ namespace Microsoft.AspNetCore.Server.IIS.Core.IO
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public ValueTask FlushAsync()
|
public ValueTask FlushAsync(bool moreData)
|
||||||
{
|
{
|
||||||
lock (_contextLock)
|
lock (_contextLock)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -67,7 +67,7 @@ namespace Microsoft.AspNetCore.Server.IIS
|
||||||
private static extern unsafe int http_write_response_bytes(IntPtr pInProcessHandler, HttpApiTypes.HTTP_DATA_CHUNK* pDataChunks, int nChunks, out bool fCompletionExpected);
|
private static extern unsafe int http_write_response_bytes(IntPtr pInProcessHandler, HttpApiTypes.HTTP_DATA_CHUNK* pDataChunks, int nChunks, out bool fCompletionExpected);
|
||||||
|
|
||||||
[DllImport(AspNetCoreModuleDll)]
|
[DllImport(AspNetCoreModuleDll)]
|
||||||
private static extern int http_flush_response_bytes(IntPtr pInProcessHandler, out bool fCompletionExpected);
|
private static extern int http_flush_response_bytes(IntPtr pInProcessHandler, bool fMoreData, out bool fCompletionExpected);
|
||||||
|
|
||||||
[DllImport(AspNetCoreModuleDll)]
|
[DllImport(AspNetCoreModuleDll)]
|
||||||
private static extern unsafe HttpApiTypes.HTTP_REQUEST_V2* http_get_raw_request(IntPtr pInProcessHandler);
|
private static extern unsafe HttpApiTypes.HTTP_REQUEST_V2* http_get_raw_request(IntPtr pInProcessHandler);
|
||||||
|
|
@ -171,9 +171,9 @@ namespace Microsoft.AspNetCore.Server.IIS
|
||||||
return http_write_response_bytes(pInProcessHandler, pDataChunks, nChunks, out fCompletionExpected);
|
return http_write_response_bytes(pInProcessHandler, pDataChunks, nChunks, out fCompletionExpected);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int HttpFlushResponseBytes(IntPtr pInProcessHandler, out bool fCompletionExpected)
|
public static int HttpFlushResponseBytes(IntPtr pInProcessHandler, bool fMoreData, out bool fCompletionExpected)
|
||||||
{
|
{
|
||||||
return http_flush_response_bytes(pInProcessHandler, out fCompletionExpected);
|
return http_flush_response_bytes(pInProcessHandler, fMoreData, out fCompletionExpected);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static unsafe HttpApiTypes.HTTP_REQUEST_V2* HttpGetRawRequest(IntPtr pInProcessHandler)
|
public static unsafe HttpApiTypes.HTTP_REQUEST_V2* HttpGetRawRequest(IntPtr pInProcessHandler)
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,10 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
|
using System.Net.Http;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNetCore.Testing.xunit;
|
using Microsoft.AspNetCore.Testing.xunit;
|
||||||
using Microsoft.Net.Http.Headers;
|
using Microsoft.Net.Http.Headers;
|
||||||
|
|
@ -75,6 +77,18 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests
|
||||||
Assert.Equal(body ?? string.Empty, await response.Content.ReadAsStringAsync());
|
Assert.Equal(body ?? string.Empty, await response.Content.ReadAsStringAsync());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[ConditionalTheory]
|
||||||
|
[RequiresNewHandler]
|
||||||
|
[InlineData(204, "GET")]
|
||||||
|
[InlineData(304, "GET")]
|
||||||
|
public async Task TransferEncodingNotSetForStatusCodes(int code, string method)
|
||||||
|
{
|
||||||
|
var request = new HttpRequestMessage(new HttpMethod(method), _fixture.Client.BaseAddress + $"SetCustomErorCode?code={code}");
|
||||||
|
var response = await _fixture.Client.SendAsync(request);
|
||||||
|
Assert.Equal((HttpStatusCode)code, response.StatusCode);
|
||||||
|
Assert.DoesNotContain(response.Headers, h => h.Key.Equals("transfer-encoding", StringComparison.InvariantCultureIgnoreCase));
|
||||||
|
}
|
||||||
|
|
||||||
[ConditionalFact]
|
[ConditionalFact]
|
||||||
public async Task ServerHeaderIsOverriden()
|
public async Task ServerHeaderIsOverriden()
|
||||||
{
|
{
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue