| 
									
										
										
										
											2015-11-19 19:27:36 +00:00
										 |  |  | 'use strict' | 
					
						
							|  |  |  | const path = require('path') | 
					
						
							|  |  |  | const http = require('http') | 
					
						
							|  |  |  | const url = require('url') | 
					
						
							|  |  |  | const arrayify = require('array-back') | 
					
						
							| 
									
										
										
										
											2015-11-24 11:46:47 +00:00
										 |  |  | const t = require('typical') | 
					
						
							| 
									
										
										
										
											2015-11-19 19:27:36 +00:00
										 |  |  | 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 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-18 11:35:11 +01:00
										 |  |  | function proxyRequest (route) { | 
					
						
							| 
									
										
										
										
											2015-11-19 19:27:36 +00:00
										 |  |  |   const httpProxy = require('http-proxy') | 
					
						
							|  |  |  |   const proxy = httpProxy.createProxyServer({ | 
					
						
							|  |  |  |     changeOrigin: true | 
					
						
							|  |  |  |   }) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-11-22 19:38:08 +00:00
										 |  |  |   return function proxyMiddleware () { | 
					
						
							| 
									
										
										
										
											2015-11-19 19:27:36 +00:00
										 |  |  |     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 | 
					
						
							| 
									
										
										
										
											2015-11-22 19:38:08 +00:00
										 |  |  |         .replace(re, arguments[index + 1] || '') | 
					
						
							| 
									
										
										
										
											2015-11-19 19:27:36 +00:00
										 |  |  |     }) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     debug('proxy request', `from: ${this.path}, to: ${url.parse(route.new).href}`) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-30 00:32:51 +01:00
										 |  |  |     return new Promise((resolve, reject) => { | 
					
						
							|  |  |  |       proxy.once('error', err => { | 
					
						
							|  |  |  |         err.message = `[PROXY] Error: ${err.message} Target: ${route.new}` | 
					
						
							|  |  |  |         reject(err) | 
					
						
							|  |  |  |       }) | 
					
						
							|  |  |  |       proxy.once('proxyReq', function (proxyReq) { | 
					
						
							|  |  |  |         proxyReq.path = url.parse(route.new).path | 
					
						
							|  |  |  |       }) | 
					
						
							|  |  |  |       proxy.once('close', resolve) | 
					
						
							|  |  |  |       proxy.web(this.req, this.res, { target: route.new }) | 
					
						
							| 
									
										
										
										
											2015-11-19 19:27:36 +00:00
										 |  |  |     }) | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 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() | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-11-24 11:46:47 +00:00
										 |  |  | 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 | 
					
						
							|  |  |  |       }) | 
					
						
							|  |  |  |     }) | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | function mockResponses (route, targets) { | 
					
						
							|  |  |  |   targets = arrayify(targets) | 
					
						
							| 
									
										
										
										
											2016-02-19 19:28:22 +00:00
										 |  |  |   debug('mock route: %s, targets: %s', route, targets.length) | 
					
						
							| 
									
										
										
										
											2015-11-24 11:46:47 +00:00
										 |  |  |   const pathRe = pathToRegexp(route) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return function mockResponse (ctx, next) { | 
					
						
							| 
									
										
										
										
											2015-11-27 22:48:53 +00:00
										 |  |  |     if (pathRe.test(ctx.path)) { | 
					
						
							| 
									
										
										
										
											2015-11-19 19:27:36 +00:00
										 |  |  |       const testValue = require('test-value') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       /* find a mock with compatible method and accepts */ | 
					
						
							| 
									
										
										
										
											2015-11-24 11:46:47 +00:00
										 |  |  |       let target = targets.find(target => { | 
					
						
							|  |  |  |         return testValue(target, { | 
					
						
							| 
									
										
										
										
											2015-11-19 19:27:36 +00:00
										 |  |  |           request: { | 
					
						
							|  |  |  |             method: [ ctx.method, undefined ], | 
					
						
							|  |  |  |             accepts: type => ctx.accepts(type) | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |         }) | 
					
						
							|  |  |  |       }) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-11-24 11:46:47 +00:00
										 |  |  |       /* else take the first target without a request (no request means 'all requests') */ | 
					
						
							|  |  |  |       if (!target) { | 
					
						
							|  |  |  |         target = targets.find(target => !target.request) | 
					
						
							| 
									
										
										
										
											2015-11-19 19:27:36 +00:00
										 |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-11-24 11:46:47 +00:00
										 |  |  |       if (target) { | 
					
						
							|  |  |  |         if (t.isFunction(target.response)) { | 
					
						
							| 
									
										
										
										
											2015-11-27 22:48:53 +00:00
										 |  |  |           const pathMatches = ctx.path.match(pathRe).slice(1) | 
					
						
							| 
									
										
										
										
											2016-02-19 19:28:22 +00:00
										 |  |  |           return target.response.apply(null, [ctx].concat(pathMatches)) | 
					
						
							| 
									
										
										
										
											2015-11-27 21:54:33 +00:00
										 |  |  |         } else if (t.isPlainObject(target.response)) { | 
					
						
							| 
									
										
										
										
											2015-11-24 12:47:27 +00:00
										 |  |  |           Object.assign(ctx.response, target.response) | 
					
						
							| 
									
										
										
										
											2015-11-27 21:54:33 +00:00
										 |  |  |         } else { | 
					
						
							|  |  |  |           throw new Error(`Invalid response: ${JSON.stringify(target.response)}`) | 
					
						
							| 
									
										
										
										
											2015-11-19 20:40:41 +00:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2015-11-19 19:27:36 +00:00
										 |  |  |       } | 
					
						
							| 
									
										
										
										
											2015-11-24 12:47:27 +00:00
										 |  |  |     } else { | 
					
						
							|  |  |  |       return next() | 
					
						
							| 
									
										
										
										
											2015-11-19 19:27:36 +00:00
										 |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } |