koa-even-better-http-proxy
Version:
http proxy middleware for Koa
116 lines (96 loc) • 3.12 kB
JavaScript
/* eslint no-param-reassign: ["error", { "props": false }] */
import _ from 'lodash';
import * as http from 'http';
import * as https from 'https';
import getRawBody from 'raw-body';
import isUnset from './isUnset';
const ensureHttpURL = (value) =>
/^http(s)?:\/\//.test(value) ? value : `http://${value}`;
const shouldSkipHeader = (header, headersToSkip) => {
if (!Array.isArray(headersToSkip)) return false;
return headersToSkip.indexOf(header) > -1;
};
const getHostFromContainer = (container) => {
let { host } = container.params;
const { ctx } = container.user;
host = typeof host === 'function' ? host(ctx) : host.toString();
return !host ? null : ensureHttpURL(host);
};
const shouldParseReqBody = (options) =>
isUnset(options.parseReqBody) ? true : options.parseReqBody;
const extend = (obj, source, headersToSkip) => {
if (!source) {
return obj;
}
const extObj = _.cloneDeep(obj);
Object.keys(source).forEach((header) => {
if (shouldSkipHeader(header, headersToSkip)) return;
extObj[header] = source[header];
});
return extObj;
};
const parseUrl = (url) => {
try {
return new URL(url);
} catch (err) {
return null;
}
};
const reqHeaders = (ctx, options) => {
const headers = options.headers || {};
const skipHdrs = ['connection', 'content-length'];
if (!options.preserveHostHdr) {
skipHdrs.push('host');
}
return extend(headers, ctx.headers, skipHdrs);
};
const maybeParseBody = (ctx, limit) => {
if (ctx.request.body) {
return Promise.resolve(ctx.request.body);
}
// Returns a promise if no callback specified and global Promise exists.
return getRawBody(ctx.req, {
length: ctx.headers['content-length'],
limit,
});
};
const isHttps = (options, parsed) =>
options.https || parsed.protocol === 'https:';
const getPort = (port, ishttps) => port || (ishttps ? 443 : 80);
const getHttpModule = (ishttps) => (ishttps ? https : http);
export const parseHost = (Container) => {
const { options } = Container;
const host = getHostFromContainer(Container);
const parsed = parseUrl(host);
if (!parsed) {
return new Error(`Failed to parse hostname.`);
}
const ishttps = isHttps(options, parsed);
return {
host: parsed.hostname,
port: getPort(parsed.port, ishttps),
isSecure: ishttps,
module: getHttpModule(ishttps),
};
};
export const createRequestOptions = (ctx, options) => {
// prepare proxyRequest
const reqOpt = {
headers: reqHeaders(ctx, options),
method: ctx.method,
path: ctx.path,
// params: req.params,
};
if (options.preserveReqSession) {
reqOpt.session = ctx.session;
}
if (options.agent) {
reqOpt.agent = options.agent;
}
return Promise.resolve(reqOpt);
};
// extract to bodyContent object
export const bodyContent = (ctx, options) => {
if (!shouldParseReqBody(options)) return null;
return maybeParseBody(ctx, options.limit || '50mb');
};