gddo-server: redirect stdlib

Logic is added for selectively redirecting stdlib pages.

Change-Id: I9ba6cecd0108f2d232e0bbf2de00eb43b18cab89
Reviewed-on: https://go-review.googlesource.com/c/gddo/+/285879
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/dynconfig/dynconfig.go b/gddo-server/dynconfig/dynconfig.go
index 4464a60..7a989ee 100644
--- a/gddo-server/dynconfig/dynconfig.go
+++ b/gddo-server/dynconfig/dynconfig.go
@@ -29,6 +29,7 @@
 	RedirectBadges   bool
 	RedirectHomepage bool
 	RedirectSearch   bool
+	RedirectStdlib   bool
 
 	RedirectPaths   []string
 	RedirectRollout uint
diff --git a/gddo-server/pkgsite.go b/gddo-server/pkgsite.go
index 033e867..e75d9dc 100644
--- a/gddo-server/pkgsite.go
+++ b/gddo-server/pkgsite.go
@@ -268,6 +268,9 @@
 		}
 		return false
 	}
+	if isStdlibURLPath(r.URL.Path) && cfg.RedirectStdlib {
+		return true
+	}
 
 	if cfg.RedirectRollout >= 100 {
 		return true
@@ -285,6 +288,17 @@
 	return uint(h.Sum32()%100) < cfg.RedirectRollout
 }
 
+func isStdlibURLPath(path string) bool {
+	if strings.HasPrefix(path, "/-/") {
+		return false
+	}
+	path = strings.TrimPrefix(path, "/")
+	if i := strings.IndexByte(path, '/'); i != -1 {
+		path = path[:i]
+	}
+	return !strings.Contains(path, ".")
+}
+
 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 8c0dddf..79d86d9 100644
--- a/gddo-server/pkgsite_test.go
+++ b/gddo-server/pkgsite_test.go
@@ -508,8 +508,11 @@
 		"https://godoc.org/-/go",
 		"https://godoc.org/-/subrepo",
 		"https://godoc.org/?q=http",
+		"https://godoc.org/cmd",
 		"https://godoc.org/net/http",
 		"https://godoc.org/cloud.google.com/go",
+		"https://godoc.org/github.com/my/module",
+		"https://godoc.org/github.com/my/module/package",
 	} {
 		u, err := url.Parse(tu)
 		if err != nil {
@@ -551,6 +554,16 @@
 				"https://godoc.org/-/subrepo": true,
 			},
 		},
+		{
+			name: "redirect stdlib packages",
+			snapshot: &dynconfig.DynamicConfig{
+				RedirectStdlib: true,
+			},
+			redirect: map[string]bool{
+				"https://godoc.org/net/http": true,
+				"https://godoc.org/cmd":      true,
+			},
+		},
 	} {
 		t.Run(test.name, func(t *testing.T) {
 			for _, req := range testRequests {