-
Notifications
You must be signed in to change notification settings - Fork 6
/
Copy pathindex.js
112 lines (100 loc) · 2.5 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
'use strict';
/**
* Module dependencies.
*/
const { domainToUnicode } = require('url');
const compose = require('koa-compose');
/**
* Expose `vhost()`.
*/
module.exports = vhost;
/**
* When `pattern` is String or RegExp,
* the request will be forwarded to the
* specified `app` if the `app` matches
* the `pattern`.
*
* When `pattern` is Array or Object,
* it will try to get fetch the `app`
* from the `pattern` map accroding
* to the request's hostname first,
* then forward the request.
*
* If `app` mismatches the `pattern`,
* or there is no such matching record
* in the `parttern`, it will yield to
* the next middleware.
*
* For examples, check README.md.
*
* @param {String | RegExp | Array | Object} pattern
* @param {Application} app
* @return {Funtion}
* @api public
*/
function vhost(pattern, app) {
return async (ctx, next) => {
try {
const hostname = domainToUnicode(ctx.get(':authority') || ctx.hostname);
const target = app || matchAndMap(hostname);
if (!target) return await next();
if (app && !isMatch(pattern, hostname)) return await next();
await compose(target.middleware)(ctx, next);
} catch (err) {
// the app is specified but malformed
const status = err.status || 500;
ctx.throw(status, err.message);
}
};
/**
* Returns the matched Koa app from
* the specified `pattern` map
* according to the `hostname`.
*
* Returns undefined if not found.
*
* The `pattern` should be either an
* Array or Object here.
*
* Check README.md for more info.
*
* @param {String} hostname
* @return {Application | undefined}
* @api private
*/
function matchAndMap(hostname) {
if (pattern instanceof Array) {
for (let i = 0; i < pattern.length; i++) {
if (isMatch(pattern[i].pattern, hostname)) {
return pattern[i].target;
}
}
return undefined;
}
if (pattern instanceof Object) {
return pattern[hostname];
}
return undefined;
}
/**
* Check if `hostname` matches the
* specified `condition`.
*
* The `condition` should be either a
* String or a RegExp here.
*
* @param {String | RegExp} condition
* @param {String} hostname
* @return {Boolean}
* @api private
*/
function isMatch(condition, hostname) {
if (typeof condition === 'string') {
return condition === hostname;
}
if (condition instanceof RegExp) {
return condition.test(hostname);
}
return false;
}
}