Skip to content
This repository was archived by the owner on Dec 18, 2018. It is now read-only.

Consume chunked request fully#619

Merged
halter73 merged 7 commits into
aspnet:devfrom
benaadams:chunked-request
Feb 29, 2016
Merged

Consume chunked request fully#619
halter73 merged 7 commits into
aspnet:devfrom
benaadams:chunked-request

Conversation

@benaadams
Copy link
Copy Markdown
Contributor

Chunked requests have an extra \r\n at end

5\r\n
Hello\r\n
6\r\n
World\r\n
0\r\n
... Trailer headers ...
\r\n

Resolves #617

@Tratcher is this correct?

/cc @CesarBS @halter73

Please note changes in tests

else
{
// Post request headers
throw new NotImplementedException("INVALID REQUEST FORMAT");
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think NotImplementedException is the right exception to throw here. InvalidOperationException seems more appropriate.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This though could be valid http (trailing headers)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, if you're not going to process incoming trailer headers you should drain them and file a bug to deal with them later.

@benaadams
Copy link
Copy Markdown
Contributor Author

Resolved issues. @CesarBS question on whether to go NotImplementedException vs InvalidOperationException for unsupported but valid features (e.g. Chunked-extensions & Trailing headers)

}
else if (ch1 == '\r' && ch2 == '\n')
{
input.ConsumingComplete(scan, scan);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ConsumingComplete should be called in a finally block. We're not consistent about doing that in this class (I'll fix that soon), but that is the recommended calling pattern.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the latest commit fixes this - but I can't compile it due to

Unable to resolve Microsoft.DotNet.CoreHost (>= 0.0.1-beta-00001) for DNXCore,Version=v5.0

@muratg muratg added this to the 1.0.0-rc2 milestone Feb 8, 2016
@muratg muratg assigned ajcvickers and cesarblum and unassigned ajcvickers Feb 8, 2016

private static void ThrowInvalidFormat()
{
throw new InvalidOperationException("INVALID REQUEST FORMAT");
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you switch to lowercase? Not sure why it was all uppercase to begin with, but since you're changing this it would be nice to be consistent (and better looking 😄) with the rest.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All caps is LogLevel.CRITICAL! ;-)

@benaadams
Copy link
Copy Markdown
Contributor Author

Capturing comment hidden in outdated diff

Oh, if you're not going to process incoming trailer headers you should drain them and file a bug to deal with them later.

@benaadams
Copy link
Copy Markdown
Contributor Author

Now parses the trailing headers

@benaadams
Copy link
Copy Markdown
Contributor Author

Test for parsing headers

@benaadams benaadams force-pushed the chunked-request branch 2 times, most recently from f5731fd to 4d2a886 Compare February 10, 2016 12:50

if (requestsReceived < requestCount)
{
Assert.Equal(new string('a', requestsReceived), request.Headers["X-Trailer-Header"]);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cool. Now I'm interested to see if this feature gets used even once in the wild. You should find a way to take advantage of this in one of your games 😉

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might be a stretch even for me 😉

Linked to discussion from "Web Hypertext Application Technology Working Group" (whatwg) in https://github.com/aspnet/KestrelHttpServer/issues/622 - think it needs a custom client rather than browser.

@benaadams benaadams changed the title Consume chunked request fully [Needs Tests] Consume chunked request fully Feb 12, 2016
@halter73
Copy link
Copy Markdown
Member

Do you see these errors? If not, I can investigate tomorrow.

Microsoft.AspNetCore.Server.KestrelTests.ChunkedRequestTests.InvalidLengthResultsIn500(testContext: TestServiceContext { App = null, AppLifetime = LifetimeNotImplemented { ApplicationStarted = (throws NotImplementedException), ApplicationStopped = (throws NotImplementedException), ApplicationStopping = (throws NotImplementedException) }, DateHeaderValueManager = TestDateHeaderValueManager { }, FrameFactory = null, Log = TestKestrelTrace { }, ... }) [FAIL]
  System.IO.IOException : Unable to write data to the transport connection: An established connection was aborted by the software in your host machine.
  ---- System.Net.Sockets.SocketException : An established connection was aborted by the software in your host machine
  Stack Trace:
       at System.Net.Sockets.NetworkStream.BeginWrite(Byte[] buffer, Int32 offset, Int32 size, AsyncCallback callback, Object state)
       at System.IO.Stream.<>c.<BeginEndWriteAsync>b__53_0(Stream stream, ReadWriteParameters args, AsyncCallback callback, Object state)
       at System.Threading.Tasks.TaskFactory`1.FromAsyncTrim[TInstance,TArgs](TInstance thisRef, TArgs args, Func`5 beginMethod, Func`3 endMethod)
       at System.IO.Stream.BeginEndWriteAsync(Byte[] buffer, Int32 offset, Int32 count)
       at System.IO.Stream.WriteAsync(Byte[] buffer, Int32 offset, Int32 count, CancellationToken cancellationToken)
       at System.IO.Stream.WriteAsync(Byte[] buffer, Int32 offset, Int32 count)
       at System.IO.StreamWriter.<FlushAsyncInternal>d__68.MoveNext()
    --- End of stack trace from previous location where exception was thrown ---
       at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
       at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
       at System.Runtime.CompilerServices.TaskAwaiter.GetResult()
    C:\Users\shalter\dev\Universe\KestrelHttpServer\test\Microsoft.AspNetCore.Server.KestrelTests\TestConnection.cs(51,0): at Microsoft.AspNetCore.Server.KestrelTests.TestConnection.<Send>d__6.MoveNext()
    --- End of stack trace from previous location where exception was thrown ---
       at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
       at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
       at System.Runtime.CompilerServices.TaskAwaiter.GetResult()
    C:\Users\shalter\dev\Universe\KestrelHttpServer\test\Microsoft.AspNetCore.Server.KestrelTests\ChunkedRequestTests.cs(366,0): at Microsoft.AspNetCore.Server.KestrelTests.ChunkedRequestTests.<InvalidLengthResultsIn500>d__9.MoveNext()
    --- End of stack trace from previous location where exception was thrown ---
       at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
       at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
    --- End of stack trace from previous location where exception was thrown ---
       at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
       at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
    --- End of stack trace from previous location where exception was thrown ---
       at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
       at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
    ----- Inner Stack Trace -----
       at System.Net.Sockets.Socket.BeginSend(Byte[] buffer, Int32 offset, Int32 size, SocketFlags socketFlags, AsyncCallback callback, Object state)
       at System.Net.Sockets.NetworkStream.BeginWrite(Byte[] buffer, Int32 offset, Int32 size, AsyncCallback callback, Object state)
Microsoft.AspNetCore.Server.KestrelTests.ChunkedRequestTests.InvalidSizedDataResultsIn500(testContext: TestServiceContext { App = null, AppLifetime = LifetimeNotImplemented { ApplicationStarted = (throws NotImplementedException), ApplicationStopped = (throws NotImplementedException), ApplicationStopping = (throws NotImplementedException) }, DateHeaderValueManager = TestDateHeaderValueManager { }, FrameFactory = null, Log = TestKestrelTrace { }, ... }) [FAIL]
  System.IO.IOException : Unable to write data to the transport connection: An established connection was aborted by the software in your host machine.
  ---- System.Net.Sockets.SocketException : An established connection was aborted by the software in your host machine
  Stack Trace:
       at System.Net.Sockets.NetworkStream.BeginWrite(Byte[] buffer, Int32 offset, Int32 size, AsyncCallback callback, Object state)
       at System.IO.Stream.<>c.<BeginEndWriteAsync>b__53_0(Stream stream, ReadWriteParameters args, AsyncCallback callback, Object state)
       at System.Threading.Tasks.TaskFactory`1.FromAsyncTrim[TInstance,TArgs](TInstance thisRef, TArgs args, Func`5 beginMethod, Func`3 endMethod)
       at System.IO.Stream.BeginEndWriteAsync(Byte[] buffer, Int32 offset, Int32 count)
       at System.IO.Stream.WriteAsync(Byte[] buffer, Int32 offset, Int32 count, CancellationToken cancellationToken)
       at System.IO.Stream.WriteAsync(Byte[] buffer, Int32 offset, Int32 count)
       at System.IO.StreamWriter.<FlushAsyncInternal>d__68.MoveNext()
    --- End of stack trace from previous location where exception was thrown ---
       at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
       at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
       at System.Runtime.CompilerServices.TaskAwaiter.GetResult()
    C:\Users\shalter\dev\Universe\KestrelHttpServer\test\Microsoft.AspNetCore.Server.KestrelTests\TestConnection.cs(51,0): at Microsoft.AspNetCore.Server.KestrelTests.TestConnection.<Send>d__6.MoveNext()
    --- End of stack trace from previous location where exception was thrown ---
       at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
       at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
       at System.Runtime.CompilerServices.TaskAwaiter.GetResult()
    C:\Users\shalter\dev\Universe\KestrelHttpServer\test\Microsoft.AspNetCore.Server.KestrelTests\ChunkedRequestTests.cs(413,0): at Microsoft.AspNetCore.Server.KestrelTests.ChunkedRequestTests.<InvalidSizedDataResultsIn500>d__10.MoveNext()
    --- End of stack trace from previous location where exception was thrown ---
       at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
       at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
    --- End of stack trace from previous location where exception was thrown ---
       at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
       at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
    --- End of stack trace from previous location where exception was thrown ---
       at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
       at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
    ----- Inner Stack Trace -----
       at System.Net.Sockets.Socket.BeginSend(Byte[] buffer, Int32 offset, Int32 size, SocketFlags socketFlags, AsyncCallback callback, Object state)
       at System.Net.Sockets.NetworkStream.BeginWrite(Byte[] buffer, Int32 offset, Int32 size, AsyncCallback callback, Object state)
Finished:    Microsoft.AspNetCore.Server.KestrelTests
=== TEST EXECUTION SUMMARY ===
Microsoft.AspNetCore.Server.KestrelTests  Total: 359, Errors: 0, Failed: 2, Skipped: 2, Time: 10.361s

@benaadams
Copy link
Copy Markdown
Contributor Author

On and off - get it with the other closing tests also (e.g. Http10ContentLength). Normally seems to happen if I run the tests repeatedly rather than in clean cmd - perhaps lingering ports?

Can wrap in a IOException catch; but that obv misses the point a little. Think it must be either sending the error post start; or the SendEnd chops the connection prior to flushing sometimes?

Couldn't get to the bottom of it though :(

@benaadams
Copy link
Copy Markdown
Contributor Author

However... Kestrel should probably also abort the connection for those tests; which cause the issue also. (As they will have poisoned the connection)

@benaadams
Copy link
Copy Markdown
Contributor Author

K should now be returning 400 and chopping the connection; not getting the earlier exception either - might have been overflow junk into the next request causing the connection to chop?

@benaadams
Copy link
Copy Markdown
Contributor Author

Hmm, not perfect; if user code caught the exception and threw it away it would still go wrong...

@benaadams
Copy link
Copy Markdown
Contributor Author

Should still close connection even if user code handles it now.

@benaadams
Copy link
Copy Markdown
Contributor Author

@halter73 that error is caused by Consume throwing the exception on read; then chopping the connection and the sender tying to continue to send the rest of the request.

Issues resolved.

@benaadams benaadams force-pushed the chunked-request branch 4 times, most recently from a7c27d0 to b82a251 Compare February 26, 2016 22:23
@benaadams
Copy link
Copy Markdown
Contributor Author

Rebased, better bad request handling for headers and invalid content lengths

@benaadams
Copy link
Copy Markdown
Contributor Author

Re-rebased for newest; resolving errors for newer tests.

@benaadams
Copy link
Copy Markdown
Contributor Author

I'm getting an failure in the cctor for MessageBody.ForChunkedEncoding of Invalid Program exception on full framework.

If I move private static Vector<byte> _vectorCRs = new Vector<byte>((byte)'\r'); into MessageBody then every frame test fails with same error. Bit odd...

@benaadams
Copy link
Copy Markdown
Contributor Author

AppVeyor:

System.Diagnostics.Debug+DebugAssertException: Block being garbage collected instead of returned to pool 
   at System.Environment.GetStackTrace(Exception e, Boolean needFileInfo)

@halter73 halter73 merged commit dab1a1f into aspnet:dev Feb 29, 2016
@cesarblum cesarblum assigned halter73 and unassigned cesarblum Mar 2, 2016
@benaadams benaadams deleted the chunked-request branch May 10, 2016 10:59
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants