liudong
2023-05-29 340f156319b863525e50e900c58e59b86ecb3d5e
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
#!/usr/bin/env node
 
process.title = 'proxy';
 
/**
 * Module dependencies.
 */
 
const args = require('args');
const pkg = require('../package');
 
args.option(
    'port',
    'Port number to the proxy server should bind to',
    3128,
    parseInt
)
    .option(
        'authenticate',
        '"authenticate" command to run when the "Proxy-Authorization" header is sent',
        '',
        String
    )
    .option(
        'local-address',
        'IP address of the network interface to send the outgoing requests through',
        '',
        String
    );
 
const flags = args.parse(process.argv, { name: pkg.name });
const { port, authenticate } = flags;
 
const http = require('http');
const setup = require('../');
const debug = require('debug')('proxy');
const spawn = require('child_process').spawn;
const basicAuthParser = require('basic-auth-parser');
 
/**
 * Setup the HTTP "proxy server" instance.
 */
 
const proxy = http.createServer();
setup(proxy);
 
/**
 * Outbound proxy requests will use `agent: false`.
 */
 
debug("setting outbound proxy request's `agent` to `false`");
proxy.agent = false;
 
/**
 * Proxy outgoing request localAddress parameter
 */
 
if (flags.localAddress) {
    proxy.localAddress = flags.localAddress;
}
 
/**
 * Proxy authenticate function.
 */
 
if (authenticate) {
    debug('setting `authenticate()` function for: "%s"', authenticate);
    proxy.authenticate = function(req, fn) {
        debug('authenticate(): "%s"', authenticate);
 
        // parse the "Proxy-Authorization" header
        var auth = req.headers['proxy-authorization'];
        if (!auth) {
            // optimization: don't invoke the child process if no
            // "Proxy-Authorization" header was given
            return fn(null, false);
        }
        var parsed = basicAuthParser(auth);
        debug('parsed "Proxy-Authorization": %j', parsed);
 
        // spawn a child process with the user-specified "authenticate" command
        var i;
        var env = {};
        for (i in process.env) {
            // inherit parent env variables
            env[i] = process.env[i];
        }
        // add "auth" related ENV variables
        for (i in parsed) {
            env['PROXY_AUTH_' + i.toUpperCase()] = parsed[i];
        }
 
        var opts = {};
        opts.stdio = ['ignore', 1, 2];
        opts.env = env;
 
        var args = ['-c', authenticate];
        // TODO: add Windows support (use `cross-spawn`?)
        var child = spawn('/bin/sh', args, opts);
 
        function onerror(err) {
            child.removeListener('exit', onexit);
            fn(err);
        }
 
        function onexit(code, signal) {
            debug(
                'authentication child process "exit" event: %s %s',
                code,
                signal
            );
            child.removeListener('error', onerror);
            fn(null, 0 == code);
        }
 
        child.once('error', onerror);
        child.once('exit', onexit);
    };
}
 
/**
 * Bind to port.
 */
 
proxy.listen(port, function() {
    console.log(
        'HTTP(s) proxy server listening on port %d',
        this.address().port
    );
});