Skip to content
This repository has been archived by the owner on Apr 24, 2019. It is now read-only.

Commit

Permalink
Merge e8a6d36 into 9934a7f
Browse files Browse the repository at this point in the history
  • Loading branch information
edorivai committed Oct 24, 2017
2 parents 9934a7f + e8a6d36 commit 55040a0
Show file tree
Hide file tree
Showing 6 changed files with 2,412 additions and 266 deletions.
5 changes: 2 additions & 3 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
language: node_js
node_js:
- 0.12
- 4
- 5
- 7
- 8

after_success: make coveralls
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
test:
node --harmony ./node_modules/.bin/istanbul cover ./node_modules/.bin/_mocha -- -R spec -t 20000
node ./node_modules/.bin/istanbul cover ./node_modules/.bin/_mocha -- -R spec -t 20000

coveralls: test
cat ./coverage/lcov.info | ./node_modules/.bin/coveralls
Expand Down
118 changes: 71 additions & 47 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,109 +1,125 @@
'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 (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;
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);
const bodyStream = pauseStream().pause();
var res = await pipe(ctx.req, requestLib(opt), bodyStream, {
end: false
});

// Ensure that the body stream is only resumed after Koa had the chance to pipe it
// through to the response.
ctx.body = bodyStream;
process.nextTick(() => bodyStream.resume());
}

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.encoding === "gbk") {
// ctx.body = iconv.decode(res.body, "gbk");
// return;
// }

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) {
Expand All @@ -128,14 +144,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 + '';
Expand All @@ -144,8 +160,16 @@ function getParsedBody(ctx){
return body;
}

function pipeRequest(readable, requestThunk){
return function(cb){
readable.pipe(requestThunk(cb));
}
/**
* Pipes the incoming request body through request(), and subsequently pipes
* the response stream of request() through to the bodyStream.
*/
function pipe(incomingRequest, requestThunk, bodyStream, options) {
return new Promise((resolve, reject) => {
incomingRequest
.pipe(requestThunk)
.on('error', reject)
.on('response', resolve)
.pipe(bodyStream, options);
});
}

0 comments on commit 55040a0

Please sign in to comment.