Ignore zero length writes when automatically chunking responses
- Zero length writes would previously be interpreted as the end of response - Optimize writing the chunked response suffix - Add tests for automatic response chunking
This commit is contained in:
parent
3fb33119ee
commit
753d64660d
|
|
@ -257,8 +257,7 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
|
||||||
|
|
||||||
if (_autoChunk)
|
if (_autoChunk)
|
||||||
{
|
{
|
||||||
WriteChunkPrefix(numOctets: 0);
|
WriteChunkedResponseSuffix();
|
||||||
WriteChunkSuffix();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
|
|
@ -278,6 +277,12 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
|
||||||
|
|
||||||
if (_autoChunk)
|
if (_autoChunk)
|
||||||
{
|
{
|
||||||
|
if (data.Count == 0)
|
||||||
|
{
|
||||||
|
callback(null, state);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
WriteChunkPrefix(data.Count);
|
WriteChunkPrefix(data.Count);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -306,6 +311,7 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
|
||||||
}
|
}
|
||||||
|
|
||||||
private static readonly ArraySegment<byte> _endChunkBytes = CreateAsciiByteArraySegment("\r\n");
|
private static readonly ArraySegment<byte> _endChunkBytes = CreateAsciiByteArraySegment("\r\n");
|
||||||
|
private static readonly ArraySegment<byte> _endChunkedResponseBytes = CreateAsciiByteArraySegment("0\r\n\r\n");
|
||||||
|
|
||||||
private void WriteChunkSuffix()
|
private void WriteChunkSuffix()
|
||||||
{
|
{
|
||||||
|
|
@ -321,6 +327,20 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
|
||||||
immediate: true);
|
immediate: true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void WriteChunkedResponseSuffix()
|
||||||
|
{
|
||||||
|
SocketOutput.Write(_endChunkedResponseBytes,
|
||||||
|
(error, _) =>
|
||||||
|
{
|
||||||
|
if (error != null)
|
||||||
|
{
|
||||||
|
Trace.WriteLine("WriteChunkedResponseSuffix" + error.ToString());
|
||||||
|
}
|
||||||
|
},
|
||||||
|
null,
|
||||||
|
immediate: true);
|
||||||
|
}
|
||||||
|
|
||||||
public void Upgrade(IDictionary<string, object> options, Func<object, Task> callback)
|
public void Upgrade(IDictionary<string, object> options, Func<object, Task> callback)
|
||||||
{
|
{
|
||||||
_keepAlive = false;
|
_keepAlive = false;
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,75 @@
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNet.Server.KestrelTests
|
||||||
|
{
|
||||||
|
public class ChunkedResponseTests
|
||||||
|
{
|
||||||
|
[Fact]
|
||||||
|
public async Task ResponsesAreChunkedAutomatically()
|
||||||
|
{
|
||||||
|
using (var server = new TestServer(async frame =>
|
||||||
|
{
|
||||||
|
frame.ResponseHeaders.Clear();
|
||||||
|
await frame.ResponseBody.WriteAsync(Encoding.ASCII.GetBytes("Hello "), 0, 6);
|
||||||
|
await frame.ResponseBody.WriteAsync(Encoding.ASCII.GetBytes("World!"), 0, 6);
|
||||||
|
}))
|
||||||
|
{
|
||||||
|
using (var connection = new TestConnection())
|
||||||
|
{
|
||||||
|
await connection.SendEnd(
|
||||||
|
"GET / HTTP/1.1",
|
||||||
|
"",
|
||||||
|
"");
|
||||||
|
await connection.ReceiveEnd(
|
||||||
|
"HTTP/1.1 200 OK",
|
||||||
|
"Transfer-Encoding: chunked",
|
||||||
|
"",
|
||||||
|
"6",
|
||||||
|
"Hello ",
|
||||||
|
"6",
|
||||||
|
"World!",
|
||||||
|
"0",
|
||||||
|
"",
|
||||||
|
"");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task ZeroLengthWritesAreIgnored()
|
||||||
|
{
|
||||||
|
using (var server = new TestServer(async frame =>
|
||||||
|
{
|
||||||
|
frame.ResponseHeaders.Clear();
|
||||||
|
await frame.ResponseBody.WriteAsync(Encoding.ASCII.GetBytes("Hello "), 0, 6);
|
||||||
|
await frame.ResponseBody.WriteAsync(new byte[0], 0, 0);
|
||||||
|
await frame.ResponseBody.WriteAsync(Encoding.ASCII.GetBytes("World!"), 0, 6);
|
||||||
|
}))
|
||||||
|
{
|
||||||
|
using (var connection = new TestConnection())
|
||||||
|
{
|
||||||
|
await connection.SendEnd(
|
||||||
|
"GET / HTTP/1.1",
|
||||||
|
"",
|
||||||
|
"");
|
||||||
|
await connection.ReceiveEnd(
|
||||||
|
"HTTP/1.1 200 OK",
|
||||||
|
"Transfer-Encoding: chunked",
|
||||||
|
"",
|
||||||
|
"6",
|
||||||
|
"Hello ",
|
||||||
|
"6",
|
||||||
|
"World!",
|
||||||
|
"0",
|
||||||
|
"",
|
||||||
|
"");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue