File size: 4,557 Bytes
15f7aec |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 |
function proxyRequest({ url, proxy, method = 'GET', body = null, headers = {}, cookies = [], sessionHeaders = {} }) {
return new Promise(async (resolve, reject) => {
if (!url) return reject("Missing url parameter");
const context = await global.browser
.createBrowserContext({
proxyServer: proxy ? `http://${proxy.host}:${proxy.port}` : undefined,
})
.catch(() => null);
if (!context) return reject("Failed to create browser context");
let isResolved = false;
var cl = setTimeout(async () => {
if (!isResolved) {
await context.close();
reject("Timeout Error");
}
}, global.timeOut || 60000);
try {
const page = await context.newPage();
if (proxy?.username && proxy?.password)
await page.authenticate({
username: proxy.username,
password: proxy.password,
});
const targetUrl = new URL(url);
if (cookies && cookies.length > 0) {
const cookiesToSet = cookies.map(cookie => ({
name: cookie.name,
value: cookie.value,
domain: cookie.domain || targetUrl.hostname,
path: cookie.path || '/',
secure: cookie.secure !== undefined ? cookie.secure : targetUrl.protocol === 'https:',
httpOnly: cookie.httpOnly || false,
sameSite: cookie.sameSite || 'Lax'
}));
await page.setCookie(...cookiesToSet);
}
if (sessionHeaders && sessionHeaders['user-agent']) {
await page.setUserAgent(sessionHeaders['user-agent']);
}
const sanitizedHeaders = { ...headers };
const headersToRemove = ['host', 'content-length', 'connection', 'accept-encoding', 'transfer-encoding'];
headersToRemove.forEach(h => {
delete sanitizedHeaders[h];
delete sanitizedHeaders[h.toLowerCase()];
});
if (sessionHeaders) {
if (sessionHeaders['accept-language'] && !sanitizedHeaders['accept-language']) {
sanitizedHeaders['accept-language'] = sessionHeaders['accept-language'];
}
}
await page.goto(targetUrl.origin, { waitUntil: 'domcontentloaded', timeout: 30000 }).catch(() => {});
const result = await page.evaluate(async (options) => {
try {
const fetchOptions = {
method: options.method,
headers: options.headers || {},
credentials: 'include'
};
if (options.body && ['POST', 'PUT', 'PATCH'].includes(options.method.toUpperCase())) {
fetchOptions.body = typeof options.body === 'string'
? options.body
: JSON.stringify(options.body);
if (typeof options.body === 'object' && !fetchOptions.headers['content-type']) {
fetchOptions.headers['content-type'] = 'application/json';
}
}
const response = await fetch(options.url, fetchOptions);
const responseHeaders = {};
response.headers.forEach((value, key) => {
responseHeaders[key] = value;
});
let responseBody;
const contentType = response.headers.get('content-type') || '';
if (contentType.includes('application/json')) {
responseBody = await response.json();
} else {
responseBody = await response.text();
}
return {
status: response.status,
statusText: response.statusText,
headers: responseHeaders,
body: responseBody,
ok: response.ok
};
} catch (e) {
return { error: e.message };
}
}, { url, method, body, headers: sanitizedHeaders });
if (result.error) {
await context.close();
isResolved = true;
clearTimeout(cl);
return reject(result.error);
}
const updatedCookies = await page.cookies();
const browserHeaders = await page.evaluate(() => {
return {
'user-agent': navigator.userAgent,
'accept-language': navigator.language || navigator.languages.join(',')
};
});
await context.close();
isResolved = true;
clearInterval(cl);
resolve({
response: result,
cookies: updatedCookies,
browserHeaders
});
} catch (e) {
if (!isResolved) {
await context.close();
clearTimeout(cl);
reject(e.message);
}
}
});
}
module.exports = proxyRequest;
|