HTTP-01: Do our own redirect handling - #8961
Open
aarongable wants to merge 3 commits into
Open
Conversation
Retry the request and validation target selected by redirect handling so IPv6 dial failures can fall back to IPv4 at each hop. Resume from the request whose dial failed to avoid replaying earlier redirects. Add regression coverage for the reported HTTP-to-HTTPS two-fallback sequence.
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.
Note
This PR builds on #8905, only the most recent commit is new. This PR also addresses all of my review comments left on that PR; I'd be happy landing that PR as-is as long as this PR follows it.
This PR makes two large simplifications to the VA's HTTP-01 validation code, and a number of smaller modifications as knock-on effects.
The first large simplification is the replacement of Go's default redirect handling with a straightforward loop that we manage directly. Although hooking into Go's http.Client.CheckRedirect function was useful, it required our code to be non-linear because that function is called as a callback. We'd set up a redirect request for Go to make, it would magically happen in the background, and then our straight-line code would deal with the result, including potentially falling back from an IPv6 attempt to an IPv4 attempt outside Go's redirect handling. This has resulted in numerous bugs over time.
The new code instead tells Go to never follow redirects on its own, and just return the redirect response to us. We then handle every validation response with a few simple cases:
This does introduce some additional complexity (e.g. having to track the referer ourselves, and not attach it when redirecting from https to http), but I think the tradeoff is worth it.
The second large simplification is in how we keep track of what requests we're making. Historically we've had both an
httpValidationTargetand acore.ValidationRecordwhich stored redundant information and were used almost interchangeably. This change gets rid of httpValidationTarget. Prior to each iteration of the loop described above, we construct a ValidationRecord. Each loop appends that record to the list prior to making the validation request, so that any errors encountered in the process will be associated with the most recent entry in the list of records. And the functions which actually make the request extract their parameters (the IP address, the port, the path, etc) directly from the ValidationRecord, ensuring that we're recording exactly what we do, with no drift.Smaller knock-on changes include:
An LLM was used to review and improve an earlier version of this PR, and to do most of the unit test case updates.