зеркало из https://github.com/golang/pkgsite.git
internal/middleware: delete GodocURL
Delete the GodocURL middleware since it is no longer needed. Change-Id: I24b717e4d060ed19320e778afae6803b5404e49f Reviewed-on: https://go-review.googlesource.com/c/pkgsite/+/286512 Reviewed-by: Jamal Carvalho <jamal@golang.org> Trust: Julie Qiu <julie@golang.org>
This commit is contained in:
Родитель
4da3fcf7c7
Коммит
34b331ad78
|
@ -191,7 +191,6 @@ func main() {
|
|||
middleware.RequestLog(cmdconfig.Logger(ctx, cfg, "frontend-log")),
|
||||
middleware.AcceptRequests(http.MethodGet, http.MethodPost, http.MethodHead), // accept only GETs, POSTs and HEADs
|
||||
middleware.Quota(cfg.Quota, cacheClient),
|
||||
middleware.GodocURL(), // potentially redirects so should be early in chain
|
||||
middleware.RedirectedFrom(),
|
||||
middleware.SecureHeaders(!*disableCSP), // must come before any caching for nonces to work
|
||||
middleware.Experiment(experimenter),
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
|
||||
{{define "main_content"}}
|
||||
<div class="Container">
|
||||
<a class="GodocButton" href="{{.GodocURL}}">Back to godoc.org</a>
|
||||
<div class="SearchResults">
|
||||
<h1 class="SearchResults-header">Results for “{{.Query}}”</h1>
|
||||
<div class="SearchResults-help"><a href="/search-help">Search help</a></div>
|
||||
|
|
|
@ -243,9 +243,6 @@ type basePage struct {
|
|||
// Experiments contains the experiments currently active.
|
||||
Experiments *experiment.Set
|
||||
|
||||
// GodocURL is the URL of the corresponding page on godoc.org (if applicable).
|
||||
GodocURL string
|
||||
|
||||
// DevMode indicates whether the server is running in development mode.
|
||||
DevMode bool
|
||||
|
||||
|
@ -285,7 +282,6 @@ func (s *Server) newBasePage(r *http.Request, title string) basePage {
|
|||
HTMLTitle: title,
|
||||
Query: searchQuery(r),
|
||||
Experiments: experiment.FromContext(r.Context()),
|
||||
GodocURL: middleware.GodocURLPlaceholder,
|
||||
DevMode: s.devMode,
|
||||
AppVersionLabel: s.appVersionLabel,
|
||||
GoogleTagManagerID: s.googleTagManagerID,
|
||||
|
|
|
@ -1,119 +0,0 @@
|
|||
// Copyright 2020 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"net/http"
|
||||
"net/url"
|
||||
|
||||
"golang.org/x/pkgsite/internal/log"
|
||||
)
|
||||
|
||||
// GodocURLPlaceholder should be used as the value for any godoc.org URL in rendered
|
||||
// content. It is substituted for the actual godoc.org URL value by the GodocURL middleware.
|
||||
const GodocURLPlaceholder = "$$GODISCOVERY_GODOCURL$$"
|
||||
|
||||
// GodocURL adds a corresponding godoc.org URL value to the rendered page
|
||||
// if the request is due to godoc.org automatically redirecting a user.
|
||||
// The value is empty otherwise.
|
||||
func GodocURL() Middleware {
|
||||
// In order to reliably know that a request is coming to pkg.go.dev from
|
||||
// godoc.org, we look for a utm_source GET parameter set to 'godoc'.
|
||||
// If we see this, we set a temporary cookie and redirect to the
|
||||
// pkg.go.dev URL with the utm_source param stripped (so that it doesn’t
|
||||
// remain in all our URLs coming from godoc.org). If this temporary cookie
|
||||
// is seen, a non-empty value for the “Back to godoc.org” link is set.
|
||||
// The existence of this value will be used to determine whether to show the
|
||||
// button in the UI.
|
||||
return func(h http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
const tmpCookieName = "tmp-from-godoc"
|
||||
|
||||
// If the user is redirected from godoc.org, the request’s URL will have
|
||||
// utm_source=godoc.
|
||||
if r.FormValue("utm_source") == "godoc" {
|
||||
http.SetCookie(w, &http.Cookie{
|
||||
Name: tmpCookieName,
|
||||
Value: "1",
|
||||
SameSite: http.SameSiteLaxMode, // request can originate from another domain via redirect
|
||||
})
|
||||
|
||||
// Redirect to the same URL only without the utm_source parameter.
|
||||
u := r.URL
|
||||
q := u.Query()
|
||||
q.Del("utm_source")
|
||||
u.RawQuery = q.Encode()
|
||||
http.Redirect(w, r, u.String(), http.StatusFound)
|
||||
return
|
||||
}
|
||||
|
||||
godocURL := godoc(r.URL)
|
||||
if _, err := r.Cookie(tmpCookieName); err == http.ErrNoCookie {
|
||||
// Cookie isn’t set, indicating user is not coming from godoc.org.
|
||||
godocURL = ""
|
||||
} else {
|
||||
http.SetCookie(w, &http.Cookie{
|
||||
Name: tmpCookieName,
|
||||
MaxAge: -1,
|
||||
})
|
||||
}
|
||||
|
||||
crw := &capturingResponseWriter{ResponseWriter: w}
|
||||
h.ServeHTTP(crw, r)
|
||||
body := crw.bytes()
|
||||
body = bytes.ReplaceAll(body, []byte(GodocURLPlaceholder), []byte(godocURL))
|
||||
if _, err := w.Write(body); err != nil {
|
||||
log.Errorf(r.Context(), "GodocURL, writing: %v", err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// godoc takes a Discovery URL and returns the corresponding godoc.org equivalent.
|
||||
func godoc(u *url.URL) string {
|
||||
result := &url.URL{Scheme: "https", Host: "godoc.org"}
|
||||
|
||||
switch u.Path {
|
||||
case "/std":
|
||||
result.Path = "/-/go"
|
||||
case "/about":
|
||||
result.Path = "/-/about"
|
||||
case "/search":
|
||||
result.Path = "/"
|
||||
result.RawQuery = u.RawQuery
|
||||
default:
|
||||
{
|
||||
result.Path = u.Path
|
||||
switch u.Query().Get("tab") {
|
||||
case "imports":
|
||||
result.RawQuery = "imports"
|
||||
case "importedby":
|
||||
result.RawQuery = "importers"
|
||||
case "subdirectories":
|
||||
result.Fragment = "pkg-subdirectories"
|
||||
}
|
||||
}
|
||||
}
|
||||
q := result.Query()
|
||||
q.Add("utm_source", "backtogodoc")
|
||||
result.RawQuery = q.Encode()
|
||||
return result.String()
|
||||
}
|
||||
|
||||
// capturingResponseWriter is an http.ResponseWriter that captures
|
||||
// the body for later processing.
|
||||
type capturingResponseWriter struct {
|
||||
http.ResponseWriter
|
||||
buf bytes.Buffer
|
||||
}
|
||||
|
||||
func (c *capturingResponseWriter) Write(b []byte) (int, error) {
|
||||
return c.buf.Write(b)
|
||||
}
|
||||
|
||||
func (c *capturingResponseWriter) bytes() []byte {
|
||||
return c.buf.Bytes()
|
||||
}
|
|
@ -1,161 +0,0 @@
|
|||
// Copyright 2020 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"net/url"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestGodocURL(t *testing.T) {
|
||||
mw := GodocURL()
|
||||
mwh := mw(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
body := []byte(`<a href="$$GODISCOVERY_GODOCURL$$">godoc</a>`)
|
||||
if _, err := w.Write(body); err != nil {
|
||||
t.Fatalf("w.Write(%q) = %v", body, err)
|
||||
}
|
||||
}))
|
||||
|
||||
testCases := []struct {
|
||||
desc string
|
||||
|
||||
// Request values
|
||||
path string
|
||||
cookies map[string]string
|
||||
|
||||
// Response values
|
||||
code int
|
||||
body []byte
|
||||
headers map[string]string
|
||||
}{
|
||||
{
|
||||
desc: "Unaffected request",
|
||||
path: "/cloud.google.com/go/storage",
|
||||
code: http.StatusOK,
|
||||
body: []byte(`<a href="">godoc</a>`),
|
||||
},
|
||||
{
|
||||
desc: "Strip utm_source, set temporary cookie, and redirect",
|
||||
path: "/cloud.google.com/go/storage?utm_source=godoc",
|
||||
code: http.StatusFound,
|
||||
headers: map[string]string{
|
||||
"Location": "/cloud.google.com/go/storage",
|
||||
"Set-Cookie": "tmp-from-godoc=1; SameSite=Lax",
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "Delete temporary cookie; godoc URL should be set",
|
||||
path: "/cloud.google.com/go/storage",
|
||||
cookies: map[string]string{
|
||||
"tmp-from-godoc": "1",
|
||||
},
|
||||
code: http.StatusOK,
|
||||
body: []byte(`<a href="https://godoc.org/cloud.google.com/go/storage?utm_source=backtogodoc">godoc</a>`),
|
||||
headers: map[string]string{
|
||||
"Set-Cookie": "tmp-from-godoc=; Max-Age=0",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range testCases {
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
req := httptest.NewRequest("GET", test.path, nil)
|
||||
for k, v := range test.cookies {
|
||||
req.AddCookie(&http.Cookie{
|
||||
Name: k,
|
||||
Value: v,
|
||||
})
|
||||
}
|
||||
w := httptest.NewRecorder()
|
||||
mwh.ServeHTTP(w, req)
|
||||
resp := w.Result()
|
||||
defer resp.Body.Close()
|
||||
if got, want := resp.StatusCode, test.code; got != want {
|
||||
t.Errorf("Status code = %d; want %d", got, want)
|
||||
}
|
||||
if resp.StatusCode >= 200 && resp.StatusCode < 300 {
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
t.Fatalf("ioutil.ReadAll(resp.Body) = %v", err)
|
||||
}
|
||||
if got, want := body, test.body; !bytes.Equal(got, want) {
|
||||
t.Errorf("Response body = %q; want %q", got, want)
|
||||
}
|
||||
}
|
||||
for k, v := range test.headers {
|
||||
if _, ok := resp.Header[k]; !ok {
|
||||
t.Errorf("%q not present in response headers", k)
|
||||
continue
|
||||
}
|
||||
if got, want := resp.Header.Get(k), v; got != want {
|
||||
t.Errorf("Response header mismatch for %q: got %q; want %q", k, got, want)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestGodoc(t *testing.T) {
|
||||
testCases := []struct {
|
||||
from, to string
|
||||
}{
|
||||
{
|
||||
from: "https://pkg.go.dev/cloud.google.com/go/storage",
|
||||
to: "https://godoc.org/cloud.google.com/go/storage?utm_source=backtogodoc",
|
||||
},
|
||||
{
|
||||
from: "https://pkg.go.dev/cloud.google.com/go/storage?tab=overview",
|
||||
to: "https://godoc.org/cloud.google.com/go/storage?utm_source=backtogodoc",
|
||||
},
|
||||
{
|
||||
from: "https://pkg.go.dev/cloud.google.com/go/storage?tab=versions",
|
||||
to: "https://godoc.org/cloud.google.com/go/storage?utm_source=backtogodoc",
|
||||
},
|
||||
{
|
||||
from: "https://pkg.go.dev/cloud.google.com/go/storage?tab=licenses",
|
||||
to: "https://godoc.org/cloud.google.com/go/storage?utm_source=backtogodoc",
|
||||
},
|
||||
{
|
||||
from: "https://pkg.go.dev/cloud.google.com/go/storage?tab=subdirectories",
|
||||
to: "https://godoc.org/cloud.google.com/go/storage?utm_source=backtogodoc#pkg-subdirectories",
|
||||
},
|
||||
{
|
||||
from: "https://pkg.go.dev/cloud.google.com/go/storage?tab=imports",
|
||||
to: "https://godoc.org/cloud.google.com/go/storage?imports=&utm_source=backtogodoc",
|
||||
},
|
||||
{
|
||||
from: "https://pkg.go.dev/cloud.google.com/go/storage?tab=importedby",
|
||||
to: "https://godoc.org/cloud.google.com/go/storage?importers=&utm_source=backtogodoc",
|
||||
},
|
||||
{
|
||||
from: "https://pkg.go.dev/std?tab=packages",
|
||||
to: "https://godoc.org/-/go?utm_source=backtogodoc",
|
||||
},
|
||||
{
|
||||
from: "https://pkg.go.dev/search?q=foo",
|
||||
to: "https://godoc.org/?q=foo&utm_source=backtogodoc",
|
||||
},
|
||||
{
|
||||
from: "https://pkg.go.dev/about",
|
||||
to: "https://godoc.org/-/about?utm_source=backtogodoc",
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range testCases {
|
||||
u, err := url.Parse(test.from)
|
||||
if err != nil {
|
||||
t.Errorf("url.Parse(%q): %v", test.from, err)
|
||||
continue
|
||||
}
|
||||
to := godoc(u)
|
||||
if got, want := to, test.to; got != want {
|
||||
t.Errorf("godocURL(%q) = %q; want %q", u, got, want)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -85,3 +85,18 @@ func LatestVersions(getLatest latestFunc) Middleware {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
// capturingResponseWriter is an http.ResponseWriter that captures
|
||||
// the body for later processing.
|
||||
type capturingResponseWriter struct {
|
||||
http.ResponseWriter
|
||||
buf bytes.Buffer
|
||||
}
|
||||
|
||||
func (c *capturingResponseWriter) Write(b []byte) (int, error) {
|
||||
return c.buf.Write(b)
|
||||
}
|
||||
|
||||
func (c *capturingResponseWriter) bytes() []byte {
|
||||
return c.buf.Bytes()
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче