使用nodejs做代理服务器

#!/usr/bin/env node
// LICENSE_CODE ZON
'use strict'; /*jslint node:true,esnext:true*/
var http = require('http');
var url = require('url');
var api_port = 11000;
var lum_customer = '用户名';
var lum_zones = {gen: '密码', gen2: '密码'};
var ports = [
    {from: 12000, count: 10, opt: {zone: 'gen'}},
    {from: 12100, count: 10, opt: {zone: 'gen2', country: 'ca'}},
];

var servers = [];
function start_servers(){
    ports.forEach(function(port_range){
        for (var i=0; i<(port_range.count||1); i++)
            servers.push(start_server(port_range.from+i, port_range.opt));
    });
    servers.push(start_api(api_port));
}

function start_server(port, opt){
    var server = http.createServer(run_proxy);
    server.on('connect', run_proxy);
    server.lum_port = port;
    server.lum_opt = {session: port};
    server.lum_agent = new http.Agent({keepAlive: true, keepAliveMsecs: 5000});
    copy_opt(server.lum_opt, opt);
    server.listen(port);
    console.log(port+': '+JSON.stringify(server.lum_opt));
    return server;
}

function start_api(port){
    var server = http.createServer(api);
    server.listen(port);
    return server;
}

function lum_auth(opt){
    var arr = ['lum-customer', lum_customer];
    var username = arr.concat(opt_as_array(opt)).join('-');
    return new Buffer(username+':'+lum_zones[opt.zone]).toString('base64');
}

function lum_superproxy(opt){
    return 'servercountry-'+(opt.superproxy||'us')+'.zproxy.luminati.io'; }

const CRLF = '\r\n';
function write_http_reply(stream, res){
    if (stream instanceof http.ServerResponse)
    {
        return stream.writeHead(res.statusCode, res.statusMessage,
            res.headers);
    }
    var str = 'HTTP/1.1 '+res.statusCode+' '+res.statusMessage+CRLF;
    for (var field in res.headers)
        str += field+': '+res.headers[field]+CRLF;
    str += CRLF;
    stream.write(str);
}

function run_proxy(client_req, client_res, head){
    var socket = client_req.socket;
    var server = socket.server;
    var lum_opt = server.lum_opt;
    var log = server.lum_port+' '+new Date().toISOString()+' '
        +client_req.socket.remoteAddress+' '+client_req.method+' '
        +client_req.url+' ';
    client_req.headers['proxy-authorization'] = 'Basic '+lum_auth(lum_opt);
    var lum_req = {
        protocol: 'http:',
        host: lum_superproxy(lum_opt),
        port: 22225,
        method: client_req.method,
        path: client_req.url,
        headers: client_req.headers,
        agent: server.lum_agent,
    };
    var proxy = http.request(lum_req);
    if (client_req.method=='CONNECT')
        proxy.end();
    else
        client_req.pipe(proxy);
    proxy.on('response', function(proxy_res){
        console.log(log+proxy_res.statusCode);
        write_http_reply(client_res, proxy_res);
        proxy_res.pipe(client_res);
    });
    proxy.on('connect', function(proxy_res, proxy_socket, proxy_head){
        console.log(log+proxy_res.statusCode);
        write_http_reply(client_res, proxy_res);
        if (proxy_res.statusCode!=200)
            return client_res.end();
        proxy_socket.write(head);
        client_res.write(proxy_head);
        proxy_socket.pipe(client_res).pipe(proxy_socket);
    });
    proxy.on('error', function(error){
        if (!client_res.ended)
        {
            write_http_reply(client_res, {statusCode: '502',
                statusMessage: 'Bad gateway', headers: {Connection: 'close'}});
        }
        client_res.end();
        console.log(log+'502');
    });
}

function api_result(res, code, message, body){
    res.writeHead(code, message);
    res.end(body);
}

// API: /get?port=NN or /set?port=NN&country=ca&...
function api(req, res){
    var request = url.parse(req.url, true);
    var query = request.query;
    if (!query.port)
        return api_result(res, '400', 'Port not specified');
    var server = servers.find(function(s){ return s.lum_port==query.port; });
    if (!server)
        return api_result(res, '400', 'Port not found');
    delete query.port;
    switch(request.pathname)
    {
    case '/get': break;
    case '/set': copy_opt(server.lum_opt, query); break;
    default: return api_result(res, '400', 'Bad API endpoint');
    }
    return api_result(res, '200', 'OK', JSON.stringify(server.lum_opt));
}

function copy_opt(to, from){
    for (var key in from)
        to[key] = from[key];
}

function opt_as_array(obj){
    var arr = [];
    for (var key in obj){
        if (key=='superproxy')
            continue;
        arr.push(key);
        arr.push(obj[key]);
    }
    return arr;
}

console.log('Starting servers:');
start_servers();

proxy.js

pm2 start proxy.js

你可能感兴趣的:(proxy,nodejs)