diff --git a/internal/webhook/handler.go b/internal/webhook/handler.go index 19d2666..783f9d1 100644 --- a/internal/webhook/handler.go +++ b/internal/webhook/handler.go @@ -7,6 +7,7 @@ import ( "crypto/sha256" "encoding/hex" "encoding/json" + "fmt" "io" "log" "net/http" @@ -30,50 +31,57 @@ func NewHandler(secret string, dispatcher Dispatcher) *Handler { } func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) { - if r.Method != http.MethodPost { - http.Error(w, "method not allowed", http.StatusMethodNotAllowed) + event := firstHeader(r, "X-Forgejo-Event", "X-Gitea-Event") + status, err := h.handle(w, r, event) + if err != nil { + log.Printf("yaju-keisatsu: %s event -> %d: %v", event, status, err) + } else { + log.Printf("yaju-keisatsu: %s event -> %d", event, status) + } + if status != http.StatusNoContent { + http.Error(w, http.StatusText(status), status) return } + w.WriteHeader(status) +} + +func (h *Handler) handle(w http.ResponseWriter, r *http.Request, event string) (int, error) { + if r.Method != http.MethodPost { + return http.StatusMethodNotAllowed, nil + } body, err := io.ReadAll(io.LimitReader(r.Body, 10<<20)) // 10MiB cap if err != nil { - http.Error(w, "read body", http.StatusBadRequest) - return + return http.StatusBadRequest, fmt.Errorf("read body: %w", err) } if !h.validSignature(r, body) { - http.Error(w, "invalid signature", http.StatusUnauthorized) - return + return http.StatusUnauthorized, fmt.Errorf("invalid signature") } - event := firstHeader(r, "X-Forgejo-Event", "X-Gitea-Event") - var dispatchErr error switch event { case "issue_comment": var p forgejo.IssueCommentPayload if err := json.Unmarshal(body, &p); err != nil { - http.Error(w, "decode payload", http.StatusBadRequest) - return + return http.StatusBadRequest, fmt.Errorf("decode payload: %w", err) + } + if err := h.dispatcher.HandleIssueComment(p); err != nil { + return http.StatusInternalServerError, err } - dispatchErr = h.dispatcher.HandleIssueComment(p) case "push": var p forgejo.PushPayload if err := json.Unmarshal(body, &p); err != nil { - http.Error(w, "decode payload", http.StatusBadRequest) - return + return http.StatusBadRequest, fmt.Errorf("decode payload: %w", err) + } + if err := h.dispatcher.HandlePush(p); err != nil { + return http.StatusInternalServerError, err } - dispatchErr = h.dispatcher.HandlePush(p) default: // Unhandled event types are not an error — the webhook may be // subscribed to more events than this bot reacts to. } - if dispatchErr != nil { - log.Printf("yaju-keisatsu: handling %s event: %v", event, dispatchErr) - http.Error(w, "internal error", http.StatusInternalServerError) - return - } - w.WriteHeader(http.StatusNoContent) + return http.StatusNoContent, nil } // validSignature checks X-Forgejo-Signature (falling back to