{"version":3,"file":"parse-proxy-response.js","sources":["../../../src/proxy/parse-proxy-response.ts"],"sourcesContent":["/**\n * This code was originally forked from https://github.com/TooTallNate/proxy-agents/tree/b133295fd16f6475578b6b15bd9b4e33ecb0d0b7\n * With the following LICENSE:\n *\n * (The MIT License)\n *\n * Copyright (c) 2013 Nathan Rajlich *\n *\n * Permission is hereby granted, free of charge, to any person obtaining\n * a copy of this software and associated documentation files (the\n * 'Software'), to deal in the Software without restriction, including\n * without limitation the rights to use, copy, modify, merge, publish,\n * distribute, sublicense, and/or sell copies of the Software, and to\n * permit persons to whom the Software is furnished to do so, subject to\n * the following conditions:*\n *\n * The above copyright notice and this permission notice shall be\n * included in all copies or substantial portions of the Software.*\n *\n * THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,\n * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\n * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\n * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\n * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\n/* eslint-disable @typescript-eslint/explicit-function-return-type */\n/* eslint-disable jsdoc/require-jsdoc */\nimport type { IncomingHttpHeaders } from 'node:http';\nimport type { Readable } from 'node:stream';\nimport { logger } from '@sentry/utils';\n\nfunction debug(...args: unknown[]): void {\n logger.log('[https-proxy-agent:parse-proxy-response]', ...args);\n}\n\nexport interface ConnectResponse {\n statusCode: number;\n statusText: string;\n headers: IncomingHttpHeaders;\n}\n\nexport function parseProxyResponse(socket: Readable): Promise<{ connect: ConnectResponse; buffered: Buffer }> {\n return new Promise((resolve, reject) => {\n // we need to buffer any HTTP traffic that happens with the proxy before we get\n // the CONNECT response, so that if the response is anything other than an \"200\"\n // response code, then we can re-play the \"data\" events on the socket once the\n // HTTP parser is hooked up...\n let buffersLength = 0;\n const buffers: Buffer[] = [];\n\n function read() {\n const b = socket.read();\n if (b) ondata(b);\n else socket.once('readable', read);\n }\n\n function cleanup() {\n socket.removeListener('end', onend);\n socket.removeListener('error', onerror);\n socket.removeListener('readable', read);\n }\n\n function onend() {\n cleanup();\n debug('onend');\n reject(new Error('Proxy connection ended before receiving CONNECT response'));\n }\n\n function onerror(err: Error) {\n cleanup();\n debug('onerror %o', err);\n reject(err);\n }\n\n function ondata(b: Buffer) {\n buffers.push(b);\n buffersLength += b.length;\n\n const buffered = Buffer.concat(buffers, buffersLength);\n const endOfHeaders = buffered.indexOf('\\r\\n\\r\\n');\n\n if (endOfHeaders === -1) {\n // keep buffering\n debug('have not received end of HTTP headers yet...');\n read();\n return;\n }\n\n const headerParts = buffered.slice(0, endOfHeaders).toString('ascii').split('\\r\\n');\n const firstLine = headerParts.shift();\n if (!firstLine) {\n socket.destroy();\n return reject(new Error('No header received from proxy CONNECT response'));\n }\n const firstLineParts = firstLine.split(' ');\n const statusCode = +(firstLineParts[1] || 0);\n const statusText = firstLineParts.slice(2).join(' ');\n const headers: IncomingHttpHeaders = {};\n for (const header of headerParts) {\n if (!header) continue;\n const firstColon = header.indexOf(':');\n if (firstColon === -1) {\n socket.destroy();\n return reject(new Error(`Invalid header from proxy CONNECT response: \"${header}\"`));\n }\n const key = header.slice(0, firstColon).toLowerCase();\n const value = header.slice(firstColon + 1).trimStart();\n const current = headers[key];\n if (typeof current === 'string') {\n headers[key] = [current, value];\n } else if (Array.isArray(current)) {\n current.push(value);\n } else {\n headers[key] = value;\n }\n }\n debug('got proxy server response: %o %o', firstLine, headers);\n cleanup();\n resolve({\n connect: {\n statusCode,\n statusText,\n headers,\n },\n buffered,\n });\n }\n\n socket.on('error', onerror);\n socket.on('end', onend);\n\n read();\n });\n}\n"],"names":[],"mappings":"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"}