diff --git a/src/cmd/go/go_test.go b/src/cmd/go/go_test.go
index d7e9ab4c74d..473f62ca5bf 100644
--- a/src/cmd/go/go_test.go
+++ b/src/cmd/go/go_test.go
@@ -3407,22 +3407,6 @@ func TestGoGetDotSlashDownload(t *testing.T) {
tg.run("get", "./pprof_mac_fix")
}
-// Issue 13037: Was not parsing tags in 404 served over HTTPS
-func TestGoGetHTTPS404(t *testing.T) {
- testenv.MustHaveExternalNetwork(t)
- switch runtime.GOOS {
- case "darwin", "linux", "freebsd":
- default:
- t.Skipf("test case does not work on %s", runtime.GOOS)
- }
-
- tg := testgo(t)
- defer tg.cleanup()
- tg.tempDir("src")
- tg.setenv("GOPATH", tg.path("."))
- tg.run("get", "bazil.org/fuse/fs/fstestutil")
-}
-
// Test that you cannot import a main package.
// See golang.org/issue/4210 and golang.org/issue/17475.
func TestImportMain(t *testing.T) {
diff --git a/src/cmd/go/internal/web/http.go b/src/cmd/go/internal/web/http.go
index 6e347fbf860..c1714b4d38b 100644
--- a/src/cmd/go/internal/web/http.go
+++ b/src/cmd/go/internal/web/http.go
@@ -25,10 +25,6 @@ import (
"cmd/internal/browser"
)
-// httpClient is the default HTTP client, but a variable so it can be
-// changed by tests, without modifying http.DefaultClient.
-var httpClient = http.DefaultClient
-
// impatientInsecureHTTPClient is used in -insecure mode,
// when we're connecting to https servers that might not be there
// or might be using self-signed certificates.
@@ -42,6 +38,18 @@ var impatientInsecureHTTPClient = &http.Client{
},
}
+// securityPreservingHTTPClient is like the default HTTP client, but rejects
+// redirects to plain-HTTP URLs if the original URL was secure.
+var securityPreservingHTTPClient = &http.Client{
+ CheckRedirect: func(req *http.Request, via []*http.Request) error {
+ if len(via) > 0 && via[0].URL.Scheme == "https" && req.URL.Scheme != "https" {
+ lastHop := via[len(via)-1].URL
+ return fmt.Errorf("redirected from secure URL %s to insecure URL %s", lastHop, req.URL)
+ }
+ return nil
+ },
+}
+
type HTTPError struct {
status string
StatusCode int
@@ -54,7 +62,7 @@ func (e *HTTPError) Error() string {
// Get returns the data from an HTTP GET request for the given URL.
func Get(url string) ([]byte, error) {
- resp, err := httpClient.Get(url)
+ resp, err := securityPreservingHTTPClient.Get(url)
if err != nil {
return nil, err
}
@@ -87,7 +95,7 @@ func GetMaybeInsecure(importPath string, security SecurityMode) (urlStr string,
if security == Insecure && scheme == "https" { // fail earlier
res, err = impatientInsecureHTTPClient.Get(urlStr)
} else {
- res, err = httpClient.Get(urlStr)
+ res, err = securityPreservingHTTPClient.Get(urlStr)
}
return
}
diff --git a/src/cmd/go/testdata/script/get_insecure_redirect.txt b/src/cmd/go/testdata/script/get_insecure_redirect.txt
new file mode 100644
index 00000000000..c3520bfcab0
--- /dev/null
+++ b/src/cmd/go/testdata/script/get_insecure_redirect.txt
@@ -0,0 +1,11 @@
+# golang.org/issue/13037: 'go get' was not parsing tags in 404 served over HTTPS.
+# golang.org/issue/29591: 'go get' was following plain-HTTP redirects even without -insecure.
+
+[!net] skip
+
+env GOPROXY=
+
+! go get -d vcs-test.golang.org/insecure/go/insecure
+stderr 'redirected .* to insecure URL'
+
+go get -d -insecure vcs-test.golang.org/insecure/go/insecure