From 01c0bc1647f7fd23b77abda8ef5e9eb0691a4afb Mon Sep 17 00:00:00 2001 From: Vincent Voyer Date: Thu, 12 Sep 2024 10:10:32 +0200 Subject: [PATCH 1/5] fix(blob): limit keys to 950 characters To respect internal limitations we have, let's limit keys to 950 charactersa and warn when you use more than that. --- packages/blob/src/index.node.test.ts | 17 +++++++++++++++++ packages/blob/src/put-helpers.ts | 12 ++++++++++++ 2 files changed, 29 insertions(+) diff --git a/packages/blob/src/index.node.test.ts b/packages/blob/src/index.node.test.ts index 1c69a534f..d4d2a8d7b 100644 --- a/packages/blob/src/index.node.test.ts +++ b/packages/blob/src/index.node.test.ts @@ -576,6 +576,23 @@ describe('blob client', () => { expect(headers['x-cache-control-max-age']).toEqual('60'); }); + it('throws when filepath is too long', async () => { + mockClient + .intercept({ + path: () => true, + method: 'PUT', + }) + .reply(200, mockedFileMetaPut); + + await expect( + put('a'.repeat(951), 'Test Body', { + access: 'public', + }), + ).rejects.toThrow( + new Error('Vercel Blob: pathname is too long, maximum length is 950'), + ); + }); + const table: [string, (signal: AbortSignal) => Promise][] = [ [ 'put', diff --git a/packages/blob/src/put-helpers.ts b/packages/blob/src/put-helpers.ts index 2b21b004d..513b186b3 100644 --- a/packages/blob/src/put-helpers.ts +++ b/packages/blob/src/put-helpers.ts @@ -68,6 +68,12 @@ export function createPutHeaders( return headers; } +// maximum path length is: +// 1024 (provider limit) - 26 chars (vercel internal suffixes) - 31 chars (blob `-randomId` suffix) = 967 +// we round it to 950 to make it more human friendly, and we apply the limit whatever the value of +// addRandomSuffix is, to make it consistent +const MAXIMUM_PATH_LENGTH = 950; + export async function createPutOptions< TOptions extends CommonPutCommandOptions, >({ @@ -85,6 +91,12 @@ export async function createPutOptions< throw new BlobError('pathname is required'); } + if (pathname.length > MAXIMUM_PATH_LENGTH) { + throw new BlobError( + `pathname is too long, maximum length is ${MAXIMUM_PATH_LENGTH}`, + ); + } + if (!options) { throw new BlobError('missing options, see usage'); } From dd505385b7c8871c46c646d08c5e71ebc65c6bf7 Mon Sep 17 00:00:00 2001 From: Vincent Voyer Date: Thu, 12 Sep 2024 10:14:22 +0200 Subject: [PATCH 2/5] changeset --- .changeset/unlucky-months-repeat.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/unlucky-months-repeat.md diff --git a/.changeset/unlucky-months-repeat.md b/.changeset/unlucky-months-repeat.md new file mode 100644 index 000000000..4cd64768c --- /dev/null +++ b/.changeset/unlucky-months-repeat.md @@ -0,0 +1,5 @@ +--- +'@vercel/blob': patch +--- + +Limit pathname length to 950 to respect internal limitations and provide better early DX. From 96c5ab311ec85c51dc26eb3212fd70f9a7a71475 Mon Sep 17 00:00:00 2001 From: Vincent Voyer Date: Thu, 12 Sep 2024 10:20:51 +0200 Subject: [PATCH 3/5] update --- packages/blob/src/put-helpers.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/blob/src/put-helpers.ts b/packages/blob/src/put-helpers.ts index 513b186b3..affc62ce1 100644 --- a/packages/blob/src/put-helpers.ts +++ b/packages/blob/src/put-helpers.ts @@ -72,7 +72,7 @@ export function createPutHeaders( // 1024 (provider limit) - 26 chars (vercel internal suffixes) - 31 chars (blob `-randomId` suffix) = 967 // we round it to 950 to make it more human friendly, and we apply the limit whatever the value of // addRandomSuffix is, to make it consistent -const MAXIMUM_PATH_LENGTH = 950; +const MAXIMUM_PATHNAME_LENGTH = 950; export async function createPutOptions< TOptions extends CommonPutCommandOptions, @@ -91,9 +91,9 @@ export async function createPutOptions< throw new BlobError('pathname is required'); } - if (pathname.length > MAXIMUM_PATH_LENGTH) { + if (pathname.length > MAXIMUM_PATHNAME_LENGTH) { throw new BlobError( - `pathname is too long, maximum length is ${MAXIMUM_PATH_LENGTH}`, + `pathname is too long, maximum length is ${MAXIMUM_PATHNAME_LENGTH}`, ); } From bb4958df7f3617af8e069d553596234700c4c8d4 Mon Sep 17 00:00:00 2001 From: Vincent Voyer Date: Thu, 12 Sep 2024 10:21:20 +0200 Subject: [PATCH 4/5] update --- packages/blob/src/put-helpers.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/blob/src/put-helpers.ts b/packages/blob/src/put-helpers.ts index affc62ce1..d3321cd46 100644 --- a/packages/blob/src/put-helpers.ts +++ b/packages/blob/src/put-helpers.ts @@ -68,7 +68,7 @@ export function createPutHeaders( return headers; } -// maximum path length is: +// maximum pathname length is: // 1024 (provider limit) - 26 chars (vercel internal suffixes) - 31 chars (blob `-randomId` suffix) = 967 // we round it to 950 to make it more human friendly, and we apply the limit whatever the value of // addRandomSuffix is, to make it consistent From cdc40b753adb9f4610e37beb3d52291c517f0eab Mon Sep 17 00:00:00 2001 From: Vincent Voyer Date: Thu, 12 Sep 2024 11:26:53 +0200 Subject: [PATCH 5/5] also implement in copy --- packages/blob/src/api.ts | 6 ++++++ packages/blob/src/copy.ts | 8 +++++++- packages/blob/src/index.node.test.ts | 19 ++++++++++++------- packages/blob/src/put-helpers.ts | 7 +------ 4 files changed, 26 insertions(+), 14 deletions(-) diff --git a/packages/blob/src/api.ts b/packages/blob/src/api.ts index 30df81808..7d5f62c60 100644 --- a/packages/blob/src/api.ts +++ b/packages/blob/src/api.ts @@ -5,6 +5,12 @@ import { debug } from './debug'; import type { BlobCommandOptions } from './helpers'; import { BlobError, getTokenFromOptionsOrEnv } from './helpers'; +// maximum pathname length is: +// 1024 (provider limit) - 26 chars (vercel internal suffixes) - 31 chars (blob `-randomId` suffix) = 967 +// we round it to 950 to make it more human friendly, and we apply the limit whatever the value of +// addRandomSuffix is, to make it consistent +export const MAXIMUM_PATHNAME_LENGTH = 950; + export class BlobAccessError extends BlobError { constructor() { super('Access denied, please provide a valid token for this resource.'); diff --git a/packages/blob/src/copy.ts b/packages/blob/src/copy.ts index ac3e55e5e..4669daed9 100644 --- a/packages/blob/src/copy.ts +++ b/packages/blob/src/copy.ts @@ -1,4 +1,4 @@ -import { requestApi } from './api'; +import { MAXIMUM_PATHNAME_LENGTH, requestApi } from './api'; import type { CommonCreateBlobOptions } from './helpers'; import { BlobError } from './helpers'; @@ -35,6 +35,12 @@ export async function copy( throw new BlobError('access must be "public"'); } + if (toPathname.length > MAXIMUM_PATHNAME_LENGTH) { + throw new BlobError( + `pathname is too long, maximum length is ${MAXIMUM_PATHNAME_LENGTH}`, + ); + } + const headers: Record = {}; if (options.addRandomSuffix !== undefined) { diff --git a/packages/blob/src/index.node.test.ts b/packages/blob/src/index.node.test.ts index d4d2a8d7b..815c2b987 100644 --- a/packages/blob/src/index.node.test.ts +++ b/packages/blob/src/index.node.test.ts @@ -577,13 +577,6 @@ describe('blob client', () => { }); it('throws when filepath is too long', async () => { - mockClient - .intercept({ - path: () => true, - method: 'PUT', - }) - .reply(200, mockedFileMetaPut); - await expect( put('a'.repeat(951), 'Test Body', { access: 'public', @@ -718,4 +711,16 @@ describe('blob client', () => { ); }); }); + + describe('copy', () => { + it('throws when filepath is too long', async () => { + await expect( + copy('source', 'a'.repeat(951), { + access: 'public', + }), + ).rejects.toThrow( + new Error('Vercel Blob: pathname is too long, maximum length is 950'), + ); + }); + }); }); diff --git a/packages/blob/src/put-helpers.ts b/packages/blob/src/put-helpers.ts index d3321cd46..afbd57da3 100644 --- a/packages/blob/src/put-helpers.ts +++ b/packages/blob/src/put-helpers.ts @@ -3,6 +3,7 @@ import type { Readable } from 'stream'; import type { ClientCommonCreateBlobOptions } from './client'; import type { CommonCreateBlobOptions } from './helpers'; import { BlobError } from './helpers'; +import { MAXIMUM_PATHNAME_LENGTH } from './api'; const putOptionHeaderMap = { cacheControlMaxAge: 'x-cache-control-max-age', @@ -68,12 +69,6 @@ export function createPutHeaders( return headers; } -// maximum pathname length is: -// 1024 (provider limit) - 26 chars (vercel internal suffixes) - 31 chars (blob `-randomId` suffix) = 967 -// we round it to 950 to make it more human friendly, and we apply the limit whatever the value of -// addRandomSuffix is, to make it consistent -const MAXIMUM_PATHNAME_LENGTH = 950; - export async function createPutOptions< TOptions extends CommonPutCommandOptions, >({