st 3.0.1 → 3.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/server.js +5 -4
- package/package.json +7 -7
- package/st.js +13 -20
- package/test/basic.js +2 -11
- package/test/cli/common.js +2 -2
- package/test/common.js +1 -1
- package/test/gzip-after-no-gzip.js +4 -1
- package/test/multi-mount.js +3 -3
- package/test/preset-cache-control.js +1 -1
package/bin/server.js
CHANGED
|
@@ -82,6 +82,7 @@ for (let i = 2; i < process.argv.length; i++) {
|
|
|
82
82
|
case '--help':
|
|
83
83
|
help()
|
|
84
84
|
process.exit(0)
|
|
85
|
+
break
|
|
85
86
|
|
|
86
87
|
case '-nc':
|
|
87
88
|
case '--no-cache':
|
|
@@ -150,9 +151,9 @@ if (isNaN(port)) {
|
|
|
150
151
|
|
|
151
152
|
const opt = {
|
|
152
153
|
path: dir,
|
|
153
|
-
url
|
|
154
|
-
index
|
|
155
|
-
dot
|
|
154
|
+
url,
|
|
155
|
+
index,
|
|
156
|
+
dot,
|
|
156
157
|
cache: {
|
|
157
158
|
fd: {},
|
|
158
159
|
stat: {},
|
|
@@ -160,7 +161,7 @@ const opt = {
|
|
|
160
161
|
readdir: {},
|
|
161
162
|
content: {}
|
|
162
163
|
},
|
|
163
|
-
cors
|
|
164
|
+
cors
|
|
164
165
|
}
|
|
165
166
|
|
|
166
167
|
if (cache === false) {
|
package/package.json
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "st",
|
|
3
|
-
"version": "3.0.
|
|
3
|
+
"version": "3.0.2",
|
|
4
4
|
"description": "A module for serving static files. Does etags, caching, etc.",
|
|
5
5
|
"main": "st.js",
|
|
6
6
|
"bin": "bin/server.js",
|
|
7
7
|
"dependencies": {
|
|
8
8
|
"async-cache": "^1.1.0",
|
|
9
|
-
"bl": "^
|
|
10
|
-
"fd": "
|
|
11
|
-
"mime": "^
|
|
12
|
-
"negotiator": "
|
|
9
|
+
"bl": "^6.1.0",
|
|
10
|
+
"fd": "^0.0.3",
|
|
11
|
+
"mime": "^3.0.0",
|
|
12
|
+
"negotiator": "^1.0.0"
|
|
13
13
|
},
|
|
14
14
|
"optionalDependencies": {
|
|
15
15
|
"graceful-fs": "^4.2.3"
|
|
@@ -17,8 +17,8 @@
|
|
|
17
17
|
"devDependencies": {
|
|
18
18
|
"request": "^2.88.2",
|
|
19
19
|
"rimraf": "^3.0.2",
|
|
20
|
-
"standard": "^
|
|
21
|
-
"tap": "^15.
|
|
20
|
+
"standard": "^17.1.2",
|
|
21
|
+
"tap": "^15.2.3"
|
|
22
22
|
},
|
|
23
23
|
"scripts": {
|
|
24
24
|
"lint": "standard",
|
package/st.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
const mime = require('mime')
|
|
2
2
|
const path = require('path')
|
|
3
|
-
const url = require('url')
|
|
4
3
|
let fs
|
|
5
4
|
try {
|
|
6
5
|
fs = require('graceful-fs')
|
|
@@ -180,22 +179,13 @@ class Mount {
|
|
|
180
179
|
|
|
181
180
|
// get the path component from a URI
|
|
182
181
|
getUriPath (u) {
|
|
183
|
-
let p =
|
|
182
|
+
let p = new URL(u, 'http://base').pathname
|
|
184
183
|
|
|
185
|
-
//
|
|
186
|
-
p = p.replace(
|
|
184
|
+
// Convert any backslashes to forward slashes (for consistency)
|
|
185
|
+
p = p.replace(/\\/g, '/')
|
|
187
186
|
|
|
188
|
-
//
|
|
189
|
-
p = p.replace(/%2f|%5c/ig, '/')
|
|
190
|
-
|
|
191
|
-
// back slashes are slashes
|
|
192
|
-
p = p.replace(/[/\\]/g, '/')
|
|
193
|
-
|
|
194
|
-
// Make sure it starts with a slash
|
|
195
|
-
p = p.replace(/^\//, '/')
|
|
187
|
+
// Remove the redundant leading slash replacement - URL().pathname always starts with /
|
|
196
188
|
if ((/[/\\]\.\.([/\\]|$)/).test(p)) {
|
|
197
|
-
// traversal urls not ever even slightly allowed. clearly shenanigans
|
|
198
|
-
// send a 403 on that noise, do not pass go, do not collect $200
|
|
199
189
|
return 403
|
|
200
190
|
}
|
|
201
191
|
|
|
@@ -204,15 +194,18 @@ class Mount {
|
|
|
204
194
|
return false
|
|
205
195
|
}
|
|
206
196
|
|
|
197
|
+
// URL constructor already decoded, but we might need additional decoding
|
|
198
|
+
// for edge cases. Only do it if it would actually change something.
|
|
207
199
|
try {
|
|
208
|
-
|
|
200
|
+
const decoded = decodeURIComponent(u)
|
|
201
|
+
if (decoded !== u) {
|
|
202
|
+
u = decoded
|
|
203
|
+
}
|
|
209
204
|
} catch (e) {
|
|
210
|
-
|
|
205
|
+
// if decodeURIComponent failed, we weren't given a valid URL to begin with.
|
|
211
206
|
return false
|
|
212
207
|
}
|
|
213
208
|
|
|
214
|
-
// /a/b/c mounted on /path/to/z/d/x
|
|
215
|
-
// /a/b/c/d --> /path/to/z/d/x/d
|
|
216
209
|
u = u.substr(this.url.length)
|
|
217
210
|
if (u.charAt(0) !== '/') {
|
|
218
211
|
u = '/' + u
|
|
@@ -445,7 +438,7 @@ class Mount {
|
|
|
445
438
|
}
|
|
446
439
|
|
|
447
440
|
streamFile (p, fd, stat, etag, req, res, end) {
|
|
448
|
-
const streamOpt = { fd
|
|
441
|
+
const streamOpt = { fd, start: 0, end: stat.size }
|
|
449
442
|
let stream = fs.createReadStream(p, streamOpt)
|
|
450
443
|
stream.destroy = () => {}
|
|
451
444
|
|
|
@@ -457,7 +450,7 @@ class Mount {
|
|
|
457
450
|
|
|
458
451
|
// need a gzipped version for the cache, so do it regardless of what the client wants
|
|
459
452
|
if (gz || (gzOpt && cachable)) {
|
|
460
|
-
gzstr = zlib.
|
|
453
|
+
gzstr = zlib.createGzip()
|
|
461
454
|
}
|
|
462
455
|
|
|
463
456
|
// too late to effectively handle any errors.
|
package/test/basic.js
CHANGED
|
@@ -125,17 +125,8 @@ test('shenanigans', (t) => {
|
|
|
125
125
|
if (er) {
|
|
126
126
|
throw er
|
|
127
127
|
}
|
|
128
|
-
|
|
129
|
-
t.
|
|
130
|
-
})
|
|
131
|
-
})
|
|
132
|
-
|
|
133
|
-
test('shenanigans2', (t) => {
|
|
134
|
-
req('/test//foo/%2e%2E', (er, res) => {
|
|
135
|
-
if (er) {
|
|
136
|
-
throw er
|
|
137
|
-
}
|
|
138
|
-
t.equal(res.statusCode, 403)
|
|
128
|
+
// resolves to simply ./etc/passwd
|
|
129
|
+
t.equal(res.statusCode, 404)
|
|
139
130
|
t.end()
|
|
140
131
|
})
|
|
141
132
|
})
|
package/test/cli/common.js
CHANGED
package/test/common.js
CHANGED
|
@@ -12,7 +12,10 @@ test('does not gzip first response', (t) => {
|
|
|
12
12
|
t.notOk(res.headers['content-encoding'])
|
|
13
13
|
t.notOk(res.headers['x-from-cache'])
|
|
14
14
|
t.equal(body.toString(), stExpect)
|
|
15
|
-
|
|
15
|
+
// response is delivered before cache is set, so we'll give it a tiny bit
|
|
16
|
+
// of grace to close out on the server side before starting the next
|
|
17
|
+
// test
|
|
18
|
+
setTimeout(t.end, 100)
|
|
16
19
|
})
|
|
17
20
|
})
|
|
18
21
|
|
package/test/multi-mount.js
CHANGED
|
@@ -47,13 +47,13 @@ function req (url, headers, cb) {
|
|
|
47
47
|
request({
|
|
48
48
|
encoding: null,
|
|
49
49
|
url: `http://localhost:${port}${url}`,
|
|
50
|
-
headers
|
|
50
|
+
headers,
|
|
51
51
|
agentOptions: { maxSockets: 50 }
|
|
52
52
|
}, next)
|
|
53
53
|
request({
|
|
54
54
|
encoding: null,
|
|
55
55
|
url: `http://localhost:${(port + 1)}${url}`,
|
|
56
|
-
headers
|
|
56
|
+
headers,
|
|
57
57
|
agentOptions: { maxSockets: 50 }
|
|
58
58
|
}, next)
|
|
59
59
|
|
|
@@ -76,7 +76,7 @@ function req (url, headers, cb) {
|
|
|
76
76
|
assert.strictEqual(`${body}`, `${prev.body}`)
|
|
77
77
|
return cb(er, res, body)
|
|
78
78
|
}
|
|
79
|
-
prev = { res
|
|
79
|
+
prev = { res, body }
|
|
80
80
|
}
|
|
81
81
|
}
|
|
82
82
|
|