diff --git a/.gitignore b/.gitignore index 98f9955..56e45ac 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ node_modules coverage .idea +*.tgz diff --git a/.npmignore b/.npmignore deleted file mode 100644 index 166cb9b..0000000 --- a/.npmignore +++ /dev/null @@ -1,6 +0,0 @@ -test/ -docs/ -.npmignore -.editorconfig -.travis.yml -.jshintrc diff --git a/.travis.yml b/.travis.yml index 415fa2c..6929422 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,5 @@ language: node_js node_js: - - 0.12 - - 4 - - 5 - -after_success: make coveralls + - "7" + - "8" + - "10" \ No newline at end of file diff --git a/Makefile b/Makefile deleted file mode 100644 index b997293..0000000 --- a/Makefile +++ /dev/null @@ -1,7 +0,0 @@ -test: - node --harmony ./node_modules/.bin/istanbul cover ./node_modules/.bin/_mocha -- -R spec -t 20000 - -coveralls: test - cat ./coverage/lcov.info | ./node_modules/.bin/coveralls - -.PHONY: test diff --git a/README.md b/README.md index 96bf7dd..1a8c7df 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# koa-proxy [![Build Status](https://travis-ci.org/popomore/koa-proxy.png?branch=master)](https://travis-ci.org/popomore/koa-proxy) [![Coverage Status](https://coveralls.io/repos/popomore/koa-proxy/badge.png?branch=master)](https://coveralls.io/r/popomore/koa-proxy?branch=master) +# koa-proxy [![Build Status](https://travis-ci.com/edorivai/koa-proxy.svg?branch=master)](https://travis-ci.com/edorivai/koa-proxy) Proxy middleware for koa @@ -70,7 +70,7 @@ app.use(proxy({ })); ``` -Proxy won't send cookie to real server, you can set `jar = true` to send it. +You can configure proxy to remember cookies for future use by setting `jar = true`. This means cookies set by server will be stored and resent in subsequent requests. For me info see the documentation for [request](https://github.com/request/request). ```js app.use(proxy({ @@ -87,6 +87,16 @@ app.use(proxy({ })); ``` +You can also add new headers to your response or override existing ones +```js +app.use(proxy({ + overrideResponseHeaders: { + "cow": "moo", + "duck": "quack" + }, +})); +``` + ## LICENSE Copyright (c) 2014 popomore. Licensed under the MIT license. diff --git a/index.js b/index.js index 0b5bf8f..47f35d1 100644 --- a/index.js +++ b/index.js @@ -1,109 +1,117 @@ 'use strict'; +var Stream = require('stream'); var join = require('url').resolve; -var iconv = require('iconv-lite'); -var coRequest = require('co-request'); +var rp = require('request-promise-native'); +var requestLib = require('request'); +var pauseStream = require('pause-stream'); module.exports = function(options) { options || (options = {}); - var request = coRequest.defaults({ jar: options.jar === true }); if (!(options.host || options.map || options.url)) { throw new Error('miss options'); } - return function* proxy(next) { - var url = resolve(this.path, options); + return async function proxy(ctx, next) { + var url = resolve(ctx.path, options); - if(typeof options.suppressRequestHeaders === 'object'){ - options.suppressRequestHeaders.forEach(function(h, i){ + if (typeof options.suppressRequestHeaders === 'object') { + options.suppressRequestHeaders.forEach(function(h, i) { options.suppressRequestHeaders[i] = h.toLowerCase(); }); } - var suppressResponseHeaders = []; // We should not be overwriting the options object! - if(typeof options.suppressResponseHeaders === 'object'){ - options.suppressResponseHeaders.forEach(function(h, i){ + var suppressResponseHeaders = []; // We should not be overwriting the options object! + if (typeof options.suppressResponseHeaders === 'object') { + options.suppressResponseHeaders.forEach(function(h, i) { suppressResponseHeaders.push(h.toLowerCase()); }); } // don't match if (!url) { - return yield* next; + return next(); } // if match option supplied, restrict proxy to that match if (options.match) { - if (!this.path.match(options.match)) { - return yield* next; + if (!ctx.path.match(options.match)) { + return next(); } } - - var parsedBody = getParsedBody(this); + + var parsedBody = getParsedBody(ctx); var opt = { - url: url + (this.querystring ? '?' + this.querystring : ''), - headers: this.header, + jar: options.jar === true, + url: url + (ctx.querystring ? '?' + ctx.querystring : ''), + headers: ctx.request.header, encoding: null, followRedirect: options.followRedirect === false ? false : true, - method: this.method, + method: ctx.method, body: parsedBody, + simple: false, + resolveWithFullResponse: true // make request-promise respond with the complete response object }; - // set 'Host' header to options.host (without protocol prefix), strip trailing slash - if (options.host) opt.headers.host = options.host.slice(options.host.indexOf('://')+3).replace(/\/$/,''); + // set "Host" header to options.host (without protocol prefix), strip trailing slash + if (options.host) + opt.headers.host = options.host + .slice(options.host.indexOf('://') + 3) + .replace(/\/$/, ''); if (options.requestOptions) { if (typeof options.requestOptions === 'function') { - opt = options.requestOptions(this.request, opt); + opt = options.requestOptions(ctx.request, opt); } else { - Object.keys(options.requestOptions).forEach(function (option) { opt[option] = options.requestOptions[option]; }); + Object.keys(options.requestOptions).forEach(function(option) { + opt[option] = options.requestOptions[option]; + }); } } - for(name in opt.headers){ - if(options.suppressRequestHeaders && options.suppressRequestHeaders.indexOf(name.toLowerCase()) >= 0){ + for (let name in opt.headers) { + if ( + options.suppressRequestHeaders && + options.suppressRequestHeaders.indexOf(name.toLowerCase()) >= 0 + ) { delete opt.headers[name]; } } - var requestThunk = request(opt); - - if (parsedBody) { - var res = yield requestThunk; + if (parsedBody || ctx.method === 'GET') { + var res = await rp(opt); } else { - // Is there a better way? - // https://github.com/leukhin/co-request/issues/11 - var res = yield pipeRequest(this.req, requestThunk); + var res = await pipe(ctx.req, opt); } - this.status = res.statusCode; for (var name in res.headers) { // http://stackoverflow.com/questions/35525715/http-get-parse-error-code-hpe-unexpected-content-length - if(suppressResponseHeaders.indexOf(name.toLowerCase())>=0){ + if (suppressResponseHeaders.indexOf(name.toLowerCase()) >= 0) { continue; } if (name === 'transfer-encoding') { continue; } - this.set(name, res.headers[name]); + ctx.set(name, res.headers[name]); } - if (options.encoding === 'gbk') { - this.body = iconv.decode(res.body, 'gbk'); - return; + if(options.overrideResponseHeaders) { + for (let headerKey in options.overrideResponseHeaders) { + ctx.set(headerKey, options.overrideResponseHeaders[headerKey]); + } } - this.body = res.body; + ctx.body = ctx.body || res.body; + ctx.status = res.statusCode; if (options.yieldNext) { - yield next; + return next(); } }; }; - function resolve(path, options) { var url = options.url; if (url) { @@ -128,14 +136,14 @@ function ignoreQuery(url) { return url ? url.split('?')[0] : null; } -function getParsedBody(ctx){ +function getParsedBody(ctx) { var body = ctx.request.body; - if (body === undefined || body === null){ + if (body === undefined || body === null) { return undefined; } var contentType = ctx.request.header['content-type']; - if (!Buffer.isBuffer(body) && typeof body !== 'string'){ - if (contentType && contentType.indexOf('json') !== -1){ + if (!Buffer.isBuffer(body) && typeof body !== 'string') { + if (contentType && contentType.indexOf('json') !== -1) { body = JSON.stringify(body); } else { body = body + ''; @@ -144,8 +152,14 @@ function getParsedBody(ctx){ return body; } -function pipeRequest(readable, requestThunk){ - return function(cb){ - readable.pipe(requestThunk(cb)); - } +/** + * Pipes the incoming request body through request() + */ +function pipe(incomingRequest, opt) { + return new Promise((resolve, reject) => { + incomingRequest.pipe(requestLib(opt, (error, response) => { + if (error) return reject(error); + resolve(response); + })) + }); } diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..7fc3fe0 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,1268 @@ +{ + "name": "koa-proxy", + "version": "1.0.0-alpha.3", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "accepts": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.4.tgz", + "integrity": "sha1-hiRnWMfdbSGmR0/whKR0DsBesh8=", + "dev": true, + "requires": { + "mime-types": "~2.1.16", + "negotiator": "0.6.1" + } + }, + "ajv": { + "version": "6.10.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.0.tgz", + "integrity": "sha512-nffhOpkymDECQyR0mnsUtoCE8RlX38G0rYP+wgLWFyZuUyuuojSSvi/+euOiQBIn63whYwYVIIH1TvE3tu4OEg==", + "requires": { + "fast-deep-equal": "^2.0.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "any-promise": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", + "integrity": "sha1-q8av7tzqUugJzcA3au0845Y10X8=", + "dev": true + }, + "asn1": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", + "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", + "requires": { + "safer-buffer": "~2.1.0" + } + }, + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" + }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" + }, + "aws-sign2": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=" + }, + "aws4": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz", + "integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==" + }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "dev": true + }, + "bcrypt-pbkdf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", + "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", + "requires": { + "tweetnacl": "^0.14.3" + } + }, + "brace-expansion": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.8.tgz", + "integrity": "sha1-wHshHHyVLsH479Uad+8NHTmQopI=", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "browser-stdout": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.0.tgz", + "integrity": "sha1-81HTKWnTL6XXpVZxVCY9korjvR8=", + "dev": true + }, + "bytes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", + "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=", + "dev": true + }, + "caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=" + }, + "co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", + "dev": true + }, + "co-body": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/co-body/-/co-body-5.1.1.tgz", + "integrity": "sha1-2XeB0eM0S6SoIP0YBr3fg0FQUjY=", + "dev": true, + "requires": { + "inflation": "^2.0.0", + "qs": "^6.4.0", + "raw-body": "^2.2.0", + "type-is": "^1.6.14" + } + }, + "combined-stream": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.5.tgz", + "integrity": "sha1-k4NwpXtKUd6ix3wV1cX9+JUWQAk=", + "dev": true, + "requires": { + "delayed-stream": "~1.0.0" + } + }, + "commander": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.11.0.tgz", + "integrity": "sha512-b0553uYA5YAEGgyYIGYROzKQ7X5RAqedkfjiZxwi0kL1g3bOaBNNZfYkzt/CL0umgD5wc9Jec2FbB98CjkMRvQ==", + "dev": true + }, + "component-emitter": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", + "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=", + "dev": true + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "content-disposition": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz", + "integrity": "sha1-DPaLud318r55YcOoUXjLhdunjLQ=", + "dev": true + }, + "content-type": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", + "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==", + "dev": true + }, + "cookies": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/cookies/-/cookies-0.7.1.tgz", + "integrity": "sha1-fIphX1SBxhq58WyDNzG8uPZjuZs=", + "dev": true, + "requires": { + "depd": "~1.1.1", + "keygrip": "~1.0.2" + } + }, + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" + }, + "dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", + "requires": { + "assert-plus": "^1.0.0" + } + }, + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "deep-equal": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.0.1.tgz", + "integrity": "sha1-9dJgKStmDghO/0zbyfCK0yR0SLU=", + "dev": true + }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" + }, + "delegates": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=", + "dev": true + }, + "depd": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.1.tgz", + "integrity": "sha1-V4O04cRZ8G+lyif5kfPQbnoxA1k=", + "dev": true + }, + "destroy": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", + "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=", + "dev": true + }, + "diff": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/diff/-/diff-3.3.1.tgz", + "integrity": "sha512-MKPHZDMB0o6yHyDryUOScqZibp914ksXwAMYMTHj6KO8UeKsRYNJD3oNCKjTqZon+V488P7N/HzXF8t7ZR95ww==", + "dev": true + }, + "ecc-jsbn": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", + "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", + "requires": { + "jsbn": "~0.1.0", + "safer-buffer": "^2.1.0" + } + }, + "ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=", + "dev": true + }, + "error-inject": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/error-inject/-/error-inject-1.0.0.tgz", + "integrity": "sha1-4rPZG1Su1nLzCdlQ0VSFD6EdTzc=", + "dev": true + }, + "escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=", + "dev": true + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true + }, + "extend": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.1.tgz", + "integrity": "sha1-p1Xqe8Gt/MWjHOfnYtuq3F5jZEQ=", + "dev": true + }, + "extsprintf": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=" + }, + "fast-deep-equal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", + "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=" + }, + "fast-json-stable-stringify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", + "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=" + }, + "forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=" + }, + "form-data": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.1.tgz", + "integrity": "sha1-b7lPvXGIUwbXPRXMSX/kzE7NRL8=", + "dev": true, + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.5", + "mime-types": "^2.1.12" + } + }, + "formidable": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/formidable/-/formidable-1.1.1.tgz", + "integrity": "sha1-lriIb3w8NQi5Mta9cMTTqI818ak=", + "dev": true + }, + "fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=", + "dev": true + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", + "requires": { + "assert-plus": "^1.0.0" + } + }, + "glob": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", + "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "growl": { + "version": "1.10.3", + "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.3.tgz", + "integrity": "sha512-hKlsbA5Vu3xsh1Cg3J7jSmX/WaW6A5oBeqzM88oNbCRQFz+zUaXm6yxS4RVytp1scBoJzSYl4YAEOQIt6O8V1Q==", + "dev": true + }, + "har-schema": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", + "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=" + }, + "har-validator": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz", + "integrity": "sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==", + "requires": { + "ajv": "^6.5.5", + "har-schema": "^2.0.0" + } + }, + "he": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/he/-/he-1.1.1.tgz", + "integrity": "sha1-k0EP0hsAlzUVH4howvJx80J+I/0=", + "dev": true + }, + "http-assert": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/http-assert/-/http-assert-1.3.0.tgz", + "integrity": "sha1-oxpc+IyHPsu1eWkH1NbxMujAHko=", + "dev": true, + "requires": { + "deep-equal": "~1.0.1", + "http-errors": "~1.6.1" + } + }, + "http-errors": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.2.tgz", + "integrity": "sha1-CgAsyFcHGSp+eUbO7cERVfYOxzY=", + "dev": true, + "requires": { + "depd": "1.1.1", + "inherits": "2.0.3", + "setprototypeof": "1.0.3", + "statuses": ">= 1.3.1 < 2" + } + }, + "http-signature": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", + "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", + "requires": { + "assert-plus": "^1.0.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" + } + }, + "inflation": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/inflation/-/inflation-2.0.0.tgz", + "integrity": "sha1-i0F+R8KPklpFEz2RTKH9OJEH8w8=", + "dev": true + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "dev": true + }, + "is-generator-function": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.6.tgz", + "integrity": "sha1-nnFlPNFf/zQcecQVFGChMdMen8Q=", + "dev": true + }, + "is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" + }, + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", + "dev": true + }, + "isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" + }, + "jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=" + }, + "json-schema": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", + "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=" + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" + }, + "json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=" + }, + "jsprim": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", + "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", + "requires": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.2.3", + "verror": "1.10.0" + } + }, + "keygrip": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/keygrip/-/keygrip-1.0.2.tgz", + "integrity": "sha1-rTKXxVcGneqLz+ek+kkbdcXd65E=", + "dev": true + }, + "koa": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/koa/-/koa-2.3.0.tgz", + "integrity": "sha1-nh6OTaQBg5xXuFJ+rcV/dhJ1Vac=", + "dev": true, + "requires": { + "accepts": "^1.2.2", + "content-disposition": "~0.5.0", + "content-type": "^1.0.0", + "cookies": "~0.7.0", + "debug": "*", + "delegates": "^1.0.0", + "depd": "^1.1.0", + "destroy": "^1.0.3", + "error-inject": "~1.0.0", + "escape-html": "~1.0.1", + "fresh": "^0.5.0", + "http-assert": "^1.1.0", + "http-errors": "^1.2.8", + "is-generator-function": "^1.0.3", + "koa-compose": "^4.0.0", + "koa-convert": "^1.2.0", + "koa-is-json": "^1.0.0", + "mime-types": "^2.0.7", + "on-finished": "^2.1.0", + "only": "0.0.2", + "parseurl": "^1.3.0", + "statuses": "^1.2.0", + "type-is": "^1.5.5", + "vary": "^1.0.0" + } + }, + "koa-body": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/koa-body/-/koa-body-2.5.0.tgz", + "integrity": "sha1-hOj82NUimozBy5ipJuk5Bp5xaRU=", + "dev": true, + "requires": { + "co-body": "^5.1.1", + "formidable": "^1.1.1" + } + }, + "koa-compose": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/koa-compose/-/koa-compose-4.0.0.tgz", + "integrity": "sha1-KAClE9nDYe8NY4UrA45Pby1adzw=", + "dev": true + }, + "koa-convert": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/koa-convert/-/koa-convert-1.2.0.tgz", + "integrity": "sha1-2kCHXfSd4FOQmNFwC1CCDOvNIdA=", + "dev": true, + "requires": { + "co": "^4.6.0", + "koa-compose": "^3.0.0" + }, + "dependencies": { + "koa-compose": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/koa-compose/-/koa-compose-3.2.1.tgz", + "integrity": "sha1-qFzLQLfZhtjlo0Wzoazo6rz1Tec=", + "dev": true, + "requires": { + "any-promise": "^1.1.0" + } + } + } + }, + "koa-is-json": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/koa-is-json/-/koa-is-json-1.0.0.tgz", + "integrity": "sha1-JzwH7c3Ljfaiwat9We52SRRR7BQ=", + "dev": true + }, + "koa-router": { + "version": "7.2.1", + "resolved": "https://registry.npmjs.org/koa-router/-/koa-router-7.2.1.tgz", + "integrity": "sha1-tApKs8attLQIld69AKnGQDBOMDk=", + "dev": true, + "requires": { + "debug": "^2.2.0", + "http-errors": "^1.3.1", + "koa-compose": "^3.0.0", + "methods": "^1.0.1", + "path-to-regexp": "^1.1.1" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "koa-compose": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/koa-compose/-/koa-compose-3.2.1.tgz", + "integrity": "sha1-qFzLQLfZhtjlo0Wzoazo6rz1Tec=", + "dev": true, + "requires": { + "any-promise": "^1.1.0" + } + } + } + }, + "koa-send": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/koa-send/-/koa-send-5.0.0.tgz", + "integrity": "sha512-90ZotV7t0p3uN9sRwW2D484rAaKIsD8tAVtypw/aBU+ryfV+fR2xrcAwhI8Wl6WRkojLUs/cB9SBSCuIb+IanQ==", + "dev": true, + "requires": { + "debug": "^3.1.0", + "http-errors": "^1.6.3", + "mz": "^2.7.0", + "resolve-path": "^1.4.0" + }, + "dependencies": { + "depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=", + "dev": true + }, + "http-errors": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz", + "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==", + "dev": true, + "requires": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.1", + "statuses": ">= 1.5.0 < 2", + "toidentifier": "1.0.0" + } + }, + "setprototypeof": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", + "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==", + "dev": true + }, + "statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=", + "dev": true + } + } + }, + "koa-static": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/koa-static/-/koa-static-5.0.0.tgz", + "integrity": "sha512-UqyYyH5YEXaJrf9S8E23GoJFQZXkBVJ9zYYMPGz919MSX1KuvAcycIuS0ci150HCoPf4XQVhQ84Qf8xRPWxFaQ==", + "dev": true, + "requires": { + "debug": "^3.1.0", + "koa-send": "^5.0.0" + } + }, + "lodash": { + "version": "4.17.11", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", + "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==" + }, + "media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=", + "dev": true + }, + "methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=", + "dev": true + }, + "mime-db": { + "version": "1.30.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.30.0.tgz", + "integrity": "sha1-dMZD2i3Z1qRTmZY0ZbJtXKfXHwE=", + "dev": true + }, + "mime-types": { + "version": "2.1.17", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.17.tgz", + "integrity": "sha1-Cdejk/A+mVp5+K+Fe3Cp4KsWVXo=", + "dev": true, + "requires": { + "mime-db": "~1.30.0" + } + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", + "dev": true + }, + "mkdirp": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "dev": true, + "requires": { + "minimist": "0.0.8" + } + }, + "mocha": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-4.0.1.tgz", + "integrity": "sha512-evDmhkoA+cBNiQQQdSKZa2b9+W2mpLoj50367lhy+Klnx9OV8XlCIhigUnn1gaTFLQCa0kdNhEGDr0hCXOQFDw==", + "dev": true, + "requires": { + "browser-stdout": "1.3.0", + "commander": "2.11.0", + "debug": "3.1.0", + "diff": "3.3.1", + "escape-string-regexp": "1.0.5", + "glob": "7.1.2", + "growl": "1.10.3", + "he": "1.1.1", + "mkdirp": "0.5.1", + "supports-color": "4.4.0" + }, + "dependencies": { + "has-flag": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz", + "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=", + "dev": true + }, + "supports-color": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.4.0.tgz", + "integrity": "sha512-rKC3+DyXWgK0ZLKwmRsrkyHVZAjNkfzeehuFWdGGcqGDTZFH73+RH6S/RDAAxl9GusSjZSUWYLmT9N5pzXFOXQ==", + "dev": true, + "requires": { + "has-flag": "^2.0.0" + } + } + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "mz": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", + "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", + "dev": true, + "requires": { + "any-promise": "^1.0.0", + "object-assign": "^4.0.1", + "thenify-all": "^1.0.0" + } + }, + "negotiator": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz", + "integrity": "sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk=", + "dev": true + }, + "oauth-sign": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", + "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==" + }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", + "dev": true + }, + "on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", + "dev": true, + "requires": { + "ee-first": "1.1.1" + } + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "requires": { + "wrappy": "1" + } + }, + "only": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/only/-/only-0.0.2.tgz", + "integrity": "sha1-Kv3oTQPlC5qO3EROMGEKcCle37Q=", + "dev": true + }, + "parseurl": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.2.tgz", + "integrity": "sha1-/CidTtiZMRlGDBViUyYs3I3mW/M=", + "dev": true + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true + }, + "path-to-regexp": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.7.0.tgz", + "integrity": "sha1-Wf3g9DW62suhA6hOnTvGTpa5k30=", + "dev": true, + "requires": { + "isarray": "0.0.1" + } + }, + "pause-stream": { + "version": "0.0.11", + "resolved": "https://registry.npmjs.org/pause-stream/-/pause-stream-0.0.11.tgz", + "integrity": "sha1-/lo0sMvOErWqaitAPuLnO2AvFEU=", + "requires": { + "through": "~2.3" + } + }, + "performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" + }, + "process-nextick-args": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz", + "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=", + "dev": true + }, + "psl": { + "version": "1.1.31", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.1.31.tgz", + "integrity": "sha512-/6pt4+C+T+wZUieKR620OpzN/LlnNKuWjy1iFLQ/UG35JqHlR/89MP1d96dUfkf6Dne3TuLQzOYEYshJ+Hx8mw==" + }, + "punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=" + }, + "qs": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.1.tgz", + "integrity": "sha512-eRzhrN1WSINYCDCbrz796z37LOe3m5tmW7RQf6oBntukAG1nmovJvhnwHHRMAfeoItc1m2Hk02WER2aQ/iqs+A==", + "dev": true + }, + "raw-body": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.3.2.tgz", + "integrity": "sha1-vNYMd9Prk83gBQKVw/N5OJvIj4k=", + "dev": true, + "requires": { + "bytes": "3.0.0", + "http-errors": "1.6.2", + "iconv-lite": "0.4.19", + "unpipe": "1.0.0" + }, + "dependencies": { + "iconv-lite": { + "version": "0.4.19", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.19.tgz", + "integrity": "sha512-oTZqweIP51xaGPI4uPa56/Pri/480R+mo7SeU+YETByQNhDG55ycFyNLIgta9vXhILrxXDmF7ZGhqZIcuN0gJQ==", + "dev": true + } + } + }, + "readable-stream": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.3.tgz", + "integrity": "sha512-m+qzzcn7KUxEmd1gMbchF+Y2eIUbieUaxkWtptyHywrX0rE8QEYqPC07Vuy4Wm32/xE16NcdBctb8S0Xe/5IeQ==", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~1.0.6", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.0.3", + "util-deprecate": "~1.0.1" + }, + "dependencies": { + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + } + } + }, + "request": { + "version": "2.88.0", + "resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz", + "integrity": "sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==", + "requires": { + "aws-sign2": "~0.7.0", + "aws4": "^1.8.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.6", + "extend": "~3.0.2", + "forever-agent": "~0.6.1", + "form-data": "~2.3.2", + "har-validator": "~5.1.0", + "http-signature": "~1.2.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.19", + "oauth-sign": "~0.9.0", + "performance-now": "^2.1.0", + "qs": "~6.5.2", + "safe-buffer": "^5.1.2", + "tough-cookie": "~2.4.3", + "tunnel-agent": "^0.6.0", + "uuid": "^3.3.2" + }, + "dependencies": { + "combined-stream": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.7.tgz", + "integrity": "sha512-brWl9y6vOB1xYPZcpZde3N9zDByXTosAeMDo4p1wzo6UMOX4vumB+TP1RZ76sfE6Md68Q0NJSrE/gbezd4Ul+w==", + "requires": { + "delayed-stream": "~1.0.0" + } + }, + "extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" + }, + "form-data": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", + "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + } + }, + "mime-db": { + "version": "1.40.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.40.0.tgz", + "integrity": "sha512-jYdeOMPy9vnxEqFRRo6ZvTZ8d9oPb+k18PKoYNYUe2stVEBPPwsln/qWzdbmaIvnhZ9v2P+CuecK+fpUfsV2mA==" + }, + "mime-types": { + "version": "2.1.24", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.24.tgz", + "integrity": "sha512-WaFHS3MCl5fapm3oLxU4eYDw77IQM2ACcxQ9RIxfaC3ooc6PFuBMGZZsYpvoXS5D5QTWPieo1jjLdAm3TBP3cQ==", + "requires": { + "mime-db": "1.40.0" + } + }, + "qs": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", + "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==" + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "tough-cookie": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz", + "integrity": "sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==", + "requires": { + "psl": "^1.1.24", + "punycode": "^1.4.1" + } + } + } + }, + "request-promise-core": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.1.tgz", + "integrity": "sha1-Pu4AssWqgyOc+wTFcA2jb4HNCLY=", + "requires": { + "lodash": "^4.13.1" + } + }, + "request-promise-native": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/request-promise-native/-/request-promise-native-1.0.5.tgz", + "integrity": "sha1-UoF3D2jgyXGeUWP9P6tIIhX0/aU=", + "requires": { + "request-promise-core": "1.1.1", + "stealthy-require": "^1.1.0", + "tough-cookie": ">=2.3.3" + } + }, + "resolve-path": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/resolve-path/-/resolve-path-1.4.0.tgz", + "integrity": "sha1-xL2p9e+y/OZSR4c6s2u02DT+Fvc=", + "dev": true, + "requires": { + "http-errors": "~1.6.2", + "path-is-absolute": "1.0.1" + } + }, + "safe-buffer": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", + "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==" + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "setprototypeof": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.0.3.tgz", + "integrity": "sha1-ZlZ+NwQ+608E2RvWWMDL77VbjgQ=", + "dev": true + }, + "should": { + "version": "13.1.2", + "resolved": "https://registry.npmjs.org/should/-/should-13.1.2.tgz", + "integrity": "sha512-oiGqKOuE4t98vdCs4ICifvzL2u9nWMaziSXVwHOYPyqqY1gBzGZS6LvzIc5uEFN0PiS69Sbvcqyw9hbYXkF4og==", + "dev": true, + "requires": { + "should-equal": "^2.0.0", + "should-format": "^3.0.3", + "should-type": "^1.4.0", + "should-type-adaptors": "^1.0.1", + "should-util": "^1.0.0" + } + }, + "should-equal": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/should-equal/-/should-equal-2.0.0.tgz", + "integrity": "sha512-ZP36TMrK9euEuWQYBig9W55WPC7uo37qzAEmbjHz4gfyuXrEUgF8cUvQVO+w+d3OMfPvSRQJ22lSm8MQJ43LTA==", + "dev": true, + "requires": { + "should-type": "^1.4.0" + } + }, + "should-format": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/should-format/-/should-format-3.0.3.tgz", + "integrity": "sha1-m/yPdPo5IFxT04w01xcwPidxJPE=", + "dev": true, + "requires": { + "should-type": "^1.3.0", + "should-type-adaptors": "^1.0.1" + } + }, + "should-type": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/should-type/-/should-type-1.4.0.tgz", + "integrity": "sha1-B1bYzoRt/QmEOmlHcZ36DUz/XPM=", + "dev": true + }, + "should-type-adaptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/should-type-adaptors/-/should-type-adaptors-1.0.1.tgz", + "integrity": "sha1-7+VVPN9oz/ZuXF9RtxLcNRx3vqo=", + "dev": true, + "requires": { + "should-type": "^1.3.0", + "should-util": "^1.0.0" + } + }, + "should-util": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/should-util/-/should-util-1.0.0.tgz", + "integrity": "sha1-yYzaN0qmsZDfi6h8mInCtNtiAGM=", + "dev": true + }, + "sshpk": { + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", + "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==", + "requires": { + "asn1": "~0.2.3", + "assert-plus": "^1.0.0", + "bcrypt-pbkdf": "^1.0.0", + "dashdash": "^1.12.0", + "ecc-jsbn": "~0.1.1", + "getpass": "^0.1.1", + "jsbn": "~0.1.0", + "safer-buffer": "^2.0.2", + "tweetnacl": "~0.14.0" + } + }, + "statuses": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz", + "integrity": "sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew==", + "dev": true + }, + "stealthy-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/stealthy-require/-/stealthy-require-1.1.1.tgz", + "integrity": "sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks=" + }, + "string_decoder": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", + "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" + } + }, + "supertest": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/supertest/-/supertest-3.0.0.tgz", + "integrity": "sha1-jUu2j9GDDuBwM7HFpamkAhyWUpY=", + "dev": true, + "requires": { + "methods": "~1.1.2", + "superagent": "^3.0.0" + }, + "dependencies": { + "cookiejar": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/cookiejar/-/cookiejar-2.1.1.tgz", + "integrity": "sha1-Qa1XsbVVlR7BcUEqgZQrHoIA00o=", + "dev": true + }, + "formidable": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/formidable/-/formidable-1.1.1.tgz", + "integrity": "sha1-lriIb3w8NQi5Mta9cMTTqI818ak=", + "dev": true + }, + "mime": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.4.1.tgz", + "integrity": "sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ==", + "dev": true + }, + "superagent": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/superagent/-/superagent-3.7.0.tgz", + "integrity": "sha512-/8trxO6NbLx4YXb7IeeFTSmsQ35pQBiTBsLNvobZx7qBzBeHYvKCyIIhW2gNcWbLzYxPAjdgFbiepd8ypwC0Gw==", + "dev": true, + "requires": { + "component-emitter": "^1.2.0", + "cookiejar": "^2.1.0", + "debug": "^3.1.0", + "extend": "^3.0.0", + "form-data": "^2.3.1", + "formidable": "^1.1.1", + "methods": "^1.1.1", + "mime": "^1.4.1", + "qs": "^6.5.1", + "readable-stream": "^2.0.5" + } + } + } + }, + "thenify": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.0.tgz", + "integrity": "sha1-5p44obq+lpsBCCB5eLn2K4hgSDk=", + "dev": true, + "requires": { + "any-promise": "^1.0.0" + } + }, + "thenify-all": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", + "integrity": "sha1-GhkY1ALY/D+Y+/I02wvMjMEOlyY=", + "dev": true, + "requires": { + "thenify": ">= 3.1.0 < 4" + } + }, + "through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=" + }, + "toidentifier": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", + "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==", + "dev": true + }, + "tough-cookie": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.3.tgz", + "integrity": "sha1-C2GKVWW23qkL80JdBNVe3EdadWE=", + "requires": { + "punycode": "^1.4.1" + } + }, + "tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", + "requires": { + "safe-buffer": "^5.0.1" + } + }, + "tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=" + }, + "type-is": { + "version": "1.6.15", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.15.tgz", + "integrity": "sha1-yrEPtJCeRByChC6v4a1kbIGARBA=", + "dev": true, + "requires": { + "media-typer": "0.3.0", + "mime-types": "~2.1.15" + } + }, + "unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=", + "dev": true + }, + "uri-js": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", + "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", + "requires": { + "punycode": "^2.1.0" + }, + "dependencies": { + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" + } + } + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", + "dev": true + }, + "uuid": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", + "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==" + }, + "vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=", + "dev": true + }, + "verror": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", + "requires": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + } + } +} diff --git a/package.json b/package.json index 14293b0..bfb4e0f 100644 --- a/package.json +++ b/package.json @@ -1,36 +1,42 @@ { "name": "koa-proxy", - "version": "0.9.0", + "version": "1.0.0-alpha.3", "description": "Proxy middleware for koa", "main": "index", "dependencies": { - "iconv-lite": "^0.2.11", - "co-request": "^0.2.0" + "pause-stream": "0.0.11", + "request": "^2.88.0", + "request-promise-native": "^1.0.5" }, + "files": [ + "index.js" + ], "keywords": [ "koa", "middleware", "proxy" ], "devDependencies": { - "coveralls": "~2.8.0", - "istanbul-harmony": "*", - "koa": "^0.5.2", - "koa-body-parser": "^1.1.2", - "koa-router": "^3.1.2", - "koa-static": "^1.4.3", - "mocha": "~1.17.1", - "should": "~3.1.3", - "supertest": "^0.10.0" + "koa": "^2.3.0", + "koa-body": "^2.5.0", + "koa-convert": "^1.2.0", + "koa-router": "^7.2.1", + "koa-static": "^5.0.0", + "mocha": "^4.0.1", + "should": "^13.1.2", + "supertest": "^3.0.0" + }, + "peerDependencies": { + "koa": "2.x" }, "repository": { "type": "git", - "url": "https://github.com/popomore/koa-proxy" + "url": "https://github.com/edorivai/koa-proxy" }, - "homepage": "https://github.com/popomore/koa-proxy", - "author": "popomore ", + "homepage": "https://github.com/edorivai/koa-proxy", + "author": "edorivai ", "license": "MIT", "scripts": { - "test": "make test" + "test": "mocha -t 20000" } } diff --git a/test/fixtures/upload.txt b/test/fixtures/upload.txt new file mode 100644 index 0000000..c3bf131 --- /dev/null +++ b/test/fixtures/upload.txt @@ -0,0 +1 @@ +test me \ No newline at end of file diff --git a/test/index.js b/test/index.js index 855166d..2c5d622 100644 --- a/test/index.js +++ b/test/index.js @@ -2,58 +2,77 @@ require('should'); var http = require('http'); +var path = require('path'); +var fs = require('fs'); var proxy = require('..'); var request = require('supertest'); -var koa = require('koa'); +var Koa = require('koa'); var serve = require('koa-static'); -var router = require('koa-router'); -var parser = require('koa-body-parser'); +var convert = require('koa-convert'); +var Router = require('koa-router'); +var parser = require('koa-body'); describe('koa-proxy', function() { var server; before(function() { - var app = koa(); - app.use(function* (next) { + var app = new Koa(); + app.use(parser({ multipart: true })); + app.use(async (ctx, next) => { // Set this in response header to allow for proxy request header testing - this.set('host', this.request.header.host); - if (this.path === '/error') { - this.body = ''; - this.status = 500; + ctx.set('host', ctx.request.header.host); + if (ctx.path === '/error') { + ctx.status = 500; return; } - if (this.path === '/postme') { - this.body = this.req; - this.set('content-type', this.request.header['content-type']); - this.status = 200; + if (ctx.path === '/postme') { + ctx.body = ctx.request.body; + ctx.set('content-type', ctx.request.header['content-type']); + ctx.status = 200; return; } - if (this.path === '/cookie-me') { - this.cookies.set('test_cookie', 'nom-nom', { httpOnly: false }); - this.status = 200; + if (ctx.path === '/upload-raw') { + // echo the uploaded file contents to the response body + ctx.body = fs + .readFileSync(ctx.request.body.files.test.path) + .toString(); + ctx.status = 200; return; } - if (this.path === '/check-cookie') { - this.body = this.cookies.get('test_cookie'); - this.status = 200; + if (ctx.path === '/cookie-me') { + ctx.cookies.set('test_cookie', 'nom-nom', { httpOnly: false }); + ctx.status = 200; return; } - if (this.path === '/redirect') { - this.redirect('http://google.com'); + if (ctx.path === '/check-cookie') { + ctx.body = ctx.cookies.get('test_cookie'); + ctx.status = 200; return; } - if (this.path === '/suppress-my-headers') { - var headers = this.request.header; - this.set('jar-jar', 'binks'); - this.body = headers; - this.status = 200; + if (ctx.path === '/redirect') { + ctx.redirect('http://google.com'); return; } - if (this.querystring) { - this.body = this.querystring; + if (ctx.path === '/suppress-my-headers') { + var headers = ctx.request.header; + ctx.set('jar-jar', 'binks'); + ctx.body = headers; + ctx.status = 200; return; } - yield* next; + if (ctx.path === '/override-my-headers') { + let headers = ctx.request.header; + ctx.set('existing-test-header', 'cows'); + ctx.body = headers; + ctx.status = 200; + return; + } + if (ctx.querystring) { + // To test query string + ctx.body = ctx.querystring; + return; + } + await next(); }); app.use(serve(__dirname + '/fixtures')); server = app.listen(1234); @@ -63,11 +82,12 @@ describe('koa-proxy', function() { }); it('should have option url', function(done) { - var app = koa(); - app.use(router(app)); - app.get('/index.js', proxy({ + var app = new Koa(); + var router = new Router(); + router.get('/index.js', proxy({ url: 'http://localhost:1234/class.js' })); + app.use(router.routes()); var server = http.createServer(app.callback()); request(server) .get('/index.js') @@ -82,16 +102,17 @@ describe('koa-proxy', function() { }); it('should have option url and host', function(done) { - var app = koa(); - app.use(router(app)); + var app = new Koa(); app.use(proxy({ host: 'http://localhost:1234', url: 'class.js' })); - app.get('/index.js', proxy({ + var router = new Router(); + router.get('/index.js', proxy({ host: 'http://localhost:1234', url: 'class.js' })); + app.use(router.routes()); var server = http.createServer(app.callback()); request(server) .get('/index.js') @@ -105,319 +126,270 @@ describe('koa-proxy', function() { }); }); - it('should have option host', function(done) { - var app = koa(); - app.use(proxy({ - host: 'http://localhost:1234' - })); + it("should have option host", function(done) { + var app = new Koa(); + app.use(proxy({ host: "http://localhost:1234" })); var server = http.createServer(app.callback()); request(server) - .get('/class.js') + .get("/class.js") .expect(200) - .expect('Content-Type', /javascript/) - .end(function (err, res) { - if (err) - return done(err); + .expect("Content-Type", /javascript/) + .end(function(err, res) { + if (err) return done(err); res.text.should.startWith('define("arale/class/1.0.0/class"'); done(); }); }); - it('should strip trailing slash from option host', function(done) { - var app = koa(); - app.use(proxy({ - host: 'http://localhost:1234/' - })); + it("should strip trailing slash from option host", function(done) { + var app = new Koa(); + app.use(proxy({ host: "http://localhost:1234/" })); var server = http.createServer(app.callback()); request(server) - .get('/class.js') + .get("/class.js") .expect(200) - .expect('Host', 'localhost:1234') - .end(function (err, res) { - if (err) - return done(err); + .expect("Host", "localhost:1234") + .end(function(err, res) { + if (err) return done(err); res.text.should.startWith('define("arale/class/1.0.0/class"'); done(); }); }); - it('should have option host and map', function(done) { - var app = koa(); + it("should have option host and map", function(done) { + var app = new Koa(); app.use(proxy({ - host: 'http://localhost:1234', - map: { - '/index.js': '/class.js' - } - })); + host: "http://localhost:1234", + map: { + "/index.js": "/class.js" + } + })); var server = http.createServer(app.callback()); request(server) - .get('/index.js') + .get("/index.js") .expect(200) - .expect('Content-Type', /javascript/) - .end(function (err, res) { - if (err) - return done(err); + .expect("Content-Type", /javascript/) + .end(function(err, res) { + if (err) return done(err); res.text.should.startWith('define("arale/class/1.0.0/class"'); done(); }); }); - it('should have option host and map function', function(done) { - var app = koa(); - app.use(proxy({ - host: 'http://localhost:1234', - map: function(path) { return path.replace('index', 'class'); } - })); + it("should have option host and map function", function(done) { + var app = new Koa(); + app.use(proxy({ host: "http://localhost:1234", map: function(path) { + return path.replace("index", "class"); + } })); var server = http.createServer(app.callback()); request(server) - .get('/index.js') + .get("/index.js") .expect(200) - .expect('Content-Type', /javascript/) - .end(function (err, res) { - if (err) - return done(err); + .expect("Content-Type", /javascript/) + .end(function(err, res) { + if (err) return done(err); res.text.should.startWith('define("arale/class/1.0.0/class"'); done(); }); }); - it('should have option host and match', function(done) { - var app = koa(); + it("should have option host and match", function(done) { + var app = new Koa(); app.use(proxy({ - host: 'http://localhost:1234', - match: /^\/[a-z]+\.js$/ - })); - app.use(proxy({ - host: 'http://localhost:1234' - })); + host: "http://localhost:1234", + match: /^\/[a-z]+\.js$/ + })); + app.use(proxy({ host: "http://localhost:1234" })); var server = http.createServer(app.callback()); request(server) - .get('/class.js') + .get("/class.js") .expect(200) - .expect('Content-Type', /javascript/) - .end(function (err, res) { - if (err) - return done(err); + .expect("Content-Type", /javascript/) + .end(function(err, res) { + if (err) return done(err); res.text.should.startWith('define("arale/class/1.0.0/class"'); done(); }); }); - it('should have option followRedirect', function(done) { - var app = koa(); - app.use(proxy({ - host: 'http://localhost:1234', - followRedirect: false, - })); + it("should have option followRedirect", function(done) { + var app = new Koa(); + app.use(proxy({ host: "http://localhost:1234", followRedirect: false })); var server = http.createServer(app.callback()); request(server) - .get('/redirect') + .get("/redirect") .expect(302) - .expect('Location', /google.com/) - .end(function (err, res) { - if (err) - return done(err); + .expect("Location", /google.com/) + .end(function(err, res) { + if (err) return done(err); done(); }); }); - it('should have option yieldNext', function(done) { - var app = koa(); - app.use(proxy({ - host: 'http://localhost:1234/', - yieldNext: true, - })); - app.use(function* () { + it("should have option yieldNext", function(done) { + var app = new Koa(); + app.use(proxy({ host: "http://localhost:1234/", yieldNext: true })); + app.use(() => { done(); - }) + }); var server = http.createServer(app.callback()); request(server) - .get('/class.js') + .get("/class.js") .expect(200) - .expect('Host', 'localhost:1234') - .end(function (err, res) { - if (err) - return done(err); + .expect("Host", "localhost:1234") + .end(function(err, res) { + if (err) return done(err); }); }); - it('url not match for url', function(done) { - var app = koa(); - app.use(proxy({ - url: 'class.js' - })); - app.use(function* () { - this.body = 'next'; + it("url not match for url", function(done) { + var app = new Koa(); + app.use(proxy({ url: "class.js" })); + app.use(ctx => { + ctx.body = "next"; }); var server = http.createServer(app.callback()); request(server) - .get('/index.js') + .get("/index.js") .expect(200) - .expect('Content-Type', 'text/plain; charset=utf-8') - .end(function (err, res) { - if (err) - return done(err); - res.text.should.eql('next'); + .expect("Content-Type", "text/plain; charset=utf-8") + .end(function(err, res) { + if (err) return done(err); + res.text.should.eql("next"); done(); }); }); - it('url not match for map', function(done) { - var app = koa(); - app.use(proxy({ - map: { - '/index.js': '/class.js' - } - })); - app.use(function* () { - this.body = 'next'; + it("url not match for map", function(done) { + var app = new Koa(); + app.use(proxy({ map: { "/index.js": "/class.js" } })); + app.use(ctx => { + ctx.body = "next"; }); var server = http.createServer(app.callback()); request(server) - .get('/index.js') + .get("/index.js") .expect(200) - .expect('Content-Type', 'text/plain; charset=utf-8') - .end(function (err, res) { - if (err) - return done(err); - res.text.should.eql('next'); + .expect("Content-Type", "text/plain; charset=utf-8") + .end(function(err, res) { + if (err) return done(err); + res.text.should.eql("next"); done(); }); }); - it('option exist', function() { + it("option exist", function() { (function() { proxy(); - }).should.throw(); + }.should.throw()); }); - it('encoding', function(done) { - var app = koa(); + it("pass query", function(done) { + var app = new Koa(); app.use(proxy({ - url: 'http://localhost:1234/index.html', - encoding: 'gbk' - })); + url: "http://localhost:1234/class.js", + encoding: "gbk" + })); var server = http.createServer(app.callback()); request(server) - .get('/index.js') + .get("/index.js?a=1") .expect(200) - .expect('Content-Type', 'text/html; charset=utf-8') - .end(function (err, res) { - if (err) - return done(err); - res.text.should.startWith('
中国
'); + .expect("Content-Type", "text/plain; charset=utf-8") + .end(function(err, res) { + if (err) return done(err); + res.text.should.startWith("a=1"); done(); }); }); - it('pass query', function(done) { - var app = koa(); - app.use(proxy({ - url: 'http://localhost:1234/class.js', - encoding: 'gbk' - })); + it("pass request body", function(done) { + var app = new Koa(); + app.use(parser()); + app.use(proxy({ host: "http://localhost:1234" })); var server = http.createServer(app.callback()); request(server) - .get('/index.js?a=1') + .post("/postme") + .send({ foo: "bar" }) .expect(200) - .expect('Content-Type', 'text/plain; charset=utf-8') - .end(function (err, res) { - if (err) - return done(err); - res.text.should.startWith('a=1'); + .end(function(err, res) { + if (err) return done(err); + res.text.should.equal('{"foo":"bar"}'); done(); }); }); - it('pass request body', function(done) { - var app = koa(); - app.use(proxy({ - host: 'http://localhost:1234', - })); + it('should pass request as stream', function(done) { + var app = new Koa(); + app.use(proxy({ host: 'http://localhost:1234' })); var server = http.createServer(app.callback()); request(server) - .post('/postme') - .send({foo:'bar'}) + .post('/upload-raw') + .attach('test', path.resolve(__dirname, 'fixtures/upload.txt')) .expect(200) - .end(function (err, res) { - if (err) - return done(err); - res.text.should.equal('{"foo":"bar"}'); + .end(function(err, res) { + if (err) return done(err); + res.text.should.equal('test me'); done(); }); }); - it('pass parsed request body', function(done) { - var app = koa(); - app.use(parser()); // sets this.request.body - app.use(proxy({ - host: 'http://localhost:1234', - })); + it("pass parsed request body", function(done) { + var app = new Koa(); + app.use(parser()); // sets ctx.request.body + app.use(proxy({ host: "http://localhost:1234" })); var server = http.createServer(app.callback()); request(server) - .post('/postme') - .send({foo:'bar'}) + .post("/postme") + .send({ foo: "bar" }) .expect(200) - .end(function (err, res) { - if (err) - return done(err); + .end(function(err, res) { + if (err) return done(err); res.text.should.equal('{"foo":"bar"}'); done(); }); }); - it('statusCode', function(done) { - var app = koa(); - app.use(proxy({ - host: 'http://localhost:1234' - })); + it("statusCode", function(done) { + var app = new Koa(); + app.use(proxy({ host: "http://localhost:1234" })); var server = http.createServer(app.callback()); request(server) - .get('/error') + .get("/error") .expect(500, done); }); - it('should pass along requestOptions', function(done) { - var app = koa(); + it("should pass along requestOptions", function(done) { + var app = new Koa(); app.use(proxy({ - url: 'http://localhost:1234/class.js', - requestOptions: { timeout: 1 } - })); + url: "http://localhost:1234/class.js", + requestOptions: { + url: 'http://localhost:12345/class.js' // change port, should yield 500 + } + })); var server = http.createServer(app.callback()); request(server) - .get('/index.js') - .expect(function sleep() { - // Using the custom assert function to make sure we get a timeout - var sleepTime = new Date().getTime() + 3; - while(new Date().getTime() < sleepTime) {} - }) + .get("/index.js") .expect(500, done); }); it('should pass along requestOptions when function', function(done) { - var app = koa(); + var app = new Koa(); app.use(proxy({ url: 'http://localhost:1234/class.js', requestOptions: function(req, opt) { - opt.timeout = 1; + opt.url = 'http://localhost:12345/class.js'; // change port, should yield 500 return opt; } })); var server = http.createServer(app.callback()); request(server) .get('/index.js') - .expect(function sleep() { - // Using the custom assert function to make sure we get a timeout - var sleepTime = new Date().getTime() + 3; - while(new Date().getTime() < sleepTime) {} - }) .expect(500, done); }); describe('with cookie jar', function () { - var app = koa(); - app.use(router(app)); + var app = new Koa(); app.use(proxy({ host: 'http://localhost:1234', jar: true @@ -457,8 +429,7 @@ describe('koa-proxy', function() { describe('without cookie jar', function () { - var app = koa(); - app.use(router(app)); + var app = new Koa(); app.use(proxy({ host: 'http://localhost:1234', })); @@ -501,8 +472,7 @@ describe('koa-proxy', function() { describe('with suppressed request and response headers', function () { - var app = koa(); - app.use(router(app)); + var app = new Koa(); app.use(proxy({ host: 'http://localhost:1234', suppressRequestHeaders: ['foO','bAr'], @@ -530,4 +500,39 @@ describe('koa-proxy', function() { }); }); }); + + describe('with overridden response header', function () { + const app = new Koa(); + app.use(proxy({ + host: 'http://localhost:1234', + overrideResponseHeaders: { + "existing-test-header" : "goats", + "nonexisting-test-header" : "bar" + } + })); + const server = http.createServer(app.callback()); + const agent = request.agent(server); + + + it('should include overriden header', function(done){ + + agent + .get("/override-my-headers") + .expect(200) + .end(function(err, res){ + if (err) + return done(err); + + if(!res.headers.hasOwnProperty('nonexisting-test-header') || res.headers['nonexisting-test-header'] !== 'bar'){ + throw new Error("overridden nonexisting-test-header header not present") + } + if(!res.headers.hasOwnProperty('existing-test-header') || res.headers['existing-test-header'] !== 'goats'){ + throw new Error("overridden existing-test-header header not present") + } + done(); + }) + }) + + + }) });