gddo: add option to redirect requests to pkg.go.dev
Updates golang/go#37099
Change-Id: Ibaf46b9182d761d56d8dc6770259ab4bc3703d59
Reviewed-on: https://go-review.googlesource.com/c/gddo/+/218697
Reviewed-by: Andrew Bonventre <andybons@golang.org>
diff --git a/gddo-server/main.go b/gddo-server/main.go
index 52186dc..ea34868 100644
--- a/gddo-server/main.go
+++ b/gddo-server/main.go
@@ -19,6 +19,7 @@
"io"
"log"
"net/http"
+ "net/url"
"os"
"path"
"regexp"
@@ -926,9 +927,10 @@
trustProxyHeaders: v.GetBool(ConfigTrustProxyHeaders),
}
}
- mux.Handle("/-/about", handler(s.serveAbout))
+
+ mux.Handle("/-/about", handler(pkgGoDevRedirectHandler(s.serveAbout)))
mux.Handle("/-/bot", handler(s.serveBot))
- mux.Handle("/-/go", handler(s.serveGoIndex))
+ mux.Handle("/-/go", handler(pkgGoDevRedirectHandler(s.serveGoIndex)))
mux.Handle("/-/subrepo", handler(s.serveGoSubrepoIndex))
mux.Handle("/-/refresh", handler(s.serveRefresh))
mux.Handle("/about", http.RedirectHandler("/-/about", http.StatusMovedPermanently))
@@ -939,7 +941,7 @@
mux.Handle("/BingSiteAuth.xml", staticServer.FileHandler("BingSiteAuth.xml"))
mux.Handle("/C", http.RedirectHandler("http://golang.org/doc/articles/c_go_cgo.html", http.StatusMovedPermanently))
mux.Handle("/code.jquery.com/", http.NotFoundHandler())
- mux.Handle("/", handler(s.serveHome))
+ mux.Handle("/", handler(pkgGoDevRedirectHandler(s.serveHome)))
ahMux := http.NewServeMux()
ready := new(health.Handler)
@@ -1017,6 +1019,64 @@
})
}
+const (
+ pkgGoDevRedirectCookie = "pkggodev-redirect"
+ pkgGoDevRedirectParam = "redirect"
+ pkgGoDevRedirectOn = "on"
+ pkgGoDevRedirectOff = "off"
+ pkgGoDevHost = "pkg.go.dev"
+)
+
+var gddoToPkgGoDevRequest = map[string]string{
+ "/-/about": "/about",
+ "/-/go": "/std",
+}
+
+// pkgGoDevRedirectHandler redirects requests from godoc.org to pkg.go.dev,
+// based on whether a cookie is set for pkggodev-redirect. The cookie
+// can be turned on/off using a query param. It determines which path to
+// direct to by checking if a path is mapped in gddoToPkgGoDevRequest, and
+// if not redirecting to the same path that was used for the godoc.org request.
+func pkgGoDevRedirectHandler(f func(http.ResponseWriter, *http.Request) error) func(http.ResponseWriter, *http.Request) error {
+ return func(w http.ResponseWriter, r *http.Request) error {
+ redirectParam := r.FormValue(pkgGoDevRedirectParam)
+
+ if redirectParam == pkgGoDevRedirectOn {
+ cookie := &http.Cookie{Name: pkgGoDevRedirectCookie, Value: redirectParam, Path: "/"}
+ http.SetCookie(w, cookie)
+ }
+ if redirectParam == pkgGoDevRedirectOff {
+ cookie := &http.Cookie{Name: pkgGoDevRedirectCookie, Value: "", MaxAge: -1, Path: "/"}
+ http.SetCookie(w, cookie)
+ }
+
+ var shouldRedirect bool
+ if redirectParam == pkgGoDevRedirectOn || redirectParam == pkgGoDevRedirectOff {
+ shouldRedirect = redirectParam == pkgGoDevRedirectOn
+ } else {
+ for _, v := range r.Cookies() {
+ if v.Name == pkgGoDevRedirectCookie {
+ shouldRedirect = v.Value == pkgGoDevRedirectOn
+ break
+ }
+ }
+ }
+
+ if !shouldRedirect {
+ return f(w, r)
+ }
+
+ path, ok := gddoToPkgGoDevRequest[r.URL.Path]
+ if !ok {
+ path = r.URL.Path
+ }
+
+ nextUrl := url.URL{Scheme: "https", Host: pkgGoDevHost, Path: path}
+ http.Redirect(w, r, nextUrl.String(), http.StatusFound)
+ return nil
+ }
+}
+
func main() {
ctx := context.Background()
v, err := loadConfig(ctx, os.Args)
diff --git a/gddo-server/main_test.go b/gddo-server/main_test.go
index 7c4bc78..8dddb8e 100644
--- a/gddo-server/main_test.go
+++ b/gddo-server/main_test.go
@@ -7,6 +7,8 @@
package main
import (
+ "net/http"
+ "net/http/httptest"
"testing"
)
@@ -33,3 +35,79 @@
}
}
}
+
+func TestHandlePkgGoDevRedirect(t *testing.T) {
+ handler := pkgGoDevRedirectHandler(func(w http.ResponseWriter, r *http.Request) error {
+ return nil
+ })
+
+ for _, test := range []struct {
+ name, url, wantLocationHeader, wantSetCookieHeader string
+ wantStatusCode int
+ cookie *http.Cookie
+ }{
+ {
+ name: "test pkggodev-redirect param is on",
+ url: "http://godoc.org/net/http?redirect=on",
+ wantLocationHeader: "https://pkg.go.dev/net/http",
+ wantSetCookieHeader: "pkggodev-redirect=on; Path=/",
+ wantStatusCode: http.StatusFound,
+ },
+ {
+ name: "test pkggodev-redirect param is off",
+ url: "http://godoc.org/net/http?redirect=off",
+ wantLocationHeader: "",
+ wantSetCookieHeader: "pkggodev-redirect=; Path=/; Max-Age=0",
+ wantStatusCode: http.StatusOK,
+ },
+ {
+ name: "test pkggodev-redirect param is unset",
+ url: "http://godoc.org/net/http",
+ wantLocationHeader: "",
+ wantSetCookieHeader: "",
+ wantStatusCode: http.StatusOK,
+ },
+ {
+ name: "toggle enabled pkggodev-redirect cookie",
+ url: "http://godoc.org/net/http?redirect=off",
+ cookie: &http.Cookie{Name: "pkggodev-redirect", Value: "true"},
+ wantLocationHeader: "",
+ wantSetCookieHeader: "pkggodev-redirect=; Path=/; Max-Age=0",
+ wantStatusCode: http.StatusOK,
+ },
+ {
+ name: "pkggodev-redirect enabled cookie should redirect",
+ url: "http://godoc.org/net/http",
+ cookie: &http.Cookie{Name: "pkggodev-redirect", Value: "on"},
+ wantLocationHeader: "https://pkg.go.dev/net/http",
+ wantSetCookieHeader: "",
+ wantStatusCode: http.StatusFound,
+ },
+ } {
+ t.Run(test.name, func(t *testing.T) {
+ req := httptest.NewRequest("GET", test.url, nil)
+ if test.cookie != nil {
+ req.AddCookie(test.cookie)
+ }
+
+ w := httptest.NewRecorder()
+ err := handler(w, req)
+ if err != nil {
+ t.Fatal(err)
+ }
+ resp := w.Result()
+
+ if got, want := resp.Header.Get("Location"), test.wantLocationHeader; got != want {
+ t.Errorf("Location header mismatch: got %q; want %q", got, want)
+ }
+
+ if got, want := resp.Header.Get("Set-Cookie"), test.wantSetCookieHeader; got != want {
+ t.Errorf("Set-Cookie header mismatch: got %q; want %q", got, want)
+ }
+
+ if got, want := resp.StatusCode, test.wantStatusCode; got != want {
+ t.Errorf("Status code mismatch: got %q; want %q", got, want)
+ }
+ })
+ }
+}