Lloyd Brookes
9 years ago
3 changed files with 155 additions and 146 deletions
-
145lib/local-web-server.js
-
120lib/middleware.js
-
36test/test.js
@ -0,0 +1,120 @@ |
|||
'use strict' |
|||
const path = require('path') |
|||
const http = require('http') |
|||
const url = require('url') |
|||
const arrayify = require('array-back') |
|||
const pathToRegexp = require('path-to-regexp') |
|||
const debug = require('debug')('local-web-server') |
|||
|
|||
/** |
|||
* @module middleware |
|||
*/ |
|||
exports.proxyRequest = proxyRequest |
|||
exports.blacklist = blacklist |
|||
exports.mockResponses = mockResponses |
|||
exports.mime = mime |
|||
|
|||
function proxyRequest (route, app) { |
|||
const httpProxy = require('http-proxy') |
|||
const proxy = httpProxy.createProxyServer({ |
|||
changeOrigin: true |
|||
}) |
|||
|
|||
return function * proxyMiddleware () { |
|||
const next = arguments[arguments.length - 1] |
|||
const keys = [] |
|||
route.re = pathToRegexp(route.from, keys) |
|||
route.new = this.url.replace(route.re, route.to) |
|||
|
|||
keys.forEach((key, index) => { |
|||
const re = RegExp(`:${key.name}`, 'g') |
|||
route.new = route.new |
|||
.replace(re, arguments[index] || '') |
|||
}) |
|||
|
|||
/* test no keys remain in the new path */ |
|||
keys.length = 0 |
|||
pathToRegexp(url.parse(route.new).path, keys) |
|||
if (keys.length) { |
|||
this.throw(500, `[PROXY] Invalid target URL: ${route.new}`) |
|||
return next() |
|||
} |
|||
|
|||
this.response = false |
|||
debug('proxy request', `from: ${this.path}, to: ${url.parse(route.new).href}`) |
|||
|
|||
proxy.once('error', err => { |
|||
this.throw(500, `[PROXY] ${err.message}: ${route.new}`) |
|||
}) |
|||
proxy.once('proxyReq', function (proxyReq) { |
|||
proxyReq.path = url.parse(route.new).path |
|||
}) |
|||
proxy.web(this.req, this.res, { target: route.new }) |
|||
} |
|||
} |
|||
|
|||
function blacklist (forbid) { |
|||
return function blacklist (ctx, next) { |
|||
if (forbid.some(expression => pathToRegexp(expression).test(ctx.path))) { |
|||
ctx.throw(403, http.STATUS_CODES[403]) |
|||
} else { |
|||
return next() |
|||
} |
|||
} |
|||
} |
|||
|
|||
function mockResponses (options) { |
|||
options = options || { root: process.cwd() } |
|||
return function mockResponses (ctx, next) { |
|||
if (/\.mock.js$/.test(ctx.path)) { |
|||
const mocks = arrayify(require(path.join(options.root, ctx.path))) |
|||
const testValue = require('test-value') |
|||
const t = require('typical') |
|||
|
|||
/* find a mock with compatible method and accepts */ |
|||
let mock = mocks.find(mock => { |
|||
return testValue(mock, { |
|||
request: { |
|||
method: [ ctx.method, undefined ], |
|||
accepts: type => ctx.accepts(type) |
|||
} |
|||
}) |
|||
}) |
|||
|
|||
/* else take the first mock without a request (no request means 'all requests') */ |
|||
if (!mock) { |
|||
mock = mocks.find(mock => !mock.request) |
|||
} |
|||
|
|||
const mockedReponse = {} |
|||
/* resolve any functions on the mock */ |
|||
Object.keys(mock.response).forEach(key => { |
|||
if (t.isFunction(mock.response[key])) { |
|||
mockedReponse[key] = mock.response[key](ctx) |
|||
} else { |
|||
mockedReponse[key] = mock.response[key] |
|||
} |
|||
}) |
|||
|
|||
if (mock) { |
|||
Object.assign(ctx.response, mockedReponse) |
|||
// debug('mocked response', JSON.stringify(mockedReponse))
|
|||
// debug('actual response', JSON.stringify(ctx.response))
|
|||
} |
|||
} else { |
|||
return next() |
|||
} |
|||
} |
|||
} |
|||
|
|||
function mime (mimeTypes) { |
|||
return function mime (ctx, next) { |
|||
return next().then(() => { |
|||
const reqPathExtension = path.extname(ctx.path).slice(1) |
|||
Object.keys(mimeTypes).forEach(mimeType => { |
|||
const extsToOverride = mimeTypes[mimeType] |
|||
if (extsToOverride.indexOf(reqPathExtension) > -1) ctx.type = mimeType |
|||
}) |
|||
}) |
|||
} |
|||
} |
Write
Preview
Loading…
Cancel
Save
Reference in new issue