This repository has been archived by the owner on Nov 4, 2020. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.js
131 lines (118 loc) · 4.64 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
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
var path = require('path');
var url = require('url');
var mime = require('mime');
var vinyl = require('vinyl-fs');
var through = require('through2');
var terminus = require('terminus');
function createPipelineFromFactories(factories) {
return function (stream) {
factories.forEach(function (factory) {
// Send matched files through user-defined pipes
stream = stream.pipe(factory());
});
return stream;
};
}
function sendThroughPipeline(files, pipeline, req, send, next, urlPath, mimeType) {
var numFiles = 0;
pipeline(vinyl.src(files), req)
.pipe(through.obj(function (file, enc, callback) {
// Count files to detect an empty stream
++numFiles;
// Replace Vinyl File with Buffer
this.push(file.contents);
callback();
}))
.pipe(terminus.concat(function (content) {
if (numFiles > 0) {
if (!mimeType) {
mimeType = mime.lookup(urlPath);
}
var charset = mime.charsets.lookup(mimeType);
send(mimeType, charset, content);
}
else {
// If no files were matched, forward to next middleware (but issue a warning)
console.warn(
'connect-resource-pipeline matched URL "' + urlPath + '" but found no files matching [' +
files + ']');
next();
}
}));
}
function sendRequest(res, mimeType, charset, content) {
res.setHeader('Content-Type', mimeType + (charset ? '; charset=' + charset : ''));
res.end(content);
}
function isAbsolute(filePath) {
return path.resolve(filePath) === path.normalize(filePath);
}
function resolveFilePaths(root, files) {
return [].concat(files).map(function (filePath) {
return isAbsolute(filePath) ? filePath : path.normalize(path.join(root, filePath));
});
}
function resourcePipeline(options, targets) {
if (Array.isArray(options)) {
targets = options;
options = {};
}
var root = options.root || path.join('.', '');
var indexFile = options.indexFile || 'index.html';
var cache = {};
if (!targets.every(function (target) {return !target.factories;})) {
console.warn('\033[31mconnect-resource-pipeline: "factories" property is deprecated\033[0m');
}
var middleware = function (req, res, next) {
for (var i = 0; i < targets.length; i++) {
var urlPath = url.parse(req.url).pathname;
if (urlPath.substr(-1) === '/') {
urlPath += indexFile;
}
var targetUrl = targets[i].url;
if (typeof targetUrl === 'string' && targetUrl.substr(-1) === '/') {
targetUrl += indexFile;
}
// Allow exact URL string or regex(-ish) match
if (targetUrl === urlPath || targetUrl.test && targetUrl.test(urlPath)) {
var cacheKey = targets[i].cache;
if (cacheKey === true) {
cacheKey = targetUrl.toString();
}
// Check cache for content
if (cacheKey && cache[cacheKey]) {
var entry = cache[cacheKey];
sendRequest(res, entry.mimeType, entry.charset, entry.content);
}
else {
// If no files are named explicitly, attempt to resolve the file requested of the server.
// NOTE: NOT SAFE! This doesn't check for malicious paths, as it is only intended for dev use.
var files = resolveFilePaths(root, targets[i].files || urlPath.replace(/^\//, ''));
var pipeline = targets[i].pipeline || createPipelineFromFactories(targets[i].factories || []);
var send = createSendFn(cacheKey);
sendThroughPipeline(files, pipeline, req, send, next, urlPath, targets[i].mimeType);
}
return;
}
}
// If no match, forward to next middleware
next();
function createSendFn(cacheKey) {
return function (mimeType, charset, content) {
if (cacheKey) {
cache[cacheKey] = {
mimeType: mimeType,
charset: charset,
content: content
};
}
sendRequest(res, mimeType, charset, content);
};
}
};
middleware.clear = function (cacheKey) {
cache[cacheKey] = null;
};
return middleware;
}
module.exports = resourcePipeline;