@@ -40,8 +40,6 @@ const realLoad = mod._load;
4040// it's deferred until the first require(), in case the user cares about
4141// require order (e.g. if they're mocking out the 'http' module completely).
4242
43- const alreadyIntercepted = [ ] ;
44-
4543// Normally false, but can be set to a list of modules to defer interception so
4644// we can use the required modules as part of the monkey patching process.
4745// E.g. global-agent requires http & https, so we would otherwise get circular
@@ -51,34 +49,33 @@ let delayedInterception = false;
5149// Given a just-loaded module's name, do whatever is required to set up interception
5250// This must return the resulting module, but due to delayed interception, that isn't
5351// used if it's hit in a circular require. Works for now, but needs careful thought.
54- function fixModule ( name , loadedModule ) {
55- if ( name === 'http' || name === 'https' ) {
52+ // All fixes must be idempotent (must not cause problems if run repeatedly).
53+ function fixModule ( requestedName , filename , loadedModule ) {
54+ let fixedModule = loadedModule ;
55+
56+ if ( requestedName === 'http' || requestedName === 'https' ) {
5657 delayedInterception = [ ] ;
5758
5859 interceptAllHttp ( ) ;
5960
6061 delayedInterception . forEach ( function ( modDetails ) {
61- fixModule ( modDetails . name , modDetails . loadedModule ) ;
62+ fixModule ( modDetails . requestedName , modDetails . filename , modDetails . loadedModule ) ;
6263 } ) ;
6364 delayedInterception = false ;
64-
65- return loadedModule ;
66- } else if ( name === 'axios' ) {
65+ } else if ( requestedName === 'axios' ) {
6766 // Disable built-in proxy support, to let global-agent/tunnel take precedence
6867 // Supported back to the very first release of Axios
69- loadedModule . defaults . proxy = false ;
70- return loadedModule ;
71- } else if ( name === 'request' ) {
68+ fixedModule . defaults . proxy = false ;
69+ } else if (
70+ requestedName === 'request' &&
71+ loadedModule . defaults && // Request >= 2.17 (before that, proxy support isn't a problem anyway)
72+ ! loadedModule . INTERCEPTED_BY_HTTPTOOLKIT // Make this idempotent
73+ ) {
7274 // Disable built-in proxy support, to let global-agent/tunnel take precedence
73- if ( loadedModule . defaults ) {
74- return loadedModule . defaults ( { proxy : false } ) ;
75- } else {
76- // Request < 2.17 (_very_ old). Predates the proxy support that makes
77- // this necessary in the first place (added in 2.38).
78- return loadedModule ;
79- }
80- } else if ( name === 'stripe' ) {
81- stripeReplacement = Object . assign ( function ( ) {
75+ fixedModule = loadedModule . defaults ( { proxy : false } ) ;
76+ fixedModule . INTERCEPTED_BY_HTTPTOOLKIT = true ;
77+ } else if ( requestedName === 'stripe' && ! loadedModule . INTERCEPTED_BY_HTTPTOOLKIT ) {
78+ fixedModule = Object . assign ( function ( ) {
8279 const result = loadedModule . apply ( this , arguments ) ;
8380
8481 if ( global . GLOBAL_AGENT ) {
@@ -90,28 +87,35 @@ function fixModule(name, loadedModule) {
9087 }
9188
9289 return result ;
93- } , loadedModule ) ;
94- return stripeReplacement ;
90+ } , fixedModule ) ;
91+ fixedModule . INTERCEPTED_BY_HTTPTOOLKIT = true ;
92+ }
93+
94+ // Very carefully overwrite node's built-in module cache:
95+ if ( fixedModule !== loadedModule && mod . _cache [ filename ] && mod . _cache [ filename ] . exports ) {
96+ mod . _cache [ filename ] . exports = fixedModule ;
9597 }
96- else return loadedModule ;
98+
99+ return fixedModule ;
97100}
98101
99102// Our hook into require():
100- mod . _load = function ( name ) {
103+ mod . _load = function ( requestedName , parent , isMain ) {
104+ const filename = mod . _resolveFilename ( requestedName , parent , isMain ) ;
101105 let loadedModule = realLoad . apply ( this , arguments ) ;
102106
103107 // Should always be set, but check just in case. This also allows users to disable
104108 // interception explicitly, if need be.
105109 if ( ! process . env . HTTP_TOOLKIT_ACTIVE ) return loadedModule ;
106110
107- // Don't mess with modules if we've seen them before
108- if ( alreadyIntercepted . indexOf ( name ) >= 0 ) return loadedModule ;
109- else alreadyIntercepted . push ( name ) ;
110-
111111 if ( delayedInterception !== false ) {
112- delayedInterception . push ( { name : name , loadedModule : loadedModule } ) ;
112+ delayedInterception . push ( {
113+ requestedName : requestedName ,
114+ filename : filename ,
115+ loadedModule : loadedModule
116+ } ) ;
113117 } else {
114- loadedModule = fixModule ( name , loadedModule ) ;
118+ loadedModule = fixModule ( requestedName , filename , loadedModule ) ;
115119 }
116120
117121 return loadedModule ;
0 commit comments