UNPKG

astro-perp-ccxt-dev

Version:

A JavaScript / TypeScript / Python / C# / PHP cryptocurrency trading library with support for 100+ exchanges

269 lines (259 loc) 10.4 kB
'use strict'; var net = require('net'); var tls = require('tls'); var assert = require('assert'); var index = require('./index-7L_QOoQw.js'); require('http'); require('https'); function _interopNamespaceDefault(e) { var n = Object.create(null); if (e) { Object.keys(e).forEach(function (k) { if (k !== 'default') { var d = Object.getOwnPropertyDescriptor(e, k); Object.defineProperty(n, k, d.get ? d : { enumerable: true, get: function () { return e[k]; } }); } }); } n.default = e; return Object.freeze(n); } var net__namespace = /*#__PURE__*/_interopNamespaceDefault(net); var tls__namespace = /*#__PURE__*/_interopNamespaceDefault(tls); // ---------------------------------------------------------------------------- // PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN: // https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code // EDIT THE CORRESPONDENT .ts FILE INSTEAD function parseProxyResponse(socket) { return new Promise((resolve, reject) => { // we need to buffer any HTTP traffic that happens with the proxy before we get // the CONNECT response, so that if the response is anything other than an "200" // response code, then we can re-play the "data" events on the socket once the // HTTP parser is hooked up... let buffersLength = 0; const buffers = []; function read() { const b = socket.read(); if (b) ondata(b); else socket.once('readable', read); } function cleanup() { socket.removeListener('end', onend); socket.removeListener('error', onerror); socket.removeListener('close', onclose); socket.removeListener('readable', read); } function onclose(err) { // debug('onclose had error %o', err); } function onend() { // debug('onend'); } function onerror(err) { cleanup(); // debug('onerror %o', err); reject(err); } function ondata(b) { buffers.push(b); buffersLength += b.length; const buffered = Buffer.concat(buffers, buffersLength); const endOfHeaders = buffered.indexOf('\r\n\r\n'); if (endOfHeaders === -1) { // keep buffering // debug('have not received end of HTTP headers yet...'); read(); return; } const headerParts = buffered.toString('ascii').split('\r\n'); const firstLine = headerParts.shift(); if (!firstLine) { throw new Error('No header received'); } const firstLineParts = firstLine.split(' '); const statusCode = +firstLineParts[1]; const statusText = firstLineParts.slice(2).join(' '); const headers = {}; for (const header of headerParts) { if (!header) continue; const firstColon = header.indexOf(':'); if (firstColon === -1) { throw new Error(`Invalid header: "${header}"`); } const key = header.slice(0, firstColon).toLowerCase(); const value = header.slice(firstColon + 1).trimStart(); const current = headers[key]; if (typeof current === 'string') { headers[key] = [current, value]; } else if (Array.isArray(current)) { current.push(value); } else { headers[key] = value; } } // debug('got proxy server response: %o', firstLine); cleanup(); resolve({ connect: { statusCode, statusText, headers, }, buffered, }); } socket.on('error', onerror); socket.on('close', onclose); socket.on('end', onend); read(); }); } // ---------------------------------------------------------------------------- /** * The `HttpsProxyAgent` implements an HTTP Agent subclass that connects to * the specified "HTTP(s) proxy server" in order to proxy HTTPS requests. * * Outgoing HTTP requests are first tunneled through the proxy server using the * `CONNECT` HTTP request method to establish a connection to the proxy server, * and then the proxy server connects to the destination target and issues the * HTTP request from the proxy server. * * `https:` requests have their socket connection upgraded to TLS once * the connection to the proxy server has been established. */ class HttpsProxyAgent extends index.Agent { constructor(proxy, opts) { super(opts); this.options = { path: undefined }; this.proxy = typeof proxy === 'string' ? new URL(proxy) : proxy; this.proxyHeaders = opts?.headers ?? {}; // debug('Creating new HttpsProxyAgent instance: %o', this.proxy.href); // Trim off the brackets from IPv6 addresses const host = (this.proxy.hostname || this.proxy.host).replace(/^\[|\]$/g, ''); const port = this.proxy.port ? parseInt(this.proxy.port, 10) : this.secureProxy ? 443 : 80; this.connectOpts = { // Attempt to negotiate http/1.1 for proxy servers that support http/2 ALPNProtocols: ['http/1.1'], ...(opts ? omit(opts, 'headers') : null), host, port, }; } get secureProxy() { return isHTTPS(this.proxy.protocol); } /** * Called when the node-core HTTP client library is creating a * new HTTP request. */ async connect(req, opts) { const { proxy, secureProxy } = this; if (!opts.host) { throw new TypeError('No "host" provided'); } // Create a socket connection to the proxy server. let socket; if (secureProxy) { // debug('Creating `tls.Socket`: %o', this.connectOpts); socket = tls__namespace.connect(this.connectOpts); } else { // debug('Creating `net.Socket`: %o', this.connectOpts); socket = net__namespace.connect(this.connectOpts); } const headers = typeof this.proxyHeaders === 'function' ? this.proxyHeaders() : { ...this.proxyHeaders }; const host = net__namespace.isIPv6(opts.host) ? `[${opts.host}]` : opts.host; let payload = `CONNECT ${host}:${opts.port} HTTP/1.1\r\n`; // Inject the `Proxy-Authorization` header if necessary. if (proxy.username || proxy.password) { const auth = `${decodeURIComponent(proxy.username)}:${decodeURIComponent(proxy.password)}`; headers['Proxy-Authorization'] = `Basic ${Buffer.from(auth).toString('base64')}`; } headers.Host = `${host}:${opts.port}`; if (!headers['Proxy-Connection']) { headers['Proxy-Connection'] = this.keepAlive ? 'Keep-Alive' : 'close'; } for (const name of Object.keys(headers)) { payload += `${name}: ${headers[name]}\r\n`; } const proxyResponsePromise = parseProxyResponse(socket); socket.write(`${payload}\r\n`); const { connect, buffered } = await proxyResponsePromise; req.emit('proxyConnect', connect); // @ts-ignore this.emit('proxyConnect', connect, req); if (connect.statusCode === 200) { req.once('socket', resume); if (opts.secureEndpoint) { // The proxy is connecting to a TLS server, so upgrade // this socket connection to a TLS connection. // debug('Upgrading socket connection to TLS'); const servername = opts.servername || opts.host; return tls__namespace.connect({ ...omit(opts, 'host', 'path', 'port'), socket, servername: net__namespace.isIP(servername) ? undefined : servername, }); } return socket; } // Some other status code that's not 200... need to re-play the HTTP // header "data" events onto the socket once the HTTP machinery is // attached so that the node core `http` can parse and handle the // error status code. // Close the original socket, and a new "fake" socket is returned // instead, so that the proxy doesn't get the HTTP request // written to it (which may contain `Authorization` headers or other // sensitive data). // // See: https://hackerone.com/reports/541502 socket.destroy(); const fakeSocket = new net__namespace.Socket({ writable: false }); fakeSocket.readable = true; // Need to wait for the "socket" event to re-play the "data" events. req.once('socket', (s) => { // debug('Replaying proxy buffer for failed request'); assert(s.listenerCount('data') > 0); // Replay the "buffered" Buffer onto the fake `socket`, since at // this point the HTTP module machinery has been hooked up for // the user. s.push(buffered); s.push(null); }); return fakeSocket; } } HttpsProxyAgent.protocols = ['http', 'https']; function resume(socket) { socket.resume(); } function isHTTPS(protocol) { return typeof protocol === 'string' ? /^https:?$/i.test(protocol) : false; } function omit(obj, ...keys) { const ret = {}; let key; for (key in obj) { if (!keys.includes(key)) { ret[key] = obj[key]; } } return ret; } exports.HttpsProxyAgent = HttpsProxyAgent;