Conversation
…plete request Requests and responses may outlive their session. The session only remembered the latest reader and writer, and an earlier one clearing that pointer on destruction made the session forget the later one. Operations on a detached writer also still used the stream of the session that was gone. The session now tracks all of its readers and writers and detaches every one of them; a detached writer's write, submit or get_response completes with connection_aborted. The HTTP/1.1 client is treated as a protocol with "max concurrent streams = 1". Interleaving requests used to corrupt the connection silently, with every write reporting success. Now, instead of waiting, which deadlocks when the caller is the one to finish the earlier one: - async_submit() fails with would_block while the previous request is not complete (header and body written; a request without a body, by its framing only, is complete after submit) - async_get_response() fails with would_block until the responses to earlier requests have been read completely - after a request or response could not be completed, later submits or get_response calls fail with connection_aborted Pipelining of complete requests keeps working. The rules and the design decisions behind them are documented in README.md, "Concurrent Requests". Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…n members Endpoint describes a local socket (address + fd); the drop rates are server configuration. send_udp() and send_udp_gso() were free functions only called by Http3ServerSession, which already owns the fd, the no_gso flag and the config, so fold them into the session: send_udp_gso() becomes the body of send_datagrams(), and send_udp() takes just the remote ngtcp2_addr and the packet. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Config::disable_gro skips enabling UDP_GRO on the server's UDP socket; Config::disable_gso starts every session with no_gso_ set, so aggregated packets go out with one sendto() each instead of a single UDP_SEGMENT sendmsg(). The "UDP listening" log line reports both. Single-threaded Release server, h2load over loopback, 1000 x 1MB, -c 10: config download MB/s upload MB/s both on 1385 1277 GRO off 1409 752 GSO off 565 1256 both off 552 741 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
/eat_request responds first and drains afterwards, so h2load, which stops uploading once the response is complete, only sends a fraction of the body and upload benchmarks against it measure almost nothing. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…ADERS, add header tests HTTP/1.1 copied the user's fields with message.set(), so of a field given several times only the last value went out, in requests and responses alike. User fields still replace defaults like User-Agent or Date. nghttp2 closes the stream of a request HEADERS frame it cannot send, but not that of a response: the client waited forever for it and the server's async_write_eof() never completed. The stream is now reset instead. The header block nghttp2 is willing to send is raised from 64 KiB to 1 MiB. test_headers.cpp covers many, large, repeated and oversized header fields in both directions for all three protocols. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
anyhttp::truncated() prints at most 256 bytes of a string, followed by "... (N bytes, truncated)". All places logging sent or received header fields use it, so a large field no longer floods the log. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…ceive server::Config::max_header_size and client::Config::max_header_size bound the header section a peer can send, 64 KiB by default; the server binary takes --max-header-size. Neither nghttp2 nor nghttp3 enforces the limit it announces (SETTINGS_MAX_HEADER_LIST_SIZE, SETTINGS_MAX_FIELD_SECTION_SIZE), so the header callbacks count every field as name + value + 32 bytes themselves and stop storing fields once the limit is exceeded. HTTP/1.1 leaves the counting to the Beast parser's header limit. A request beyond the limit is answered with 431 without ever reaching the request handler; a response beyond it fails async_get_response() with http::error::header_limit and resets the stream. HTTP/2 and HTTP/3 sessions survive both, HTTP/1.1 connections are closed. nghttp2 closes a connection whose peer sends more CONTINUATION frames than a header section is allowed to need, 8 by default. That cap now follows max_header_size, so raising the limit no longer runs into it instead. Verified with 40 concurrent requests of 800 KB of headers each: the server's peak RSS grows by nothing (HTTP/1.1) and 4 MB (HTTP/3) with the default limit, against 32 MB and 25 MB with it effectively turned off. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Looking up each expected field with equal_range built a fresh vector of values per field, 200 of them for the larger tests. Flatten the actual fields into (name, value) pairs once instead and match against that. StrCaseEq keeps the name comparison case-insensitive, as the beast field lookup it replaces was. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The setting is advisory in both directions: nghttp2 stores the local and the remote value but never compares a header section against either, and its own default is unlimited. Header sections beyond max_header_size are rejected where they arrive, so announcing the limit bought nothing but bytes on the wire. HTTP/3 keeps announcing it, because nghttp3 writes SETTINGS_MAX_FIELD_SECTION_ SIZE into its SETTINGS frame unconditionally. Leaving that at the default would announce an unlimited header section, in four more bytes of varint than the real limit takes. Also documents nghttp2_unique_ptr. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
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.
No description provided.