Skip to content

Commit

Permalink
fix(blob): limit keys to 950 characters (#750)
Browse files Browse the repository at this point in the history
* 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.

* changeset
  • Loading branch information
vvo authored Sep 12, 2024
1 parent 50c298d commit 8d7e8b9
Show file tree
Hide file tree
Showing 5 changed files with 47 additions and 1 deletion.
5 changes: 5 additions & 0 deletions .changeset/unlucky-months-repeat.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@vercel/blob': patch
---

Limit pathname length to 950 to respect internal limitations and provide better early DX.
6 changes: 6 additions & 0 deletions packages/blob/src/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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.');
Expand Down
8 changes: 7 additions & 1 deletion packages/blob/src/copy.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { requestApi } from './api';
import { MAXIMUM_PATHNAME_LENGTH, requestApi } from './api';
import type { CommonCreateBlobOptions } from './helpers';
import { BlobError } from './helpers';

Expand Down Expand Up @@ -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<string, string> = {};

if (options.addRandomSuffix !== undefined) {
Expand Down
22 changes: 22 additions & 0 deletions packages/blob/src/index.node.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -576,6 +576,16 @@ describe('blob client', () => {
expect(headers['x-cache-control-max-age']).toEqual('60');
});

it('throws when filepath is too long', async () => {
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<unknown>][] = [
[
'put',
Expand Down Expand Up @@ -701,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'),
);
});
});
});
7 changes: 7 additions & 0 deletions packages/blob/src/put-helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand Down Expand Up @@ -85,6 +86,12 @@ export async function createPutOptions<
throw new BlobError('pathname is required');
}

if (pathname.length > MAXIMUM_PATHNAME_LENGTH) {
throw new BlobError(
`pathname is too long, maximum length is ${MAXIMUM_PATHNAME_LENGTH}`,
);
}

if (!options) {
throw new BlobError('missing options, see usage');
}
Expand Down

0 comments on commit 8d7e8b9

Please sign in to comment.