Use send-range and mime packages to send multipart/byteranges responses

This commit is contained in:
Alice Gaudon 2020-11-20 15:34:17 +01:00
parent 18f3f93db6
commit c519b8a884
4 changed files with 68 additions and 5 deletions

View File

@ -26,6 +26,7 @@
"@types/feather-icons": "^4.7.0", "@types/feather-icons": "^4.7.0",
"@types/formidable": "^1.0.31", "@types/formidable": "^1.0.31",
"@types/jest": "^26.0.4", "@types/jest": "^26.0.4",
"@types/mime": "^2.0.3",
"@types/mysql": "^2.15.15", "@types/mysql": "^2.15.15",
"@types/node": "^14.6.3", "@types/node": "^14.6.3",
"@types/nodemailer": "^6.4.0", "@types/nodemailer": "^6.4.0",
@ -60,6 +61,8 @@
"dependencies": { "dependencies": {
"config": "^3.3.1", "config": "^3.3.1",
"express": "^4.17.1", "express": "^4.17.1",
"mime": "^2.4.6",
"send-ranges": "^4.0.0",
"swaf": "^0.22.5" "swaf": "^0.22.5"
} }
} }

View File

@ -7,6 +7,8 @@ import {NotFoundHttpError, ServiceUnavailableHttpError} from "swaf/HttpError";
import * as fs from "fs"; import * as fs from "fs";
import {promisify} from "util"; import {promisify} from "util";
import path from "path"; import path from "path";
import sendRanges, {SendRangeGetStreamFn} from "send-ranges";
import mime from "mime";
export const ASSETS_BASE_DIR = config.get<string>('assets_base_dir'); export const ASSETS_BASE_DIR = config.get<string>('assets_base_dir');
@ -110,8 +112,25 @@ export default class GiteaRepoLatestReleaseController extends Controller {
await promisify(fs.rename)(tmpAssetPath, assetPath); await promisify(fs.rename)(tmpAssetPath, assetPath);
} }
// Respond log.debug('Download', assetPath, downloadProperties.asset.name);
return res.download(assetPath, downloadProperties.asset.name);
sendRanges(async _ => {
const filePath = assetPath;
const getStream: SendRangeGetStreamFn = range => fs.createReadStream(filePath, range);
const type = mime.getType(downloadProperties.asset.name) || 'application/json';
const stats = await promisify(fs.stat)(filePath);
return {getStream, type, size: stats.size};
}, {
maxRanges: 1024,
})(req, res, (err: unknown) => {
if (err) return next(err);
log.info('Fallback to express download.');
// Respond
return res.download(assetPath, downloadProperties.asset.name);
});
} }
} }

24
src/types/send-ranges.d.ts vendored Normal file
View File

@ -0,0 +1,24 @@
declare module 'send-ranges' {
import {NextFunction, Request, RequestHandler} from "express";
import {ReadStream} from "fs";
export default function (
fetchStream: ((req: Request) => Promise<SendRangeParams | null>),
options: SendRangeOptions = {},
): RequestHandler;
export type SendRangeOptions = {
beforeSend?: (info, next: NextFunction) => void,
maxRanges?: number,
};
export type SendRangeParams = {
getStream: SendRangeGetStreamFn;
type: string;
size: number;
};
export type SendRangeGetStreamFn = (range: {
start?: number;
end?: number;
}) => ReadStream;
}

View File

@ -1281,7 +1281,7 @@
resolved "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.6.tgz#f4c7ec43e81b319a9815115031709f26987891f0" resolved "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.6.tgz#f4c7ec43e81b319a9815115031709f26987891f0"
integrity sha512-3c+yGKvVP5Y9TYBEibGNR+kLtijnj7mYrXRg+WpFb2X9xm04g/DXYkfg4hmzJQosc9snFNUPkbYIhu+KAm6jJw== integrity sha512-3c+yGKvVP5Y9TYBEibGNR+kLtijnj7mYrXRg+WpFb2X9xm04g/DXYkfg4hmzJQosc9snFNUPkbYIhu+KAm6jJw==
"@types/mime@*": "@types/mime@*", "@types/mime@^2.0.3":
version "2.0.3" version "2.0.3"
resolved "https://registry.npmjs.org/@types/mime/-/mime-2.0.3.tgz#c893b73721db73699943bfc3653b1deb7faa4a3a" resolved "https://registry.npmjs.org/@types/mime/-/mime-2.0.3.tgz#c893b73721db73699943bfc3653b1deb7faa4a3a"
integrity sha512-Jus9s4CDbqwocc5pOAnh8ShfrnMcPHuJYzVcSUU7lrh8Ni5HuIqX3oilL86p3dlTrk0LzHRCgA/GQ7uNCw6l2Q== integrity sha512-Jus9s4CDbqwocc5pOAnh8ShfrnMcPHuJYzVcSUU7lrh8Ni5HuIqX3oilL86p3dlTrk0LzHRCgA/GQ7uNCw6l2Q==
@ -2212,6 +2212,14 @@ buffer@^5.2.1:
base64-js "^1.3.1" base64-js "^1.3.1"
ieee754 "^1.1.13" ieee754 "^1.1.13"
byte-range-stream@^2.0.1:
version "2.0.1"
resolved "https://registry.npmjs.org/byte-range-stream/-/byte-range-stream-2.0.1.tgz#bf62271ddd07c2dad3bf9feee5f1f3ff1a96938a"
integrity sha512-qifcJeL6kLv7GfJk/2h27/3VmU046AFrt6PWJ9hxrvP9A2IHHEGIC9cFvgEMRKIZjkd5Z56kKukQ7nzIBp5cuQ==
dependencies:
combined-stream "^1.0.5"
range-parser "^1.2.0"
bytes@3.0.0: bytes@3.0.0:
version "3.0.0" version "3.0.0"
resolved "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048" resolved "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048"
@ -2547,7 +2555,7 @@ colors@^1.1.2:
resolved "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz#c50491479d4c1bdaed2c9ced32cf7c7dc2360f78" resolved "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz#c50491479d4c1bdaed2c9ced32cf7c7dc2360f78"
integrity sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA== integrity sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==
combined-stream@^1.0.6, combined-stream@~1.0.6: combined-stream@^1.0.5, combined-stream@^1.0.6, combined-stream@~1.0.6:
version "1.0.8" version "1.0.8"
resolved "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" resolved "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f"
integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==
@ -7432,7 +7440,7 @@ randombytes@^2.1.0:
dependencies: dependencies:
safe-buffer "^5.1.0" safe-buffer "^5.1.0"
range-parser@~1.2.1: range-parser@^1.2.0, range-parser@^1.2.1, range-parser@~1.2.1:
version "1.2.1" version "1.2.1"
resolved "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031" resolved "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031"
integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg== integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==
@ -7974,6 +7982,15 @@ semver@^6.0.0, semver@^6.2.0, semver@^6.3.0:
resolved "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" resolved "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d"
integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==
send-ranges@^4.0.0:
version "4.0.0"
resolved "https://registry.npmjs.org/send-ranges/-/send-ranges-4.0.0.tgz#b5fd5e8f324d31ad48eef3c2e7a9fdca6c973197"
integrity sha512-BwhMXcHIwxCAo8P7RHbLz1PlASAvTiIAL9cV8oZxBATa8WZTJy1cZn4RBlA62pJZly6L/x+97baWhKhsp0Uh0Q==
dependencies:
byte-range-stream "^2.0.1"
pump "^3.0.0"
range-parser "^1.2.1"
send@0.17.1: send@0.17.1:
version "0.17.1" version "0.17.1"
resolved "https://registry.npmjs.org/send/-/send-0.17.1.tgz#c1d8b059f7900f7466dd4938bdc44e11ddb376c8" resolved "https://registry.npmjs.org/send/-/send-0.17.1.tgz#c1d8b059f7900f7466dd4938bdc44e11ddb376c8"