Skip to content

Commit b595d94

Browse files
authored
Add Content-Range capability to the File getObject adapter. (#358)
1 parent 0fb6962 commit b595d94

File tree

1 file changed

+41
-15
lines changed

1 file changed

+41
-15
lines changed

src/storage/backend/file.ts

Lines changed: 41 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import {
1010
ObjectMetadata,
1111
ObjectResponse,
1212
withOptionalVersion,
13+
BrowserCacheHeaders,
1314
} from './generic'
1415
import { StorageBackendError } from '../errors'
1516
const pipeline = promisify(stream.pipeline)
@@ -52,33 +53,58 @@ export class FileBackend implements StorageBackendAdapter {
5253
* @param bucketName
5354
* @param key
5455
* @param version
56+
* @param headers
5557
*/
5658
async getObject(
5759
bucketName: string,
5860
key: string,
59-
version: string | undefined
61+
version: string | undefined,
62+
headers?: BrowserCacheHeaders
6063
): Promise<ObjectResponse> {
64+
// 'Range: bytes=#######-######
6165
const file = path.resolve(this.filePath, withOptionalVersion(`${bucketName}/${key}`, version))
62-
const body = fs.createReadStream(file)
6366
const data = await fs.stat(file)
67+
const checksum = await fileChecksum(file)
68+
const fileSize = data.size
6469
const { cacheControl, contentType } = await this.getFileMetadata(file)
6570
const lastModified = new Date(0)
6671
lastModified.setUTCMilliseconds(data.mtimeMs)
6772

68-
const checksum = await fileChecksum(file)
73+
if (headers?.range) {
74+
const parts = headers.range.replace(/bytes=/, '').split('-')
75+
const startRange = parseInt(parts[0], 10)
76+
const endRange = parts[1] ? parseInt(parts[1], 10) : fileSize - 1
77+
const size = endRange - startRange
78+
const chunkSize = size + 1
79+
const body = fs.createReadStream(file, { start: startRange, end: endRange })
6980

70-
return {
71-
metadata: {
72-
cacheControl: cacheControl || 'no-cache',
73-
mimetype: contentType || 'application/octet-stream',
74-
lastModified: lastModified,
75-
// contentRange: data.ContentRange, @todo: support range requests
76-
httpStatusCode: 200,
77-
size: data.size,
78-
eTag: checksum,
79-
contentLength: data.size,
80-
},
81-
body,
81+
return {
82+
metadata: {
83+
cacheControl: cacheControl || 'no-cache',
84+
mimetype: contentType || 'application/octet-stream',
85+
lastModified: lastModified,
86+
contentRange: `bytes ${startRange}-${endRange}/${fileSize}`,
87+
httpStatusCode: 206,
88+
size: size,
89+
eTag: checksum,
90+
contentLength: chunkSize,
91+
},
92+
body,
93+
}
94+
} else {
95+
const body = fs.createReadStream(file)
96+
return {
97+
metadata: {
98+
cacheControl: cacheControl || 'no-cache',
99+
mimetype: contentType || 'application/octet-stream',
100+
lastModified: lastModified,
101+
httpStatusCode: 200,
102+
size: data.size,
103+
eTag: checksum,
104+
contentLength: fileSize,
105+
},
106+
body,
107+
}
82108
}
83109
}
84110

0 commit comments

Comments
 (0)