diff --git a/packages/blobs/src/server.test.ts b/packages/blobs/src/server.test.ts index 2d0196c9a..689451fc2 100644 --- a/packages/blobs/src/server.test.ts +++ b/packages/blobs/src/server.test.ts @@ -554,6 +554,36 @@ test('Handles conditional writes', async () => { await fs.rm(directory.path, { force: true, recursive: true }) }) +test('Returns ETags and handles conditional reads', async () => { + const directory = await tmp.dir() + const server = new BlobsServer({ + directory: directory.path, + token, + }) + const { port } = await server.start() + const store = getStore({ + edgeURL: `http://localhost:${port}`, + name: 'my-store', + token, + siteID, + }) + const key = 'conditional-key' + const value = 'value' + const metadata = { name: 'test-metadata', } + + const writeResult = await store.set(key, value, { metadata }) + const etag = writeResult.etag + + expect(etag).toBeTypeOf('string') + expect(await store.getWithMetadata(key)).toEqual({ data: value, etag, metadata }) + expect(await store.getMetadata(key)).toEqual({ etag, metadata }) + expect(await store.getWithMetadata(key, { etag: '"stale-etag"' })).toEqual({ data: value, etag, metadata }) + expect(await store.getWithMetadata(key, { etag })).toEqual({ data: null, etag, metadata }) + + await server.stop() + await fs.rm(directory.path, { force: true, recursive: true }) +}) + test('Deletes all blobs from a store', async () => { const directory = await tmp.dir() const server = new BlobsServer({ diff --git a/packages/blobs/src/server.ts b/packages/blobs/src/server.ts index 0e56ab4bb..47acbd324 100644 --- a/packages/blobs/src/server.ts +++ b/packages/blobs/src/server.ts @@ -210,7 +210,8 @@ export class BlobsServer { this.dispatchOnRequestEvent(Operation.GET, url) - const headers: Record = {} + const etag = await BlobsServer.generateETag(dataPath) + const headers: Record = { etag } try { const rawData = await fs.readFile(metadataPath, 'utf8') @@ -226,6 +227,10 @@ export class BlobsServer { } } + if (req.headers.get('if-none-match') === etag) { + return new Response(null, { headers, status: 304 }) + } + try { const fileStream = createReadStream(dataPath) const chunks: Buffer[] = [] @@ -260,9 +265,11 @@ export class BlobsServer { const rawData = await fs.readFile(metadataPath, 'utf8') const metadata = JSON.parse(rawData) const encodedMetadata = encodeMetadata(metadata) + const etag = await BlobsServer.generateETag(dataPath) return new Response(null, { headers: { + etag, [METADATA_HEADER_INTERNAL]: encodedMetadata ?? '', }, })