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
}