cmd/golangorg: add support for module form of Go distributions
Add https://golang.org/toolchain serving appropriate meta tags
with mod redirect to https://go.dev/dl/mod.
Add https://go.dev/dl/mod/golang.org/toolchain/@v/ redirecting
to files in https://dl.google.com/go/.
Add https://go.dev/dl/mod/golang.org/toolchain/@v/list listing
stable toolchain versions.
For golang/go#57001.
Change-Id: Ib3283cab1d8ead0373ca7549f0e17ccba7cfaa22
Reviewed-on: https://go-review.googlesource.com/c/website/+/480840
Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
Reviewed-by: Dmitri Shuralyov <dmitshur@golang.org>
Run-TryBot: Russ Cox <rsc@golang.org>
Auto-Submit: Russ Cox <rsc@golang.org>
TryBot-Result: Gopher Robot <gobot@golang.org>
diff --git a/cmd/golangorg/server.go b/cmd/golangorg/server.go
index 239831a..488e838 100644
--- a/cmd/golangorg/server.go
+++ b/cmd/golangorg/server.go
@@ -222,6 +222,7 @@
// Note: Only golang.org/x/, no go.dev/x/.
mux.Handle("golang.org/x/", http.HandlerFunc(xHandler))
+ mux.Handle("golang.org/toolchain", http.HandlerFunc(toolchainHandler))
redirect.Register(mux)
@@ -573,8 +574,8 @@
}
var xTemplate = template.Must(template.New("x").Parse(`<!DOCTYPE html>
-<html>
-<head>
+<html lang="en">
+<title>The Go Programming Language</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<meta name="go-import" content="golang.org/x/{{.Proj}} git https://go.googlesource.com/{{.Proj}}">
<meta name="go-source" content="golang.org/x/{{.Proj}} https://github.com/golang/{{.Proj}}/ https://github.com/golang/{{.Proj}}/tree/master{/dir} https://github.com/golang/{{.Proj}}/blob/master{/dir}/{file}#L{line}">
@@ -586,6 +587,30 @@
</html>
`))
+func toolchainHandler(w http.ResponseWriter, r *http.Request) {
+ if r.URL.Path != "/toolchain" {
+ // Shouldn't happen if handler is registered correctly.
+ http.NotFound(w, r)
+ return
+ }
+ w.Write(toolchainPage)
+}
+
+var toolchainPage = []byte(`<!DOCTYPE html>
+<html lang="en">
+<head>
+<title>The Go Programming Language</title>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
+<meta name="go-import" content="golang.org/toolchain mod https://go.dev/dl/mod">
+<meta http-equiv="refresh" content="0; url=https://go.dev/dl/">
+</head>
+<body>
+golang.org/toolchain is the module form of the Go toolchain releases.
+<a href="https://go.dev/dl/">Redirecting to Go toolchain download page...</a>
+</body>
+</html>
+`)
+
var _ fs.ReadDirFS = unionFS{}
// A unionFS is an FS presenting the union of the file systems in the slice.
diff --git a/cmd/golangorg/testdata/web.txt b/cmd/golangorg/testdata/web.txt
index 68bcfba..bdff81d 100644
--- a/cmd/golangorg/testdata/web.txt
+++ b/cmd/golangorg/testdata/web.txt
@@ -2,6 +2,11 @@
code == 301
redirect == https://go.dev/
+GET https://golang.org/toolchain
+code == 200
+body contains <meta name="go-import" content="golang.org/toolchain mod https://go.dev/dl/mod">
+body contains <meta http-equiv="refresh" content="0; url=https://go.dev/dl/">
+
GET http://localhost:6060/
redirect == /go.dev/
@@ -419,6 +424,24 @@
body contains .windows-amd64.msi
body !contains UA-
+GET https://go.dev/dl/go1.10.darwin-amd64.tar.gz
+redirect == https://dl.google.com/go/go1.10.darwin-amd64.tar.gz
+
+GET https://go.dev/dl/mod/golang.org/toolchain/@v/v0.0.1-go1.20.2.darwin-amd64.zip
+redirect == https://dl.google.com/go/v0.0.1-go1.20.2.darwin-amd64.zip
+
+GET https://go.dev/dl/mod/golang.org/toolchain/@v/v0.0.1-go1.20.2.darwin-amd64.mod
+redirect == https://dl.google.com/go/v0.0.1-go1.20.2.darwin-amd64.mod
+
+GET https://go.dev/dl/mod/golang.org/toolchain/@v/v0.0.1-go1.20.2.darwin-amd64.info
+redirect == https://dl.google.com/go/v0.0.1-go1.20.2.darwin-amd64.info
+
+GET https://go.dev/dl/mod/golang.org/toolchain/@v/list
+body ~ (?m)^v0\.0\.1-go1\.\d+\.\d+.darwin-arm64$
+body ~ (?m)^v0\.0\.1-go1\.\d+\.\d+.darwin-amd64$
+body ~ (?m)^v0\.0\.1-go1\.\d+\.\d+.linux-386$
+body ~ (?m)^v0\.0\.1-go1\.\d+\.\d+.windows-amd64$
+
GET https://go.dev/ref
redirect == /doc/#references
diff --git a/internal/dl/server.go b/internal/dl/server.go
index 101fc4b..8dc1c7d 100644
--- a/internal/dl/server.go
+++ b/internal/dl/server.go
@@ -42,6 +42,8 @@
s := server{site, dc, gob}
mux.HandleFunc(host+"/dl", s.getHandler)
mux.HandleFunc(host+"/dl/", s.getHandler) // also serves listHandler
+ mux.HandleFunc(host+"/dl/mod/golang.org/toolchain/@v/", s.toolchainRedirect)
+ mux.HandleFunc(host+"/dl/mod/golang.org/toolchain/@v/list", s.toolchainList)
mux.HandleFunc(host+"/dl/upload", s.uploadHandler)
// NOTE(cbro): this only needs to be run once per project,
@@ -78,6 +80,38 @@
})
}
+// toolchainList serves the toolchain module version list.
+// We only list the stable releases, even though older releases are available as well.
+func (h server) toolchainList(w http.ResponseWriter, r *http.Request) {
+ d, err := h.listData(r.Context())
+ if err != nil {
+ log.Printf("ERROR listing downloads: %v", err)
+ http.Error(w, "Could not get module list. Try again in a few minutes.", 500)
+ return
+ }
+
+ var buf bytes.Buffer
+ for _, r := range d.Stable {
+ for _, f := range r.Files {
+ if f.Kind != "archive" {
+ continue
+ }
+ buf.WriteString("v0.0.1-")
+ buf.WriteString(f.Version)
+ buf.WriteString(".")
+ buf.WriteString(f.OS)
+ buf.WriteString("-")
+ arch := f.Arch
+ if arch == "armv6l" {
+ arch = "arm"
+ }
+ buf.WriteString(arch)
+ buf.WriteString("\n")
+ }
+ }
+ w.Write(buf.Bytes())
+}
+
// dl.gob was generated 2021-11-08 from the live server data, for offline testing.
//
//go:embed dl.gob
@@ -254,6 +288,22 @@
`, html.EscapeString(redirectURL), html.EscapeString(redirectURL))
}
+// toolchainRedirect redirects /dl/mod/golang.org/toolchain/@v/v___ to https://dl.google.com/go/v___.
+func (server) toolchainRedirect(w http.ResponseWriter, r *http.Request) {
+ if r.Method != "GET" && r.Method != "HEAD" && r.Method != "OPTIONS" {
+ http.Error(w, "method not allowed", http.StatusMethodNotAllowed)
+ return
+ }
+
+ _, file, _ := strings.Cut(r.URL.Path, "/@v/")
+ if (!strings.HasPrefix(file, "v0.") && !strings.HasPrefix(file, "v1.")) || strings.Contains(file, "/") {
+ http.NotFound(w, r)
+ return
+ }
+
+ http.Redirect(w, r, "https://dl.google.com/go/"+file, http.StatusFound)
+}
+
func (h server) initHandler(w http.ResponseWriter, r *http.Request) {
var fileRoot struct {
Root string