Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 8259e5e

Browse files
feat: respect accept header in server (#153)
1 parent 1b712fe commit 8259e5e

File tree

3 files changed

+65
-6
lines changed

3 files changed

+65
-6
lines changed

‎src/client.ts‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ import { encodeMetadata, Metadata, METADATA_HEADER_EXTERNAL, METADATA_HEADER_INT
44
import { fetchAndRetry } from './retry.ts'
55
import { BlobInput, Fetcher, HTTPMethod } from './types.ts'
66

7+
export const SIGNED_URL_ACCEPT_HEADER = 'application/json;type=signed-url'
8+
79
interface MakeStoreRequestOptions {
810
body?: BlobInput | null
911
consistency?: ConsistencyMode
@@ -135,7 +137,7 @@ export class Client {
135137
}
136138

137139
const res = await this.fetch(url.toString(), {
138-
headers: { ...apiHeaders, accept: `application/json;type=signed-url` },
140+
headers: { ...apiHeaders, accept: SIGNED_URL_ACCEPT_HEADER },
139141
method,
140142
})
141143

‎src/server.test.ts‎

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -366,3 +366,60 @@ test('Lists site stores', async () => {
366366

367367
expect(stores).toStrictEqual(['coldplay', 'phoenix'])
368368
})
369+
370+
test('Returns a signed URL or the blob directly based on the request parameters', async () => {
371+
const siteID = '9a003659-aaaa-0000-aaaa-63d3720d8621'
372+
const token = 'some token'
373+
const value = 'value 1'
374+
const directory = await tmp.dir()
375+
const server = new BlobsServer({
376+
directory: directory.path,
377+
token,
378+
})
379+
380+
const { port } = await server.start()
381+
const store = getStore({
382+
edgeURL: `http://localhost:${port}`,
383+
name: 'my-store',
384+
token,
385+
siteID,
386+
})
387+
388+
await store.set('key-1', value)
389+
390+
// When reading through a legacy API endpoint, we should get a signed URL.
391+
const res1 = await fetch(`http://localhost:${port}/api/v1/sites/${siteID}/blobs/key-1?context=site:my-store`, {
392+
headers: {
393+
authorization: `Bearer ${token}`,
394+
},
395+
})
396+
const { url: url1 } = await res1.json()
397+
const data1 = await fetch(url1)
398+
399+
expect(await data1.text()).toBe(value)
400+
401+
// When reading through a new API endpoint, we should get the blob data by
402+
// default.
403+
const res2 = await fetch(`http://localhost:${port}/api/v1/blobs/${siteID}/site:my-store/key-1`, {
404+
headers: {
405+
authorization: `Bearer ${token}`,
406+
},
407+
})
408+
expect(await res2.text()).toBe(value)
409+
410+
// When reading through a new API endpoint and requesting a signed URL, we
411+
// should get one.
412+
const res3 = await fetch(`http://localhost:${port}/api/v1/blobs/${siteID}/site:my-store/key-1`, {
413+
headers: {
414+
accept: 'application/json;type=signed-url',
415+
authorization: `Bearer ${token}`,
416+
},
417+
})
418+
const { url: url3 } = await res3.json()
419+
const data3 = await fetch(url3)
420+
421+
expect(await data3.text()).toBe(value)
422+
423+
await server.stop()
424+
await fs.rm(directory.path, { force: true, recursive: true })
425+
})

‎src/server.ts‎

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import stream from 'node:stream'
88
import { promisify } from 'node:util'
99

1010
import { ListResponse } from './backend/list.ts'
11+
import { SIGNED_URL_ACCEPT_HEADER } from './client.ts'
1112
import { decodeMetadata, encodeMetadata, METADATA_HEADER_INTERNAL } from './metadata.ts'
1213
import { HTTPMethod } from './types.ts'
1314
import { isNodeError, Logger } from './util.ts'
@@ -137,11 +138,11 @@ export class BlobsServer {
137138
const apiMatch = this.parseAPIRequest(req)
138139
const url = apiMatch?.url ?? new URL(req.url ?? '', this.address)
139140

140-
if (apiMatch?.key) {
141+
if (apiMatch?.key&&apiMatch?.useSignedURL) {
141142
return this.sendResponse(req, res, 200, JSON.stringify({ url: apiMatch.url.toString() }))
142143
}
143144

144-
const { dataPath, key, metadataPath, rootPath } = this.getLocalPaths(url)
145+
const { dataPath, key, metadataPath, rootPath } = this.getLocalPaths(apiMatch?.url??url)
145146

146147
// If there's no root path, the request is invalid.
147148
if (!rootPath) {
@@ -404,7 +405,7 @@ export class BlobsServer {
404405
siteID,
405406
storeName,
406407
url,
407-
useSignedURL: req.headers.accept === 'application/json;type=signed-url',
408+
useSignedURL: req.headers.accept === SIGNED_URL_ACCEPT_HEADER,
408409
}
409410
}
410411

@@ -481,9 +482,8 @@ export class BlobsServer {
481482
}
482483

483484
const { authorization = '' } = req.headers
484-
const parts = authorization.split(' ')
485485

486-
if (parts.length===2||(parts[0].toLowerCase()==='bearer' && parts[1]=== this.token)) {
486+
if (authorization.toLowerCase().startsWith('bearer ') && authorization.slice('bearer '.length)=== this.token) {
487487
return true
488488
}
489489

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /