diff --git a/modules/cabana/account.go b/modules/cabana/account.go index 56bfa47..39207c6 100644 --- a/modules/cabana/account.go +++ b/modules/cabana/account.go @@ -587,7 +587,7 @@ func (s *service) avatarUpload(w http.ResponseWriter, r *http.Request) { } part, err := mr.NextPart() if err != nil { - s.writeAvatarError(w, r, body, err) + s.writeAvatarError(w, r, body, multipartFailure(body, err)) return } if part.FormName() != "file_data" || strings.TrimSpace(part.FileName()) == "" { @@ -614,7 +614,7 @@ func (s *service) avatarUpload(w http.ResponseWriter, r *http.Request) { if err == nil { return invalidBody() } - return err + return multipartFailure(body, err) } q := tx.Session(&gorm.Session{NewDB: true, Context: ctx}) if err := q.Model(&attach.File{}).Where("id = ?", f.ID).Updates(map[string]any{ @@ -680,6 +680,17 @@ func (s *service) avatarRemove(w http.ResponseWriter, r *http.Request) { WriteData(w, http.StatusOK, s.profileFor(r.Context(), db, saved), map[string]any{}) } +// multipartFailure is the error of a multipart read: a body past the cap +// stays a *http.MaxBytesError (413), and an empty or malformed body (no +// part at all, a broken boundary) is the invalid-body 422, never a 500. +func multipartFailure(body *bodyReader, err error) error { + var tooBig *http.MaxBytesError + if errors.As(err, &tooBig) || (body != nil && errors.As(body.err, &tooBig)) { + return err + } + return invalidBody() +} + // writeAvatarError maps an avatar upload failure as writeFileError does, // with the field name avatar: a body past the cap is 413, an attach.Store // refusal a 422 on avatar and a malformed multipart body a 422 on body.