@luminati-io/luminati-proxy
Version:
A configurable local proxy for brightdata.com
111 lines (101 loc) • 3.68 kB
JavaScript
// LICENSE_CODE ZON ISC
; /*jslint node:true, esnext: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} = require('./util.js');
const E = module.exports;
const https_servername = 'brd.superproxy.io';
const secure_protocol = 'TLSv1_2_method';
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,
secureProtocol: secure_protocol,
}, 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),
secureProtocol: secure_protocol,
});
request.on('connect', (res, socket, head)=>task.spawn(etask(
function*_on_custom_tls_connect(){
this.alarm(60*date.ms.SEC, {throw: new Error('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)
tls_connect = require('../../svc/unblocker/agent/client.js').tls_connect;
const et_tls_socket = tls_connect({
host: ctx.domain,
socket,
use_flex_tls: 1,
http1: true,
ignore_throw_on_close: 1,
});
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,
});
}
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,
});
}
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};