Package: npm Version: 1.4.21+ds-2 Followup-For: Bug #801897 I get the same backtrace that Stephen reported, and for the same reason (http_proxy et al. environment variables and/or .npmrc config settings), so I decided to step through code using the builtin nodejs debugger to see what's going on.
$ nodejs debug /usr/share/npm/bin/npm-cli.js view npm … debug> sb('/usr/lib/nodejs/tunnel-agent/index.js', 117) … debug> c break in /usr/lib/nodejs/tunnel-agent/index.js:117 115 116 debug('making CONNECT request') >117 var connectReq = self.request(connectOptions) 118 connectReq.useChunkedEncodingByDefault = false // for v0.6 119 connectReq.once('response', onResponse) // for v0.6 debug> repl Press Ctrl + C to leave debug repl > connectOptions { host: 'proxy.local', port: 3128, proxyAuth: null, headers: { Host: 'registry.npmjs.org:443' }, method: 'CONNECT', path: '[object Object]:undefined', agent: false } > There's the culprit, connectOptions.path = '[object Object]:undefined' when it should probably be 'registry.npmjs.org:443'. The connectOptions variable is created earlier in this function (createSocket) with the following code at line 104: var connectOptions = mergeOptions({}, self.proxyOptions, { method: 'CONNECT' , path: options.host + ':' + options.port , agent: false } ) The options variable, which is referenced when assigning the path member, is an argument passed into this function call. Back in the debugger, I examine the options.host and options.port members: > options.host { path: '/npm', strictSSL: true, headers: { 'npm-session': 'fd065128873578be', version: '1.4.21', referer: 'view npm', accept: 'application/json', 'accept-encoding': 'gzip', 'user-agent': 'npm/1.4.21 node/v4.3.1 linux x64', host: 'registry.npmjs.org' }, proxy: { protocol: 'http:', slashes: true, auth: null, host: 'proxy.local:3128', port: '3128', hostname: 'proxy.local', hash: null, search: null, query: null, pathname: '/', path: '/', href: 'http://proxy.local:3128/' }, uri: { protocol: 'https:', slashes: true, auth: null, host: 'registry.npmjs.org', port: 443, hostname: 'registry.npmjs.org', hash: null, search: null, query: null, pathname: '/npm', path: '/npm', href: 'https://registry.npmjs.org/npm' }, redirects: [], ca: null, localAddress: undefined, __isRequestRequest: true, agent: { options: { proxy: [Object], rejectUnauthorized: undefined, ca: null }, proxyOptions: { host: 'proxy.local', port: 3128, proxyAuth: null, headers: [Object] }, maxSockets: 'Infinity', requests: [], sockets: [ {} ], _events: { free: [Function] }, _eventsCount: 1, request: [Function], createSocket: [Function] }, _eventsCount: 4, method: 'GET', setHost: true, _maxListeners: undefined, httpModule: { Server: [Function], createServer: [Function], globalAgent: { domain: null, _events: [Object], _eventsCount: 1, _maxListeners: undefined, defaultPort: 443, protocol: 'https:', options: [Object], requests: {}, sockets: {}, freeSockets: {}, keepAliveMsecs: 1000, keepAlive: false, maxSockets: 'Infinity', maxFreeSockets: 256, maxCachedSessions: 100, _sessionCache: [Object] }, Agent: [Function], request: [Function], get: [Function] }, originalCookieHeader: undefined, cert: null, followRedirect: true, encoding: null, callback: [Function], _jar: undefined, pool: {}, dests: [], port: 443, followAllRedirects: false, clientErrorHandler: [Function], href: 'https://registry.npmjs.org/npm', readable: true, writable: true, domain: null, _started: true, _events: { error: [ [Function], [Function] ], complete: [Function], pipe: [Function], socket: [Function] }, host: 'registry.npmjs.org', _defaultAgent: { domain: null, _events: { free: [Function] }, _eventsCount: 1, _maxListeners: undefined, defaultPort: 443, protocol: 'https:', options: { path: null }, requests: {}, sockets: {}, freeSockets: {}, keepAliveMsecs: 1000, keepAlive: false, maxSockets: 'Infinity', maxFreeSockets: 256, maxCachedSessions: 100, _sessionCache: { map: {}, list: [] } }, explicitMethod: true, tunnel: true, _redirectsFollowed: 0, _disableCookies: true, maxRedirects: 10, key: null, _callback: [Function], _parserErrorHandler: [Function] } > options.port > That explains the '[object Object]:undefined' value of the path member since options.host is a large object and options.port is undefined. So I restart the debugger and set a breakpoint earlier to the preceding line in the backtrace: $ nodejs debug /usr/share/npm/bin/npm-cli.js view npm debug> sb('/usr/lib/nodejs/tunnel-agent/index.js', 184) debug> c break in /usr/lib/nodejs/tunnel-agent/index.js:184 182 function createSecureSocket(options, cb) { 183 var self = this >184 TunnelingAgent.prototype.createSocket.call(self, options, function(socket) { 185 // 0 is dummy port for v0.6 186 var secureSocket = tls.connect(0, mergeOptions({}, self.options, debug> repl > options.host { path: '/npm', … > options.port > Here the options.host member is still that large object and options.port is undefined. So I restart the debugger once more with the preceding line in the backtrace: $ nodejs debug /usr/share/npm/bin/npm-cli.js view npm debug> sb('/usr/lib/nodejs/tunnel-agent/index.js', 80) debug> c break in /usr/lib/nodejs/tunnel-agent/index.js:80 78 79 // If we are under maxSockets create a new one. >80 self.createSocket({host: host, port: port, request: req}, function(socket) { 81 socket.on('free', onFree) 82 socket.on('close', onCloseOrRemove) debug> repl > host { path: '/npm', … > port > Interesting - the options object is created here, host and port members reference the arguments passed into this function (addRequest), which yet again are the large object and undefined respectively. The function prototype is defined with the following code: TunnelingAgent.prototype.addRequest = function addRequest(req, host, port) { var self = this if (self.sockets.length >= this.maxSockets) { // We are over limit so we'll add it to the queue. self.requests.push({host: host, port: port, request: req}) return } // If we are under maxSockets create a new one. self.createSocket({host: host, port: port, request: req}, function(socket) { … I get the feeling that addRequest is being called from some internal nodejs library since the next couple frames of the backtrace have no apparent source code: npm ERR! at TunnelingAgent.addRequest (/usr/lib/nodejs/tunnel-agent/index.js:80:8) npm ERR! at new ClientRequest (_http_client.js:131:16) npm ERR! at Object.exports.request (http.js:31:10) npm ERR! at Object.exports.request (https.js:167:15) npm ERR! at Request.start (/usr/lib/nodejs/request/index.js:607:30) Looking at /usr/lib/nodejs/request/index.js line 607 yields the following code: self.req = self.httpModule.request(reqOptions, self.onResponse.bind(self)) Quite likely matching the documentation for nodejs http.request()¹ API, however I haven't found any API documentation for addRequest. Sorry that I haven't found a solution, but I believe I'm onto something, an API incompatibility perhaps? Also parodon my ignorance - this whole JavaScript outside the browser is completely foreign to me - and rather scary, heck one of the stackoverflow answers to this bug was to 'curl http://some-random-script | sh'² and another work-around is to change the npm repository URL from https to http³ with no hint about it's security implications (I get the feeling that TLS is the only defense in this ecosystem). ¹ https://nodejs.org/api/http.html#http_http_request_options_callback ² http://stackoverflow.com/questions/18006179/typeerror-request-path-contains-unescaped-characters/33216498#33216498 ³ http://stackoverflow.com/questions/18006179/typeerror-request-path-contains-unescaped-characters/18012840#18012840 -- System Information: Debian Release: stretch/sid APT prefers testing-updates APT policy: (500, 'testing-updates'), (500, 'testing'), (50, 'unstable') Architecture: amd64 (x86_64) Kernel: Linux 4.4.0-1-amd64 (SMP w/8 CPU cores) Locale: LANG=en_US.UTF-8, LC_CTYPE=en_US.UTF-8 (charmap=UTF-8) (ignored: LC_ALL set to en_US.UTF-8) Shell: /bin/sh linked to /bin/dash Init: systemd (via /run/systemd/system) Versions of packages npm depends on: ii node-abbrev 1.0.5-2 ii node-ansi 0.3.0-2 ii node-ansi-color-table 1.0.0-1 ii node-archy 0.0.2-1 ii node-block-stream 0.0.7-1 ii node-fstream 0.1.24-1 ii node-fstream-ignore 0.0.6-2 ii node-github-url-from-git 1.1.1-1 ii node-glob 4.0.5-1 ii node-graceful-fs 3.0.2-1 ii node-gyp 3.3.1-2 ii node-inherits 2.0.1-3 ii node-ini 1.1.0-1 ii node-lockfile 0.4.1-1 ii node-lru-cache 2.3.1-1 ii node-minimatch 1.0.0-1 ii node-mkdirp 0.5.0-1 ii node-nopt 3.0.1-1 ii node-npmlog 0.0.4-1 ii node-once 1.1.1-1 ii node-osenv 0.1.0-1 ii node-read 1.0.5-1 ii node-read-package-json 1.2.4-1 ii node-request 2.26.1-1 ii node-retry 0.6.0-1 ii node-rimraf 2.2.8-1 ii node-semver 2.1.0-2 ii node-sha 1.2.3-1 ii node-slide 1.1.4-1 ii node-tar 1.0.3-2 ii node-underscore 1.7.0~dfsg-1 ii node-which 1.0.5-2 ii nodejs 4.3.1~dfsg-3 npm recommends no packages. npm suggests no packages. -- no debconf information -- Gerald Turner <gtur...@unzane.com> Encrypted mail preferred! OpenPGP: 4096R / CA89 B27A 30FA 66C5 1B80 3858 EC94 2276 FDB8 716D
signature.asc
Description: PGP signature