gddo-server: add initial redirect logic
Logic is added to redirect specific paths to pkg.go.dev.
Change-Id: I49b3d446e99c5684dd9121322b822f84b1cda1be
Reviewed-on: https://go-review.googlesource.com/c/gddo/+/281732
Trust: Julie Qiu <julie@golang.org>
Run-TryBot: Julie Qiu <julie@golang.org>
Reviewed-by: Jonathan Amsterdam <jba@google.com>
diff --git a/gddo-server/main.go b/gddo-server/main.go
index d0f12a5..57eac28 100644
--- a/gddo-server/main.go
+++ b/gddo-server/main.go
@@ -961,9 +961,9 @@
}
mux.Handle("/-/about", handler(pkgGoDevRedirectHandler(s.serveAbout)))
- mux.Handle("/-/bot", handler(s.serveBot))
+ mux.Handle("/-/bot", handler(pkgGoDevRedirectHandler(s.serveBot)))
mux.Handle("/-/go", handler(pkgGoDevRedirectHandler(s.serveGoIndex)))
- mux.Handle("/-/subrepo", handler(s.serveGoSubrepoIndex))
+ mux.Handle("/-/subrepo", handler(pkgGoDevRedirectHandler(s.serveGoSubrepoIndex)))
mux.Handle("/-/refresh", handler(s.serveRefresh))
mux.Handle("/about", http.RedirectHandler("/-/about", http.StatusMovedPermanently))
mux.Handle("/favicon.ico", staticServer.FileHandler("favicon.ico"))
@@ -1075,6 +1075,10 @@
}
func (s *server) teeRequestToPkgGoDev(r *http.Request, latency time.Duration, status int) {
+ if shouldRedirectRequest(r) {
+ log.Printf("shouldRedirectToPkgGoDev(%q, %q)= true: not teeing request because it is redirected to pkg.go.dev", r.URL.Host, r.URL.Path)
+ return
+ }
if !shouldTeeRequest(r.URL.Path) {
log.Printf("s.teeRequestToPkgGoDev: shouldTeeRequest(%q): not teeing request", r.URL.Path)
return
diff --git a/gddo-server/pkgsite.go b/gddo-server/pkgsite.go
index 3e185c9..5c883f8 100644
--- a/gddo-server/pkgsite.go
+++ b/gddo-server/pkgsite.go
@@ -187,12 +187,15 @@
// can be turned on/off using a query param.
func pkgGoDevRedirectHandler(f func(http.ResponseWriter, *http.Request) error) func(http.ResponseWriter, *http.Request) error {
return func(w http.ResponseWriter, r *http.Request) error {
+ if shouldRedirectRequest(r) {
+ http.Redirect(w, r, pkgGoDevURL(r.URL).String(), http.StatusFound)
+ return nil
+ }
+
if userReturningFromPkgGoDev(r) {
return f(w, r)
}
-
redirectParam := r.FormValue(pkgGoDevRedirectParam)
-
if redirectParam == pkgGoDevRedirectOn {
cookie := &http.Cookie{Name: pkgGoDevRedirectCookie, Value: redirectParam, Path: "/"}
http.SetCookie(w, cookie)
@@ -201,16 +204,39 @@
cookie := &http.Cookie{Name: pkgGoDevRedirectCookie, Value: "", MaxAge: -1, Path: "/"}
http.SetCookie(w, cookie)
}
-
if !shouldRedirectToPkgGoDev(r) {
return f(w, r)
}
-
http.Redirect(w, r, pkgGoDevURL(r.URL).String(), http.StatusFound)
return nil
}
}
+// alwaysRedirectPaths is a set of paths that are always redirected to
+// pkg.go.dev.
+var alwaysRedirectPaths = map[string]bool{
+ "/-/about": true,
+}
+
+func shouldRedirectRequest(r *http.Request) bool {
+ // Requests to api.godoc.org and talks.godoc.org are not redirected.
+ if strings.HasPrefix(r.URL.Host, "api") || strings.HasPrefix(r.URL.Host, "talks") {
+ return false
+ }
+ // Badge SVGs will be redirected last.
+ _, isSVG := r.URL.Query()["status.svg"]
+ _, isPNG := r.URL.Query()["status.png"]
+ if isSVG || isPNG {
+ return false
+ }
+
+ if alwaysRedirectPaths[r.URL.Path] {
+ return true
+ }
+ // TODO: redirect based on rollout percentage.
+ return false
+}
+
const goGithubRepoURLPath = "/github.com/golang/go"
func pkgGoDevURL(godocURL *url.URL) *url.URL {
diff --git a/gddo-server/pkgsite_test.go b/gddo-server/pkgsite_test.go
index ac2808a..18ffe08 100644
--- a/gddo-server/pkgsite_test.go
+++ b/gddo-server/pkgsite_test.go
@@ -18,10 +18,6 @@
)
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
@@ -70,12 +66,21 @@
cookie: &http.Cookie{Name: "pkggodev-redirect", Value: "on"},
wantStatusCode: http.StatusOK,
},
+ {
+ name: "always redirect /-/about",
+ url: "http://godoc.org/-/about",
+ wantLocationHeader: "https://pkg.go.dev/about?utm_source=godoc",
+ 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)
}
+ handler := pkgGoDevRedirectHandler(func(w http.ResponseWriter, r *http.Request) error {
+ return nil
+ })
w := httptest.NewRecorder()
err := handler(w, req)
@@ -87,11 +92,9 @@
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 %d; want %d", got, want)
}