Skip to content
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

HttpForwarder throw exception when trying to forward a POST request. #1665

Closed
DeepWaterWhale opened this issue Apr 21, 2022 · 11 comments
Closed
Assignees
Labels
Type: Bug Something isn't working
Milestone

Comments

@DeepWaterWhale
Copy link

Describe the bug

HttpForwarder throw exception when trying to forward a POST request.

To Reproduce

Forward any POST request with body can repro.

Got Exceptions? Include both the message and the stack trace
Error Message: (Parameter 'size') Actual value was 0.

CallStack:
at Microsoft.AspNetCore.Server.HttpSys.RequestStream.ValidateReadBuffer(Byte[] buffer, Int32 offset, Int32 size)
at Microsoft.AspNetCore.Server.HttpSys.RequestStream.ReadAsync(Byte[] buffer, Int32 offset, Int32 size, CancellationToken cancellationToken)
at System.IO.Stream.ReadAsync(Memory`1 buffer, CancellationToken cancellationToken)
at Yarp.ReverseProxy.Forwarder.StreamCopier.d__3.MoveNext() in D:_GItRepo_\reverse-proxy\src\ReverseProxy\Forwarder\StreamCopier.cs:line 53

-->

Further technical details

  • Include the version of the packages you are using
    Use the latest source code to build the package and testing.
    commit id is: b8a58a6

  • The platform (Linux/macOS/Windows): Windows

I took a look at the code, in my understanding, yarp create a StreamCopyHttpContent in the proxy request to copy the original request's body.

And in StreamCopyHttpContent, it uses StreamCopier to do the real copy work, code is like below. But it throws exception when use an empty buffer directly, then return RequestBodyClient error back.

                // Issue a zero-byte read to the input stream to defer buffer allocation until data is available.
                // Note that if the underlying stream does not supporting blocking on zero byte reads, then this will
                // complete immediately and won't save any memory, but will still function correctly.
                var zeroByteReadTask = input.ReadAsync(Memory<byte>.Empty, cancellation);
                if (zeroByteReadTask.IsCompletedSuccessfully)
                {
                    // Consume the ValueTask's result in case it is backed by an IValueTaskSource
                    _ = zeroByteReadTask.Result;
                }
                else
                {
                    // Take care not to return the same buffer to the pool twice in case zeroByteReadTask throws
                    var bufferToReturn = buffer;
                    buffer = null;
                    ArrayPool<byte>.Shared.Return(bufferToReturn);

                    await zeroByteReadTask;

                    buffer = ArrayPool<byte>.Shared.Rent(DefaultBufferSize);
                }
@DeepWaterWhale DeepWaterWhale added the Type: Bug Something isn't working label Apr 21, 2022
@karelz
Copy link
Member

karelz commented Apr 21, 2022

Triage:

  • We need ASP.NET issue
  • Proposal for YARP - disable 0-byte reads on .NET 3.1 and 5.0

@Tratcher
Copy link
Member

Tratcher commented Apr 21, 2022

Thanks @DeepWaterWhale. I've filed dotnet/aspnetcore#41305 to fix this in asp.net 6 and 7. We'll disable zero-byte reads in YARP for earlier runtime versions. Which version of asp.net are you using?

Working around this would require wrapping the request body stream and having zero-byte reads no-op.

@Tratcher
Copy link
Member

Related: #1657

@DeepWaterWhale
Copy link
Author

@Tratcher I am using asp.net 6.0

@karelz
Copy link
Member

karelz commented Apr 26, 2022

Fixed by #1666

@ztoliver
Copy link

Is there a work-around for .net 6.0? I'm having this exact issue while attempting basic direct forwarding and it's blocking any POST request I'm trying to forward. Using YARP 1.1.0.

@samsp-msft
Copy link
Contributor

Rollback to 1.0 until ASP.NET gets fixed?

@MihaZupan
Copy link
Member

Or if you are not bound to HttpSys, Kestrel is not affected by this issue.

@ztoliver
Copy link

ztoliver commented May 18, 2022

Rolling back to 1.0 just causes the forwarder to timeout. At least with 1.1.0 it returns an error (ForwarderError.RequestBodyClient) with the following exceptions.

  • Sent 0 request content bytes, but Content-Length promised 1220.
  • Error while copying content to a stream.

@MihaZupan
Copy link
Member

If you are seeing such problems with YARP 1.0, it's not the same issue.
Please open a new issue and share your config & code. Most likely case is that you are modifying/reading the request body before forwarding.

@ztoliver
Copy link

Yep we are reading the request which is injected into a controller method and is required by Swagger to recognize the request model. When removing that parameter I can successfully forward the request, but then we lose Swagger support. Thanks for the help.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Type: Bug Something isn't working
Projects
None yet
Development

No branches or pull requests

6 participants