@luminati-io/luminati-proxy
Version:
A configurable local proxy for luminati.io
621 lines (587 loc) • 18.5 kB
JavaScript
// LICENSE_CODE ZON ISC
; /*jslint node:true, browser:true*//*global Map*/
(function(){
var define, hash, assert, zerr, vm;
var is_node = typeof module=='object' && module.exports && module.children;
var is_rn = typeof global=='object' && !!global.nativeRequire ||
typeof navigator=='object' && navigator.product=='ReactNative';
if (!is_node)
{
if (is_rn)
{
define = require('./require_node.js').define(module, '../',
require('/util/util.js'));
}
else
define = self.define;
assert = function(){}; // XXX romank: add proper assert
// XXX romank: use zerr.js
if (!is_rn && self.hola && self.hola.zerr)
zerr = self.hola.zerr;
else
{
// IE8 does not support console.log.bind(console)
zerr = function(){ console.log.apply(console, arguments); };
zerr.perr = zerr;
}
}
else
{
require('./config.js');
zerr = require('./zerr.js');
hash = require('crypto');
assert = require('assert');
vm = require('vm');
define = require('./require_node.js').define(module, '../');
}
define(['/util/util.js'], function(zutil){
var E = {};
var has_map = typeof Map=='function' && Map.prototype.get && Map.prototype.set;
has_map = 0; // XXX: unit-test and remove
E.cache_str_map_fn = function(fn){
var cache = new Map();
return function(s){
s = ''+s;
var v = cache.get(s);
if (v!==undefined || cache.has(s))
return v;
cache.set(s, v = fn(s));
return v;
};
};
E.cache_str_obj_fn = function(fn){
var cache = {};
return function(s){
if (s in cache)
return cache[s];
return cache[s] = fn(s);
};
};
E.cache_str_fn = has_map ? E.cache_str_map_fn : E.cache_str_obj_fn;
E.cache_str_fn2 = function(fn){
var cache = {};
return function(s1, s2){
var cache2 = cache[s1] = cache[s1]||{};
if (s2 in cache2)
return cache2[s2];
return cache2[s2] = fn(s1, s2);
};
};
E.o = function(oct_str){ return parseInt(oct_str, 8); };
// XXX vladimir: only nodejs
E.hash = function(buf, hash_len, encoding, type){
type = type||'sha256';
// update() ignores encoding if buf is a Buffer
return hash.createHash(type).update(buf, encoding||'utf8')
.digest('hex').slice(0, hash_len);
};
E.md5 = function(buf, hash_len, encoding){
return E.hash(buf, hash_len, encoding, 'md5');
};
E.md5_zero = function(key, hash_len){
assert(hash_len<=32, 'invalid hash len'+hash_len);
if (!key || !key.length)
return '0'.repeat(hash_len);
return E.md5(key, hash_len);
};
E.md5_etag = function(buf){ return E.md5(buf, 8); };
E.inet_ntoa_t = function(ip){
return ((ip & 0xff000000)>>>24)+'.'+((ip & 0xff0000)>>>16)+'.'
+((ip & 0xff00)>>>8)+'.'+(ip & 0xff);
};
E.inet_addr = function(ip){
var code, res = 0, shift = 24, num = undefined;
ip = ''+ip;
for (var i = 0, l = ip.length; i < l; ++i)
{
code = ip.charCodeAt(i);
if (code>47&&code<58)
{
num = (num||0)*10+code-48;
continue;
}
if (code==46)
{
if (num==undefined||num>255)
return null;
res += num<<shift;
num = undefined;
shift -= 8;
continue;
}
return null;
}
return shift==0 && num!=undefined && num<256 ? res+(num|0)>>>0 : null;
};
function flags_to_str_once(flags, conv){
var f = 'var s = "";\n';
f += 'if (!flags) return "";\n';
for (var i in conv)
{
if (!conv.hasOwnProperty(i))
continue;
f += 'if (flags & '+conv[i]+') '
+'{ s += '+JSON.stringify(i.toLowerCase())+'+" "; '
+'flags &= ~'+conv[i]+'; }\n';
}
f += 'if (flags && conv.__conv_to_str.err) '
+'conv.__conv_to_str.err(flags, conv);\n';
f += 'return s.slice(0, -1);\n';
var func = new Function(['flags', 'conv'], f);
Object.defineProperty(conv, '__conv_to_str',
{enumerable: false, writable: true});
conv.__conv_to_str = func;
func.err = function(_flags, _conv){
zerr.perr('flags_str_invalid', 'flags '+_flags+' '
+JSON.stringify(_conv).slice(0, 30));
};
return conv.__conv_to_str(flags, conv);
}
E.flags_to_str = function(flags, conv){
if (conv.__conv_to_str)
return conv.__conv_to_str(flags, conv);
return flags_to_str_once(flags, conv);
};
function flags_from_str_once(s, conv){
var f = 'var flags = 0, a, i;\n';
f += 'if (!s) return 0;\n';
f += 's = s.toUpperCase();\n';
f += 'a = s.split(",");\n';
f += 'for (i=0; i<a.length; i++)\n';
f += '{\n';
f += ' if (!conv[a[i]])\n';
f += ' {\n';
f += ' if (flags && conv.__conv_from_str.err) '
+'conv.__conv_from_str.err(flags, conv);\n';
f += ' return -1;\n';
f += ' }\n';
f += ' flags |= conv[a[i]];\n';
f += '}\n';
f += 'return flags;\n';
var func = new Function(['s', 'conv'], f);
Object.defineProperty(conv, '__conv_from_str',
{enumerable: false, writable: true});
conv.__conv_from_str = func;
func.err = function(_s, _conv){
zerr.perr('flags_str_invalid', 'flags '+_s+' '
+JSON.stringify(_conv).slice(0, 30));
};
return conv.__conv_from_str(s, conv);
}
E.flags_from_str = function(s, conv){
if (conv.__conv_from_str)
return conv.__conv_from_str(s, conv);
return flags_from_str_once(s, conv);
};
E.scale_vals = {
1000: [{s: '', n: 1}, {s: 'K', n: 1e3}, {s: 'M', n: 1e6},
{s: 'G', n: 1e9}, {s: 'T', n: 1e12}, {s: 'P', n: 1e15}],
1024: [{s: '', n: 1}, {s: 'K', n: 1024}, {s: 'M', n: Math.pow(1024, 2)},
{s: 'G', n: Math.pow(1024, 3)}, {s: 'T', n: Math.pow(1024, 4)},
{s: 'P', n: Math.pow(1024, 5)}],
};
E.scaled_number = function(num, opt){
opt = opt||{};
var sign = '', per = opt.per, scale = opt.scale;
var base = opt.base==1024 ? 1024 : 1000, ratio = opt.ratio||1;
var units = opt.units===undefined||opt.units;
function _per(){ return per ? E.fmt_per(per) : ''; }
if (num<0)
{
sign = '-';
num = -num;
}
if (num===undefined)
return '';
if (isNaN(num))
return opt.nan||'x';
if (num==Infinity)
return sign+'\u221e';
var scale_vals = E.scale_vals[base], i = 0;
if (scale==null)
for (; i<scale_vals.length-1 && num>=scale_vals[i+1].n*ratio; i++);
else
i = scale_vals.findIndex(function(_scale){ return _scale.s==scale; });
if (per=='ms' && i)
{
per = 's';
i--;
num = num/1000;
}
scale = scale_vals[i];
if (opt.is_scale)
return scale.n;
num /= scale.n;
if (num<0.001)
return '0'+_per();
if (num>=base-1)
num = Math.trunc(num);
var str = num.toFixed(opt.decimals!=null ? opt.decimals
: num<1 ? 3 : num<10 ? 2 : num<100 ? 1 : 0);
return sign+str.replace(/((\.\d*[1-9])|\.)0*$/, '$2')
+(units ? (opt.space ? ' ' : '')+scale.s : '')+_per();
};
E.scaled_bytes = function(num, opt){
return E.scaled_number(num, Object.assign({base: 1000}, opt)); };
E.fmt_currency = function(amount, digits, currency_sign){
if (amount===undefined)
return;
if (digits===undefined)
digits = 2;
if (currency_sign===undefined)
currency_sign = '$';
var sign = amount<0 ? '-' : '';
amount = Math.abs(amount);
amount = (+amount).toLocaleString('en-GB', {useGrouping: true,
maximumFractionDigits: digits})||amount;
return sign+currency_sign+amount;
};
E.fmt_per = function(per){
if (!per)
return '';
switch (per)
{
case 's': case 'ms': return per;
case '%': case '%%': return '%';
default: return '/'+per[0];
}
};
// Takes a function or its string serialization (f.toString()), returns object:
// name: declared name or null
// args: array of declared argument names
// body: function body excluding the outermost braces
// XXX: when necessary, add support for comments inside argument list,
// arrow functions, generator functions, rest parameters, default parameters,
// destructuring parameters
E.parse_function = function(f){
var m = /^function\s*([\w$]+)?\s*\(\n?([\s\w$,]*?)(\s*\/\*`*\*\/)?\)\s*\{\n?([\s\S]*?)\n?\}$/
.exec(f);
return {
name: m[1]||null,
args: m[2] ? m[2].split(/\s*,\s*/) : [],
body: m[4],
};
};
function date_stringify(d){ return {__ISODate__: d.toISOString()}; }
var pos_inf = {__Infinity__: 1};
var neg_inf = {__Infinity__: -1};
function replace_inf(k, v){
switch (v)
{
case Infinity: return pos_inf;
case -Infinity: return neg_inf;
default: return v;
}
}
E.JSON_stringify = function(obj, opt){
var s, prev_date, _date, prev_func, prev_re;
var date_class, func_class, re_class;
opt = opt||{};
if (opt.date)
_date = typeof opt.date=='function' ? opt.date : date_stringify;
if (opt.mongo||opt.mongoku)
_date = date_stringify;
if (_date)
{
date_class = opt.vm_context ?
vm.runInContext('Date', opt.vm_context) : Date;
prev_date = date_class.prototype.toJSON;
date_class.prototype.toJSON = function(){ return _date(this); };
}
if (opt.func)
{
func_class = opt.vm_context ?
vm.runInContext('Function', opt.vm_context) : Function;
prev_func = func_class.prototype.toJSON;
func_class.prototype.toJSON = function(){
return {__Function__: this.toString()}; };
}
if (opt.re)
{
re_class = opt.vm_context ?
vm.runInContext('RegExp', opt.vm_context) : RegExp;
prev_re = re_class.prototype.toJSON;
Object.defineProperty(re_class.prototype, 'toJSON', {
value: function(){ return {__RegExp__: this.toString()}; },
writable: true,
});
}
var opt_replacer = opt.replacer;
var replacer = opt_replacer;
if (opt.inf)
{
if (opt_replacer && typeof opt_replacer=='function')
{
replacer = function(k, v){
if (this==pos_inf || this==neg_inf)
return v;
// http://es5.github.io/#x15.12.3 replacer.call(this, k, v)
return opt_replacer.call(this, k,
replace_inf.call(this, k, v));
};
}
else if (opt_replacer && Array.isArray(opt_replacer))
{
replacer = function(k, v){
// when replacer is an array - original object SHOULD be kept
if (v==obj || this==pos_inf || this==neg_inf)
return v;
if (opt_replacer.includes(k))
return replace_inf.call(this, k, v);
};
}
else
replacer = replace_inf;
}
if (opt.circular)
{
var ignore_circular = opt.circular=='ignore';
var orig_replacer = replacer, keys, objects, stack;
replacer = function(k, v){
if (!k)
{
keys = [];
stack = [];
objects = [{keys: '', value: v}];
return orig_replacer ? orig_replacer.call(this, k, v) : v;
}
while (stack.length && this!==stack[0])
{
stack.shift();
keys.pop();
}
var found;
for (var i = 0; i<objects.length; i++)
{
if (objects[i].value===v)
{
found = objects[i];
break;
}
}
if (!found)
{
keys.push(k);
stack.unshift(v);
objects.push({keys: keys.join('.'), value: v});
return orig_replacer ? orig_replacer.call(this, k, v) : v;
}
if (!ignore_circular)
return {__Ref__: found.keys};
};
}
try { s = JSON.stringify(obj, replacer, opt.spaces); }
finally {
if (_date)
date_class.prototype.toJSON = prev_date;
if (opt.func)
func_class.prototype.toJSON = prev_func;
if (opt.re)
re_class.prototype.toJSON = prev_re;
}
if (opt.mongo||opt.mongoku)
{
s = s.replace(/\{"__ISODate__":("[0-9TZ:.-]+")\}/g,
opt.mongoku ? 'Date($1)' : 'ISODate($1)');
}
return s;
};
function parse_leaf(v, opt){
if (!v || typeof v!='object' || Object.keys(v).length!=1)
return v;
if (v.__ISODate__ && opt.date)
return new Date(v.__ISODate__);
if (v.__Function__ && opt.func)
{
if (vm)
return vm.runInThisContext('"use strict";('+v.__Function__+')');
// fallback for browser environment
return new Function('', '"use strict";return ('+v.__Function__+');')();
}
if (v.__RegExp__ && opt.re)
{
var parsed = /^\/(.*)\/(\w*)$/.exec(v.__RegExp__);
if (!parsed)
throw new Error('failed parsing regexp');
return new RegExp(parsed[1], parsed[2]);
}
if (v.__Infinity__ && opt.inf)
return v.__Infinity__ < 0 ? -Infinity : Infinity;
if (v.__ObjectId__ && typeof opt.object_id=='function')
return opt.object_id(v.__ObjectId__);
return v;
}
function parse_obj(v, opt){
if (!v || typeof v!='object')
return v;
if (Array.isArray(v))
{
for (var i = 0; i<v.length; i++)
v[i] = parse_obj(v[i], opt);
return v;
}
var v2 = parse_leaf(v, opt);
if (v2!==v)
return v2;
for (var key in v)
v[key] = parse_obj(v[key], opt);
return v;
}
function traverse_obj(obj, key, parent, cb){
cb(obj, key, parent);
if (!obj || typeof obj!='object')
return;
for (var k in obj)
traverse_obj(obj[k], k, obj, cb);
}
function deref_obj(obj){
traverse_obj(obj, null, null, function(v, key, parent){
if (v && typeof v.__Ref__=='string')
parent[key] = zutil.get(obj, v.__Ref__);
});
}
E.JSON_parse = function(s, opt){
opt = Object.assign({date: true, re: true, func: true, inf: true,
circular: true}, opt);
var has_circular;
var ret = JSON.parse(s, function(k, v){
v = parse_leaf(v, opt);
if (v && typeof v.__Ref__=='string')
has_circular = true;
return v;
});
if (has_circular && opt.circular)
deref_obj(ret);
return ret;
};
E.JSON_parse_obj = function(v, opt){
opt = Object.assign({date: true, re: true, func: true, inf: true}, opt);
return parse_obj(v, opt);
};
E.hex2bin = function(hex, opt){
var byte_array = opt && opt.byte_array;
var bin = byte_array ? new Uint8Array() : [];
var re = /('.)|([0-9a-f][0-9a-f]?)|\s+|[.-]|(.)/gi;
var m, v;
for (re.lastIndex = 0; m = re.exec(hex);)
{
if (m[1])
v = m[1].charCodeAt(1);
else if (m[2])
v = parseInt(m[2], 16);
else if (m[3])
return null; // throw new Error('invalid hex code');
else
continue;
bin.push(v);
}
return bin;
};
E.bin2hex = function(arr){
var s = '', v, i;
for (i=0; i<arr.length; i++)
{
v = (arr[i]&0xff).toString(16).toUpperCase();
s += (v.length<2 ? '0' : '')+v+' ';
}
return s.trim();
};
E.str2bin = function(s, offset){
var len;
if (!s || !(len = s.length))
return;
offset = offset||0;
var arr = new Uint8Array(len-offset);
for (var i=offset, j=0; i<len; i++, j++)
arr[j] = s.charCodeAt(i);
return arr;
};
E.tab2sp = function(line){
var added = 0;
return line.replace(/\t/g, function(m, offset, str){
var insert = 8-(added+offset)%8;
added += insert-1;
return ' '.repeat(insert);
});
};
E.str2utf8bin = function(s){
if (!s||!s.length)
return;
var arr = new Uint8Array(s.length*3);
var len = s.length, i = 0, j = 0, c, extra;
while (i<len)
{
c = s.charCodeAt(i++);
if (c >= 0xD800 && c <= 0xDBFF && i < len)
{
extra = s.charCodeAt(i++);
if ((extra & 0xFC00) == 0xDC00)
c = ((c & 0x3FF) << 10) + (extra & 0x3FF) + 0x10000;
else
i--;
}
if ((c & 0xFFFFFF80) == 0)
arr[j++] = c;
else
{
if ((c & 0xFFFFF800) == 0)
arr[j++] = c >> 6 & 0x1F | 0xC0;
else if ((c & 0xFFFF0000) == 0)
{
arr[j++] = c >> 12 & 0x0F | 0xE0;
arr[j++] = c >> 6 & 0x3F | 0x80;
}
else if ((c & 0xFFE00000) == 0)
{
arr[j++] = c >> 18 & 0x07 | 0xF0;
arr[j++] = c >> 12 & 0x3F | 0x80;
arr[j++] = c >> 6 & 0x3F | 0x80;
}
arr[j++] = c & 0x3F | 0x80;
}
}
return arr.slice(0, j);
};
E.utf8bin2str = function(arr, offset, len){
if (arr.byteLength&&!arr.length)
arr = new Uint8Array(arr);
var out = '', i = offset||0, cp;
var c, char2, char3, char4;
len = len ? i+len : arr.length;
while (i<len)
{
c = arr[i++];
switch (c >> 4)
{
case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7:
// 0xxxxxxx
out += String.fromCharCode(c);
break;
case 12: case 13:
// 110x xxxx 10xx xxxx
char2 = arr[i++];
out += String.fromCharCode((c & 0x1F) << 6 | char2 & 0x3F);
break;
case 14:
// 1110 xxxx 10xx xxxx 10xx xxxx
char2 = arr[i++];
char3 = arr[i++];
out += String.fromCharCode((c & 0x0F) << 12 |
(char2 & 0x3F) << 6 |
(char3 & 0x3F) << 0);
break;
case 15:
char2 = arr[i++];
char3 = arr[i++];
char4 = arr[i++];
cp = (c & 0x03) << 18 | (char2 & 0x3F) << 12 |
(char3 & 0x3F) << 6 | char4 & 0x3F;
cp -= 0x10000;
out += String.fromCharCode(0xD800|cp>>10);
out += String.fromCharCode(0xDC00|cp&0x3ff);
break;
}
}
return out;
};
return E; }); }());