New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
net/http: on CheckRedirect failure, error message should refer to the original (redirected) URL, not the rejected redirect #34080
Comments
Hey @bcmills thanks for filing this issue! Firstly here is a standalone repro so that the code can be easily adapted to a test https://play.golang.org/p/uEh5qr5Cq_K and inlined package main
import (
"fmt"
"log"
"net/http"
"net/http/httptest"
)
var _2HopsMaxClient = &http.Client{
CheckRedirect: func(req *http.Request, via []*http.Request) error {
if len(via) > 2 {
return fmt.Errorf("max 2 hops")
}
return nil
},
}
func main() {
cst1 := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("Hello, world!"))
}))
defer cst1.Close()
cst2 := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Location", cst1.URL)
w.WriteHeader(308)
}))
defer cst2.Close()
cst3 := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Location", cst2.URL)
w.WriteHeader(308)
}))
defer cst3.Close()
cst4 := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Location", cst3.URL)
w.WriteHeader(308)
}))
defer cst4.Close()
println("original URL: ", cst4.URL)
if _, err := _2HopsMaxClient.Get(cst4.URL); err != nil {
log.Fatalf("Failed to fetch URL: %v\n", err)
}
} So while I understand that pointing you directly to the parent URL in the subject clause with <VERB> "<START_URL>" I believe that unfortunately such a change would break usability for code with multiple redirects e.g. 10 redirects in and then an obscure failure, for which it is vital for one to know which URL exactly the failure occurred on, but it also will break code for users who've had it like this since Go1.7 (4 years ago) when that code was added. With your CheckRedirect, you have access to the first URL and you can even compose for your use case a custom error that you can then unwrap since *url.Error is always returned i.e. invoke (*url.Error).Unwrap https://golang.org/pkg/net/url/#Error.Unwrap. Please let me know what you think. |
That depends, I think. There are two ways one might want to work around a rejected redirect: one is by fixing the server to avoid issuing that redirect, and the other is by fixing the client to avoid trying to fetch the problematic URL. I think most Go users are in more of a position to avoid fetching a URL — or to contact the owner of a public API endpoint — than to fix an Nth-level redirect within that public endpoint's CDN configuration. |
Go error messages are generally not covered under the Go 1 compatibility guarantee. Whether the fallout in practice from changing this error message would be too large, I do not know. |
The problem here is the default behavior. Yes, we can work around the subpar error message by adding more redundancy — but that won't make the failure condition any clearer for users who don't already know about the problem (and thus don't know to apply the workaround). |
What version of Go are you using (
go version
)?Does this issue reproduce with the latest release?
Yes.
What operating system and processor architecture are you using (
go env
)?go env
OutputWhat did you do?
Ran the program found at https://play.golang.org/p/42egMHzeuTR.
What did you expect to see?
Since the
http.Client
should not have attempted to fetch the insecure URL in the first place, the insecure URL should not be the one reported for the failedGet
operation.What did you see instead?
The URL that follows the
Get
token is one for which no HTTPGET
was actually attempted.CC @bradfitz
The text was updated successfully, but these errors were encountered: