blackbird-server
Version:
HTTP for JavaScript
570 lines (569 loc) • 18 kB
HTML
<html lang="en">
<head>
<title>Code coverage report for modules/middleware/file.js</title>
<meta charset="utf-8" />
<link rel="stylesheet" href="../../prettify.css" />
<link rel="stylesheet" href="../../base.css" />
<meta name="viewport" content="width=device-width, initial-scale=1">
<style type='text/css'>
.coverage-summary .sorter {
background-image: url(../../sort-arrow-sprite.png);
}
</style>
</head>
<body>
<div class='wrapper'>
<div class='pad1'>
<h1>
<a href="../../index.html">all files</a> / <a href="index.html">modules/middleware/</a> file.js
</h1>
<div class='clearfix'>
<div class='fl pad1y space-right2'>
<span class="strong">83.05% </span>
<span class="quiet">Statements</span>
<span class='fraction'>49/59</span>
</div>
<div class='fl pad1y space-right2'>
<span class="strong">72.34% </span>
<span class="quiet">Branches</span>
<span class='fraction'>34/47</span>
</div>
<div class='fl pad1y space-right2'>
<span class="strong">87.5% </span>
<span class="quiet">Functions</span>
<span class='fraction'>7/8</span>
</div>
<div class='fl pad1y space-right2'>
<span class="strong">83.05% </span>
<span class="quiet">Lines</span>
<span class='fraction'>49/59</span>
</div>
</div>
</div>
<div class='status-line high'></div>
<pre><table class="coverage">
<tr><td class="line-count quiet">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
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169</td><td class="line-coverage quiet"><span class="cline-any cline-yes">1×</span>
<span class="cline-any cline-yes">1×</span>
<span class="cline-any cline-yes">1×</span>
<span class="cline-any cline-yes">1×</span>
<span class="cline-any cline-yes">1×</span>
<span class="cline-any cline-yes">1×</span>
<span class="cline-any cline-yes">1×</span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-yes">1×</span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-yes">1×</span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-yes">1×</span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-yes">3×</span>
<span class="cline-any cline-yes">3×</span>
<span class="cline-any cline-yes">3×</span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-yes">3×</span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-yes">3×</span>
<span class="cline-any cline-no"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-yes">3×</span>
<span class="cline-any cline-yes">3×</span>
<span class="cline-any cline-no"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-yes">3×</span>
<span class="cline-any cline-yes">3×</span>
<span class="cline-any cline-yes">3×</span>
<span class="cline-any cline-yes">2×</span>
<span class="cline-any cline-yes">1×</span>
<span class="cline-any cline-no"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-yes">3×</span>
<span class="cline-any cline-yes">3×</span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-yes">1×</span>
<span class="cline-any cline-yes">5×</span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-yes">5×</span>
<span class="cline-any cline-yes">3×</span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-yes">5×</span>
<span class="cline-any cline-yes">2×</span>
<span class="cline-any cline-yes">2×</span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-yes">3×</span>
<span class="cline-any cline-yes">7×</span>
<span class="cline-any cline-no"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-yes">7×</span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-yes">7×</span>
<span class="cline-any cline-yes">1×</span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-yes">6×</span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-yes">6×</span>
<span class="cline-any cline-yes">6×</span>
<span class="cline-any cline-yes">3×</span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-yes">3×</span>
<span class="cline-any cline-yes">1×</span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-yes">2×</span>
<span class="cline-any cline-yes">4×</span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-yes">2×</span>
<span class="cline-any cline-yes">2×</span>
<span class="cline-any cline-yes">3×</span>
<span class="cline-any cline-yes">2×</span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-no"> </span>
<span class="cline-any cline-no"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-no"> </span>
<span class="cline-any cline-no"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-no"> </span>
<span class="cline-any cline-no"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-neutral"> </span>
<span class="cline-any cline-yes">1×</span>
<span class="cline-any cline-neutral"> </span></td><td class="text"><pre class="prettyprint lang-js">const fs = require("fs");
const mach = require("../index");
const Promise = require("../utils/Promise");
const getFileStats = require("../utils/getFileStats");
const generateETag = require("../utils/generateETag");
const generateIndex = require("../utils/generateIndex");
const joinPaths = require("../utils/joinPaths");
const {is, contains} = require("ramda");
mach.extend(
require("../extensions/server")
);
/**
* A middleware for serving files efficiently from the file system according
* to the path specified in the `pathname` variable.
*
* Options may be any of the following:
*
* - root The path to the root directory to serve files from
* - index An array of file names to try and serve when the
* request targets a directory (e.g. ["index.html", "index.htm"]).
* May simply be truthy to use ["index.html"]
* - autoIndex Set this true to automatically generate an index page
* listing a directory's contents when the request targets
* a directory with no index file
* - useLastModified Set this true to include the Last-Modified header
* based on the mtime of the file. Defaults to true
* - useETag Set this true to include the ETag header based on
* the MD5 checksum of the file. Defaults to false
*
* Alternatively, options may be a file path to the root directory.
*
* If a matching file cannot be found, the request is forwarded to the
* downstream app. Otherwise, the file is streamed through to the response.
*
* Examples:
*
* // Use the root directory name directly.
* app.use(mach.file, '/public');
*
* // Serve static files out of /public, and automatically
* // serve an index.htm from any directory that has one.
* app.use(mach.file, {
* root: '/public',
* index: 'index.htm',
* useETag: true
* });
*
* // Serve static files out of /public, and automatically
* // serve an index.html from any directory that has one.
* // Also, automatically generate a directory listing for
* // any directory without an index.html file.
* app.use(mach.file, {
* root: '/public',
* index: true,
* autoIndex: true
* });
*
* This function may also be used outside of the context of a middleware
* stack to create a standalone app.
*
* let app = mach.file('/public');
* mach.serve(app);
*/
function file(app, options) {
// Allow mach.file(path|options)
<span class="missing-if-branch" title="else path not taken" >E</span>if (typeof app === "string" || typeof app === "object") {
options = app;
app = null;
}
options = options || <span class="branch-1 cbranch-no" title="branch not covered" >{};</span>
// Allow mach.file(path) and app.use(mach.file, path)
<span class="missing-if-branch" title="if path not taken" >I</span>if (is(String, options)) {
<span class="cstat-no" title="statement not covered" > options = {root: options};</span>
}
const root = options.root;
<span class="missing-if-branch" title="if path not taken" >I</span>if (!is(String, root) || !fs.existsSync(root) || !fs.statSync(root).isDirectory()) {
<span class="cstat-no" title="statement not covered" > throw new Error(`Invalid root directory: ${root}`);</span>
}
let index = options.index || <span class="branch-1 cbranch-no" title="branch not covered" >[];</span>
<span class="missing-if-branch" title="else path not taken" >E</span>if (index) {
if (typeof index === "string") {
index = [index];
} else <span class="missing-if-branch" title="if path not taken" >I</span>if (!Array.isArray(index)) {
<span class="cstat-no" title="statement not covered" > index = ["index.html"];</span>
}
}
const useLastModified = "useLastModified" in options ? Boolean(options.useLastModified) : true;
const useETag = Boolean(options.useETag);
function sendFile(conn, path, stats) {
conn.file({
path,
size: stats.size
});
if (useLastModified) {
conn.response.headers["Last-Modified"] = stats.mtime.toUTCString();
}
if (useETag) {
return generateETag(path).then(function (etag) {
conn.response.headers.ETag = etag;
});
}
}
return function (conn) {
<span class="missing-if-branch" title="if path not taken" >I</span>if (conn.method !== "GET" && <span class="branch-1 cbranch-no" title="branch not covered" >conn.method !== "HEAD")</span> {
<span class="cstat-no" title="statement not covered" > return conn.call(app);</span>
}
const pathname = conn.pathname;
// Reject paths that contain "..".
if (contains("..", pathname)) {
return conn.text(403, "Forbidden");
}
const path = joinPaths(root, pathname);
return getFileStats(path).then(function (stats) {
if (stats && stats.isFile()) {
return sendFile(conn, path, stats);
}
if (!stats || !stats.isDirectory()) {
return conn.call(app);
}
// Try to serve one of the index files.
const indexPaths = index.map(function (indexPath) {
return joinPaths(path, indexPath);
});
return Promise.all(indexPaths.map(getFileStats)).then(function (stats) {
for (let i = 0, len = stats.length; i < len; ++i) {
if (stats[i]) {
return sendFile(conn, indexPaths[i], stats[i]);
}
}
<span class="cstat-no" title="statement not covered" > if (!options.autoIndex) {</span>
<span class="cstat-no" title="statement not covered" > return conn.call(app);</span>
}
// Redirect /images => /images/
<span class="cstat-no" title="statement not covered" > if (!(/\/$/).test(pathname)) {</span>
<span class="cstat-no" title="statement not covered" > return conn.redirect(`${pathname}/`);</span>
}
// Automatically generate and serve an index file.
<span class="cstat-no" title="statement not covered" > return generateIndex(root, pathname, conn.basename).then(<span class="fstat-no" title="function not covered" >function (html) {</span></span>
<span class="cstat-no" title="statement not covered" > conn.html(html);</span>
});
});
});
};
}
module.exports = file;
</pre></td></tr>
</table></pre>
<div class='push'></div><!-- for sticky footer -->
</div><!-- /wrapper -->
<div class='footer quiet pad2 space-top1 center small'>
Code coverage
generated by <a href="http://istanbul-js.org/" target="_blank">istanbul</a> at Wed Jul 06 2016 20:37:18 GMT-0500 (CDT)
</div>
</div>
<script src="../../prettify.js"></script>
<script>
window.onload = function () {
if (typeof prettyPrint === 'function') {
prettyPrint();
}
};
</script>
<script src="../../sorter.js"></script>
</body>
</html>