summaryrefslogtreecommitdiff
path: root/packages/backend/src
diff options
context:
space:
mode:
Diffstat (limited to 'packages/backend/src')
-rw-r--r--packages/backend/src/core/DownloadService.ts34
-rw-r--r--packages/backend/src/core/HttpRequestService.ts90
-rw-r--r--packages/backend/src/core/activitypub/ApRequestService.ts17
-rw-r--r--packages/backend/src/core/activitypub/ApResolverService.ts10
-rw-r--r--packages/backend/src/misc/dev-null.ts11
-rw-r--r--packages/backend/src/server/web/views/base.pug2
6 files changed, 103 insertions, 61 deletions
diff --git a/packages/backend/src/core/DownloadService.ts b/packages/backend/src/core/DownloadService.ts
index a3078bff45..c5b2bcaef4 100644
--- a/packages/backend/src/core/DownloadService.ts
+++ b/packages/backend/src/core/DownloadService.ts
@@ -4,8 +4,8 @@ import * as util from 'node:util';
import { Inject, Injectable } from '@nestjs/common';
import IPCIDR from 'ip-cidr';
import PrivateIp from 'private-ip';
-import got, * as Got from 'got';
import chalk from 'chalk';
+import { buildConnector } from 'undici';
import { DI } from '@/di-symbols.js';
import type { Config } from '@/config.js';
import { HttpRequestService, UndiciFetcher } from '@/core/HttpRequestService.js';
@@ -13,7 +13,6 @@ import { createTemp } from '@/misc/create-temp.js';
import { StatusError } from '@/misc/status-error.js';
import { LoggerService } from '@/core/LoggerService.js';
import type Logger from '@/logger.js';
-import { buildConnector } from 'undici';
const pipeline = util.promisify(stream.pipeline);
import { bindThis } from '@/decorators.js';
@@ -32,23 +31,20 @@ export class DownloadService {
) {
this.logger = this.loggerService.getLogger('download');
- this.undiciFetcher = new UndiciFetcher(this.httpRequestService.getStandardUndiciFetcherOption(
- {
- 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);
+ 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
diff --git a/packages/backend/src/core/HttpRequestService.ts b/packages/backend/src/core/HttpRequestService.ts
index 2864ad4405..cd859d0023 100644
--- a/packages/backend/src/core/HttpRequestService.ts
+++ b/packages/backend/src/core/HttpRequestService.ts
@@ -1,14 +1,14 @@
import * as http from 'node:http';
import * as https from 'node:https';
+import { LookupFunction } from 'node:net';
import CacheableLookup from 'cacheable-lookup';
import { HttpProxyAgent, HttpsProxyAgent } from 'hpagent';
import { Inject, Injectable } from '@nestjs/common';
+import * as undici from 'undici';
import { DI } from '@/di-symbols.js';
import type { Config } from '@/config.js';
import { StatusError } from '@/misc/status-error.js';
import { bindThis } from '@/decorators.js';
-import * as undici from 'undici';
-import { LookupFunction } from 'node:net';
import { LoggerService } from '@/core/LoggerService.js';
import type Logger from '@/logger.js';
@@ -62,7 +62,7 @@ export class UndiciFetcher {
undici.buildConnector(args.agentOptions.connect as undici.buildConnector.BuildOptions)(options, (err, socket) => {
this.logger?.debug('Socket connector called', socket);
if (err) {
- this.logger?.debug(`Socket error`, err);
+ this.logger?.debug('Socket error', err);
cb(new Error(`Error while socket connecting\n${err}`), null);
return;
}
@@ -79,20 +79,20 @@ export class UndiciFetcher {
uri: args.proxy.uri,
- connect: (process.env.NODE_ENV !== 'production' && typeof (args.proxy?.options?.connect ?? args.agentOptions.connect) !== 'function')
+ connect: (process.env.NODE_ENV !== 'production' && typeof (args.proxy.options?.connect ?? args.agentOptions.connect) !== 'function')
? (options, cb) => {
// Custom connector for debug
undici.buildConnector((args.proxy?.options?.connect ?? args.agentOptions.connect) as undici.buildConnector.BuildOptions)(options, (err, socket) => {
this.logger?.debug('Socket connector called (secure)', socket);
if (err) {
- this.logger?.debug(`Socket error`, err);
+ this.logger?.debug('Socket error', err);
cb(new Error(`Error while socket connecting\n${err}`), null);
return;
}
this.logger?.debug(`Socket connected (secure): port ${socket.localPort} => remote ${socket.remoteAddress}`);
cb(null, socket);
});
- } : (args.proxy?.options?.connect ?? args.agentOptions.connect),
+ } : (args.proxy.options?.connect ?? args.agentOptions.connect),
})
: this.nonProxiedAgent;
}
@@ -115,7 +115,7 @@ export class UndiciFetcher {
public async fetch(
url: string | URL,
options: undici.RequestInit = {},
- privateOptions: { noOkError?: boolean; bypassProxy?: boolean; } = { noOkError: false, bypassProxy: false }
+ privateOptions: { noOkError?: boolean; bypassProxy?: boolean; } = { noOkError: false, bypassProxy: false },
): Promise<undici.Response> {
const res = await undici.fetch(url, {
dispatcher: this.getAgentByUrl(new URL(url), privateOptions.bypassProxy),
@@ -135,31 +135,56 @@ export class UndiciFetcher {
}
@bindThis
+ public async request(
+ url: string | URL,
+ options: { dispatcher?: undici.Dispatcher } & Omit<undici.Dispatcher.RequestOptions, 'origin' | 'path' | 'method'> & Partial<Pick<undici.Dispatcher.RequestOptions, 'method'>> = {},
+ privateOptions: { noOkError?: boolean; bypassProxy?: boolean; } = { noOkError: false, bypassProxy: false },
+ ): Promise<undici.Dispatcher.ResponseData> {
+ const res = await undici.request(url, {
+ dispatcher: this.getAgentByUrl(new URL(url), privateOptions.bypassProxy),
+ ...options,
+ headers: {
+ 'user-agent': this.userAgent ?? '',
+ ...(options.headers ?? {}),
+ },
+ }).catch((err) => {
+ this.logger?.error(`fetch error to ${typeof url === 'string' ? url : url.href}`, err);
+ throw new StatusError('Resource Unreachable', 500, 'Resource Unreachable');
+ });
+
+ if (res.statusCode >= 400) {
+ throw new StatusError(`${res.statusCode}`, res.statusCode, '');
+ }
+
+ return res;
+ }
+
+ @bindThis
public async getJson<T extends unknown>(url: string, accept = 'application/json, */*', headers?: Record<string, string>): Promise<T> {
- const res = await this.fetch(
+ const { body } = await this.request(
url,
{
headers: Object.assign({
Accept: accept,
}, headers ?? {}),
- }
+ },
);
- return await res.json() as T;
+ return await body.json() as T;
}
@bindThis
public async getHtml(url: string, accept = 'text/html, */*', headers?: Record<string, string>): Promise<string> {
- const res = await this.fetch(
+ const { body } = await this.request(
url,
{
headers: Object.assign({
Accept: accept,
}, headers ?? {}),
- }
+ },
);
- return await res.text();
+ return await body.text();
}
}
@@ -167,6 +192,7 @@ export class UndiciFetcher {
export class HttpRequestService {
public defaultFetcher: UndiciFetcher;
public fetch: UndiciFetcher['fetch'];
+ public request: UndiciFetcher['request'];
public getHtml: UndiciFetcher['getHtml'];
public defaultJsonFetcher: UndiciFetcher;
public getJson: UndiciFetcher['getJson'];
@@ -219,18 +245,19 @@ export class HttpRequestService {
maxCachedSessions: 300, // TLSセッションのキャッシュ数 https://github.com/nodejs/undici/blob/v5.14.0/lib/core/connect.js#L80
lookup: this.dnsCache.lookup as LookupFunction, // https://github.com/nodejs/undici/blob/v5.14.0/lib/core/connect.js#L98
},
- }
+ };
- this.maxSockets = Math.max(64, this.config.deliverJobConcurrency ?? 128);
+ this.maxSockets = Math.max(64, ((this.config.deliverJobConcurrency ?? 128) / (this.config.clusterLimit ?? 1)));
- this.defaultFetcher = new UndiciFetcher(this.getStandardUndiciFetcherOption(), this.logger);
+ this.defaultFetcher = this.createFetcher({}, {}, this.logger);
this.fetch = this.defaultFetcher.fetch;
+ this.request = this.defaultFetcher.request;
this.getHtml = this.defaultFetcher.getHtml;
- this.defaultJsonFetcher = new UndiciFetcher(this.getStandardUndiciFetcherOption({
+ this.defaultJsonFetcher = this.createFetcher({
maxResponseSize: 1024 * 256,
- }), this.logger);
+ }, {}, this.logger);
this.getJson = this.defaultJsonFetcher.getJson;
@@ -272,23 +299,28 @@ export class HttpRequestService {
}
@bindThis
- public getStandardUndiciFetcherOption(opts: undici.Agent.Options = {}, proxyOpts: undici.Agent.Options = {}) {
+ private getStandardUndiciFetcherOption(opts: undici.Agent.Options = {}, proxyOpts: undici.Agent.Options = {}) {
return {
agentOptions: {
...this.clientDefaults,
...opts,
},
...(this.config.proxy ? {
- proxy: {
- uri: this.config.proxy,
- options: {
- connections: this.maxSockets,
- ...proxyOpts,
- }
- }
+ proxy: {
+ uri: this.config.proxy,
+ options: {
+ connections: this.maxSockets,
+ ...proxyOpts,
+ },
+ },
} : {}),
userAgent: this.config.userAgent,
- }
+ };
+ }
+
+ @bindThis
+ public createFetcher(opts: undici.Agent.Options = {}, proxyOpts: undici.Agent.Options = {}, logger: Logger) {
+ return new UndiciFetcher(this.getStandardUndiciFetcherOption(opts, proxyOpts), logger);
}
/**
@@ -314,13 +346,13 @@ export class HttpRequestService {
connector(options, (err, socket) => {
this.logger.debug('Socket connector (with ip checker) called', socket);
if (err) {
- this.logger.error(`Socket error`, err)
+ this.logger.error('Socket error', err);
cb(new Error(`Error while socket connecting\n${err}`), null);
return;
}
if (socket.remoteAddress == undefined) {
- this.logger.error(`Socket error: remoteAddress is undefined`);
+ this.logger.error('Socket error: remoteAddress is undefined');
cb(new Error('remoteAddress is undefined (maybe socket destroyed)'), null);
return;
}
diff --git a/packages/backend/src/core/activitypub/ApRequestService.ts b/packages/backend/src/core/activitypub/ApRequestService.ts
index ab22a0c411..db87475c4c 100644
--- a/packages/backend/src/core/activitypub/ApRequestService.ts
+++ b/packages/backend/src/core/activitypub/ApRequestService.ts
@@ -9,10 +9,12 @@ import { HttpRequestService, UndiciFetcher } from '@/core/HttpRequestService.js'
import { LoggerService } from '@/core/LoggerService.js';
import { bindThis } from '@/decorators.js';
import type Logger from '@/logger.js';
+import type { Dispatcher } from 'undici';
+import { DevNull } from '@/misc/dev-null.js';
type Request = {
url: string;
- method: string;
+ method: Dispatcher.HttpMethod;
headers: Record<string, string>;
};
@@ -41,10 +43,10 @@ export class ApRequestService {
private httpRequestService: HttpRequestService,
private loggerService: LoggerService,
) {
- this.logger = this.loggerService?.getLogger('ap-request'); // なぜか TypeError: Cannot read properties of undefined (reading 'getLogger') と言われる
- this.undiciFetcher = new UndiciFetcher(this.httpRequestService.getStandardUndiciFetcherOption({
+ this.logger = this.loggerService.getLogger('ap-request'); // なぜか TypeError: Cannot read properties of undefined (reading 'getLogger') と言われる
+ this.undiciFetcher = this.httpRequestService.createFetcher({
maxRedirections: 0,
- }), this.logger );
+ }, {}, this.logger);
}
@bindThis
@@ -163,14 +165,15 @@ export class ApRequestService {
},
});
- await this.undiciFetcher.fetch(
+ const response = await this.undiciFetcher.request(
url,
{
method: req.request.method,
headers: req.request.headers,
body,
- }
+ },
);
+ response.body.pipe(new DevNull());
}
/**
@@ -197,7 +200,7 @@ export class ApRequestService {
{
method: req.request.method,
headers: req.request.headers,
- }
+ },
);
return await res.json();
diff --git a/packages/backend/src/core/activitypub/ApResolverService.ts b/packages/backend/src/core/activitypub/ApResolverService.ts
index e51ae37954..ca7760af81 100644
--- a/packages/backend/src/core/activitypub/ApResolverService.ts
+++ b/packages/backend/src/core/activitypub/ApResolverService.ts
@@ -8,13 +8,13 @@ import { HttpRequestService, UndiciFetcher } from '@/core/HttpRequestService.js'
import { DI } from '@/di-symbols.js';
import { UtilityService } from '@/core/UtilityService.js';
import { bindThis } from '@/decorators.js';
+import { LoggerService } from '@/core/LoggerService.js';
+import type Logger from '@/logger.js';
import { isCollectionOrOrderedCollection } from './type.js';
import { ApDbResolverService } from './ApDbResolverService.js';
import { ApRendererService } from './ApRendererService.js';
import { ApRequestService } from './ApRequestService.js';
-import { LoggerService } from '@/core/LoggerService.js';
import type { IObject, ICollection, IOrderedCollection } from './type.js';
-import type Logger from '@/logger.js';
export class Resolver {
private history: Set<string>;
@@ -39,10 +39,10 @@ export class Resolver {
private recursionLimit = 100,
) {
this.history = new Set();
- this.logger = this.loggerService?.getLogger('ap-resolve'); // なぜか TypeError: Cannot read properties of undefined (reading 'getLogger') と言われる
- this.undiciFetcher = new UndiciFetcher(this.httpRequestService.getStandardUndiciFetcherOption({
+ this.logger = this.loggerService?.getLogger('ap-resolve'); // なぜか TypeError: Cannot read properties of undefined (reading 'getLogger') と言われる
+ this.undiciFetcher = this.httpRequestService.createFetcher({
maxRedirections: 0,
- }), this.logger);
+ }, {}, this.logger);
}
@bindThis
diff --git a/packages/backend/src/misc/dev-null.ts b/packages/backend/src/misc/dev-null.ts
new file mode 100644
index 0000000000..38b9d82669
--- /dev/null
+++ b/packages/backend/src/misc/dev-null.ts
@@ -0,0 +1,11 @@
+import { Writable, WritableOptions } from "node:stream";
+
+export class DevNull extends Writable implements NodeJS.WritableStream {
+ constructor(opts?: WritableOptions) {
+ super(opts);
+ }
+
+ _write (chunk: any, encoding: BufferEncoding, cb: (err?: Error | null) => void) {
+ setImmediate(cb);
+ }
+}
diff --git a/packages/backend/src/server/web/views/base.pug b/packages/backend/src/server/web/views/base.pug
index b27bbcbce0..d05901baec 100644
--- a/packages/backend/src/server/web/views/base.pug
+++ b/packages/backend/src/server/web/views/base.pug
@@ -35,7 +35,7 @@ html
link(rel='prefetch' href='https://xn--931a.moe/assets/info.jpg')
link(rel='prefetch' href='https://xn--931a.moe/assets/not-found.jpg')
link(rel='prefetch' href='https://xn--931a.moe/assets/error.jpg')
- link(rel='stylesheet' href='/assets/tabler-icons/tabler-icons.css')
+ link(rel='stylesheet' href='/assets/tabler-icons/tabler-icons.min.css')
link(rel='modulepreload' href=`/vite/${clientEntry.file}`)
if !config.clientManifestExists