summaryrefslogtreecommitdiff
path: root/packages/backend/src/core/DownloadService.ts
diff options
context:
space:
mode:
Diffstat (limited to 'packages/backend/src/core/DownloadService.ts')
-rw-r--r--packages/backend/src/core/DownloadService.ts76
1 files changed, 53 insertions, 23 deletions
diff --git a/packages/backend/src/core/DownloadService.ts b/packages/backend/src/core/DownloadService.ts
index c5b2bcaef4..a971e06fd8 100644
--- a/packages/backend/src/core/DownloadService.ts
+++ b/packages/backend/src/core/DownloadService.ts
@@ -5,10 +5,10 @@ import { Inject, Injectable } from '@nestjs/common';
import IPCIDR from 'ip-cidr';
import PrivateIp from 'private-ip';
import chalk from 'chalk';
-import { buildConnector } from 'undici';
+import got, * as Got from 'got';
import { DI } from '@/di-symbols.js';
import type { Config } from '@/config.js';
-import { HttpRequestService, UndiciFetcher } from '@/core/HttpRequestService.js';
+import { HttpRequestService } from '@/core/HttpRequestService.js';
import { createTemp } from '@/misc/create-temp.js';
import { StatusError } from '@/misc/status-error.js';
import { LoggerService } from '@/core/LoggerService.js';
@@ -20,7 +20,6 @@ import { bindThis } from '@/decorators.js';
@Injectable()
export class DownloadService {
private logger: Logger;
- private undiciFetcher: UndiciFetcher;
constructor(
@Inject(DI.config)
@@ -30,21 +29,6 @@ export class DownloadService {
private loggerService: LoggerService,
) {
this.logger = this.loggerService.getLogger('download');
-
- this.undiciFetcher = this.httpRequestService.createFetcher({
- connect: process.env.NODE_ENV === 'development' ?
- this.httpRequestService.clientDefaults.connect
- :
- this.httpRequestService.getConnectorWithIpCheck(
- buildConnector({
- ...this.httpRequestService.clientDefaults.connect,
- }),
- (ip) => !this.isPrivateIp(ip),
- ),
- bodyTimeout: 30 * 1000,
- }, {
- connect: this.httpRequestService.clientDefaults.connect,
- }, this.logger);
}
@bindThis
@@ -55,13 +39,59 @@ export class DownloadService {
const operationTimeout = 60 * 1000;
const maxSize = this.config.maxFileSize ?? 262144000;
- const response = await this.undiciFetcher.fetch(url);
+ const req = got.stream(url, {
+ headers: {
+ 'User-Agent': this.config.userAgent,
+ },
+ timeout: {
+ lookup: timeout,
+ connect: timeout,
+ secureConnect: timeout,
+ socket: timeout, // read timeout
+ response: timeout,
+ send: timeout,
+ request: operationTimeout, // whole operation timeout
+ },
+ agent: {
+ http: this.httpRequestService.httpAgent,
+ https: this.httpRequestService.httpsAgent,
+ },
+ http2: false, // default
+ retry: {
+ limit: 0,
+ },
+ }).on('response', (res: Got.Response) => {
+ if ((process.env.NODE_ENV === 'production' || process.env.NODE_ENV === 'test') && !this.config.proxy && res.ip) {
+ if (this.isPrivateIp(res.ip)) {
+ this.logger.warn(`Blocked address: ${res.ip}`);
+ req.destroy();
+ }
+ }
- if (response.body === null) {
- throw new StatusError('No body', 400, 'No body');
- }
+ const contentLength = res.headers['content-length'];
+ if (contentLength != null) {
+ const size = Number(contentLength);
+ if (size > maxSize) {
+ this.logger.warn(`maxSize exceeded (${size} > ${maxSize}) on response`);
+ req.destroy();
+ }
+ }
+ }).on('downloadProgress', (progress: Got.Progress) => {
+ if (progress.transferred > maxSize) {
+ this.logger.warn(`maxSize exceeded (${progress.transferred} > ${maxSize}) on downloadProgress`);
+ req.destroy();
+ }
+ });
- await pipeline(stream.Readable.fromWeb(response.body), fs.createWriteStream(path));
+ try {
+ await pipeline(req, fs.createWriteStream(path));
+ } catch (e) {
+ if (e instanceof Got.HTTPError) {
+ throw new StatusError(`${e.response.statusCode} ${e.response.statusMessage}`, e.response.statusCode, e.response.statusMessage);
+ } else {
+ throw e;
+ }
+ }
this.logger.succ(`Download finished: ${chalk.cyan(url)}`);
}