From 50f187aa3e1c877370dac1c415e96aa00115b748 Mon Sep 17 00:00:00 2001 From: Stephen Halter Date: Fri, 1 Apr 2016 12:38:26 -0700 Subject: [PATCH] Ensure entire request body is consumed before handling fin This completes the fix for #704 --- .../Http/MessageBody.cs | 77 +++++++++++++------ .../Http/SocketInputExtensions.cs | 8 +- 2 files changed, 61 insertions(+), 24 deletions(-) diff --git a/src/Microsoft.AspNetCore.Server.Kestrel/Http/MessageBody.cs b/src/Microsoft.AspNetCore.Server.Kestrel/Http/MessageBody.cs index d4072572f8..3a151fc560 100644 --- a/src/Microsoft.AspNetCore.Server.Kestrel/Http/MessageBody.cs +++ b/src/Microsoft.AspNetCore.Server.Kestrel/Http/MessageBody.cs @@ -249,29 +249,46 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Http { while (_mode == Mode.Prefix) { + var fin = input.RemoteIntakeFin; + ParseChunkedPrefix(input); + if (_mode != Mode.Prefix) { break; } + else if (fin) + { + ThrowChunkedRequestIncomplete(); + } - await GetDataAsync(input); + await input; } while (_mode == Mode.Extension) { + var fin = input.RemoteIntakeFin; + ParseExtension(input); + if (_mode != Mode.Extension) { break; } + else if (fin) + { + ThrowChunkedRequestIncomplete(); + } - await GetDataAsync(input); + await input; } while (_mode == Mode.Data) { + var fin = input.RemoteIntakeFin; + int actual = ReadChunkedData(input, buffer.Array, buffer.Offset, buffer.Count); + if (actual != 0) { return actual; @@ -280,39 +297,69 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Http { break; } + else if (fin) + { + ThrowChunkedRequestIncomplete(); + } - await GetDataAsync(input); + await input; } while (_mode == Mode.Suffix) { + var fin = input.RemoteIntakeFin; + ParseChunkedSuffix(input); + if (_mode != Mode.Suffix) { break; } + else if (fin) + { + ThrowChunkedRequestIncomplete(); + } - await GetDataAsync(input); + await input; } } // Chunks finished, parse trailers while (_mode == Mode.Trailer) { + var fin = input.RemoteIntakeFin; + ParseChunkedTrailer(input); + if (_mode != Mode.Trailer) { break; } + else if (fin) + { + ThrowChunkedRequestIncomplete(); + } - await GetDataAsync(input); + await input; } if (_mode == Mode.TrailerHeaders) { while (!_context.TakeMessageHeaders(input, _requestHeaders)) { - await GetDataAsync(input); + if (input.RemoteIntakeFin) + { + if (_context.TakeMessageHeaders(input, _requestHeaders)) + { + break; + } + else + { + ThrowChunkedRequestIncomplete(); + } + } + + await input; } _mode = Mode.Complete; @@ -444,10 +491,6 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Http { _mode = Mode.Suffix; } - else if (actual == 0) - { - ThrowIfRequestIncomplete(input); - } return actual; } @@ -532,19 +575,9 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Http } } - private SocketInput GetDataAsync(SocketInput input) + private void ThrowChunkedRequestIncomplete() { - ThrowIfRequestIncomplete(input); - - return input; - } - - private void ThrowIfRequestIncomplete(SocketInput input) - { - if (input.RemoteIntakeFin) - { - ThrowBadRequestException("Chunked request incomplete"); - } + ThrowBadRequestException("Chunked request incomplete"); } private enum Mode diff --git a/src/Microsoft.AspNetCore.Server.Kestrel/Http/SocketInputExtensions.cs b/src/Microsoft.AspNetCore.Server.Kestrel/Http/SocketInputExtensions.cs index 4b3beab538..9b647c4c91 100644 --- a/src/Microsoft.AspNetCore.Server.Kestrel/Http/SocketInputExtensions.cs +++ b/src/Microsoft.AspNetCore.Server.Kestrel/Http/SocketInputExtensions.cs @@ -12,6 +12,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Http { while (input.IsCompleted) { + var fin = input.RemoteIntakeFin; + var begin = input.ConsumingStart(); int actual; var end = begin.CopyTo(buffer, offset, count, out actual); @@ -21,7 +23,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Http { return actual; } - if (input.RemoteIntakeFin) + else if (fin) { return 0; } @@ -36,6 +38,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Http { await input; + var fin = input.RemoteIntakeFin; + var begin = input.ConsumingStart(); int actual; var end = begin.CopyTo(buffer, offset, count, out actual); @@ -45,7 +49,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Http { return actual; } - if (input.RemoteIntakeFin) + else if (fin) { return 0; }