playground: the nghttp3 sample for both directions streamed at once - #217
Merged
Conversation
The nghttp3 set had three of the four corners - buffered both ways, request streamed, response streamed - and no sample doing both at once. The pure-C# stack has one (Http3/ManagedStreamedBoth) and its pane points at the nghttp3 side for the contrast, so the thing being contrasted did not exist. Nothing new was needed to make it work: RunStreamedResponseAsync already sets _streaming, so the request arrives through Nghttp3Request.BodyReader at end-of-headers while the response goes out through the writer. One call is both directions; no sample showed it. Same routes as the managed twin so the two can be diffed - "/" chunked down, "/upload" pulled up, "/echo" both at once, which is the shape a proxy needs. Verified against the running sample, one listener asserted: "/" returns the full 1 MiB, "/upload" of 64 MiB is counted exactly, and "/echo" of 64 MiB comes back byte-identical in 0.37s while the server's RSS moves 51 -> 57 MB. It keeps serving afterwards and the reactors go back to idle. No "/feed" here, unlike the managed twin, because an endless response does not work on this stack: no headers reach the peer at all, and after the client goes away a reactor spins and the connection serves nothing further. That reproduces on the SHIPPED Http3/Nghttp3Response, whose banner and site pane both tell you to run it, so it is not this sample's problem to solve and not this sample's place to repeat. Reported separately.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The nghttp3 HTTP/3 samples covered three of the four corners and not the fourth:
Http3/Nghttp3BufferedHttp3/Nghttp3ResponseHttp3/Nghttp3RequestThe pure-C# stack has that corner as
Http3/ManagedStreamedBoth, and its pane on the site points at the nghttp3 side for the contrast — so the thing being contrasted did not exist.Nothing new was needed to make it work.
RunStreamedResponseAsyncalready sets_streaming, so the request arrives throughNghttp3Request.BodyReaderat end-of-headers while the response goes out through the writer: one call is both directions. No sample showed it.The sample
Same routes as the managed twin, so the two can be diffed line for line:
/echois the point: read a chunk, write a chunk, never hold more than one. Neither side can outrun the other, becauseReadAsyncwaits on the peer andFlushAsyncwaits on nghttp3.Underneath, the mechanism is the opposite of the managed twin's, which is what makes having both worth it. nghttp3 owns the framing and pulls body bytes when it has room to emit DATA, so a flush here means nghttp3 has taken the chunk; the managed writer stages a DATA frame the moment you flush.
Registered in
ioxide.slnx,Playground/README.mdandbench/samples.tsv, and on the site as h3 · request + response streamed (nghttp3), generated from the sample like every other pane.Verified
Against the running sample with a single listener asserted (no leaked co-bound servers):
/at 64 × 16 KiB/uploadof 64 MiB/echoof 64 MiBNo
/feedhere, unlike the managed twinAn endless response does not work on this stack, and this is worth its own issue rather than a workaround in a sample. On the shipped
Http3/Nghttp3Response, one listener, nothing else bound:/(finite)/feed(endless)ioxide.nghttp3ioxide.http3text/event-stream, 2.1 GB in 3 sLikely mechanism, offered as a hypothesis rather than a finding:
DrainStreamedCorereturns only when the producer stops orPumpEgressreports nothing moved. An endless handler keeps staging chunks that nghttp3 keeps accepting, soproducednever goes false, the loop never hands the thread back, and the reactor never gets to send — which is also why no headers arrive. Theif (!produced) return;guard is commented as covering exactly this case and does not fire.That is not this sample's to solve, and not its place to repeat, so every route here is bounded. It does mean
Http3/Nghttp3Response's banner and its site pane currently tell you to run a request that wedges the server — worth fixing in one direction or the other, separately from this.