| 
						 | 
						- 'use strict';
 - const util = require('util');
 - const urlutil = require('url');
 - const http = require('http');
 - const https = require('https');
 - const debug = require('debug')('urllib');
 - const ms = require('humanize-ms');
 - let REQUEST_ID = 0;
 - const MAX_VALUE = Math.pow(2, 31) - 10;
 - const PROTO_RE = /^https?:\/\//i;
 - 
 - function getAgent(agent, defaultAgent) {
 -   return agent === undefined ? defaultAgent : agent;
 - }
 - 
 - function parseContentType(str) {
 -   if (!str) {
 -     return '';
 -   }
 - 
 -   return str.split(';')[0].trim().toLowerCase();
 - }
 - 
 - function makeCallback(resolve, reject) {
 -   return function (err, data, res) {
 -     if (err) {
 -       return reject(err);
 -     }
 -     resolve({
 -       data: data,
 -       status: res.statusCode,
 -       headers: res.headers,
 -       res: res
 -     });
 -   };
 - }
 - 
 - // exports.TIMEOUT = ms('5s');
 - exports.TIMEOUTS = [ms('300s'), ms('300s')];
 - 
 - const TEXT_DATA_TYPES = ['json', 'text'];
 - 
 - exports.request = function request(url, args, callback) {
 -   // request(url, callback)
 -   if (arguments.length === 2 && typeof args === 'function') {
 -     callback = args;
 -     args = null;
 -   }
 -   if (typeof callback === 'function') {
 -     return exports.requestWithCallback(url, args, callback);
 -   }
 - 
 -   return new Promise(function (resolve, reject) {
 -     exports.requestWithCallback(url, args, makeCallback(resolve, reject));
 -   });
 - };
 - 
 - exports.requestWithCallback = function requestWithCallback(url, args, callback) {
 -   if (!url || (typeof url !== 'string' && typeof url !== 'object')) {
 -     const msg = util.format('expect request url to be a string or a http request options, but got' + ' %j', url);
 -     throw new Error(msg);
 -   }
 - 
 -   if (arguments.length === 2 && typeof args === 'function') {
 -     callback = args;
 -     args = null;
 -   }
 - 
 -   args = args || {};
 -   if (REQUEST_ID >= MAX_VALUE) {
 -     REQUEST_ID = 0;
 -   }
 -   const reqId = ++REQUEST_ID;
 - 
 -   args.requestUrls = args.requestUrls || [];
 - 
 -   const reqMeta = {
 -     requestId: reqId,
 -     url: url,
 -     args: args,
 -     ctx: args.ctx
 -   };
 -   if (args.emitter) {
 -     args.emitter.emit('request', reqMeta);
 -   }
 - 
 -   args.timeout = args.timeout || exports.TIMEOUTS;
 -   args.maxRedirects = args.maxRedirects || 10;
 -   args.streaming = args.streaming || args.customResponse;
 -   const requestStartTime = Date.now();
 -   let parsedUrl;
 - 
 -   if (typeof url === 'string') {
 -     if (!PROTO_RE.test(url)) {
 -       // Support `request('www.server.com')`
 -       url = 'https://' + url;
 -     }
 -     parsedUrl = urlutil.parse(url);
 -   } else {
 -     parsedUrl = url;
 -   }
 - 
 -   const method = (args.type || args.method || parsedUrl.method || 'GET').toUpperCase();
 -   let port = parsedUrl.port || 80;
 -   let httplib = http;
 -   let agent = getAgent(args.agent, exports.agent);
 -   const fixJSONCtlChars = args.fixJSONCtlChars;
 - 
 -   if (parsedUrl.protocol === 'https:') {
 -     httplib = https;
 -     agent = getAgent(args.httpsAgent, exports.httpsAgent);
 - 
 -     if (!parsedUrl.port) {
 -       port = 443;
 -     }
 -   }
 - 
 -   // request through proxy tunnel
 -   // var proxyTunnelAgent = detectProxyAgent(parsedUrl, args);
 -   // if (proxyTunnelAgent) {
 -   //   agent = proxyTunnelAgent;
 -   // }
 - 
 -   const options = {
 -     host: parsedUrl.hostname || parsedUrl.host || 'localhost',
 -     path: parsedUrl.path || '/',
 -     method: method,
 -     port: port,
 -     agent: agent,
 -     headers: args.headers || {},
 -     // default is dns.lookup
 -     // https://github.com/nodejs/node/blob/master/lib/net.js#L986
 -     // custom dnslookup require node >= 4.0.0
 -     // https://github.com/nodejs/node/blob/archived-io.js-v0.12/lib/net.js#L952
 -     lookup: args.lookup
 -   };
 - 
 -   if (Array.isArray(args.timeout)) {
 -     options.requestTimeout = args.timeout[args.timeout.length - 1];
 -   } else if (typeof args.timeout !== 'undefined') {
 -     options.requestTimeout = args.timeout;
 -   }
 - 
 -   // const sslNames = [
 -   //   'pfx',
 -   //   'key',
 -   //   'passphrase',
 -   //   'cert',
 -   //   'ca',
 -   //   'ciphers',
 -   //   'rejectUnauthorized',
 -   //   'secureProtocol',
 -   //   'secureOptions',
 -   // ];
 -   // for (let i = 0; i < sslNames.length; i++) {
 -   //   const name = sslNames[i];
 -   //   if (args.hasOwnProperty(name)) {
 -   //     options[name] = args[name];
 -   //   }
 -   // }
 - 
 -   // don't check ssl
 -   // if (options.rejectUnauthorized === false && !options.hasOwnProperty('secureOptions')) {
 -   //   options.secureOptions = require('constants').SSL_OP_NO_TLSv1_2;
 -   // }
 - 
 -   const auth = args.auth || parsedUrl.auth;
 -   if (auth) {
 -     options.auth = auth;
 -   }
 - 
 -   // content undefined  data 有值
 -   let body = args.content || args.data;
 -   const dataAsQueryString = method === 'GET' || method === 'HEAD' || args.dataAsQueryString;
 -   if (!args.content) {
 -     if (body && !(typeof body === 'string' || Buffer.isBuffer(body))) {
 -       if (dataAsQueryString) {
 -         // read: GET, HEAD, use query string
 -         body = args.nestedQuerystring ? qs.stringify(body) : querystring.stringify(body);
 -       } else {
 -         let contentType = options.headers['Content-Type'] || options.headers['content-type'];
 -         // auto add application/x-www-form-urlencoded when using urlencode form request
 -         if (!contentType) {
 -           if (args.contentType === 'json') {
 -             contentType = 'application/json';
 -           } else {
 -             contentType = 'application/x-www-form-urlencoded';
 -           }
 -           options.headers['Content-Type'] = contentType;
 -         }
 - 
 -         if (parseContentType(contentType) === 'application/json') {
 -           body = JSON.stringify(body);
 -         } else {
 -           // 'application/x-www-form-urlencoded'
 -           body = args.nestedQuerystring ? qs.stringify(body) : querystring.stringify(body);
 -         }
 -       }
 -     }
 -   }
 - 
 -   // if it's a GET or HEAD request, data should be sent as query string
 -   if (dataAsQueryString && body) {
 -     options.path += (parsedUrl.query ? '&' : '?') + body;
 -     body = null;
 -   }
 - 
 -   let requestSize = 0;
 -   if (body) {
 -     let length = body.length;
 -     if (!Buffer.isBuffer(body)) {
 -       length = Buffer.byteLength(body);
 -     }
 -     requestSize = options.headers['Content-Length'] = length;
 -   }
 - 
 -   if (args.dataType === 'json') {
 -     options.headers.Accept = 'application/json';
 -   }
 - 
 -   if (typeof args.beforeRequest === 'function') {
 -     // you can use this hook to change every thing.
 -     args.beforeRequest(options);
 -   }
 -   let connectTimer = null;
 -   let responseTimer = null;
 -   let __err = null;
 -   let connected = false; // socket connected or not
 -   let keepAliveSocket = false; // request with keepalive socket
 -   let responseSize = 0;
 -   let statusCode = -1;
 -   let responseAborted = false;
 -   let remoteAddress = '';
 -   let remotePort = '';
 -   let timing = null;
 -   if (args.timing) {
 -     timing = {
 -       // socket assigned
 -       queuing: 0,
 -       // dns lookup time
 -       dnslookup: 0,
 -       // socket connected
 -       connected: 0,
 -       // request sent
 -       requestSent: 0,
 -       // Time to first byte (TTFB)
 -       waiting: 0,
 -       contentDownload: 0
 -     };
 -   }
 - 
 -   function cancelConnectTimer() {
 -     if (connectTimer) {
 -       clearTimeout(connectTimer);
 -       connectTimer = null;
 -     }
 -   }
 -   function cancelResponseTimer() {
 -     if (responseTimer) {
 -       clearTimeout(responseTimer);
 -       responseTimer = null;
 -     }
 -   }
 - 
 -   function done(err, data, res) {
 -     cancelResponseTimer();
 -     if (!callback) {
 -       console.warn(
 -         '[urllib:warn] [%s] [%s] [worker:%s] %s %s callback twice!!!',
 -         Date(),
 -         reqId,
 -         process.pid,
 -         options.method,
 -         url
 -       );
 -       // https://github.com/node-modules/urllib/pull/30
 -       if (err) {
 -         console.warn(
 -           '[urllib:warn] [%s] [%s] [worker:%s] %s: %s\nstack: %s',
 -           Date(),
 -           reqId,
 -           process.pid,
 -           err.name,
 -           err.message,
 -           err.stack
 -         );
 -       }
 -       return;
 -     }
 -     const cb = callback;
 -     callback = null;
 -     let headers = {};
 -     if (res) {
 -       statusCode = res.statusCode;
 -       headers = res.headers;
 -     }
 - 
 -     // handle digest auth
 -     // if (statusCode === 401 && headers['www-authenticate']
 -     //   && (!args.headers || !args.headers.Authorization) && args.digestAuth) {
 -     //   const authenticate = headers['www-authenticate'];
 -     //   if (authenticate.indexOf('Digest ') >= 0) {
 -     //     debug('Request#%d %s: got digest auth header WWW-Authenticate: %s', reqId, url, authenticate);
 -     //     args.headers = args.headers || {};
 -     //     args.headers.Authorization = digestAuthHeader(options.method, options.path, authenticate, args.digestAuth);
 -     //     debug('Request#%d %s: auth with digest header: %s', reqId, url, args.headers.Authorization);
 -     //     if (res.headers['set-cookie']) {
 -     //       args.headers.Cookie = res.headers['set-cookie'].join(';');
 -     //     }
 -     //     return exports.requestWithCallback(url, args, cb);
 -     //   }
 -     // }
 - 
 -     const requestUseTime = Date.now() - requestStartTime;
 -     if (timing) {
 -       timing.contentDownload = requestUseTime;
 -     }
 - 
 -     debug(
 -       '[%sms] done, %s bytes HTTP %s %s %s %s, keepAliveSocket: %s, timing: %j',
 -       requestUseTime,
 -       responseSize,
 -       statusCode,
 -       options.method,
 -       options.host,
 -       options.path,
 -       keepAliveSocket,
 -       timing
 -     );
 - 
 -     const response = {
 -       status: statusCode,
 -       statusCode: statusCode,
 -       headers: headers,
 -       size: responseSize,
 -       aborted: responseAborted,
 -       rt: requestUseTime,
 -       keepAliveSocket: keepAliveSocket,
 -       data: data,
 -       requestUrls: args.requestUrls,
 -       timing: timing,
 -       remoteAddress: remoteAddress,
 -       remotePort: remotePort
 -     };
 - 
 -     if (err) {
 -       let agentStatus = '';
 -       if (agent && typeof agent.getCurrentStatus === 'function') {
 -         // add current agent status to error message for logging and debug
 -         agentStatus = ', agent status: ' + JSON.stringify(agent.getCurrentStatus());
 -       }
 -       err.message +=
 -         ', ' +
 -         options.method +
 -         ' ' +
 -         url +
 -         ' ' +
 -         statusCode +
 -         ' (connected: ' +
 -         connected +
 -         ', keepalive socket: ' +
 -         keepAliveSocket +
 -         agentStatus +
 -         ')' +
 -         '\nheaders: ' +
 -         JSON.stringify(headers);
 -       err.data = data;
 -       err.path = options.path;
 -       err.status = statusCode;
 -       err.headers = headers;
 -       err.res = response;
 -     }
 - 
 -     cb(err, data, args.streaming ? res : response);
 - 
 -     if (args.emitter) {
 -       // keep to use the same reqMeta object on request event before
 -       reqMeta.url = url;
 -       reqMeta.socket = req && req.connection;
 -       reqMeta.options = options;
 -       reqMeta.size = requestSize;
 - 
 -       args.emitter.emit('response', {
 -         requestId: reqId,
 -         error: err,
 -         ctx: args.ctx,
 -         req: reqMeta,
 -         res: response
 -       });
 -     }
 -   }
 - 
 -   function handleRedirect(res) {
 -     let err = null;
 -     if (args.followRedirect && statuses.redirect[res.statusCode]) {
 -       // handle redirect
 -       args._followRedirectCount = (args._followRedirectCount || 0) + 1;
 -       const location = res.headers.location;
 -       if (!location) {
 -         err = new Error('Got statusCode ' + res.statusCode + ' but cannot resolve next location from headers');
 -         err.name = 'FollowRedirectError';
 -       } else if (args._followRedirectCount > args.maxRedirects) {
 -         err = new Error('Exceeded maxRedirects. Probably stuck in a redirect loop ' + url);
 -         err.name = 'MaxRedirectError';
 -       } else {
 -         const newUrl = args.formatRedirectUrl ? args.formatRedirectUrl(url, location) : urlutil.resolve(url, location);
 -         debug('Request#%d %s: `redirected` from %s to %s', reqId, options.path, url, newUrl);
 -         // make sure timer stop
 -         cancelResponseTimer();
 -         // should clean up headers.Host on `location: http://other-domain/url`
 -         if (args.headers && args.headers.Host && PROTO_RE.test(location)) {
 -           args.headers.Host = null;
 -         }
 -         // avoid done will be execute in the future change.
 -         const cb = callback;
 -         callback = null;
 -         exports.requestWithCallback(newUrl, args, cb);
 -         return {
 -           redirect: true,
 -           error: null
 -         };
 -       }
 -     }
 -     return {
 -       redirect: false,
 -       error: err
 -     };
 -   }
 - 
 -   if (args.gzip) {
 -     if (!options.headers['Accept-Encoding'] && !options.headers['accept-encoding']) {
 -       options.headers['Accept-Encoding'] = 'gzip';
 -     }
 -   }
 - 
 -   function decodeContent(res, body, cb) {
 -     const encoding = res.headers['content-encoding'];
 -     // if (body.length === 0) {
 -     //   return cb(null, body, encoding);
 -     // }
 - 
 -     // if (!encoding || encoding.toLowerCase() !== 'gzip') {
 -     return cb(null, body, encoding);
 -     // }
 - 
 -     // debug('gunzip %d length body', body.length);
 -     // zlib.gunzip(body, cb);
 -   }
 - 
 -   const writeStream = args.writeStream;
 - 
 -   debug('Request#%d %s %s with headers %j, options.path: %s', reqId, method, url, options.headers, options.path);
 - 
 -   args.requestUrls.push(url);
 - 
 -   function onResponse(res) {
 -     if (timing) {
 -       timing.waiting = Date.now() - requestStartTime;
 -     }
 -     debug('Request#%d %s `req response` event emit: status %d, headers: %j', reqId, url, res.statusCode, res.headers);
 - 
 -     if (args.streaming) {
 -       const result = handleRedirect(res);
 -       if (result.redirect) {
 -         res.resume();
 -         return;
 -       }
 -       if (result.error) {
 -         res.resume();
 -         return done(result.error, null, res);
 -       }
 - 
 -       return done(null, null, res);
 -     }
 - 
 -     res.on('close', function () {
 -       debug('Request#%d %s: `res close` event emit, total size %d', reqId, url, responseSize);
 -     });
 - 
 -     res.on('error', function () {
 -       debug('Request#%d %s: `res error` event emit, total size %d', reqId, url, responseSize);
 -     });
 - 
 -     res.on('aborted', function () {
 -       responseAborted = true;
 -       debug('Request#%d %s: `res aborted` event emit, total size %d', reqId, url, responseSize);
 -     });
 - 
 -     if (writeStream) {
 -       // If there's a writable stream to recieve the response data, just pipe the
 -       // response stream to that writable stream and call the callback when it has
 -       // finished writing.
 -       //
 -       // NOTE that when the response stream `res` emits an 'end' event it just
 -       // means that it has finished piping data to another stream. In the
 -       // meanwhile that writable stream may still writing data to the disk until
 -       // it emits a 'close' event.
 -       //
 -       // That means that we should not apply callback until the 'close' of the
 -       // writable stream is emited.
 -       //
 -       // See also:
 -       // - https://github.com/TBEDP/urllib/commit/959ac3365821e0e028c231a5e8efca6af410eabb
 -       // - http://nodejs.org/api/stream.html#stream_event_end
 -       // - http://nodejs.org/api/stream.html#stream_event_close_1
 -       const result = handleRedirect(res);
 -       if (result.redirect) {
 -         res.resume();
 -         return;
 -       }
 -       if (result.error) {
 -         res.resume();
 -         // end ths stream first
 -         writeStream.end();
 -         return done(result.error, null, res);
 -       }
 -       // you can set consumeWriteStream false that only wait response end
 -       if (args.consumeWriteStream === false) {
 -         res.on('end', done.bind(null, null, null, res));
 -       } else {
 -         // node 0.10, 0.12: only emit res aborted, writeStream close not fired
 -         // if (isNode010 || isNode012) {
 -         //   first([
 -         //     [ writeStream, 'close' ],
 -         //     [ res, 'aborted' ],
 -         //   ], function(_, stream, event) {
 -         //     debug('Request#%d %s: writeStream or res %s event emitted', reqId, url, event);
 -         //     done(__err || null, null, res);
 -         //   });
 -         if (false) {
 -         } else {
 -           writeStream.on('close', function () {
 -             debug('Request#%d %s: writeStream close event emitted', reqId, url);
 -             done(__err || null, null, res);
 -           });
 -         }
 -       }
 -       return res.pipe(writeStream);
 -     }
 - 
 -     // Otherwise, just concat those buffers.
 -     //
 -     // NOTE that the `chunk` is not a String but a Buffer. It means that if
 -     // you simply concat two chunk with `+` you're actually converting both
 -     // Buffers into Strings before concating them. It'll cause problems when
 -     // dealing with multi-byte characters.
 -     //
 -     // The solution is to store each chunk in an array and concat them with
 -     // 'buffer-concat' when all chunks is recieved.
 -     //
 -     // See also:
 -     // http://cnodejs.org/topic/4faf65852e8fb5bc65113403
 - 
 -     const chunks = [];
 - 
 -     res.on('data', function (chunk) {
 -       debug('Request#%d %s: `res data` event emit, size %d', reqId, url, chunk.length);
 -       responseSize += chunk.length;
 -       chunks.push(chunk);
 -     });
 - 
 -     res.on('end', function () {
 -       const body = Buffer.concat(chunks, responseSize);
 -       debug('Request#%d %s: `res end` event emit, total size %d, _dumped: %s', reqId, url, responseSize, res._dumped);
 - 
 -       if (__err) {
 -         // req.abort() after `res data` event emit.
 -         return done(__err, body, res);
 -       }
 - 
 -       const result = handleRedirect(res);
 -       if (result.error) {
 -         return done(result.error, body, res);
 -       }
 -       if (result.redirect) {
 -         return;
 -       }
 - 
 -       decodeContent(res, body, function (err, data, encoding) {
 -         if (err) {
 -           return done(err, body, res);
 -         }
 -         // if body not decode, dont touch it
 -         if (!encoding && TEXT_DATA_TYPES.indexOf(args.dataType) >= 0) {
 -           // try to decode charset
 -           try {
 -             data = decodeBodyByCharset(data, res);
 -           } catch (e) {
 -             debug('decodeBodyByCharset error: %s', e);
 -             // if error, dont touch it
 -             return done(null, data, res);
 -           }
 - 
 -           if (args.dataType === 'json') {
 -             if (responseSize === 0) {
 -               data = null;
 -             } else {
 -               const r = parseJSON(data, fixJSONCtlChars);
 -               if (r.error) {
 -                 err = r.error;
 -               } else {
 -                 data = r.data;
 -               }
 -             }
 -           }
 -         }
 - 
 -         if (responseAborted) {
 -           // err = new Error('Remote socket was terminated before `response.end()` was called');
 -           // err.name = 'RemoteSocketClosedError';
 -           debug('Request#%d %s: Remote socket was terminated before `response.end()` was called', reqId, url);
 -         }
 - 
 -         done(err, data, res);
 -       });
 -     });
 -   }
 - 
 -   let connectTimeout, responseTimeout;
 -   if (Array.isArray(args.timeout)) {
 -     connectTimeout = ms(args.timeout[0]);
 -     responseTimeout = ms(args.timeout[1]);
 -   } else {
 -     // set both timeout equal
 -     connectTimeout = responseTimeout = ms(args.timeout);
 -   }
 -   debug('ConnectTimeout: %d, ResponseTimeout: %d', connectTimeout, responseTimeout);
 - 
 -   function startConnectTimer() {
 -     debug('Connect timer ticking, timeout: %d', connectTimeout);
 -     connectTimer = setTimeout(function () {
 -       connectTimer = null;
 -       if (statusCode === -1) {
 -         statusCode = -2;
 -       }
 -       let msg = 'Connect timeout for ' + connectTimeout + 'ms';
 -       let errorName = 'ConnectionTimeoutError';
 -       if (!req.socket) {
 -         errorName = 'SocketAssignTimeoutError';
 -         msg += ', working sockets is full';
 -       }
 -       __err = new Error(msg);
 -       __err.name = errorName;
 -       __err.requestId = reqId;
 -       debug('ConnectTimeout: Request#%d %s %s: %s, connected: %s', reqId, url, __err.name, msg, connected);
 -       abortRequest();
 -     }, connectTimeout);
 -   }
 - 
 -   function startResposneTimer() {
 -     debug('Response timer ticking, timeout: %d', responseTimeout);
 -     responseTimer = setTimeout(function () {
 -       responseTimer = null;
 -       const msg = 'Response timeout for ' + responseTimeout + 'ms';
 -       const errorName = 'ResponseTimeoutError';
 -       __err = new Error(msg);
 -       __err.name = errorName;
 -       __err.requestId = reqId;
 -       debug('ResponseTimeout: Request#%d %s %s: %s, connected: %s', reqId, url, __err.name, msg, connected);
 -       abortRequest();
 -     }, responseTimeout);
 -   }
 - 
 -   let req;
 -   // request headers checker will throw error
 -   options.mode = args.mode ? args.mode : '';
 -   try {
 -     req = httplib.request(options, onResponse);
 -   } catch (err) {
 -     return done(err);
 -   }
 - 
 -   // environment detection: browser or nodejs
 -   if (typeof window === 'undefined') {
 -     // start connect timer just after `request` return, and just in nodejs environment
 -     startConnectTimer();
 -   } else {
 -     req.on('requestTimeout', function () {
 -       if (statusCode === -1) {
 -         statusCode = -2;
 -       }
 -       const msg = 'Connect timeout for ' + connectTimeout + 'ms';
 -       const errorName = 'ConnectionTimeoutError';
 -       __err = new Error(msg);
 -       __err.name = errorName;
 -       __err.requestId = reqId;
 -       abortRequest();
 -     });
 -   }
 - 
 -   function abortRequest() {
 -     debug('Request#%d %s abort, connected: %s', reqId, url, connected);
 -     // it wont case error event when req haven't been assigned a socket yet.
 -     if (!req.socket) {
 -       __err.noSocket = true;
 -       done(__err);
 -     }
 -     req.abort();
 -   }
 - 
 -   if (timing) {
 -     // request sent
 -     req.on('finish', function () {
 -       timing.requestSent = Date.now() - requestStartTime;
 -     });
 -   }
 - 
 -   req.once('socket', function (socket) {
 -     if (timing) {
 -       // socket queuing time
 -       timing.queuing = Date.now() - requestStartTime;
 -     }
 - 
 -     // https://github.com/nodejs/node/blob/master/lib/net.js#L377
 -     // https://github.com/nodejs/node/blob/v0.10.40-release/lib/net.js#L352
 -     // should use socket.socket on 0.10.x
 -     // if (isNode010 && socket.socket) {
 -     //   socket = socket.socket;
 -     // }
 - 
 -     const readyState = socket.readyState;
 -     if (readyState === 'opening') {
 -       socket.once('lookup', function (err, ip, addressType) {
 -         debug('Request#%d %s lookup: %s, %s, %s', reqId, url, err, ip, addressType);
 -         if (timing) {
 -           timing.dnslookup = Date.now() - requestStartTime;
 -         }
 -         if (ip) {
 -           remoteAddress = ip;
 -         }
 -       });
 -       socket.once('connect', function () {
 -         if (timing) {
 -           // socket connected
 -           timing.connected = Date.now() - requestStartTime;
 -         }
 - 
 -         // cancel socket timer at first and start tick for TTFB
 -         cancelConnectTimer();
 -         startResposneTimer();
 - 
 -         debug('Request#%d %s new socket connected', reqId, url);
 -         connected = true;
 -         if (!remoteAddress) {
 -           remoteAddress = socket.remoteAddress;
 -         }
 -         remotePort = socket.remotePort;
 -       });
 -       return;
 -     }
 - 
 -     debug('Request#%d %s reuse socket connected, readyState: %s', reqId, url, readyState);
 -     connected = true;
 -     keepAliveSocket = true;
 -     if (!remoteAddress) {
 -       remoteAddress = socket.remoteAddress;
 -     }
 -     remotePort = socket.remotePort;
 - 
 -     // reuse socket, timer should be canceled.
 -     cancelConnectTimer();
 -     startResposneTimer();
 -   });
 - 
 -   req.on('error', function (err) {
 -     //TypeError for browser fetch api, Error for browser xmlhttprequest api
 -     if (err.name === 'Error' || err.name === 'TypeError') {
 -       err.name = connected ? 'ResponseError' : 'RequestError';
 -     }
 -     err.message += ' (req "error")';
 -     debug('Request#%d %s `req error` event emit, %s: %s', reqId, url, err.name, err.message);
 -     done(__err || err);
 -   });
 - 
 -   if (writeStream) {
 -     writeStream.once('error', function (err) {
 -       err.message += ' (writeStream "error")';
 -       __err = err;
 -       debug('Request#%d %s `writeStream error` event emit, %s: %s', reqId, url, err.name, err.message);
 -       abortRequest();
 -     });
 -   }
 - 
 -   if (args.stream) {
 -     args.stream.pipe(req);
 -     args.stream.once('error', function (err) {
 -       err.message += ' (stream "error")';
 -       __err = err;
 -       debug('Request#%d %s `readStream error` event emit, %s: %s', reqId, url, err.name, err.message);
 -       abortRequest();
 -     });
 -   } else {
 -     req.end(body);
 -   }
 - 
 -   req.requestId = reqId;
 -   return req;
 - };
 
 
  |