diff options
Diffstat (limited to 'deps/npm/node_modules/npm-profile/node_modules/make-fetch-happen/node_modules/node-fetch-npm/src/index.js')
-rw-r--r-- | deps/npm/node_modules/npm-profile/node_modules/make-fetch-happen/node_modules/node-fetch-npm/src/index.js | 214 |
1 files changed, 214 insertions, 0 deletions
diff --git a/deps/npm/node_modules/npm-profile/node_modules/make-fetch-happen/node_modules/node-fetch-npm/src/index.js b/deps/npm/node_modules/npm-profile/node_modules/make-fetch-happen/node_modules/node-fetch-npm/src/index.js new file mode 100644 index 0000000000..b2cf80f9ec --- /dev/null +++ b/deps/npm/node_modules/npm-profile/node_modules/make-fetch-happen/node_modules/node-fetch-npm/src/index.js @@ -0,0 +1,214 @@ +'use strict' + +/** + * index.js + * + * a request API compatible with window.fetch + */ + +const url = require('url') +const http = require('http') +const https = require('https') +const zlib = require('zlib') +const PassThrough = require('stream').PassThrough + +const Body = require('./body.js') +const writeToStream = Body.writeToStream +const Response = require('./response') +const Headers = require('./headers') +const Request = require('./request') +const getNodeRequestOptions = Request.getNodeRequestOptions +const FetchError = require('./fetch-error') +const isURL = /^https?:/ + +/** + * Fetch function + * + * @param Mixed url Absolute url or Request instance + * @param Object opts Fetch options + * @return Promise + */ +exports = module.exports = fetch +function fetch (uri, opts) { + // allow custom promise + if (!fetch.Promise) { + throw new Error('native promise missing, set fetch.Promise to your favorite alternative') + } + + Body.Promise = fetch.Promise + + // wrap http.request into fetch + return new fetch.Promise((resolve, reject) => { + // build request object + const request = new Request(uri, opts) + const options = getNodeRequestOptions(request) + + const send = (options.protocol === 'https:' ? https : http).request + + // http.request only support string as host header, this hack make custom host header possible + if (options.headers.host) { + options.headers.host = options.headers.host[0] + } + + // send request + const req = send(options) + let reqTimeout + + if (request.timeout) { + req.once('socket', socket => { + reqTimeout = setTimeout(() => { + req.abort() + reject(new FetchError(`network timeout at: ${request.url}`, 'request-timeout')) + }, request.timeout) + }) + } + + req.on('error', err => { + clearTimeout(reqTimeout) + reject(new FetchError(`request to ${request.url} failed, reason: ${err.message}`, 'system', err)) + }) + + req.on('response', res => { + clearTimeout(reqTimeout) + + // handle redirect + if (fetch.isRedirect(res.statusCode) && request.redirect !== 'manual') { + if (request.redirect === 'error') { + reject(new FetchError(`redirect mode is set to error: ${request.url}`, 'no-redirect')) + return + } + + if (request.counter >= request.follow) { + reject(new FetchError(`maximum redirect reached at: ${request.url}`, 'max-redirect')) + return + } + + if (!res.headers.location) { + reject(new FetchError(`redirect location header missing at: ${request.url}`, 'invalid-redirect')) + return + } + // Remove authorization if changing hostnames (but not if just + // changing ports or protocols). This matches the behavior of request: + // https://github.com/request/request/blob/b12a6245/lib/redirect.js#L134-L138 + const resolvedUrl = url.resolve(request.url, res.headers.location) + let redirectURL = '' + if (!isURL.test(res.headers.location)) { + redirectURL = url.parse(resolvedUrl) + } else { + redirectURL = url.parse(res.headers.location) + } + if (url.parse(request.url).hostname !== redirectURL.hostname) { + request.headers.delete('authorization') + } + + // per fetch spec, for POST request with 301/302 response, or any request with 303 response, use GET when following redirect + if (res.statusCode === 303 || + ((res.statusCode === 301 || res.statusCode === 302) && request.method === 'POST')) { + request.method = 'GET' + request.body = null + request.headers.delete('content-length') + } + + request.counter++ + + resolve(fetch(resolvedUrl, request)) + return + } + + // normalize location header for manual redirect mode + const headers = new Headers() + for (const name of Object.keys(res.headers)) { + if (Array.isArray(res.headers[name])) { + for (const val of res.headers[name]) { + headers.append(name, val) + } + } else { + headers.append(name, res.headers[name]) + } + } + if (request.redirect === 'manual' && headers.has('location')) { + headers.set('location', url.resolve(request.url, headers.get('location'))) + } + + // prepare response + let body = res.pipe(new PassThrough()) + const responseOptions = { + url: request.url, + status: res.statusCode, + statusText: res.statusMessage, + headers: headers, + size: request.size, + timeout: request.timeout + } + + // HTTP-network fetch step 16.1.2 + const codings = headers.get('Content-Encoding') + + // HTTP-network fetch step 16.1.3: handle content codings + + // in following scenarios we ignore compression support + // 1. compression support is disabled + // 2. HEAD request + // 3. no Content-Encoding header + // 4. no content response (204) + // 5. content not modified response (304) + if (!request.compress || request.method === 'HEAD' || codings === null || res.statusCode === 204 || res.statusCode === 304) { + resolve(new Response(body, responseOptions)) + return + } + + // Be less strict when decoding compressed responses, since sometimes + // servers send slightly invalid responses that are still accepted + // by common browsers. + // Always using Z_SYNC_FLUSH is what cURL does. + const zlibOptions = { + flush: zlib.Z_SYNC_FLUSH, + finishFlush: zlib.Z_SYNC_FLUSH + } + + // for gzip + if (codings === 'gzip' || codings === 'x-gzip') { + body = body.pipe(zlib.createGunzip(zlibOptions)) + resolve(new Response(body, responseOptions)) + return + } + + // for deflate + if (codings === 'deflate' || codings === 'x-deflate') { + // handle the infamous raw deflate response from old servers + // a hack for old IIS and Apache servers + const raw = res.pipe(new PassThrough()) + raw.once('data', chunk => { + // see http://stackoverflow.com/questions/37519828 + if ((chunk[0] & 0x0F) === 0x08) { + body = body.pipe(zlib.createInflate(zlibOptions)) + } else { + body = body.pipe(zlib.createInflateRaw(zlibOptions)) + } + resolve(new Response(body, responseOptions)) + }) + return + } + + // otherwise, use response as-is + resolve(new Response(body, responseOptions)) + }) + + writeToStream(req, request) + }) +}; + +/** + * Redirect code matching + * + * @param Number code Status code + * @return Boolean + */ +fetch.isRedirect = code => code === 301 || code === 302 || code === 303 || code === 307 || code === 308 + +// expose Promise +fetch.Promise = global.Promise +exports.Headers = Headers +exports.Request = Request +exports.Response = Response +exports.FetchError = FetchError |