net/http: follow redirects in the client again - #72
Open
yohimik wants to merge 1 commit into
Open
Conversation
The client keeps CheckRedirect and ErrUseLastResponse, but Client.do lost its redirect loop, so a 3xx went straight back to the caller with an unread body. A request for a GitHub release asset returned 302 and zero bytes where Go returns 200 and the file. Port the loop of Go back. It makes up to 10 hops through checkRedirect and defaultCheckRedirect, has redirectBehavior for the 301, 302 and 303 change to GET and for the 307 and 308 replay with GetBody, resolves Location against the URL of the current request, drops sensitive headers when a hop leaves the initial domain, reads and closes an intermediate body, and honours ErrUseLastResponse. The port makes two changes. shouldCopyHeaderOnRedirect compares the hostnames as they are and not through idnaASCII, so the Unicode and the punycode spelling of one IDN host count as two hosts. And roundTrip uses Request.URL.Host when Request.Host is empty, because only NewRequest fills Request.Host and a redirect hop builds its request directly.
This was referenced Aug 30, 2026
Author
|
tinygo-org/net main has not moved since this branch was opened. It is still |
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.
net/http: follow redirects in the client again
Repository tinygo-org/net. Branch
upstream-pr/http-redirects, basemain.What this does
The client keeps
CheckRedirectandErrUseLastResponse, butClient.dolostits redirect loop, so a 3xx went straight back to the caller with an unread
body. A request for a GitHub release asset returned 302 and zero bytes where Go
returns 200 and the file.
This ports the loop of Go back into
http/client.go. It hascheckRedirectanddefaultCheckRedirect,redirectBehaviorwith the 301, 302 and 303 change to GET and the 307 and 308replay with
GetBody,Locationresolved against the URL of the current request,ErrUseLastResponsehonoured,refererForURLwith the https to http rule.The code follows the upstream Go source, with its comments, so a later update
from upstream is a straight comparison.
Two changes from upstream
shouldCopyHeaderOnRedirectcompares the hostnames as they are and notthrough
idnaASCII, which needsgolang.org/x/net/idnaand its tables. TheUnicode and the punycode spelling of one IDN host thus count as two hosts and
lose their sensitive headers. That is the safe direction. The rule for a
subdomain is the upstream one.
roundTripusesRequest.URL.HostwhenRequest.Hostis empty, because onlyNewRequestfillsRequest.Hostand a redirect hop builds its requestdirectly.
Evidence
There is no CI in this repository. Checked by hand on macOS 26.6 arm64 with a
TinyGo build that carries the matching toolchain change.
http.Get("https://example.com/")builds and completes.A downstream product ships binaries built with these changes in a production
release. dispat v1.4.0 is published and is not a prerelease. It carries
dispat-tiny-linux-amd64anddispat-tiny-linux-arm64, built by the forkrelease v0.42.0-net.4 from sha256-pinned tarballs and smoke-executed under
binfmt before upload, beside six binaries from the gc toolchain.
https://github.com/yohimik/dispat/releases/tag/services%2Fdispat%2Fv1.4.0
The acceptance record of that repository is committed at
packages/docs/docs/internals/tinygo.md. It reports the net.2 to net.4acceptance history, an integration suite of 694 rows that passes with 0 failures
and 1 documented skip on darwin, and a size table of 0.58x to 0.63x against the
gc equivalents with TinyGo
-opt=z -no-debugagainstgo build -trimpath -ldflags "-s -w". Those figures come from that document. They are not ameasurement of this branch.
The self-update path of that program downloads a release asset over HTTPS, which
is the redirect case above.
Scope
http/client.go. No API change.linux as it stands.
Known gaps
http.Client.Timeoutis still inert in this port. The loop does not add adeadline of its own. That is a separate piece of work.
Transportimplementation, so a caller-suppliedTransportisstill driven directly and does not take part in the redirect handling.
Related pull requests
This change is part of one body of work. Together the changes make programs that use the network and child processes work on hosted linux and macOS. A full CLI was tested end to end with all of them and ships binaries built this way, see dispat v1.4.0 in the evidence section.
In tinygo-org/tinygo
In this repository
A merge order that works. The three bug fixes are independent. tinygo-org/tinygo#5633 goes before tinygo-org/tinygo#5635. HTTPS on linux needs only tinygo-org/tinygo#5633 and tinygo-org/tinygo#5635. Full darwin support also needs tinygo-org/tinygo#5636, the net changes and a new src/net submodule pin.