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

How to support client streaming with custom HttpHandler #1964

Closed
doctorseus opened this issue Nov 25, 2022 · 3 comments
Closed

How to support client streaming with custom HttpHandler #1964

doctorseus opened this issue Nov 25, 2022 · 3 comments
Labels
question Further information is requested

Comments

@doctorseus
Copy link

doctorseus commented Nov 25, 2022

Hi, in the context of 1309 I have a custom HttpClientHandler implementation using a custom HTTP2 client implementation which I provide via the ChannelSettings. I can support streaming data up to the server in chunks and also down but I am not able to figure out how I can actually read the original grpc request content in a streaming mode so I can then forward these client messages to the server in the moment they are available.

When I call :

public class BestHttpMessageHandler : HttpClientHandler
{
    protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {
            request.Content.ReadAsStreamAsync().ContinueWith(task =>
            {
                Logger.Info(" >> CONTENT 1 ");
            });

            request.Content.ReadAsStreamAsync().ContinueWith(task =>
            {
                Logger.Info(" >> CONTENT 2 ");
            });
    }
}

then the first handler will print CONTENT 1 only after the client stream has reached EOF (after you call call.RequestStream.CompleteAsync(). All my buffered messages will be sent at this point.

The second handler will actually complete immediatly and print CONTENT 2 right after headers have been sent. However, the stream returned there is some empty MemoryStream() and not the actual underlaying client stream which I could read messages from.

In the other direction, to support server streaming, the grpc implementation excpects me to provide a HttpContent object which supports blocking reading from the embedded stream for each time the server sent a message. But it seems that this behavior is then not replicated for the client stream so I could do the same on my side..

At the moment I see no way how to actually implement this with the given API, I am even wondering how NET does it with it's own HTTP2 implementation..

I would appreciate if someone could provide some input/insight as I feel I am at my wits end here.

@doctorseus doctorseus added the question Further information is requested label Nov 25, 2022
@JamesNK
Copy link
Member

JamesNK commented Nov 29, 2022

I'm pretty sure request.Content.ReadAsStreamAsync() won't do what you want. It has been a couple of years since I did low-level work with intercepting content, but I found that it buffered.

Some examples of code intercepts and uses HTTP content as it arrives in https://github.com/grpc/grpc-dotnet/tree/master/src/Grpc.Net.Client.Web. I needed to wrap HttpContent instances in my own and use its internal APIs to work with data correctly.

@doctorseus
Copy link
Author

Hi, thanks for the info. Yes I think I came to the same conclusion (it is buffered there).

@doctorseus doctorseus closed this as not planned Won't fix, can't repro, duplicate, stale Nov 29, 2022
@doctorseus
Copy link
Author

Just to answer this: The behavior of HttpContent.Content.CopyToAsync is that it will replace the underlying Stream with the stream provided to the function call as long as nothing has yet been written. This allows you to inject your own stream and implement blocking (and unblocking) behavior as required when grpc actually writes to the stream and avoid any buffering.

@doctorseus doctorseus reopened this Dec 3, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question Further information is requested
Projects
None yet
Development

No branches or pull requests

2 participants