Fix response connection persistence handling - #788
Merged
haga-rak merged 3 commits intoSep 8, 2026
Merged
Conversation
Co-authored-by: bbartels <23058572+bbartels@users.noreply.github.com>
Added support for HTTP/2 in InProcessHost configuration.
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.
Problem
HTTP/1.1 connections are persistent unless either peer requests closure. Fluxzy instead gives a response without an explicit
Keep-Alive: timeoutan implicit one-second protocol idle timeout. The pool subtracts 200 ms from that value, so a healthy connection can be discarded after roughly 800 ms even though the origin never limited its lifetime.Changing that default without considering HTTP/1.0 would make HTTP/1.0 responses persistent even when they did not negotiate
Connection: keep-alive. Connection options are also comma-separated token lists, but the existing whole-value comparison misses values such asConnection: custom, closeandConnection: custom, keep-alive.HTTP/1.0 persistence is safe only when the response has a self-defined message length. Treating an unbounded HTTP/1.0 body as persistent can leave the proxy waiting for EOF while the origin waits for the next request. A non-final-chunked
Transfer-Encodingis likewise close-delimited and overrides any accompanyingContent-Length; trusting that length can recycle a connection with unread transfer-coded bytes. A bare205 Reset Contentis not self-delimiting without explicit zero-length framing.Solution
Represent an absent HTTP/1.1 protocol idle limit as
-1, matching the pool's existing "no peer-supplied limit" sentinel. Preserve explicitKeep-Alivetimeout/max handling and the existing global unused-pool timeout.Retain the source response version while parsing flat HTTP/1 headers. HTTP/1.0 remains close-by-default and is reusable only when
Connection: keep-aliveis present and the response is self-delimiting throughContent-Lengthor valid no-body status semantics. Direct field-based responses are H2 and do not inherit HTTP/1.0 behavior.Parse
Connectionas a comma-separated, case-insensitive token list with optional whitespace. Use that parser consistently forclose,keep-alive, andupgradedecisions.For a response whose final transfer coding is not
chunked, removeContent-Length, reset the parsed length, and force close-delimited handling for both HTTP/1.0 and HTTP/1.1.Benefits
Connectionfields without substring matching.The original current-master performance campaign used four request waves separated by 1.25 seconds:
New measured upstream TLS connections fell from 64/61/224 to zero. Across all three workloads p99 fell 58-65%, allocation/request fell 53-69%, and CPU/request fell 34-38%. The later HTTP/1.0, token-parsing, and transfer-framing hardening does not alter the measured HTTP/1.1 path, but was not separately benchmarked.
Changes
ResponseHeader.TimeoutIdleSecondsto the existing unlimited sentinel.close,keep-alive, andupgradeoptions.Verification
The updated branch was built and tested locally with .NET 10.0.101. Existing compiler, analyzer, and obsolete-API warnings remain; no new errors were introduced.
Fluxzy.Tests.UnitTests.Coreset: 189 passed, 0 failed, 0 skipped.Fluxzy.Tests.UnitTests.Coreset: 189 passed, 0 failed, 0 skipped.Fluxzy.Tests.UnitTests.H11Clientset: 10 passed, 0 failed, 0 skipped.core.whitespace=cr-at-eol).The complete repository test suite was not run because it includes environment-dependent external-network, certificate-installation, and raw-capture cases. The test startup reported the expected inability to install its development CA in the unprivileged DevPod; the selected tests still completed successfully.
Line Count