@luminati-io/luminati-proxy
Version:
A configurable local proxy for brightdata.com
204 lines (192 loc) • 7.33 kB
JavaScript
// LICENSE_CODE ZON ISC
; /*jslint node:true, browser:true*/
(function(){
var define;
var is_node_ff = typeof module=='object' && module.exports;
if (!is_node_ff)
define = self.define;
else
define = require('./require_node.js').define(module, '../');
define(['jquery', '/util/etask.js', '/util/date.js', '/util/escape.js',
'/util/zerr.js', 'events'],
function($, etask, date, zescape, zerr, events){
var assign = Object.assign;
var E = function(){ return E.send.apply(this, arguments); };
var fields_to_hide = ['password', 'new_pass'];
var hide_fields = function(data){
var _data = assign({}, data);
fields_to_hide.forEach(function(field){
if (_data[field])
_data[field] = _data[field].toString().replace(/./g, '*');
});
return _data;
};
function def_timeout(){
try {
if (window.location.hostname.match(/\.cn$/))
return 60*date.ms.SEC;
} catch(e){ /* nodejs */ }
return 20*date.ms.SEC;
}
E.send = function(opt){
var timeout = typeof opt.timeout=='number' ? opt.timeout : def_timeout();
var slow = opt.slow||2*date.ms.SEC;
var retry = opt.retry, data = opt.data, qs = zescape.qs(opt.qs,
opt.qs_opt);
var url = zescape.uri(opt.url, qs), perr = opt.perr;
// opt.type is deprecated
var method = opt.method||opt.type||'GET';
var data_type = opt.json ? 'json' : 'text';
var t0 = Date.now();
var ajopt, xhr, xhr_data;
zerr.debug('ajax('+data_type+') url '+url+' retry '+retry);
return etask([function(){
ajopt = {type: method, url: url, headers: assign({}, opt.headers),
dataType: data_type, data: data, timeout: timeout, xhrFields: {}};
if (opt.content_type)
ajopt.contentType = opt.content_type;
if (opt.with_credentials)
ajopt.xhrFields.withCredentials = true;
if (opt.onprogress)
ajopt.xhrFields.onprogress = opt.onprogress;
if (opt.onuploadprogress)
{
ajopt.xhr = function(){
var _xhr = $.ajaxSettings.xhr();
_xhr.upload.onprogress = opt.onuploadprogress;
return _xhr;
};
}
if (opt.multipart)
{
ajopt.contentType = false;
ajopt.processData = false;
delete ajopt.dataType;
}
if (opt.async!==undefined)
ajopt.async = opt.async;
E.ajopt_modifiers.forEach(function(modifier){
modifier(ajopt); });
xhr = $.ajax(ajopt);
var _this = this;
xhr.done(function(v){
if (opt.restore_dates && v && typeof v=='object')
zescape.restore_dates(v);
_this.continue(v);
});
xhr.fail(function(_xhr, status_text, err){
if (data_type=='json' && _xhr && _xhr.status==200 &&
['', 'ok', 'OK'].includes(_xhr.responseText))
{
_this.continue(null);
return;
}
if (!err && _xhr && _xhr.responseText && !_xhr.responseJSON)
err = _xhr.responseText;
if (!(err instanceof Error))
err = new Error(''+err);
xhr_data = get_res_data(xhr);
if (opt.restore_dates && xhr_data && typeof xhr_data=='object')
zescape.restore_dates(xhr_data);
err.xhr_info = {url: url, method: method, status: xhr.status,
data: xhr_data, response_text: xhr.responseText};
_this.throw(err);
});
return this.wait();
}, function catch$(err){
xhr = xhr||{};
var data_log = hide_fields(data);
var opt_log = assign({}, opt, {data: data_log});
zerr('ajax('+data_type+') failed url '+url+' data '+
zerr.json(data_log).substr(0, 200)+' status: '+xhr.status+' '+
xhr.statusText+'\nresponseText: '+
(xhr.responseText||'').substr(0, 200));
if (retry && (!opt.should_retry||opt.should_retry(err, xhr, ajopt)))
return this.return(E.send(assign({}, opt, {retry: retry-1})));
if (xhr.statusText=='timeout' && !opt.no_emit_err)
E.events.emit('timeout', this);
if (xhr.status==403 && !opt.no_emit_err)
{
if (typeof console!=='undefined' && console.error)
console.error('unauthorized debug '+JSON.stringify(opt_log));
E.events.emit('unauthorized', this, xhr);
}
if (xhr.status==406 && !opt.no_emit_err)
E.events.emit('maintenance', this, xhr);
if (xhr.status==500 && !opt.no_emit_err)
E.events.emit('unhandledException', this, xhr);
if (opt.no_throw)
{
return {
err: err,
url: url,
method: method,
status: +xhr.status || 0,
data: xhr_data,
xhr: xhr,
// legacy
error: xhr.statusText||'no_status', message: xhr.responseText,
};
}
err.x_error = xhr.getResponseHeader('X-Luminati-Error') ||
xhr.getResponseHeader('X-Hola-Error');
throw err;
}, function(_data){
var res, t = Date.now()-t0;
zerr[t>slow ? 'err' : 'debug'](
'ajax('+data_type+') '+(t>slow ? 'SLOW ' : 'ok ')+t+'ms url '+url);
if (t>slow && perr)
perr({id: 'be_ajax_slow', info: t+'ms '+url});
if (E.do_op)
E.do_op(_data&&_data.do_op);
if (Array.isArray(opt.return_headers))
{
res = {
data: _data,
headers: opt.return_headers.reduce(function(obj, h){
obj[h] = xhr.getResponseHeader(h);
return obj;
}, {}),
};
}
else
res = _data;
return this.return(res);
}, function abort(){
// reachable only via E.abort
xhr.abort();
if (opt.abort_value)
return opt.abort_value;
}]);
};
E.abort = function(aj){ aj.goto('abort'); };
['GET', 'POST', 'PUT', 'DELETE'].forEach(function(m){
E[m.toLowerCase()] = function(url, params, opt){
url = typeof url=='string' ? {url: url} : url;
var send_opt = assign({method: m, json: 1}, url, params, opt);
if (!{get: 1, delete: 1}[send_opt.method.toLowerCase()]
&& send_opt.data!=null && typeof send_opt.data!='string')
{
send_opt.content_type = send_opt.content_type||'application/json';
if (send_opt.content_type.startsWith('application/json'))
send_opt.data = JSON.stringify(send_opt.data);
}
return E.send(send_opt);
};
});
E.json = function(opt){ return E.send(assign({}, opt, {json: 1})); };
E.events = new events.EventEmitter();
E.ajopt_modifiers = [];
// -- internal utils ---
function get_res_data(xhr){
if (xhr.responseJSON!=null && xhr.responseJSON!=='')
return xhr.responseJSON;
var content_type = xhr.getResponseHeader('content-type')||'';
if (xhr.responseText && content_type.includes('application/json'))
{
try { return JSON.parse(xhr.responseText); }
catch(e){ }
}
return xhr.responseText||'';
}
return E; }); }());