1+ /*
2+ --require'd by node before loading any other modules.
3+ This file sets up a global agent for both the http
4+ and https modules, so they pick up the proxy from
5+ the environment.
6+
7+ Tested against Node 6, 8, 10 and 12.
8+ */
9+
10+ let httpAlreadyIntercepted = false ;
11+
12+ function interceptAllHttp ( ) {
13+ if ( httpAlreadyIntercepted ) return ;
14+ httpAlreadyIntercepted = true ;
15+
16+ const MAJOR_NODEJS_VERSION = parseInt ( process . version . slice ( 1 ) . split ( '.' ) [ 0 ] , 10 ) ;
17+
18+ if ( MAJOR_NODEJS_VERSION >= 10 ) {
19+ // `global-agent` works with Node.js v10 and above.
20+ const globalAgent = require ( 'global-agent' ) ;
21+ globalAgent . bootstrap ( ) ;
22+ } else {
23+ // `global-tunnel-ng` works only with Node.js v10 and below.
24+ const globalTunnel = require ( 'global-tunnel-ng' ) ;
25+ globalTunnel . initialize ( ) ;
26+ }
27+ }
28+
29+ // Intercept calls to require() certain modules, to monkey-patch/wrap them.
30+
31+ // Primarily exists to intercept http/https, but could be used for any
32+ // other modules in future if required.
33+
34+ // For HTTP/HTTPS, we inject a global agent that adds our proxy settings as
35+ // the default for all HTTP requests. We could do this upfront, but instead
36+ // it's deferred until the first require(), in case the user cares about
37+ // require order (e.g. if they're mocking out the 'http' module completely).
38+
39+ const alreadyIntercepted = [ ] ;
40+
41+ // Normally false, but can be set to a list of modules to defer interception so
42+ // we can use the required modules as part of the monkey patching process.
43+ // E.g. global-agent requires http & https, so we would otherwise get circular
44+ // requires that can cause problems here.
45+ let delayedInterception = false ;
46+
47+ const mod = require ( 'module' ) ;
48+ const realLoad = mod . _load ;
49+
50+ // Given a just-loaded module's name, do whatever is required to set up interception
51+ function fixModule ( name ) {
52+ if ( name === 'http' || name === 'https' ) {
53+ delayedInterception = [ ] ;
54+
55+ interceptAllHttp ( ) ;
56+
57+ delayedInterception . forEach ( function ( modDetails ) {
58+ fixModule ( modDetails . name ) ;
59+ } ) ;
60+ }
61+ }
62+
63+ // Our hook into require():
64+ mod . _load = function ( name ) {
65+ const loadedModule = realLoad . apply ( this , arguments ) ;
66+
67+ // Should always be set, but check just in case. This also allows users to disable
68+ // interception explicitly, if need be.
69+ if ( ! process . env . HTTP_TOOLKIT_ACTIVE ) return loadedModule ;
70+
71+ // Don't mess with modules if we've seen them before
72+ if ( alreadyIntercepted . indexOf ( name ) >= 0 ) return loadedModule ;
73+ else alreadyIntercepted . push ( name ) ;
74+
75+ if ( delayedInterception !== false ) {
76+ delayedInterception . push ( { name : name , loadedModule : loadedModule } ) ;
77+ } else {
78+ fixModule ( name ) ;
79+ }
80+
81+ return loadedModule ;
82+ } ;
0 commit comments