feat: intercept undici and use fetch dispatcher

This commit is contained in:
DIYgod
2024-03-28 02:45:08 +08:00
parent 23104cd1f6
commit 759c03cd23
3 changed files with 88 additions and 1 deletions
+1 -1
View File
@@ -1,4 +1,4 @@
import '@/utils/request-wrapper';
import '@/utils/request-interceptor';
import { Hono } from 'hono';
+7
View File
@@ -2,6 +2,7 @@ import { config } from '@/config';
import { PacProxyAgent } from 'pac-proxy-agent';
import { HttpsProxyAgent } from 'https-proxy-agent';
import { SocksProxyAgent } from 'socks-proxy-agent';
import { ProxyAgent } from 'undici';
const proxyIsPAC = config.pacUri || config.pacScript;
@@ -24,11 +25,16 @@ if (proxyIsPAC) {
}
let agent: PacProxyAgent<string> | HttpsProxyAgent<string> | SocksProxyAgent | null = null;
let dispatcher: ProxyAgent | null = null;
if (proxyIsPAC) {
agent = new PacProxyAgent(`pac+${proxyUri}`);
} else if (proxyUri) {
if (proxyUri.startsWith('http')) {
agent = new HttpsProxyAgent(proxyUri);
dispatcher = new ProxyAgent({
uri: proxyUri,
token: proxyObj?.auth ? `Basic ${proxyObj.auth}` : undefined,
});
} else if (proxyUri.startsWith('socks')) {
agent = new SocksProxyAgent(proxyUri);
}
@@ -36,6 +42,7 @@ if (proxyIsPAC) {
export default {
agent,
dispatcher,
proxyUri,
proxyObj,
proxyUrlHandler,
+80
View File
@@ -0,0 +1,80 @@
import { setupServer } from 'msw/node';
import { http, passthrough } from 'msw';
import logger from '@/utils/logger';
import { config } from '@/config';
import { fetch, Headers, FormData, ProxyAgent, Request, RequestInfo, RequestInit, Response } from 'undici';
import proxy from '@/utils/proxy';
import type nodehttp from 'node:http';
class ExtendedRequest extends Request {
public dispatcher: ProxyAgent | undefined;
public agent: nodehttp.ClientRequestArgs['agent'];
constructor(input: RequestInfo, init?: RequestInit & nodehttp.ClientRequestArgs) {
super(input, init);
this.dispatcher = init?.dispatcher; // fetch
this.agent = init?.agent; // http
}
}
Object.defineProperties(globalThis, {
fetch: { value: fetch, writable: true },
Headers: { value: Headers },
FormData: { value: FormData },
Request: { value: ExtendedRequest },
Response: { value: Response },
});
const handler = (request: ExtendedRequest) => {
request.headers.set('debug', '1');
// ua
if (!request.headers.get('user-agent')) {
request.headers.set('user-agent', config.ua);
}
// accept
if (!request.headers.get('accept')) {
request.headers.set('accept', '*/*');
}
// referer
if (!request.headers.get('referer')) {
try {
const urlHandler = new URL(request.url);
request.headers.set('referer', urlHandler.origin);
} catch {
// ignore
}
}
// proxy
if (!request.dispatcher && !request.agent && proxy.dispatcher) {
const proxyRegex = new RegExp(proxy.proxyObj.url_regex);
let urlHandler;
try {
urlHandler = new URL(request.url);
} catch {
// ignore
}
if (proxyRegex.test(request.url) && request.url.startsWith('http') && !(urlHandler && urlHandler.host === proxy.proxyUrlHandler?.host)) {
// fetch
request.dispatcher = proxy.dispatcher;
// http
request.agent = proxy.agent || undefined;
if (proxy.proxyObj.auth) {
request.headers.set('Proxy-Authorization', `Basic ${proxy.proxyObj.auth}`);
}
}
}
};
const server = setupServer(
http.all('*', ({ request }) => {
logger.debug(`Outgoing request: ${request.method} ${request.url}`);
handler(request);
return passthrough();
})
);
server.listen();