Document Bearer-authenticated multipart uploads with curl and Wget2. Return 413 for oversized multipart bodies and report attachment size limits accurately.
This commit is contained in:
1 parent
12631ecd09
commit
61018a90b5
5 files changed
+149
-6
No files matched your search
@@ -1,6 +1,7 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net/http"
|
||||
|
||||
"github.com/lgcosta/notas-online/internal/store"
|
||||
@@ -19,7 +20,12 @@ const maxUploadBody = store.MaxFileBytes + 64<<10
|
||||
func (s *Server) handleFileUpload(w http.ResponseWriter, r *http.Request) {
|
||||
r.Body = http.MaxBytesReader(w, r.Body, maxUploadBody)
|
||||
if err := r.ParseMultipartForm(8 << 20); err != nil {
|
||||
writeError(w, http.StatusBadRequest, "multipart inválido ou excede limite: "+err.Error())
|
||||
var maxErr *http.MaxBytesError
|
||||
if errors.As(err, &maxErr) {
|
||||
writeError(w, http.StatusRequestEntityTooLarge, "upload excede o limite de 64 MiB")
|
||||
} else {
|
||||
writeError(w, http.StatusBadRequest, "multipart inválido")
|
||||
}
|
||||
return
|
||||
}
|
||||
defer r.MultipartForm.RemoveAll()
|
||||
|
||||
@@ -252,7 +252,36 @@ func TestUploadRejectsOversizeBody(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
resp.Body.Close()
|
||||
if resp.StatusCode != http.StatusBadRequest {
|
||||
t.Fatalf("esperava 400 para corpo acima do cap, obtive %s", resp.Status)
|
||||
if resp.StatusCode != http.StatusRequestEntityTooLarge {
|
||||
t.Fatalf("esperava 413 para corpo acima do cap, obtive %s", resp.Status)
|
||||
}
|
||||
}
|
||||
|
||||
func TestUploadRejectsFileOver64MiB(t *testing.T) {
|
||||
var buf bytes.Buffer
|
||||
w := multipart.NewWriter(&buf)
|
||||
fw, err := w.CreateFormFile("file", "big.bin")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
_, _ = fw.Write(bytes.Repeat([]byte("A"), store.MaxFileBytes+1))
|
||||
if err := w.Close(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
srv := newTestServer(t)
|
||||
req, err := http.NewRequest("POST", srv.URL+"/api/files/upload", &buf)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
req.Header.Set("Content-Type", w.FormDataContentType())
|
||||
req.Header.Set("Authorization", "Bearer "+testToken)
|
||||
resp, err := srv.Client().Do(req)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
if resp.StatusCode != http.StatusRequestEntityTooLarge {
|
||||
t.Fatalf("esperava 413 para arquivo >64 MiB, obtive %s", resp.Status)
|
||||
}
|
||||
}
|
||||
@@ -292,7 +292,11 @@ func mapStoreErrorFor(w http.ResponseWriter, err error, resource string) {
|
||||
case errors.Is(err, store.ErrInvalid):
|
||||
writeError(w, http.StatusBadRequest, err.Error())
|
||||
case errors.Is(err, store.ErrTooLarge):
|
||||
writeError(w, http.StatusRequestEntityTooLarge, "conteúdo excede 2 MiB")
|
||||
if resource == "arquivo" {
|
||||
writeError(w, http.StatusRequestEntityTooLarge, "arquivo excede 64 MiB ou a quota total de anexos excede 2 GiB")
|
||||
} else {
|
||||
writeError(w, http.StatusRequestEntityTooLarge, "conteúdo excede 2 MiB")
|
||||
}
|
||||
case errors.Is(err, store.ErrUnchanged):
|
||||
writeError(w, http.StatusConflict, "o conteúdo dessa revisão já está ativo")
|
||||
default:
|
||||
|
||||
Reference in new issue
Block a user