Skip to content

client: release the connection after any response - #1246

Merged
mhutchinson merged 1 commit into
transparency-dev:mainfrom
grempe:http-fetcher-close-body
Nov 9, 2026
Merged

mhutchinson merged 1 commit into
transparency-dev:mainfrom
grempe:http-fetcher-close-body

Conversation

@grempe

@grempe grempe commented Oct 22, 2026

Copy link
Copy Markdown
Contributor

Fixes #1245.

fetch returned on a 404, or any other status but 200, before it deferred closing the response body. When that response had a body, the transport couldn't reuse the connection:

  • each such response cost a new connection;
  • for as long as the request's context lived, the connection and its two transport goroutines stayed open.

This change defers closing the body as soon as Do succeeds, and reads the body to the end first, so that the connection can be reused. The 200 path is unchanged apart from where the close is deferred.

Testing

  • New TestHTTPFetcherReleasesConnections: 10 sequential requests against an httptest server, counting new connections. On main, 404 and 500 use 10 connections each, and 200 uses 1. With the fix, all three use 1.
  • Race tests: go test -race ./client/... passes.
  • Lint: golangci-lint v2.13.2 reports 0 issues.
  • With a long-lived context, 50 requests answered 404 or 500 left +100 goroutines on main, two per leaked connection, and none with the fix.

One choice to note: error bodies are now read in full before closing. If you'd rather not read a large error body, a bounded read (io.LimitReader) would keep the leak fixed; a body larger than the limit would then just not have its connection reused. Happy to change it.

My first contribution, #1238, adds me to AUTHORS and CONTRIBUTORS under the individual CLA (commit 69ba233), so this PR doesn't repeat that change.


Reviewed and submitted by me, a human. The investigation, the fix and its testing were developed with the assistance of an AI coding agent.

@grempe
grempe requested a review from a team as a code owner October 22, 2026 19:46
@grempe
grempe requested a review from mhutchinson October 22, 2026 19:46
HTTPFetcher returned on a 404, or any other status but 200, before it
deferred closing the response body. The transport then could not reuse
the connection, so every such response cost a new connection, and for
as long as the request's context lived, the connection and its two
transport goroutines stayed open.

Close the body on every path, after reading it to the end so that the
connection can be reused.
@mhutchinson
mhutchinson force-pushed the http-fetcher-close-body branch from 9cf88d2 to e66a44b Compare November 9, 2026 09:46
@mhutchinson
mhutchinson merged commit cbf72b4 into transparency-dev:main Nov 9, 2026
19 of 20 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

client.HTTPFetcher doesn't close non-200 response bodies, so connections leak

2 participants