Skip to content

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

Closed
@DeepWaterWhale

Description

@DeepWaterWhale

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);
                }

Metadata

Metadata

Assignees

Labels

Type: BugSomething isn't working

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions