Add file-transfer module: multipart limits, filename handling, Range downloads, streaming under -Xmx64m, S3 presigned URLs
Co-Authored-By: Claude Sonnet 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01VRLbHYdXVEBzGVhYq3pz4q
This commit is contained in:
@@ -0,0 +1,6 @@
|
||||
limits: max-file-size=1MB, max-request-size=2MB
|
||||
real HTTP, one 500 KB file -> status=201 body={"id":"d8d0b4b8-d530-42aa-b005-9e1b747449a7","originalFilename":"a.txt","displayName":"a.txt","size":512000,"declaredContentType":"text/plai...
|
||||
real HTTP, one 1.5 MB file -> status=413 body={"detail":"The upload is larger than the configured limit (spring.servlet.multipart.max-file-size / max-request-size).","instance":"/files",...
|
||||
real HTTP, 3 x 900 KB in one request -> status=413 body={"detail":"The upload is larger than the configured limit (spring.servlet.multipart.max-file-size / max-request-size).","instance":"/files",...
|
||||
real HTTP, one 10 MB file, 10 attempts -> 7 x status=413, 3 x connection error
|
||||
MockMvc, the same 1.5 MB file -> status=201
|
||||
@@ -0,0 +1,4 @@
|
||||
client sent filename=../../etc/cron.d/evil.txt Content-Type=image/png
|
||||
server response: {"id":"4980219c-b92a-46d4-a5ab-b5d7636fb7f0","originalFilename":"../../etc/cron.d/evil.txt","displayName":"evil.txt","size":5,"declaredContentType":"image/png"}
|
||||
root.resolve(originalFilename).normalize() stays inside the storage dir: false
|
||||
client sent a Windows-style path; server response: {"id":"d436e57e-6855-4fff-b5ca-b9dd0fec25c2","originalFilename":"..\\..\\windows\\system32\\evil.dll","displayName":"evil.dll","size":1,"declaredContentType":"text/plain"}
|
||||
@@ -0,0 +1,12 @@
|
||||
GET /files/{id}
|
||||
status=200 body=ABCDEFGHIJKLMNOPQRSTUVWXYZ
|
||||
content-type: application/octet-stream
|
||||
content-length: 26
|
||||
content-disposition: attachment; filename="resume 2026.txt"; filename*=UTF-8''r%C3%A9sum%C3%A9%202026.txt
|
||||
accept-ranges: bytes
|
||||
x-content-type-options: nosniff
|
||||
GET /files/{id} with Range: bytes=10-19
|
||||
status=206 body=KLMNOPQRST
|
||||
content-range: bytes 10-19/26
|
||||
GET /files/{id} with Range: bytes=500-
|
||||
status=416 content-range: bytes */26
|
||||
@@ -0,0 +1,18 @@
|
||||
PUT a URL signed for 1 second, sent after 2.2 seconds -> status=403 <Error><Code>AccessDenied</Code></Error>
|
||||
POST /presign/upload {"contentType":"image/png"} -> status=200
|
||||
method=PUT expiresInSeconds=300 headers={"content-type":"image/png"}
|
||||
url path: http://<fake-s3>/uploads/4dfdf0af-141a-4d1b-9d35-3609a9385791
|
||||
query: X-Amz-Algorithm=AWS4-HMAC-SHA256
|
||||
query: X-Amz-Date=20261017T154013Z
|
||||
query: X-Amz-SignedHeaders=content-type%3Bhost
|
||||
query: X-Amz-Credential=AKIAIOSFODNN7EXAMPLE%2F20261017%2Fus-east-1%2Fs3%2Faws4_request
|
||||
query: X-Amz-Expires=300
|
||||
query: X-Amz-Signature=4e5c56c29980cf521e477119788a0616c392deac4686df7259957af9f1445203
|
||||
PUT with the signed Content-Type (image/png) -> status=200
|
||||
PUT the same URL again (presigned URLs are reusable) -> status=200
|
||||
PUT with a different Content-Type (text/html) -> status=403 <Error><Code>SignatureDoesNotMatch</Code></Error>
|
||||
PUT with no Content-Type header -> status=403 <Error><Code>SignatureDoesNotMatch</Code></Error>
|
||||
PUT after changing the last character of the key -> status=403 <Error><Code>SignatureDoesNotMatch</Code></Error>
|
||||
PUT after raising X-Amz-Expires to 7 days -> status=403 <Error><Code>SignatureDoesNotMatch</Code></Error>
|
||||
GET presigned URL -> status=200 bytes match upload=true content-disposition=attachment; filename="holiday.png"
|
||||
disallowed type: POST /presign/upload text/html -> status=400
|
||||
@@ -0,0 +1,4 @@
|
||||
JVM started with -Xmx64m
|
||||
GET /buffered/200 (200 MB) -> status=500 downloaded=108 bytes in 0.273337s
|
||||
GET /stream/200 (200 MB) -> status=200 downloaded=209715200 bytes in 0.337059s
|
||||
GET /stream/1 afterwards -> status=200
|
||||
@@ -0,0 +1,3 @@
|
||||
JVM started with -Xmx64m, multipart limits removed, uploading a 150 MB file
|
||||
multipart POST /files -> status=201 sent=157286616 bytes in 1.518657s
|
||||
raw POST /files/raw -> status=201 sent=157286400 bytes in 1.850810s
|
||||
Reference in New Issue
Block a user