diff options
Diffstat (limited to 'internal/web/handlers_blog.go')
| -rw-r--r-- | internal/web/handlers_blog.go | 14 |
1 files changed, 13 insertions, 1 deletions
diff --git a/internal/web/handlers_blog.go b/internal/web/handlers_blog.go index f138c58..55cec2e 100644 --- a/internal/web/handlers_blog.go +++ b/internal/web/handlers_blog.go @@ -1,6 +1,7 @@ package web import ( + "context" "encoding/xml" "errors" "net/http" @@ -159,6 +160,9 @@ func (s *Server) handleBlogTag(w http.ResponseWriter, r *http.Request) { // from every page of the blog. A blank query shows just the box; no matches // is an ordinary result, not a 404. func (s *Server) handleBlogSearch(w http.ResponseWriter, r *http.Request) { + if !s.throttle(w, r, s.searchLimit, s.clientIP(r)) { + return + } q := strings.TrimSpace(r.URL.Query().Get("q")) if utf8.RuneCountInString(q) > maxSearchRunes { q = string([]rune(q)[:maxSearchRunes]) @@ -172,7 +176,15 @@ func (s *Server) handleBlogSearch(w http.ResponseWriter, r *http.Request) { pattern := searchPattern(q) if pattern != "" { n := pageNum(r) - posts, total, err := blogStore(r).SearchPublishedPosts(r.Context(), pattern, searchPerPage, (n-1)*searchPerPage) + // Bounded: pgx cancels the statement when the context ends, and the + // reader sees "nothing found" rather than an error page. + ctx, cancel := context.WithTimeout(r.Context(), searchDeadline) + defer cancel() + posts, total, err := blogStore(r).SearchPublishedPosts(ctx, pattern, searchPerPage, (n-1)*searchPerPage) + if errors.Is(err, context.DeadlineExceeded) || errors.Is(ctx.Err(), context.DeadlineExceeded) { + logf("search %q on %s timed out", q, currentBlog(r).Subdomain) + posts, total, err = nil, 0, nil + } if err != nil { s.serverError(w, err) return |
