-
Notifications
You must be signed in to change notification settings - Fork 10.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Ugly exception after closing the browser(firefox,chrome) with serverside-blazor, kestrel #14727
Comments
This is with 3.0? |
Yes. Dotnet Version is 3.0.100. |
This exception is pretty weird. Have you seen it more than once @mshobohm? If so, do you have a reliable way to reproduce this exception? Normally "System.InvalidOperationException: Reading is already in progress." would indicate the request handler completed while still reading from the request body. However, in that case, I would expect to see the exception to be thrown from MessageBody.ConsumeAsync() rather than by Http1Connection.BeginRead(). I suppose it's possible that the request handler held on to a reference to the request body stream, and then started reading after MessageBody.ConsumeAsync() completed, but in that case I would expect the request body stream to be poisoned since the next request didn't fully arrive yet. I think we're going to need some more details to get to the bottom of this. |
After further investigation I found out that I had modified Properties\launchSettings.json: This is needed to reproduce, and try with firefox (closing without additional questions). |
Real Exception is hidden: |
Looks like it might be a missing call to Advance somewhere |
Thanks for including the first chance exception details @mshobohm. It was really helpful. @davidfowl and I think we know what happened. Http1ContentLengthMessageBody.ReadAsyncInternal() throws the BadHttpRequestException "Unexpected end of request content" when it calls CheckCompletedReadResult() after the connection-level pipe successfully returned a completed ReadResult. Since Kestrel's HttpRequestStream sees an exception thrown PipeReader.ReadAsync() and never gets a ReadResult, it never calls PipeReader.AdvanceTo() on the request body pipe which is the correct behavior for HttpRequestStream. Http1ContentLengthMessageBody.ReadAsyncInternal() should be the one calling PipeReader.AdvanceTo() on the connection-level pipe if it throws an exception after successfully getting a ReadResult from the connection-level pipe. When we fix this bug, we should audit all the other HTTP/1.x MessageBody implementations to verify their ReadAsync() implementations never throw while leaving the connection-level pipe in an unadvanced state. To make matters worse, Blazor's CircuitDisconnectMiddleware swallows the BadHttpRequestException without logging it, making it hard to notice the first BadHttpRequestException even happened without looking for first chance exceptions. I think the CircuitDisconnectMiddleware should be logging the exception. Normally, after middleware exits, Kestrel will try to drain any part of the request body that might not have been read by the application. This should resurface the BadHttpRequestException even though it was initially swallowed. The problem here is that the request body draining logic uses Http1ContentLengthMessageBody.TryReadInternal() instead of Http1ContentLengthMessageBody.ReadAsyncInternal() which as of today, doesn't call CheckCompletedReadResult() which means the draining logic doesn't set bad request state like it should. If bad request state had been set, the request processing loop would stop preventing Http1Connection.BeginRead() from being called again meaning there would be no "System.InvalidOperationException: Reading is already in progress." The draining logic doesn't observe the InvalidOperationException that Http1Connection.BeginRead() does because Http1ContentLengthMessageBody.TryReadInternal() elides the call to PipeReader.TryRead() on the connection-level pipe since the MessageBody has already seen the end of the request. Here's what should be done before we close this issue:
|
Many thanks in advance for your efforts. Please log the exception(s) only on debug level, if they happen on a regular base. I switched to Loglevel debug and saw that Edge also does have a regular closing exception "System.Net.WebSockets.WebSocketException (0x80004005): The remote party closed the WebSocket connection without completing the close" which is hidden by debug level (thats ok for me). If you can't completely avoid exceptions on closing, hide them from the normal application development protocol(loglevel inf). |
@anurse - this is sitting in the 3.1.0-Preview2 milestone. Can you get it updated? |
I'm the one who tentatively put this into preview2. I know it's getting pretty late to change this, and the only functional impact is the extra first-chance exception and warning log AFAIK, so I'm going to tentatively put this into preview3. @anurse by all means feel free to move the milestone again. |
The following exception was found in Console after closing the browser (running blazor serverside default application and kestrel):
It seems to happen with Chrome and Firefox but not with edge.
The text was updated successfully, but these errors were encountered: