koa-files 2.3.7 → 2.3.8
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/README.md +9 -11
- package/cjs/Files.cjs +389 -0
- package/cjs/index.cjs +12 -12
- package/cjs/utils.cjs +75 -78
- package/esm/Files.js +378 -0
- package/esm/index.js +12 -12
- package/esm/utils.js +71 -76
- package/package.json +5 -5
- package/types/Files.d.ts +98 -0
- package/types/index.d.ts +3 -3
- package/types/utils.d.ts +23 -27
- package/cjs/Send.cjs +0 -376
- package/esm/Send.js +0 -367
- package/types/Send.d.ts +0 -86
package/esm/utils.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @package koa-files
|
|
3
3
|
* @license MIT
|
|
4
|
-
* @version 2.3.
|
|
4
|
+
* @version 2.3.8
|
|
5
5
|
* @author nuintun <nuintun@qq.com>
|
|
6
6
|
* @description A static files serving middleware for koa.
|
|
7
7
|
* @see https://github.com/nuintun/koa-files#readme
|
|
@@ -18,122 +18,117 @@ import { relative, isAbsolute } from 'path';
|
|
|
18
18
|
const CHARS = Array.from('0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz');
|
|
19
19
|
/**
|
|
20
20
|
* @function isOutRoot
|
|
21
|
-
* @description
|
|
22
|
-
* @param
|
|
23
|
-
* @param
|
|
24
|
-
* @returns {boolean}
|
|
21
|
+
* @description Check if path is out of root
|
|
22
|
+
* @param path The path to check
|
|
23
|
+
* @param root The root path
|
|
25
24
|
*/
|
|
26
25
|
function isOutRoot(path, root) {
|
|
27
|
-
|
|
28
|
-
|
|
26
|
+
path = relative(root, path);
|
|
27
|
+
return /\.\.(?:[\\/]|$)/.test(path) || isAbsolute(path);
|
|
29
28
|
}
|
|
30
29
|
/**
|
|
31
30
|
* @function unixify
|
|
32
|
-
* @description Convert path
|
|
33
|
-
* @param
|
|
34
|
-
* @returns {string}
|
|
31
|
+
* @description Convert path to unix style
|
|
32
|
+
* @param path The path to convert
|
|
35
33
|
*/
|
|
36
34
|
function unixify(path) {
|
|
37
|
-
|
|
35
|
+
return path.replace(/\\/g, '/');
|
|
38
36
|
}
|
|
39
37
|
/**
|
|
40
38
|
* @function decodeURI
|
|
41
|
-
* @description Decode URI component
|
|
42
|
-
* @param
|
|
43
|
-
* @returns {string|-1}
|
|
39
|
+
* @description Decode URI component
|
|
40
|
+
* @param URI The URI to decode
|
|
44
41
|
*/
|
|
45
42
|
function decodeURI(URI) {
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
}
|
|
43
|
+
try {
|
|
44
|
+
return decodeURIComponent(URI);
|
|
45
|
+
} catch (error) {
|
|
46
|
+
return -1;
|
|
47
|
+
}
|
|
52
48
|
}
|
|
53
49
|
/**
|
|
54
50
|
* @function boundaryGenerator
|
|
55
|
-
* @description
|
|
56
|
-
* @returns {string}
|
|
51
|
+
* @description Generate a boundary
|
|
57
52
|
*/
|
|
58
53
|
function boundaryGenerator() {
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
54
|
+
let boundary = '';
|
|
55
|
+
// Create boundary
|
|
56
|
+
for (let i = 0; i < 38; i++) {
|
|
57
|
+
boundary += CHARS[Math.floor(Math.random() * 62)];
|
|
58
|
+
}
|
|
59
|
+
// Return boundary
|
|
60
|
+
return boundary;
|
|
66
61
|
}
|
|
67
62
|
/**
|
|
68
63
|
* @function fstat
|
|
69
|
-
* @
|
|
70
|
-
* @
|
|
64
|
+
* @description Get file stats
|
|
65
|
+
* @param path The file path
|
|
71
66
|
*/
|
|
72
67
|
function fstat(path) {
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
});
|
|
68
|
+
return new Promise((resolve, reject) => {
|
|
69
|
+
fs.stat(path, (error, stats) => {
|
|
70
|
+
error ? reject(error) : resolve(stats);
|
|
77
71
|
});
|
|
72
|
+
});
|
|
78
73
|
}
|
|
79
74
|
/**
|
|
80
75
|
* @function hasTrailingSlash
|
|
81
|
-
* @
|
|
82
|
-
* @
|
|
76
|
+
* @description Check if path has trailing slash
|
|
77
|
+
* @param path The path to check
|
|
83
78
|
*/
|
|
84
79
|
function hasTrailingSlash(path) {
|
|
85
|
-
|
|
80
|
+
return /\/$/.test(path);
|
|
86
81
|
}
|
|
87
82
|
/**
|
|
88
83
|
* @function parseTokens
|
|
89
|
-
* @description Parse
|
|
90
|
-
* @param
|
|
84
|
+
* @description Parse HTTP tokens
|
|
85
|
+
* @param value The tokens value string
|
|
91
86
|
*/
|
|
92
87
|
function parseTokens(value) {
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
}
|
|
104
|
-
break;
|
|
105
|
-
case 0x2c:
|
|
106
|
-
// ','
|
|
107
|
-
tokens.push(value.substring(start, end));
|
|
108
|
-
start = end = i + 1;
|
|
109
|
-
break;
|
|
110
|
-
default:
|
|
111
|
-
end = i + 1;
|
|
112
|
-
break;
|
|
88
|
+
let end = 0;
|
|
89
|
+
let start = 0;
|
|
90
|
+
let tokens = [];
|
|
91
|
+
// gather tokens
|
|
92
|
+
for (let i = 0, length = value.length; i < length; i++) {
|
|
93
|
+
switch (value.charCodeAt(i)) {
|
|
94
|
+
case 0x20:
|
|
95
|
+
// ' '
|
|
96
|
+
if (start === end) {
|
|
97
|
+
start = end = i + 1;
|
|
113
98
|
}
|
|
99
|
+
break;
|
|
100
|
+
case 0x2c:
|
|
101
|
+
// ','
|
|
102
|
+
tokens.push(value.substring(start, end));
|
|
103
|
+
start = end = i + 1;
|
|
104
|
+
break;
|
|
105
|
+
default:
|
|
106
|
+
end = i + 1;
|
|
107
|
+
break;
|
|
114
108
|
}
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
109
|
+
}
|
|
110
|
+
// final token
|
|
111
|
+
tokens.push(value.substring(start, end));
|
|
112
|
+
return tokens;
|
|
118
113
|
}
|
|
119
114
|
/**
|
|
120
|
-
* @function
|
|
121
|
-
* @
|
|
122
|
-
* @param
|
|
123
|
-
* @returns {boolean}
|
|
115
|
+
* @function isETag
|
|
116
|
+
* @description Check if etag is valid
|
|
117
|
+
* @param value The value to check
|
|
124
118
|
*/
|
|
125
|
-
function
|
|
126
|
-
|
|
127
|
-
return match === etag || match === 'W/' + etag || 'W/' + match === etag;
|
|
128
|
-
});
|
|
119
|
+
function isETag(value) {
|
|
120
|
+
return /^(?:W\/)?"[\s\S]+"$/.test(value);
|
|
129
121
|
}
|
|
130
122
|
/**
|
|
131
|
-
* @function
|
|
132
|
-
* @
|
|
133
|
-
* @
|
|
123
|
+
* @function isETagFresh
|
|
124
|
+
* @description Check if etag is fresh
|
|
125
|
+
* @param match The match value
|
|
126
|
+
* @param etag The etag value
|
|
134
127
|
*/
|
|
135
|
-
function
|
|
136
|
-
|
|
128
|
+
function isETagFresh(match, etag) {
|
|
129
|
+
return parseTokens(match).some(match => {
|
|
130
|
+
return match === etag || match === 'W/' + etag || 'W/' + match === etag;
|
|
131
|
+
});
|
|
137
132
|
}
|
|
138
133
|
|
|
139
134
|
export { boundaryGenerator, decodeURI, fstat, hasTrailingSlash, isETag, isETagFresh, isOutRoot, parseTokens, unixify };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "koa-files",
|
|
3
|
-
"version": "2.3.
|
|
3
|
+
"version": "2.3.8",
|
|
4
4
|
"description": "A static files serving middleware for koa.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "cjs/index.cjs",
|
|
@@ -45,10 +45,10 @@
|
|
|
45
45
|
"test": "node tests",
|
|
46
46
|
"lint": "tsc --noEmit",
|
|
47
47
|
"clean": "node tools/clean.js",
|
|
48
|
-
"format": "prettier --write .",
|
|
49
48
|
"prepublishOnly": "npm run build",
|
|
50
49
|
"build:cjs": "rollup -c tools/rollup.cjs.js",
|
|
51
50
|
"build:esm": "rollup -c tools/rollup.esm.js",
|
|
51
|
+
"format": "prettier --write . --ignore-path .prettierignore",
|
|
52
52
|
"build": "npm run clean && npm run build:main && npm run format",
|
|
53
53
|
"build:main": "npm run build:cjs && npm run build:esm && npm run build:types",
|
|
54
54
|
"build:types": "tsc --declaration --emitDeclarationOnly --declarationDir types"
|
|
@@ -65,12 +65,12 @@
|
|
|
65
65
|
"@types/etag": "^1.8.3",
|
|
66
66
|
"@types/koa": "^2.15.0",
|
|
67
67
|
"@types/range-parser": "^1.2.7",
|
|
68
|
-
"koa": "^2.15.
|
|
68
|
+
"koa": "^2.15.1",
|
|
69
69
|
"magic-string": "^0.30.8",
|
|
70
70
|
"prettier": "^3.2.5",
|
|
71
71
|
"rimraf": "^5.0.5",
|
|
72
|
-
"rollup": "^4.
|
|
73
|
-
"typescript": "^5.
|
|
72
|
+
"rollup": "^4.13.0",
|
|
73
|
+
"typescript": "^5.4.2"
|
|
74
74
|
},
|
|
75
75
|
"peerDependencies": {
|
|
76
76
|
"koa": "^2.0.0"
|
package/types/Files.d.ts
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module Files
|
|
3
|
+
* @license MIT
|
|
4
|
+
* @author nuintun
|
|
5
|
+
*/
|
|
6
|
+
import { Context } from 'koa';
|
|
7
|
+
export interface Options {
|
|
8
|
+
etag?: boolean;
|
|
9
|
+
cacheControl?: string;
|
|
10
|
+
acceptRanges?: boolean;
|
|
11
|
+
lastModified?: boolean;
|
|
12
|
+
ignore?: (path: string) => boolean;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* @class Files
|
|
16
|
+
*/
|
|
17
|
+
export default class Files {
|
|
18
|
+
private root;
|
|
19
|
+
private options;
|
|
20
|
+
/**
|
|
21
|
+
* @constructor
|
|
22
|
+
* @description Create files service
|
|
23
|
+
* @param root Files service root
|
|
24
|
+
* @param options Files service options
|
|
25
|
+
*/
|
|
26
|
+
constructor(root: string, options?: Options);
|
|
27
|
+
/**
|
|
28
|
+
* @private
|
|
29
|
+
* @method isConditionalGET
|
|
30
|
+
* @description Check if request is conditional GET
|
|
31
|
+
* @param context Koa context
|
|
32
|
+
*/
|
|
33
|
+
private isConditionalGET;
|
|
34
|
+
/**
|
|
35
|
+
* @private
|
|
36
|
+
* @method isPreconditionFailure
|
|
37
|
+
* @description Check if request precondition failure
|
|
38
|
+
* @param context Koa context
|
|
39
|
+
*/
|
|
40
|
+
private isPreconditionFailure;
|
|
41
|
+
/**
|
|
42
|
+
* @private
|
|
43
|
+
* @method isRangeFresh
|
|
44
|
+
* @description Check if request range fresh
|
|
45
|
+
* @param context Koa context
|
|
46
|
+
*/
|
|
47
|
+
private isRangeFresh;
|
|
48
|
+
/**
|
|
49
|
+
* @private
|
|
50
|
+
* @method isIgnore
|
|
51
|
+
* @description Check if path is ignore
|
|
52
|
+
* @param path File path
|
|
53
|
+
*/
|
|
54
|
+
private isIgnore;
|
|
55
|
+
/**
|
|
56
|
+
* @private
|
|
57
|
+
* @method parseRange
|
|
58
|
+
* @description Parse range
|
|
59
|
+
* @param context Koa context
|
|
60
|
+
* @param stats File stats
|
|
61
|
+
*/
|
|
62
|
+
private parseRange;
|
|
63
|
+
/**
|
|
64
|
+
* @private
|
|
65
|
+
* @method setupHeaders
|
|
66
|
+
* @description Setup headers
|
|
67
|
+
* @param context Koa context
|
|
68
|
+
* @param path File path
|
|
69
|
+
* @param stats File stats
|
|
70
|
+
*/
|
|
71
|
+
private setupHeaders;
|
|
72
|
+
/**
|
|
73
|
+
* @private
|
|
74
|
+
* @method read
|
|
75
|
+
* @description Read file
|
|
76
|
+
* @param path File path
|
|
77
|
+
* @param range Read range
|
|
78
|
+
* @param buffer Destination stream
|
|
79
|
+
* @param end Is destory destination stream after read
|
|
80
|
+
*/
|
|
81
|
+
private read;
|
|
82
|
+
/**
|
|
83
|
+
* @private
|
|
84
|
+
* @method send
|
|
85
|
+
* @description Send file
|
|
86
|
+
* @param context Koa context
|
|
87
|
+
* @param path File path
|
|
88
|
+
* @param ranges Read ranges
|
|
89
|
+
*/
|
|
90
|
+
private send;
|
|
91
|
+
/**
|
|
92
|
+
* @public
|
|
93
|
+
* @method response
|
|
94
|
+
* @description Response to koa context
|
|
95
|
+
* @param context Koa context
|
|
96
|
+
*/
|
|
97
|
+
response(context: Context): Promise<boolean>;
|
|
98
|
+
}
|
package/types/index.d.ts
CHANGED
|
@@ -4,9 +4,9 @@
|
|
|
4
4
|
* @author nuintun
|
|
5
5
|
*/
|
|
6
6
|
import { Middleware } from 'koa';
|
|
7
|
-
import { Options as
|
|
8
|
-
export interface Options extends
|
|
9
|
-
|
|
7
|
+
import { Options as FilesOptions } from './Files';
|
|
8
|
+
export interface Options extends FilesOptions {
|
|
9
|
+
defer?: boolean;
|
|
10
10
|
}
|
|
11
11
|
/**
|
|
12
12
|
* @function server
|
package/types/utils.d.ts
CHANGED
|
@@ -7,60 +7,56 @@
|
|
|
7
7
|
import { Stats } from 'fs';
|
|
8
8
|
/**
|
|
9
9
|
* @function isOutRoot
|
|
10
|
-
* @description
|
|
11
|
-
* @param
|
|
12
|
-
* @param
|
|
13
|
-
* @returns {boolean}
|
|
10
|
+
* @description Check if path is out of root
|
|
11
|
+
* @param path The path to check
|
|
12
|
+
* @param root The root path
|
|
14
13
|
*/
|
|
15
14
|
export declare function isOutRoot(path: string, root: string): boolean;
|
|
16
15
|
/**
|
|
17
16
|
* @function unixify
|
|
18
|
-
* @description Convert path
|
|
19
|
-
* @param
|
|
20
|
-
* @returns {string}
|
|
17
|
+
* @description Convert path to unix style
|
|
18
|
+
* @param path The path to convert
|
|
21
19
|
*/
|
|
22
20
|
export declare function unixify(path: string): string;
|
|
23
21
|
/**
|
|
24
22
|
* @function decodeURI
|
|
25
|
-
* @description Decode URI component
|
|
26
|
-
* @param
|
|
27
|
-
* @returns {string|-1}
|
|
23
|
+
* @description Decode URI component
|
|
24
|
+
* @param URI The URI to decode
|
|
28
25
|
*/
|
|
29
26
|
export declare function decodeURI(URI: string): string | -1;
|
|
30
27
|
/**
|
|
31
28
|
* @function boundaryGenerator
|
|
32
|
-
* @description
|
|
33
|
-
* @returns {string}
|
|
29
|
+
* @description Generate a boundary
|
|
34
30
|
*/
|
|
35
31
|
export declare function boundaryGenerator(): string;
|
|
36
32
|
/**
|
|
37
33
|
* @function fstat
|
|
38
|
-
* @
|
|
39
|
-
* @
|
|
34
|
+
* @description Get file stats
|
|
35
|
+
* @param path The file path
|
|
40
36
|
*/
|
|
41
37
|
export declare function fstat(path: string): Promise<Stats>;
|
|
42
38
|
/**
|
|
43
39
|
* @function hasTrailingSlash
|
|
44
|
-
* @
|
|
45
|
-
* @
|
|
40
|
+
* @description Check if path has trailing slash
|
|
41
|
+
* @param path The path to check
|
|
46
42
|
*/
|
|
47
43
|
export declare function hasTrailingSlash(path: string): boolean;
|
|
48
44
|
/**
|
|
49
45
|
* @function parseTokens
|
|
50
|
-
* @description Parse
|
|
51
|
-
* @param
|
|
46
|
+
* @description Parse HTTP tokens
|
|
47
|
+
* @param value The tokens value string
|
|
52
48
|
*/
|
|
53
49
|
export declare function parseTokens(value: string): string[];
|
|
54
50
|
/**
|
|
55
|
-
* @function
|
|
56
|
-
* @
|
|
57
|
-
* @param
|
|
58
|
-
* @returns {boolean}
|
|
51
|
+
* @function isETag
|
|
52
|
+
* @description Check if etag is valid
|
|
53
|
+
* @param value The value to check
|
|
59
54
|
*/
|
|
60
|
-
export declare function
|
|
55
|
+
export declare function isETag(value: string): boolean;
|
|
61
56
|
/**
|
|
62
|
-
* @function
|
|
63
|
-
* @
|
|
64
|
-
* @
|
|
57
|
+
* @function isETagFresh
|
|
58
|
+
* @description Check if etag is fresh
|
|
59
|
+
* @param match The match value
|
|
60
|
+
* @param etag The etag value
|
|
65
61
|
*/
|
|
66
|
-
export declare function
|
|
62
|
+
export declare function isETagFresh(match: string, etag: string): boolean;
|