func()

in internal/frontend/search.go [37:129]


func (s *Server) serveSearch(w http.ResponseWriter, r *http.Request, ds internal.DataSource) error {
	if r.Method != http.MethodGet && r.Method != http.MethodHead {
		return &serverError{status: http.StatusMethodNotAllowed}
	}
	db, ok := ds.(*postgres.DB)
	if !ok {
		// The proxydatasource does not support the imported by page.
		return datasourceNotSupportedErr()
	}

	ctx := r.Context()
	cq, filters := searchQueryAndFilters(r)
	if !utf8.ValidString(cq) {
		return &serverError{status: http.StatusBadRequest}
	}
	if len(filters) > 1 {
		return &serverError{
			status: http.StatusBadRequest,
			epage: &errorPage{
				messageTemplate: template.MakeTrustedTemplate(
					`<h3 class="Error-message">Search query contains more than one symbol.</h3>`),
			},
		}
	}
	if len(cq) > maxSearchQueryLength {
		return &serverError{
			status: http.StatusBadRequest,
			epage: &errorPage{
				messageTemplate: template.MakeTrustedTemplate(
					`<h3 class="Error-message">Search query too long.</h3>`),
			},
		}
	}
	if cq == "" {
		http.Redirect(w, r, "/", http.StatusFound)
		return nil
	}
	pageParams := newPaginationParams(r, defaultSearchLimit)
	if pageParams.offset() > maxSearchOffset {
		return &serverError{
			status: http.StatusBadRequest,
			epage: &errorPage{
				messageTemplate: template.MakeTrustedTemplate(
					`<h3 class="Error-message">Search page number too large.</h3>`),
			},
		}
	}
	if pageParams.limit > maxSearchPageSize {
		return &serverError{
			status: http.StatusBadRequest,
			epage: &errorPage{
				messageTemplate: template.MakeTrustedTemplate(
					`<h3 class="Error-message">Search page size too large.</h3>`),
			},
		}
	}
	if path := searchRequestRedirectPath(ctx, ds, cq); path != "" {
		http.Redirect(w, r, path, http.StatusFound)
		return nil
	}

	var symbol string
	if len(filters) > 0 {
		symbol = filters[0]
	}
	mode := searchMode(r)
	var getVulnEntries vulnEntriesFunc
	if s.vulnClient != nil {
		getVulnEntries = s.vulnClient.GetByModule
	}
	page, err := fetchSearchPage(ctx, db, cq, symbol, pageParams, mode == searchModeSymbol, getVulnEntries)
	if err != nil {
		// Instead of returning a 500, return a 408, since symbol searches may
		// timeout for very popular symbols.
		if mode == searchModeSymbol && strings.Contains(err.Error(), "i/o timeout") {
			return &serverError{
				status: http.StatusRequestTimeout,
				epage: &errorPage{
					messageTemplate: template.MakeTrustedTemplate(
						`<h3 class="Error-message">Request timed out. Please try again!</h3>`),
				},
			}
		}
		return fmt.Errorf("fetchSearchPage(ctx, db, %q): %v", cq, err)
	}
	page.basePage = s.newBasePage(r, fmt.Sprintf("%s - Search Results", cq))
	page.SearchMode = mode
	if s.shouldServeJSON(r) {
		return s.serveJSONPage(w, r, page)
	}
	s.servePage(ctx, w, "search", page)
	return nil
}