@luminati-io/luminati-proxy
Version:
A configurable local proxy for brightdata.com
125 lines (115 loc) • 4.06 kB
JavaScript
// LICENSE_CODE ZON ISC
; /*jslint node:true, esnext:true es9:true*/
const http = require('http');
const https = require('https');
const etask = require('../util/etask.js');
const date = require('../util/date.js');
const Https_agent = require('./https_agent.js');
const {get_host_port, alarm_throw_msg} = require('./util.js');
const {MIN_TLS} = require('./consts.js');
const E = module.exports;
const https_servername = 'brd.superproxy.io';
let tls_connect;
E.create_requester = opt=>{
if (opt.proxy_connection_type=='https')
return new Https_requester();
return new Http_requester();
};
function http_request(lib){
return function _http_request(ctx, opt){
return lib.request(Object.assign({
host: ctx.host,
port: ctx.proxy_port,
agent: this.agent,
minVersion: MIN_TLS,
}, opt));
};
}
function*request_socket(_this, parent_task, ctx, opt){
const task = this;
const port = isNaN(ctx.domain_port) ? 443 : ctx.domain_port;
const request = _this.request(ctx, {
method: 'CONNECT',
path: ctx.domain+':'+port,
headers: ctx.format_headers(ctx.connect_headers),
rejectUnauthorized: false,
// option passed down to https_agent
lpm_username: ctx.cred.username,
host_port: get_host_port(ctx),
minVersion: MIN_TLS,
});
request.on('connect', (res, socket, head)=>task.spawn(etask(
function*_on_custom_tls_connect(){
alarm_throw_msg(this, 60*date.ms.SEC, 'tls connect timeout');
this.finally(()=>{
et_tls_socket.return();
});
this.on('uncaught', opt.on_error);
ctx.timeline.track('connect');
// no reason to try flex if proxy returned error
if (!opt.use_flex_tls || res.statusCode!=200)
return task.continue({res, socket, head});
if (!tls_connect)
{
const flex_tls = require('../../svc/flex_tls/flex_tls.js');
tls_connect = flex_tls.connect;
}
const et_tls_socket = tls_connect({
host: ctx.domain,
socket,
http1: true,
min_tls: MIN_TLS,
ignore_throw_on_close: true,
...opt.flex_tls_reject_unauthorized===true&&{
reject_unauthorized: false,
},
});
const flex_tls_socket = yield et_tls_socket;
parent_task.once('cancel', ()=>flex_tls_socket.destroy());
flex_tls_socket.once('error', opt.on_flex_tls_err);
const conn_socket = flex_tls_socket.socket;
conn_socket.once('agentRemove', ()=>{
flex_tls_socket.emit('agentRemove');
});
conn_socket.once('close', ()=>{
flex_tls_socket.unpipe();
flex_tls_socket.end();
flex_tls_socket.emit('agentRemove');
flex_tls_socket.off('error', opt.on_flex_tls_err);
});
return task.continue({res, socket: flex_tls_socket, head});
})));
request.on('error', opt.on_error).end();
return yield this.wait();
}
function destroy_agents(){
this.agent.destroy();
}
function Https_requester(){
this.agent = new Https_agent({
keepAlive: true,
keepAliveMsecs: 5000,
servername: https_servername,
maxCachedSessions: 1000,
minVersion: MIN_TLS,
maxSockets: 100,
maxFreeSockets: 100,
timeout: 30000,
});
}
Https_requester.prototype.request_socket = etask._fn(request_socket);
Https_requester.prototype.request = http_request(https);
Https_requester.prototype.stop = destroy_agents;
function Http_requester(){
this.agent = new http.Agent({
keepAlive: true,
keepAliveMsecs: 5000,
maxSockets: 100,
maxFreeSockets: 100,
timeout: 30000,
});
}
Http_requester.prototype.request_socket = etask._fn(request_socket);
Http_requester.prototype.request = http_request(http);
Http_requester.prototype.stop = destroy_agents;
E.t = {Http_requester, Https_requester};