somratpro commited on
Commit
2543611
·
1 Parent(s): d68b341

fix: use original unpatched http/https functions to 100% avoid recursion

Browse files
Files changed (1) hide show
  1. dns-fix.js +36 -43
dns-fix.js CHANGED
@@ -14,14 +14,22 @@ function isBlocked(hostname) {
14
  const _origHttpRequest = http.request;
15
  const _origHttpsRequest = https.request;
16
 
17
- const { AsyncLocalStorage } = require("async_hooks");
18
- const asyncStorage = new AsyncLocalStorage();
 
 
 
 
 
 
 
 
 
 
 
 
19
 
20
  function transparentProxyRequest(protocol, origFn, ...args) {
21
- if (asyncStorage.getStore()) {
22
- return origFn.apply(this, args);
23
- }
24
-
25
  let options = args[0];
26
  let callback = args[1];
27
 
@@ -38,6 +46,11 @@ function transparentProxyRequest(protocol, origFn, ...args) {
38
  options = { ...options };
39
  }
40
 
 
 
 
 
 
41
  if (typeof callback !== "function" && typeof args[2] === "function") {
42
  callback = args[2];
43
  }
@@ -46,56 +59,36 @@ function transparentProxyRequest(protocol, origFn, ...args) {
46
  const path = options.path || options.pathname || "/";
47
 
48
  if (isBlocked(hostname)) {
49
- console.error(`[DNS-FIX] Transparently proxying ${protocol}//${hostname}${path} via fetch()`);
50
 
51
  const requestUrl = `${protocol}//${hostname}${path}`;
52
  const requestHeaders = { ...options.headers };
53
 
54
  const reqStream = new PassThrough();
55
- const resStream = new PassThrough();
56
 
57
  let requestBody = Buffer.alloc(0);
58
  reqStream.on("data", (chunk) => {
59
  requestBody = Buffer.concat([requestBody, chunk]);
60
  });
61
 
62
- reqStream.on("finish", () => {
63
- asyncStorage.run(true, async () => {
64
- try {
65
- const fetchRes = await fetch(requestUrl, {
66
- method: options.method || "GET",
67
- headers: requestHeaders,
68
- body: options.method !== "GET" && options.method !== "HEAD" ? requestBody : undefined,
69
- redirect: "manual",
70
- });
71
-
72
- resStream.statusCode = fetchRes.status;
73
- resStream.statusMessage = fetchRes.statusText;
74
- resStream.headers = Object.fromEntries(fetchRes.headers.entries());
75
- resStream.rawHeaders = [];
76
- for (const [k, v] of fetchRes.headers.entries()) {
77
- resStream.rawHeaders.push(k, v);
78
- }
79
-
80
- if (callback) callback(resStream);
81
- reqStream.emit("response", resStream);
82
-
83
- if (fetchRes.body) {
84
- const reader = fetchRes.body.getReader();
85
- while (true) {
86
- const { done, value } = await reader.read();
87
- if (done) break;
88
- resStream.write(value);
89
- }
90
- }
91
- resStream.end();
92
- } catch (err) {
93
- console.error(`[DNS-FIX] Proxy error for ${requestUrl}: ${err.message}`);
94
- reqStream.emit("error", err);
95
- }
96
- });
97
  });
98
 
 
99
  reqStream.abort = () => reqStream.destroy();
100
  reqStream.end = (chunk) => {
101
  if (chunk) reqStream.write(chunk);
 
14
  const _origHttpRequest = http.request;
15
  const _origHttpsRequest = https.request;
16
 
17
+ // Robust fetch-like wrapper using original (unpatched) http/https modules
18
+ function originalRequest(protocol, url, options, body) {
19
+ const parsedUrl = new URL(url);
20
+ const origFn = protocol === "https:" ? _origHttpsRequest : _origHttpRequest;
21
+
22
+ return new Promise((resolve, reject) => {
23
+ const req = origFn(parsedUrl, options, (res) => {
24
+ resolve(res);
25
+ });
26
+ req.on("error", reject);
27
+ if (body) req.write(body);
28
+ req.end();
29
+ });
30
+ }
31
 
32
  function transparentProxyRequest(protocol, origFn, ...args) {
 
 
 
 
33
  let options = args[0];
34
  let callback = args[1];
35
 
 
46
  options = { ...options };
47
  }
48
 
49
+ // RECURSION GUARD: Check for a custom property we'll set
50
+ if (options && options.__isProxyRequest) {
51
+ return origFn.apply(this, args);
52
+ }
53
+
54
  if (typeof callback !== "function" && typeof args[2] === "function") {
55
  callback = args[2];
56
  }
 
59
  const path = options.path || options.pathname || "/";
60
 
61
  if (isBlocked(hostname)) {
62
+ console.error(`[DNS-FIX] Transparently proxying ${protocol}//${hostname}${path}`);
63
 
64
  const requestUrl = `${protocol}//${hostname}${path}`;
65
  const requestHeaders = { ...options.headers };
66
 
67
  const reqStream = new PassThrough();
 
68
 
69
  let requestBody = Buffer.alloc(0);
70
  reqStream.on("data", (chunk) => {
71
  requestBody = Buffer.concat([requestBody, chunk]);
72
  });
73
 
74
+ reqStream.on("finish", async () => {
75
+ try {
76
+ const fetchRes = await originalRequest(protocol, requestUrl, {
77
+ method: options.method || "GET",
78
+ headers: requestHeaders,
79
+ __isProxyRequest: true, // Internal flag to prevent recursion
80
+ }, options.method !== "GET" && options.method !== "HEAD" ? requestBody : undefined);
81
+
82
+ if (callback) callback(fetchRes);
83
+ reqStream.emit("response", fetchRes);
84
+ // fetchRes is already an IncomingMessage (readable stream)
85
+ } catch (err) {
86
+ console.error(`[DNS-FIX] Proxy error for ${requestUrl}: ${err.message}`);
87
+ reqStream.emit("error", err);
88
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
89
  });
90
 
91
+ // Mock ClientRequest methods
92
  reqStream.abort = () => reqStream.destroy();
93
  reqStream.end = (chunk) => {
94
  if (chunk) reqStream.write(chunk);