diff --git a/package-lock.json b/package-lock.json index 086a0eb8d..dbbde12fd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,7 +14,7 @@ "@aws-sdk/lib-storage": "3.654.0", "@aws-sdk/s3-request-presigner": "3.654.0", "@fastify/accepts": "^4.3.0", - "@fastify/multipart": "^8.3.1", + "@fastify/multipart": "github:supabase/fastify-multipart#v8.3.1-patched", "@fastify/rate-limit": "^7.6.0", "@fastify/swagger": "^8.3.1", "@fastify/swagger-ui": "^4.1.0", @@ -11306,8 +11306,7 @@ }, "node_modules/@fastify/multipart": { "version": "8.3.1", - "resolved": "https://registry.npmjs.org/@fastify/multipart/-/multipart-8.3.1.tgz", - "integrity": "sha512-pncbnG28S6MIskFSVRtzTKE9dK+GrKAJl0NbaQ/CG8ded80okWFsYKzSlP9haaLNQhNRDOoHqmGQNvgbiPVpWQ==", + "resolved": "git+ssh://git@github.com/supabase/fastify-multipart.git#79cc473d42a225319546ee1f9f8fcc411b27aaee", "license": "MIT", "dependencies": { "@fastify/busboy": "^3.0.0", @@ -31602,9 +31601,8 @@ } }, "@fastify/multipart": { - "version": "8.3.1", - "resolved": "https://registry.npmjs.org/@fastify/multipart/-/multipart-8.3.1.tgz", - "integrity": "sha512-pncbnG28S6MIskFSVRtzTKE9dK+GrKAJl0NbaQ/CG8ded80okWFsYKzSlP9haaLNQhNRDOoHqmGQNvgbiPVpWQ==", + "version": "git+ssh://git@github.com/supabase/fastify-multipart.git#79cc473d42a225319546ee1f9f8fcc411b27aaee", + "from": "@fastify/multipart@github:supabase/fastify-multipart#v8.3.1-patched", "requires": { "@fastify/busboy": "^3.0.0", "@fastify/deepmerge": "^2.0.0", diff --git a/package.json b/package.json index efe5e5e16..a211a124e 100644 --- a/package.json +++ b/package.json @@ -33,7 +33,7 @@ "@aws-sdk/lib-storage": "3.654.0", "@aws-sdk/s3-request-presigner": "3.654.0", "@fastify/accepts": "^4.3.0", - "@fastify/multipart": "^8.3.1", + "@fastify/multipart": "github:supabase/fastify-multipart#v8.3.1-patched", "@fastify/rate-limit": "^7.6.0", "@fastify/swagger": "^8.3.1", "@fastify/swagger-ui": "^4.1.0", diff --git a/src/storage/uploader.ts b/src/storage/uploader.ts index 4bad81cd3..540eefcf6 100644 --- a/src/storage/uploader.ts +++ b/src/storage/uploader.ts @@ -349,7 +349,7 @@ export async function fileUploadFromRequest( try { userMetadata = JSON.parse(customMd) - } catch (e) { + } catch { // no-op } } @@ -381,6 +381,13 @@ export async function fileUploadFromRequest( } } + // Detect if the request stream closed before we could pass it to the storage backend + // Without this check, the storage backend (S3) would throw a 500 "Premature close" error + // when attempting to read from the closed stream. We catch this early and return 400. + if (!body || body.closed || body.destroyed || body.readableEnded) { + throw ERRORS.NoContentProvided(new Error('Request stream closed before upload could begin')) + } + return { body, mimeType, @@ -395,7 +402,7 @@ export function parseUserMetadata(metadata: string) { try { const json = Buffer.from(metadata, 'base64').toString('utf8') return JSON.parse(json) as Record - } catch (e) { + } catch { // no-op return undefined }