| 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; | |