blob: fe16e637b19351f311e71f042fcd072089b67997 [file] [log] [blame]
// Copyright 2019 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 frontend
import (
"fmt"
"net/http"
"strings"
"golang.org/x/mod/module"
"golang.org/x/pkgsite/internal"
"golang.org/x/pkgsite/internal/derrors"
"golang.org/x/pkgsite/internal/stdlib"
)
// serveStdLib handles a request for a stdlib package or module.
func (s *Server) serveStdLib(w http.ResponseWriter, r *http.Request) error {
path, version, err := parseStdLibURLPath(r.URL.Path)
if err != nil {
return &serverError{
status: http.StatusBadRequest,
err: fmt.Errorf("handleStdLib: %v", err),
}
}
if path == stdlib.ModulePath {
return s.serveModulePage(w, r, stdlib.ModulePath, version)
}
// Package "C" is a special case: redirect to the Go Blog article on cgo.
// (This is what godoc.org does.)
if path == "C" {
http.Redirect(w, r, "https://golang.org/doc/articles/c_go_cgo.html", http.StatusMovedPermanently)
return nil
}
return s.servePackagePage(w, r, path, stdlib.ModulePath, version)
}
func parseStdLibURLPath(urlPath string) (path, version string, err error) {
defer derrors.Wrap(&err, "parseStdLibURLPath(%q)", urlPath)
// This splits urlPath into either:
// /<path>@<tag> or /<path>
parts := strings.SplitN(urlPath, "@", 2)
path = strings.TrimSuffix(strings.TrimPrefix(parts[0], "/"), "/")
if err := module.CheckImportPath(path); err != nil {
return "", "", err
}
if len(parts) == 1 {
return path, internal.LatestVersion, nil
}
version = stdlib.VersionForTag(parts[1])
if version == "" {
return "", "", fmt.Errorf("invalid Go tag for url: %q", urlPath)
}
return path, version, nil
}