in internal/frontend/unit.go [95:222]
func (s *Server) serveUnitPage(ctx context.Context, w http.ResponseWriter, r *http.Request,
ds internal.DataSource, info *urlPathInfo) (err error) {
defer derrors.Wrap(&err, "serveUnitPage(ctx, w, r, ds, %v)", info)
defer middleware.ElapsedStat(ctx, "serveUnitPage")()
tab := r.FormValue("tab")
if tab == "" {
// Default to details tab when there is no tab param.
tab = tabMain
}
// Redirect to clean URL path when tab param is invalid.
if _, ok := unitTabLookup[tab]; !ok {
http.Redirect(w, r, r.URL.Path, http.StatusFound)
return nil
}
um, err := ds.GetUnitMeta(ctx, info.fullPath, info.modulePath, info.requestedVersion)
if err != nil {
if !errors.Is(err, derrors.NotFound) {
return err
}
return s.servePathNotFoundPage(w, r, ds, info.fullPath, info.modulePath, info.requestedVersion)
}
// Use GOOS and GOARCH query parameters to create a build context, which
// affects the documentation and synopsis. Omitting both results in an empty
// build context, which will match the first (and preferred) build context.
// It's also okay to provide just one (e.g. GOOS=windows), which will select
// the first doc with that value, ignoring the other one.
bc := internal.BuildContext{GOOS: r.FormValue("GOOS"), GOARCH: r.FormValue("GOARCH")}
var getVulnEntries vulnEntriesFunc
if s.vulnClient != nil {
getVulnEntries = s.vulnClient.GetByModule
}
d, err := fetchDetailsForUnit(ctx, r, tab, ds, um, info.requestedVersion, bc, getVulnEntries)
if err != nil {
return err
}
if s.shouldServeJSON(r) {
return s.serveJSONPage(w, r, d)
}
recordVersionTypeMetric(ctx, info.requestedVersion)
if _, ok := internal.DefaultBranches[info.requestedVersion]; ok {
// Since path@master is a moving target, we don't want it to be stale.
// As a result, we enqueue every request of path@master to the frontend
// task queue, which will initiate a fetch request depending on the
// last time we tried to fetch this module version.
//
// Use a separate context here to prevent the context from being canceled
// elsewhere before a task is enqueued.
go func() {
ctx, cancel := context.WithTimeout(context.Background(), 1*time.Minute)
defer cancel()
log.Infof(ctx, "serveUnitPage: Scheduling %q@%q to be fetched", um.ModulePath, info.requestedVersion)
if _, err := s.queue.ScheduleFetch(ctx, um.ModulePath, info.requestedVersion, nil); err != nil {
log.Errorf(ctx, "serveUnitPage(%q): scheduling fetch for %q@%q: %v",
r.URL.Path, um.ModulePath, info.requestedVersion, err)
}
}()
}
if !isValidTabForUnit(tab, um) {
// Redirect to clean URL path when tab param is invalid for the unit
// type.
http.Redirect(w, r, r.URL.Path, http.StatusFound)
return nil
}
// If we've already called GetUnitMeta for an unknown module path and the latest version, pass
// it to GetLatestInfo to avoid a redundant call.
var latestUnitMeta *internal.UnitMeta
if info.modulePath == internal.UnknownModulePath && info.requestedVersion == version.Latest {
latestUnitMeta = um
}
latestInfo := s.GetLatestInfo(ctx, um.Path, um.ModulePath, latestUnitMeta)
var redirectPath string
redirectPath, err = cookie.Extract(w, r, cookie.AlternativeModuleFlash)
if err != nil {
// Don't fail, but don't display a banner either.
log.Errorf(ctx, "extracting AlternativeModuleFlash cookie: %v", err)
}
title := pageTitle(um)
basePage := s.newBasePage(r, title)
tabSettings := unitTabLookup[tab]
basePage.AllowWideContent = true
if tabSettings.Name == "" {
basePage.UseResponsiveLayout = true
}
lv := linkVersion(um.ModulePath, info.requestedVersion, um.Version)
page := UnitPage{
basePage: basePage,
Unit: um,
Breadcrumb: displayBreadcrumb(um, info.requestedVersion),
Title: title,
SelectedTab: tabSettings,
URLPath: constructUnitURL(um.Path, um.ModulePath, info.requestedVersion),
CanonicalURLPath: canonicalURLPath(um.Path, um.ModulePath, info.requestedVersion, um.Version),
DisplayVersion: displayVersion(um.ModulePath, info.requestedVersion, um.Version),
LinkVersion: lv,
LatestURL: constructUnitURL(um.Path, um.ModulePath, version.Latest),
LatestMinorClass: latestMinorClass(lv, latestInfo),
LatestMajorVersionURL: latestInfo.MajorUnitPath,
PageLabels: pageLabels(um),
PageType: pageType(um),
RedirectedFromPath: redirectPath,
}
// Show the banner if there was no error getting the latest major version,
// and it is different from the major version of the current module path.
latestMajor := internal.MajorVersionForModule(latestInfo.MajorModulePath)
if latestMajor != "" && latestMajor != internal.MajorVersionForModule(um.ModulePath) {
page.LatestMajorVersion = latestMajor
}
page.Details = d
main, ok := d.(*MainDetails)
if ok {
page.MetaDescription = metaDescription(main.DocSynopsis)
}
// Get vulnerability information.
if s.vulnClient != nil && experiment.IsActive(ctx, internal.ExperimentVulns) {
page.Vulns = VulnsForPackage(um.ModulePath, um.Version, um.Path, s.vulnClient.GetByModule)
}
s.servePage(ctx, w, tabSettings.TemplateName, page)
return nil
}