I have a function that forces a file download in the browser, and it works on small files but on large files it doesn't seem to work. When the download starts I get Failed - No File, and I have narrowed it down to the reason is that I am setting a 206
status code (Partial Content). This used to work just fine, but now I am getting the No File message.
When changing it to a status code of 200
the file gets downloaded. When keeping the status code to 206
and removing the Content-Disposition
, the file plays in the browser.
Is 206
even needed for large files when downloading?
export class Server {
private static async send(client: Client, req: http.IncomingMessage, res: http.ServerResponse) {
let fileSize = client.response.contentLength
let start = 0, end = fileSize - 1 < start ? start : fileSize - 1
if (fileSize > (this.app.chunkSize || 5e5)) {
let range = (req.headers.range || '') as string
let positions = range.replace(/bytes=/, '').trim().split('-')
start = parseInt(positions[0] || '0', 10)
end = parseInt(positions[1] || (fileSize - 1).toString(), 10)
let chunkSize = (end - start) + 1
// Setting the Code to 206 here breaks
client.response.setCode(206)
.setHeaders({
'Content-Range': `bytes ${start}-${end}/${fileSize}`,
'Accept-Ranges': 'bytes',
'Connection': 'Keep-Alive',
'Content-Length': chunkSize
})
}
res.writeHead(client.response.code, <any>headers)
let { store, file } = client.response.fileStore
let stream: fs.ReadStream = store.readStream(file, { start, end })
.on('open', () => stream.pipe(res))
.on('close', () => res.end())
.on('error', err => res.end(err))
}
}
The read stream here is pretty simple:
export default class extends Storage {
public readStream(filePath: string, options?: FileReadOptions) {
return fs.createReadStream(this.toPath(filePath), options)
}
}