serve: answer the go toolchain's ?go-get=1 vanity-import probe
commit 52092f45a78764cd6f370ec6fbd857657321133c · parent 701ac20d8a
· browse this tree
Ximianth, 2026-10-27 17:08:02 UTC
The probe outranks all other dispatch under a repo: go queries the
full package path (not just the module root), and the home's
trailing-slash redirect would drop the query string, so the check
sits right after repo matching.
The page carries go-import (prefix, vcs git, clone URL -- fetch of
which socle already serves) and go-source (pkg.go.dev deep links
into the tree pages; no #L{line} fragment since file views have no
line anchors). Meta tag shapes per https://go.dev/ref/mod#vcs-find.
Gated on the configured baseurl, so socle never claims an import
prefix for a domain nobody chose.
diff --git a/serve.go b/serve.go index 23b1226..5a23982 100644 --- a/serve.go +++ b/serve.go @@ -95,6 +95,16 @@ func (s *server) ServeHTTP(w http.ResponseWriter, r *http.Request) { http.NotFound(w, r) return } + // The go toolchain's vanity-import probe outranks all other dispatch under a repo: + // go queries the full package path (so this must answer on subpaths, not just the home), + // and it must run before the trailing-slash redirect below, which would drop the query. + // Gated on a configured baseurl: the import prefix is a public claim that ends up in + // module caches and trackers, so socle only makes it on purpose -- without a baseurl + // the probe is inert and the URL means whatever it meant before. + if snap.baseURL != "" && r.URL.Query().Get("go-get") == "1" { + serveGoGetMeta(w, rp, snap.baseURL) + return + } if rest == "" { // Canonicalize the repo home to a trailing slash, so relative URLs in the // rendered README resolve under the repo's own prefix. @@ -125,6 +135,25 @@ func (s *server) ServeHTTP(w http.ResponseWriter, r *http.Request) { } } +// serveGoGetMeta answers the vanity-import probe: a minimal page whose go-import meta tag +// maps the import prefix onto this repo's clone URL, plus a go-source tag teaching +// pkg.go.dev to deep-link into socle's own tree pages. +// (The go-source file template carries no #L{line} fragment: file views have no line +// anchors, and an anchor that lands nowhere would be a small lie.) +// Written with Fprintf, no templating or escaping: both inputs are config-validated into +// HTML-inert charsets (baseURL to scheme://host, repo names to segments of [A-Za-z0-9._-]). +func serveGoGetMeta(w http.ResponseWriter, rp *repo, baseURL string) { + prefix := strings.TrimPrefix(strings.TrimPrefix(baseURL, "https://"), "http://") + "/" + rp.name + repoURL := baseURL + "/" + rp.name + w.Header().Set("Content-Type", "text/html; charset=utf-8") + fmt.Fprintf(w, `<!DOCTYPE html> +<html><head> +<meta name="go-import" content="%s git %s"> +<meta name="go-source" content="%s %s/ %s/tree/HEAD{/dir} %s/tree/HEAD{/dir}/{file}"> +</head><body><a href="/%s/">%s</a></body></html> +`, prefix, repoURL, prefix, repoURL, repoURL, repoURL, rp.name, prefix) +} + // httpError maps a plumbing-layer error onto an HTTP response: // errInvalid is the client's fault (400), errNotFound speaks for itself (404), // and anything else is internal (500) -- logged in full, reported generically. diff --git a/serve_test.go b/serve_test.go index 70aef6e..ea7c364 100644 --- a/serve_test.go +++ b/serve_test.go @@ -272,3 +272,50 @@ func TestCommitPageShapes(t *testing.T) { t.Errorf("merge commit shows %d parent links, want 2", got) } } + +// TestGoGetMeta covers the vanity-import answers: with a configured baseurl, any GET +// under a repo carrying ?go-get=1 gets the meta-tag page (exact content asserted, +// since the go toolchain parses it); without one, the probe is inert -- fail closed, +// so socle never claims an import path for a domain nobody chose. +func TestGoGetMeta(t *testing.T) { + t.Parallel() + wantImport := `<meta name="go-import" content="code.example/fixturama git https://code.example/fixturama">` + wantSource := `<meta name="go-source" content="code.example/fixturama https://code.example/fixturama/ https://code.example/fixturama/tree/HEAD{/dir} https://code.example/fixturama/tree/HEAD{/dir}/{file}">` + + s := newServer(map[string]*repo{"fixturama": fixtureRepo(t)}, "https://code.example", display.NewTheme("test")) + for _, target := range []string{ + "/fixturama?go-get=1", // the slashless home: no redirect detour (it would drop the query) + "/fixturama/?go-get=1", // the home itself + "/fixturama/sub/pkg?go-get=1", // go queries the full package path, not just the module root + "/fixturama/tree/main?go-get=1", // even paths that mean something else to socle answer the probe + } { + rec := do(s, target, nil, nil) + if rec.Code != 200 { + t.Fatalf("GET %s: status %d, want 200", target, rec.Code) + } + body := rec.Body.String() + if !strings.Contains(body, wantImport) { + t.Errorf("GET %s: body lacks the go-import tag\nwant: %s\ngot body:\n%s", target, wantImport, body) + } + if !strings.Contains(body, wantSource) { + t.Errorf("GET %s: body lacks the go-source tag\nwant: %s", target, wantSource) + } + } + // The configured address also becomes the displayed clone URL. + if body := do(s, "/fixturama/", nil, nil).Body.String(); !strings.Contains(body, "git clone https://code.example/fixturama") { + t.Errorf("home page clone line does not use the configured baseurl") + } + + // Without a baseurl: the probe must change nothing. + bare := fixtureServer(t) + if rec := do(bare, "/fixturama?go-get=1", nil, nil); rec.Code != 301 { + t.Errorf("no baseurl: slashless home with go-get=1: status %d, want the usual 301", rec.Code) + } + rec := do(bare, "/fixturama/?go-get=1", nil, nil) + if rec.Code != 200 { + t.Fatalf("no baseurl: home with go-get=1: status %d, want 200", rec.Code) + } + if body := rec.Body.String(); strings.Contains(body, "go-import") { + t.Errorf("no baseurl: home page must not carry a go-import tag") + } +}