req.on('response', function(res){ debug('%s %s -> %s', self.method, self.url, res.statusCode); var max = self._maxRedirects; var mime = utils.type(res.headers['content-type'] || ''); var len = res.headers['content-length']; var type = mime.split('/'); var subtype = type[1]; var type = type[0]; var multipart = 'multipart' == type; var redirect = isRedirect(res.statusCode); if (self.piped) { res.on('end', function(){ self.emit('end'); }); return; } // redirect if (redirect && self._redirects++ != max) { return self.redirect(res); } // zlib support if (/^(deflate|gzip)$/.test(res.headers['content-encoding'])) { utils.unzip(req, res); } // don't buffer multipart if (multipart) buffer = false; // TODO: make all parsers take callbacks if (multipart) { var form = new formidable.IncomingForm; form.parse(res, function(err, fields, files){ if (err) return self.callback(err); var response = new Response(req, res); response.body = fields; response.files = files; response.redirects = self._redirectList; self.emit('end'); self.callback(null, response); }); return; } // by default only buffer text/*, json // and messed up thing from hell var text = isText(mime); if (null == buffer && text) buffer = true; // parser var parse = 'text' == type ? exports.parse.text : exports.parse[mime]; // buffered response if (buffer) parse = parse || exports.parse.text; // explicit parser if (self._parser) parse = self._parser; // parse if (parse) { parse(res, function(err, obj){ // TODO: handle error res.body = obj; }); } // unbuffered if (!buffer) { debug('unbuffered %s %s', self.method, self.url); self.res = res; var response = new Response(self.req, self.res); response.redirects = self._redirectList; self.emit('response', response); if (multipart) return // allow multipart to handle end event res.on('end', function(){ debug('end %s %s', self.method, self.url); self.emit('end'); }) return; } // end event self.res = res; res.on('end', function(){ debug('end %s %s', self.method, self.url); // TODO: unless buffering emit earlier to stream var response = new Response(self.req, self.res); response.redirects = self._redirectList; self.emit('response', response); self.emit('end'); }); });
req.on('response', function(res){ debug('%s %s -> %s', self.method, self.url, res.statusCode); var max = self._maxRedirects; var mime = utils.type(res.headers['content-type'] || '') || 'text/plain'; var len = res.headers['content-length']; var type = mime.split('/'); var subtype = type[1]; var type = type[0]; var multipart = 'multipart' == type; var redirect = isRedirect(res.statusCode); var parser = self._parser; self.res = res; if ('HEAD' == self.method) { var response = new Response(self); self.response = response; response.redirects = self._redirectList; self.emit('response', response); self.callback(null, response); self.emit('end'); return; } if (self.piped) { return; } // redirect if (redirect && self._redirects++ != max) { return self._redirect(res); } // zlib support if (/^(deflate|gzip)$/.test(res.headers['content-encoding'])) { utils.unzip(req, res); } // don't buffer multipart if (multipart) buffer = false; // TODO: make all parsers take callbacks if (!parser && multipart) { var form = new formidable.IncomingForm; form.parse(res, function(err, fields, files){ if (err) return self.callback(err); var response = new Response(self); self.response = response; response.body = fields; response.files = files; response.redirects = self._redirectList; self.emit('end'); self.callback(null, response); }); return; } // check for images, one more special treatment if (!parser && isImage(mime)) { exports.parse.image(res, function(err, obj){ if (err) return self.callback(err); var response = new Response(self); self.response = response; response.body = obj; response.redirects = self._redirectList; self.emit('end'); self.callback(null, response); }); return; } // by default only buffer text/*, json and messed up thing from hell if (null == buffer && isText(mime) || isJSON(mime)) buffer = true; // parser var parse = 'text' == type ? exports.parse.text : exports.parse[mime]; // everyone wants their own white-labeled json if (!parse && isJSON(mime)) parse = exports.parse['application/json']; // buffered response if (buffer) parse = parse || exports.parse.text; // explicit parser if (parser) parse = parser; // parse if (parse) { try { parse(res, function(err, obj){ if (err && !self._aborted) self.callback(err); res.body = obj; }); } catch (err) { self.callback(err); return; } } // unbuffered if (!buffer) { debug('unbuffered %s %s', self.method, self.url); self.res = res; var response = new Response(self); self.response = response; response.redirects = self._redirectList; self.emit('response', response); self.callback(null, response); if (multipart) return // allow multipart to handle end event res.on('end', function(){ debug('end %s %s', self.method, self.url); self.emit('end'); }) return; } // terminating events self.res = res; res.on('error', function(err){ self.callback(err, null); }); res.on('end', function(){ debug('end %s %s', self.method, self.url); // TODO: unless buffering emit earlier to stream var response = new Response(self); self.response = response; response.redirects = self._redirectList; self.emit('response', response); self.callback(null, response); self.emit('end'); }); });
req.once('response', res => { debug('%s %s -> %s', this.method, this.url, res.statusCode); if (this._responseTimeoutTimer) { clearTimeout(this._responseTimeoutTimer); } if (this.piped) { return; } const max = this._maxRedirects; const mime = utils.type(res.headers['content-type'] || '') || 'text/plain'; const type = mime.split('/')[0]; const multipart = 'multipart' == type; const redirect = isRedirect(res.statusCode); const responseType = this._responseType; this.res = res; // redirect if (redirect && this._redirects++ != max) { return this._redirect(res); } if ('HEAD' == this.method) { this.emit('end'); this.callback(null, this._emitResponse()); return; } // zlib support if (this._shouldUnzip(res)) { unzip(req, res); } let buffer = this._buffer; if (buffer === undefined && mime in exports.buffer){ buffer = !!exports.buffer[mime]; } let parser = this._parser; if (undefined === buffer) { if (parser) { console.warn("A custom superagent parser has been set, but buffering strategy for the parser hasn't been configured. Call `req.buffer(true or false)` or set `superagent.buffer[mime] = true or false`"); buffer = true; } } if (!parser) { if (responseType) { parser = exports.parse.image; // It's actually a generic Buffer buffer = true; } else if (multipart) { const form = new formidable.IncomingForm(); parser = form.parse.bind(form); buffer = true; } else if (isImageOrVideo(mime)) { parser = exports.parse.image; buffer = true; // For backwards-compatibility buffering default is ad-hoc MIME-dependent } else if (exports.parse[mime]) { parser = exports.parse[mime]; } else if ('text' == type) { parser = exports.parse.text; buffer = (buffer !== false); // everyone wants their own white-labeled json } else if (isJSON(mime)) { parser = exports.parse['application/json']; buffer = (buffer !== false); } else if (buffer) { parser = exports.parse.text; } else if (undefined === buffer) { parser = exports.parse.image; // It's actually a generic Buffer buffer = true; } } // by default only buffer text/*, json and messed up thing from hell if ((undefined === buffer && isText(mime)) || isJSON(mime)) { buffer = true; } this._resBuffered = buffer; let parserHandlesEnd = false; if (buffer) { // Protectiona against zip bombs and other nuisance let responseBytesLeft = this._maxResponseSize || 200000000; res.on('data', buf => { responseBytesLeft -= buf.byteLength || buf.length; if (responseBytesLeft < 0) { // This will propagate through error event const err = Error("Maximum response size reached"); err.code = "ETOOLARGE"; // Parsers aren't required to observe error event, // so would incorrectly report success parserHandlesEnd = false; // Will emit error event res.destroy(err); } }); } if (parser) { try { // Unbuffered parsers are supposed to emit response early, // which is weird BTW, because response.body won't be there. parserHandlesEnd = buffer; parser(res, (err, obj, files) => { if (this.timedout) { // Timeout has already handled all callbacks return; } // Intentional (non-timeout) abort is supposed to preserve partial response, // even if it doesn't parse. if (err && !this._aborted) { return this.callback(err); } if (parserHandlesEnd) { this.emit('end'); this.callback(null, this._emitResponse(obj, files)); } }); } catch (err) { this.callback(err); return; } } this.res = res; // unbuffered if (!buffer) { debug('unbuffered %s %s', this.method, this.url); this.callback(null, this._emitResponse()); if (multipart) return; // allow multipart to handle end event res.once('end', () => { debug('end %s %s', this.method, this.url); this.emit('end'); }); return; } // terminating events res.once('error', err => { parserHandlesEnd = false; this.callback(err, null); }); if (!parserHandlesEnd) res.once('end', () => { debug('end %s %s', this.method, this.url); // TODO: unless buffering emit earlier to stream this.emit('end'); this.callback(null, this._emitResponse()); }); });
req.once('response', function(res){ debug('%s %s -> %s', self.method, self.url, res.statusCode); if (self._responseTimeoutTimer) { clearTimeout(self._responseTimeoutTimer); } if (self.piped) { return; } var max = self._maxRedirects; var mime = utils.type(res.headers['content-type'] || '') || 'text/plain'; var type = mime.split('/')[0]; var multipart = 'multipart' == type; var redirect = isRedirect(res.statusCode); var parser = self._parser; var responseType = self._responseType; self.res = res; // redirect if (redirect && self._redirects++ != max) { return self._redirect(res); } if ('HEAD' == self.method) { self.emit('end'); self.callback(null, self._emitResponse()); return; } // zlib support if (self._shouldUnzip(res)) { unzip(req, res); } if (!parser) { if (responseType) { parser = exports.parse.image; // It's actually a generic Buffer buffer = true; } else if (multipart) { var form = new formidable.IncomingForm(); parser = form.parse.bind(form); buffer = true; } else if (isImageOrVideo(mime)) { parser = exports.parse.image; buffer = true; // For backwards-compatibility buffering default is ad-hoc MIME-dependent } else if (exports.parse[mime]) { parser = exports.parse[mime]; } else if ('text' == type) { parser = exports.parse.text; buffer = (buffer !== false); // everyone wants their own white-labeled json } else if (isJSON(mime)) { parser = exports.parse['application/json']; buffer = (buffer !== false); } else if (buffer) { parser = exports.parse.text; } } // by default only buffer text/*, json and messed up thing from hell if (undefined === buffer && isText(mime) || isJSON(mime)) { buffer = true; } var parserHandlesEnd = false; if (parser) { try { // Unbuffered parsers are supposed to emit response early, // which is weird BTW, because response.body won't be there. parserHandlesEnd = buffer; parser(res, function(err, obj, files) { if (self.timedout) { // Timeout has already handled all callbacks return; } // Intentional (non-timeout) abort is supposed to preserve partial response, // even if it doesn't parse. if (err && !self._aborted) { return self.callback(err); } if (parserHandlesEnd) { self.emit('end'); self.callback(null, self._emitResponse(obj, files)); } }); } catch (err) { self.callback(err); return; } } self.res = res; // unbuffered if (!buffer) { debug('unbuffered %s %s', self.method, self.url); self.callback(null, self._emitResponse()); if (multipart) return // allow multipart to handle end event res.once('end', function(){ debug('end %s %s', self.method, self.url); self.emit('end'); }) return; } // terminating events res.once('error', function(err){ self.callback(err, null); }); if (!parserHandlesEnd) res.once('end', function(){ debug('end %s %s', self.method, self.url); // TODO: unless buffering emit earlier to stream self.emit('end'); self.callback(null, self._emitResponse()); }); });
req.on('response', function(res) { debug('%s %s -> %s', self.method, self.url, res.statusCode); var max = self._maxRedirects; var mime = utils.type(res.headers['content-type'] || '') || 'text/plain'; var len = res.headers['content-length']; var type = mime.split('/'); var subtype = type[1]; var type = type[0]; var multipart = 'multipart' == type; var redirect = isRedirect(res.statusCode); var parser = self._parser; self.res = res; if ('HEAD' == self.method) { var response = new Response(self); self.response = response; response.redirects = self._redirectList; self.emit('response', response); self.callback(null, response); self.emit('end'); return; } if (self.piped) { return; } if (redirect && self._redirects++ != max) { return self.redirect(res); } if (/^(deflate|gzip)$/.test(res.headers['content-encoding'])) { utils.unzip(req, res); } if (multipart) buffer = false; if (!parser && multipart) { var form = new formidable.IncomingForm; form.parse(res, function(err, fields, files) { if (err) return self.callback(err); var response = new Response(self); self.response = response; response.body = fields; response.files = files; response.redirects = self._redirectList; self.emit('end'); self.callback(null, response); }); return; } if (!parser && isImage(mime)) { exports.parse.image(res, function(err, obj) { if (err) return self.callback(err); var response = new Response(self); self.response = response; response.body = obj; response.redirects = self._redirectList; self.emit('end'); self.callback(null, response); }); return; } if (null == buffer && isText(mime) || isJSON(mime)) buffer = true; var parse = 'text' == type ? exports.parse.text : exports.parse[mime]; if (!parse && isJSON(mime)) parse = exports.parse['application/json']; if (buffer) parse = parse || exports.parse.text; if (parser) parse = parser; if (parse) { try { parse(res, function(err, obj) { if (err && !self._aborted) self.callback(err); res.body = obj; }); } catch (err) { self.callback(err); return; } } if (!buffer) { debug('unbuffered %s %s', self.method, self.url); self.res = res; var response = new Response(self); self.response = response; response.redirects = self._redirectList; self.emit('response', response); self.callback(null, response); if (multipart) return; res.on('end', function() { debug('end %s %s', self.method, self.url); self.emit('end'); }); return; } self.res = res; res.on('error', function(err) { self.callback(err, null); }); res.on('end', function() { debug('end %s %s', self.method, self.url); var response = new Response(self); self.response = response; response.redirects = self._redirectList; self.emit('response', response); self.callback(null, response); self.emit('end'); }); });