| // 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" |
| |
| "github.com/google/safehtml/template" |
| "golang.org/x/pkgsite/internal" |
| "golang.org/x/pkgsite/internal/derrors" |
| "golang.org/x/pkgsite/internal/log" |
| "golang.org/x/pkgsite/internal/stdlib" |
| ) |
| |
| // errUnitNotFoundWithoutFetch returns a 404 with instructions to the user on |
| // how to manually fetch the package. No fetch button is provided. This is used |
| // for very large modules or modules that previously 500ed. |
| var errUnitNotFoundWithoutFetch = &serverError{ |
| status: http.StatusNotFound, |
| epage: &errorPage{ |
| messageTemplate: template.MakeTrustedTemplate(` |
| <h3 class="Error-message">{{.StatusText}}</h3> |
| <p class="Error-message">Check that you entered the URL correctly or try fetching it following the |
| <a href="/about#adding-a-package">instructions here</a>.</p>`), |
| MessageData: struct{ StatusText string }{http.StatusText(http.StatusNotFound)}, |
| }, |
| } |
| |
| func (s *Server) servePathNotFoundPage(w http.ResponseWriter, r *http.Request, ds internal.DataSource, fullPath, requestedVersion string) (err error) { |
| defer derrors.Wrap(&err, "servePathNotFoundPage(w, r, %q, %q)", fullPath, requestedVersion) |
| |
| ctx := r.Context() |
| path, err := stdlibPathForShortcut(ctx, ds, fullPath) |
| if err != nil { |
| // Log the error, but prefer a "path not found" error for a |
| // better user experience. |
| log.Error(ctx, err) |
| } |
| if path != "" { |
| http.Redirect(w, r, fmt.Sprintf("/%s", path), http.StatusFound) |
| return |
| } |
| if stdlib.Contains(fullPath) { |
| return &serverError{status: http.StatusNotFound} |
| } |
| return pathNotFoundError(fullPath, requestedVersion) |
| } |
| |
| // pathNotFoundError returns a page with an option on how to |
| // add a package or module to the site. |
| func pathNotFoundError(fullPath, requestedVersion string) error { |
| if !isSupportedVersion(fullPath, requestedVersion) { |
| return invalidVersionError(fullPath, requestedVersion) |
| } |
| if stdlib.Contains(fullPath) { |
| return &serverError{status: http.StatusNotFound} |
| } |
| path := fullPath |
| if requestedVersion != internal.LatestVersion { |
| path = fmt.Sprintf("%s@%s", fullPath, requestedVersion) |
| } |
| return &serverError{ |
| status: http.StatusNotFound, |
| epage: &errorPage{ |
| templateName: "fetch.tmpl", |
| MessageData: path, |
| }, |
| } |
| } |