koa-classic-server 3.0.0 → 3.1.0
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 +44 -120
- package/index.cjs +236 -21
- package/package.json +10 -5
- package/.github/workflows/npm-publish.yml +0 -98
- package/CLAUDE.md +0 -101
- package/__tests__/benchmark-results-baseline-v1.2.0.txt +0 -354
- package/__tests__/benchmark-results-optimized-v2.0.0.txt +0 -354
- package/__tests__/benchmark-results-v3.0.0.txt +0 -372
- package/__tests__/benchmark.js +0 -239
- package/__tests__/caching-headers.test.js +0 -556
- package/__tests__/compression-fixtures/data.json +0 -1
- package/__tests__/compression-fixtures/large.txt +0 -1
- package/__tests__/compression-fixtures/small.txt +0 -1
- package/__tests__/compression.test.js +0 -284
- package/__tests__/customTest/README.md +0 -6
- package/__tests__/customTest/loadConfig.util.js +0 -41
- package/__tests__/customTest/serversToLoad.util.js +0 -93
- package/__tests__/demo-regex-index.js +0 -140
- package/__tests__/deprecation-warnings.test.js +0 -105
- package/__tests__/directory-sorting-links.test.js +0 -135
- package/__tests__/dt-unknown.test.js +0 -635
- package/__tests__/ejs.test.js +0 -299
- package/__tests__/hidden-fixtures/.dot-dir/inside.txt +0 -1
- package/__tests__/hidden-fixtures/.env +0 -2
- package/__tests__/hidden-fixtures/.well-known/acme-challenge.txt +0 -1
- package/__tests__/hidden-fixtures/config/secrets/password.txt +0 -1
- package/__tests__/hidden-fixtures/data.key +0 -1
- package/__tests__/hidden-fixtures/file.secret +0 -1
- package/__tests__/hidden-fixtures/index.html +0 -1
- package/__tests__/hidden-fixtures/normal.txt +0 -1
- package/__tests__/hidden-fixtures/subdir/.env +0 -1
- package/__tests__/hidden-fixtures/subdir/regular.txt +0 -1
- package/__tests__/hidden-option.test.js +0 -407
- package/__tests__/hideExtension.test.js +0 -607
- package/__tests__/index-option.test.js +0 -449
- package/__tests__/index.test.js +0 -345
- package/__tests__/listing.test.js +0 -437
- package/__tests__/logger.test.js +0 -232
- package/__tests__/performance.test.js +0 -370
- package/__tests__/publicWwwTest/cartella/sottocartella/ciao.html +0 -11
- package/__tests__/publicWwwTest/cartella/sottocartella/provaEjs/testEjs.ejs +0 -11
- package/__tests__/publicWwwTest/cartella vuota con spazi nel nome/file con spazio nel nome .txt +0 -1
- package/__tests__/publicWwwTest/cartella vuota con spazi nel nome /file con spazio nel nome .txt +0 -1
- package/__tests__/publicWwwTest/ejs-templates/complex.ejs +0 -56
- package/__tests__/publicWwwTest/ejs-templates/index.ejs +0 -30
- package/__tests__/publicWwwTest/ejs-templates/simple.ejs +0 -13
- package/__tests__/publicWwwTest/ejs-templates/with-conditional.ejs +0 -28
- package/__tests__/publicWwwTest/ejs-templates/with-escaping.ejs +0 -26
- package/__tests__/publicWwwTest/ejs-templates/with-loop.ejs +0 -16
- package/__tests__/publicWwwTest/hideext-test/about/index.html +0 -1
- package/__tests__/publicWwwTest/hideext-test/about.EJS +0 -1
- package/__tests__/publicWwwTest/hideext-test/about.ejs +0 -2
- package/__tests__/publicWwwTest/hideext-test/blog/articolo.ejs +0 -2
- package/__tests__/publicWwwTest/hideext-test/conflict-test/pagina +0 -1
- package/__tests__/publicWwwTest/hideext-test/conflict-test/pagina.ejs +0 -1
- package/__tests__/publicWwwTest/hideext-test/file.ejs.bak +0 -1
- package/__tests__/publicWwwTest/hideext-test/index.ejs +0 -2
- package/__tests__/publicWwwTest/hideext-test/photo.txt +0 -1
- package/__tests__/publicWwwTest/hideext-test/sezione/index.ejs +0 -1
- package/__tests__/publicWwwTest/hideext-test/style.css +0 -1
- package/__tests__/publicWwwTest/ile_vuoto.txt +0 -0
- package/__tests__/publicWwwTest/index.html +0 -11
- package/__tests__/publicWwwTest/prova file .txt +0 -2
- package/__tests__/publicWwwTest/semplicetxt.txt +0 -1
- package/__tests__/publicWwwTest/test-page.html +0 -1
- package/__tests__/publicWwwTest/test.txt +0 -1
- package/__tests__/range-fixtures/sample.txt +0 -1
- package/__tests__/range.test.js +0 -223
- package/__tests__/security-headers.test.js +0 -165
- package/__tests__/security.test.js +0 -322
- package/__tests__/server-cache-fixtures/large.txt +0 -1
- package/__tests__/server-cache-fixtures/small.txt +0 -1
- package/__tests__/server-cache.test.js +0 -594
- package/__tests__/setup-benchmark.js +0 -178
- package/__tests__/symlink.test.js +0 -441
- package/__tests__/template-timeout.test.js +0 -321
- package/__tests__/test-regex-quick.js +0 -158
- package/__tests__/useOriginalUrl.test.js +0 -213
- package/docs/ACTION_PLAN.md +0 -293
- package/docs/BENCHMARKS.md +0 -317
- package/docs/CHANGELOG.md +0 -880
- package/docs/CODE_REVIEW.md +0 -300
- package/docs/DEBUG_REPORT.md +0 -593
- package/docs/DOCUMENTATION.md +0 -1864
- package/docs/EXAMPLES_INDEX_OPTION.md +0 -395
- package/docs/FLOW_DIAGRAM.md +0 -954
- package/docs/INDEX_OPTION_PRIORITY.md +0 -527
- package/docs/OPTIMIZATION_HTTP_CACHING.md +0 -689
- package/docs/OPTIMIZATION_ROADMAP_for_V3.md +0 -864
- package/docs/PERFORMANCE_ANALYSIS.md +0 -839
- package/docs/PERFORMANCE_COMPARISON.md +0 -388
- package/docs/noteExports.md +0 -148
- package/docs/security_improvement_for_V3.md +0 -421
- package/docs/template-engine/TEMPLATE_ENGINE_GUIDE.md +0 -1734
- package/docs/template-engine/esempi-incrementali.js +0 -192
- package/docs/template-engine/examples/esempio1-nessun-dato.ejs +0 -12
- package/docs/template-engine/examples/esempio2-una-variabile.ejs +0 -11
- package/docs/template-engine/examples/esempio3-piu-variabili.ejs +0 -15
- package/docs/template-engine/examples/esempio4-condizionale.ejs +0 -18
- package/docs/template-engine/examples/esempio5-loop.ejs +0 -18
- package/docs/template-engine/examples/index-esempi.html +0 -181
- package/docs/template-engine/examples/index.html +0 -40
- package/docs/template-engine/examples/test.ejs +0 -64
- package/eslint.config.mjs +0 -17
- package/jest.config.js +0 -18
|
@@ -1,322 +0,0 @@
|
|
|
1
|
-
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
2
|
-
//
|
|
3
|
-
// SECURITY & BUG TESTS
|
|
4
|
-
// These tests verify the security properties and bug fixes documented in DEBUG_REPORT.md
|
|
5
|
-
//
|
|
6
|
-
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
7
|
-
|
|
8
|
-
const supertest = require('supertest');
|
|
9
|
-
const koaClassicServer = require('../index.cjs');
|
|
10
|
-
const Koa = require('koa');
|
|
11
|
-
const fs = require('fs');
|
|
12
|
-
const path = require('path');
|
|
13
|
-
|
|
14
|
-
const rootDir = path.join(__dirname, 'publicWwwTest');
|
|
15
|
-
|
|
16
|
-
// ─── Path Traversal ───────────────────────────────────────────────────────────
|
|
17
|
-
|
|
18
|
-
describe('Security Tests - Path Traversal', () => {
|
|
19
|
-
let app;
|
|
20
|
-
let server;
|
|
21
|
-
|
|
22
|
-
beforeAll(() => {
|
|
23
|
-
app = new Koa();
|
|
24
|
-
app.use(koaClassicServer(rootDir, {
|
|
25
|
-
dirListing: { enabled: true }
|
|
26
|
-
}));
|
|
27
|
-
server = app.listen();
|
|
28
|
-
});
|
|
29
|
-
|
|
30
|
-
afterAll(() => {
|
|
31
|
-
server.close();
|
|
32
|
-
});
|
|
33
|
-
|
|
34
|
-
// On Linux, path.normalize() cannot escape '/' (the OS root), so '/../package.json'
|
|
35
|
-
// resolves to rootDir/package.json — which simply does not exist → 404.
|
|
36
|
-
// On Windows, backslash sequences can escape rootDir and the startsWith() check
|
|
37
|
-
// fires → 403. Both outcomes prove the traversal was blocked (no 200 with file content).
|
|
38
|
-
|
|
39
|
-
test('../ traversal is blocked (403 or 404, never 200 with file content)', async () => {
|
|
40
|
-
const res = await supertest(server).get('/../package.json');
|
|
41
|
-
expect([403, 404]).toContain(res.status);
|
|
42
|
-
expect(res.text).not.toContain('"name"');
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
test('URL-encoded ../ traversal (%2e%2e%2f) is blocked (403 or 404)', async () => {
|
|
46
|
-
const res = await supertest(server).get('/%2e%2e%2f%2e%2e%2fpackage.json');
|
|
47
|
-
expect([403, 404]).toContain(res.status);
|
|
48
|
-
expect(res.text).not.toContain('"name"');
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
test('multi-level traversal (/../../../etc/hosts) is blocked (403 or 404)', async () => {
|
|
52
|
-
const res = await supertest(server).get('/../../../etc/hosts');
|
|
53
|
-
expect([403, 404]).toContain(res.status);
|
|
54
|
-
});
|
|
55
|
-
|
|
56
|
-
test('null byte in path is rejected with 400', async () => {
|
|
57
|
-
// path.normalize() throws ERR_INVALID_ARG_VALUE for paths with \0;
|
|
58
|
-
// the null byte guard returns 400 before reaching fs operations.
|
|
59
|
-
const res = await supertest(server).get('/file%00.txt');
|
|
60
|
-
expect(res.status).toBe(400);
|
|
61
|
-
});
|
|
62
|
-
|
|
63
|
-
test('backslash sequences are not treated as path separators on Linux', async () => {
|
|
64
|
-
// On Linux, \\ is a literal filename character, not a path separator.
|
|
65
|
-
// path.normalize leaves it intact and the resolved path stays within rootDir.
|
|
66
|
-
// The file simply does not exist → 404 (not a traversal escape).
|
|
67
|
-
const res = await supertest(server).get('/..%5C..%5Cetc%5Chosts');
|
|
68
|
-
expect([403, 404]).toContain(res.status);
|
|
69
|
-
// On Windows, path.normalize converts \ to / and the traversal check catches it → 403.
|
|
70
|
-
});
|
|
71
|
-
});
|
|
72
|
-
|
|
73
|
-
// ─── Status Code 404 ─────────────────────────────────────────────────────────
|
|
74
|
-
|
|
75
|
-
describe('Bug Tests - Status Code 404', () => {
|
|
76
|
-
let app;
|
|
77
|
-
let server;
|
|
78
|
-
|
|
79
|
-
beforeAll(() => {
|
|
80
|
-
app = new Koa();
|
|
81
|
-
app.use(koaClassicServer(rootDir, {
|
|
82
|
-
dirListing: { enabled: true }
|
|
83
|
-
}));
|
|
84
|
-
server = app.listen();
|
|
85
|
-
});
|
|
86
|
-
|
|
87
|
-
test('FIXED: Non-existent file returns 404', async () => {
|
|
88
|
-
const res = await supertest(server).get('/file-che-non-esiste-xyz123.txt');
|
|
89
|
-
expect(res.status).toBe(404);
|
|
90
|
-
expect(res.text).toContain('Not Found');
|
|
91
|
-
});
|
|
92
|
-
|
|
93
|
-
test('FIXED: Directory with dirListing.enabled=false returns 404', async () => {
|
|
94
|
-
const app2 = new Koa();
|
|
95
|
-
app2.use(koaClassicServer(rootDir, {
|
|
96
|
-
dirListing: { enabled: false }
|
|
97
|
-
}));
|
|
98
|
-
const server2 = app2.listen();
|
|
99
|
-
|
|
100
|
-
const res = await supertest(server2).get('/');
|
|
101
|
-
expect(res.status).toBe(404);
|
|
102
|
-
|
|
103
|
-
server2.close();
|
|
104
|
-
});
|
|
105
|
-
|
|
106
|
-
afterAll(() => {
|
|
107
|
-
server.close();
|
|
108
|
-
});
|
|
109
|
-
});
|
|
110
|
-
|
|
111
|
-
// ─── Template Rendering Errors ────────────────────────────────────────────────
|
|
112
|
-
|
|
113
|
-
describe('Bug Tests - Template Rendering Errors', () => {
|
|
114
|
-
test('FIXED: Template render error returns 500 HTML page, server does not crash', async () => {
|
|
115
|
-
const app = new Koa();
|
|
116
|
-
|
|
117
|
-
const brokenRender = async (ctx, next, filePath) => {
|
|
118
|
-
throw new Error('Simulated template rendering error');
|
|
119
|
-
};
|
|
120
|
-
|
|
121
|
-
app.use(koaClassicServer(rootDir, {
|
|
122
|
-
template: {
|
|
123
|
-
render: brokenRender,
|
|
124
|
-
ext: ['txt']
|
|
125
|
-
}
|
|
126
|
-
}));
|
|
127
|
-
|
|
128
|
-
const server = app.listen();
|
|
129
|
-
const testFile = path.join(rootDir, 'test-template.txt');
|
|
130
|
-
fs.writeFileSync(testFile, 'test content');
|
|
131
|
-
|
|
132
|
-
try {
|
|
133
|
-
const res = await supertest(server).get('/test-template.txt');
|
|
134
|
-
|
|
135
|
-
expect(res.status).toBe(500);
|
|
136
|
-
expect(res.headers['content-type']).toMatch(/html/);
|
|
137
|
-
expect(res.text).toContain('Internal Server Error');
|
|
138
|
-
} finally {
|
|
139
|
-
if (fs.existsSync(testFile)) fs.unlinkSync(testFile);
|
|
140
|
-
server.close();
|
|
141
|
-
}
|
|
142
|
-
});
|
|
143
|
-
});
|
|
144
|
-
|
|
145
|
-
// ─── File Extension Extraction ────────────────────────────────────────────────
|
|
146
|
-
|
|
147
|
-
describe('Bug Tests - File Extension Extraction', () => {
|
|
148
|
-
let app;
|
|
149
|
-
let server;
|
|
150
|
-
|
|
151
|
-
beforeAll(() => {
|
|
152
|
-
app = new Koa();
|
|
153
|
-
|
|
154
|
-
const trackingRender = async (ctx, next, filePath) => {
|
|
155
|
-
ctx.body = 'Rendered: ' + path.basename(filePath);
|
|
156
|
-
};
|
|
157
|
-
|
|
158
|
-
app.use(koaClassicServer(rootDir, {
|
|
159
|
-
template: {
|
|
160
|
-
render: trackingRender,
|
|
161
|
-
ext: ['txt']
|
|
162
|
-
}
|
|
163
|
-
}));
|
|
164
|
-
|
|
165
|
-
server = app.listen();
|
|
166
|
-
});
|
|
167
|
-
|
|
168
|
-
afterAll(() => {
|
|
169
|
-
server.close();
|
|
170
|
-
});
|
|
171
|
-
|
|
172
|
-
test('FIXED: File without extension does not trigger template rendering', async () => {
|
|
173
|
-
const testFile = path.join(rootDir, 'README');
|
|
174
|
-
fs.writeFileSync(testFile, 'readme content');
|
|
175
|
-
|
|
176
|
-
try {
|
|
177
|
-
const res = await supertest(server).get('/README');
|
|
178
|
-
const responseBody = res.text !== undefined ? res.text : res.body.toString('utf8');
|
|
179
|
-
expect(responseBody).not.toContain('Rendered');
|
|
180
|
-
} finally {
|
|
181
|
-
if (fs.existsSync(testFile)) fs.unlinkSync(testFile);
|
|
182
|
-
}
|
|
183
|
-
});
|
|
184
|
-
|
|
185
|
-
test('Unix hidden file (.gitignore) is served as a regular file, not rendered', async () => {
|
|
186
|
-
// dotFiles are hidden by default; make them visible for this test so we can
|
|
187
|
-
// verify that the extension check (not the template renderer) handles the file.
|
|
188
|
-
const appVisible = new Koa();
|
|
189
|
-
appVisible.use(koaClassicServer(rootDir, {
|
|
190
|
-
hidden: { dotFiles: { default: 'visible' } },
|
|
191
|
-
template: {
|
|
192
|
-
render: async (ctx, next, filePath) => { ctx.body = 'Rendered: ' + path.basename(filePath); },
|
|
193
|
-
ext: ['txt']
|
|
194
|
-
}
|
|
195
|
-
}));
|
|
196
|
-
const serverVisible = appVisible.listen();
|
|
197
|
-
|
|
198
|
-
const testFile = path.join(rootDir, '.gitignore');
|
|
199
|
-
fs.writeFileSync(testFile, 'node_modules/');
|
|
200
|
-
|
|
201
|
-
try {
|
|
202
|
-
const res = await supertest(serverVisible).get('/.gitignore');
|
|
203
|
-
// .gitignore has no .txt extension — template must not be invoked
|
|
204
|
-
expect(res.status).toBe(200);
|
|
205
|
-
const responseBody = res.text !== undefined ? res.text : res.body.toString('utf8');
|
|
206
|
-
expect(responseBody).not.toContain('Rendered');
|
|
207
|
-
expect(responseBody).toContain('node_modules/');
|
|
208
|
-
} finally {
|
|
209
|
-
if (fs.existsSync(testFile)) fs.unlinkSync(testFile);
|
|
210
|
-
serverVisible.close();
|
|
211
|
-
}
|
|
212
|
-
});
|
|
213
|
-
});
|
|
214
|
-
|
|
215
|
-
// ─── Race Condition File Access ───────────────────────────────────────────────
|
|
216
|
-
//
|
|
217
|
-
// BEHAVIOUR GUARANTEE (not tested — timing is non-deterministic):
|
|
218
|
-
// If a file is deleted between the access check and the stream open,
|
|
219
|
-
// the stream error handler fires and — if headers have not been sent yet —
|
|
220
|
-
// the server returns 500. When rawFile cache is warm the race cannot occur
|
|
221
|
-
// because the file is served entirely from memory.
|
|
222
|
-
//
|
|
223
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
224
|
-
|
|
225
|
-
// ─── Directory Read Errors ────────────────────────────────────────────────────
|
|
226
|
-
|
|
227
|
-
describe('Bug Tests - Directory Read Errors', () => {
|
|
228
|
-
test('FIXED: Unreadable directory returns 500, server does not crash', async () => {
|
|
229
|
-
// Skip on Windows (chmod has no effect) and when running as root
|
|
230
|
-
// (root ignores permission bits, so chmod 0o000 has no effect).
|
|
231
|
-
if (process.platform === 'win32') return;
|
|
232
|
-
if (typeof process.getuid === 'function' && process.getuid() === 0) return;
|
|
233
|
-
|
|
234
|
-
const app = new Koa();
|
|
235
|
-
const tempDir = path.join(rootDir, 'temp-perm-test-dir');
|
|
236
|
-
if (!fs.existsSync(tempDir)) fs.mkdirSync(tempDir);
|
|
237
|
-
|
|
238
|
-
app.use(koaClassicServer(rootDir, { dirListing: { enabled: true } }));
|
|
239
|
-
const server = app.listen();
|
|
240
|
-
|
|
241
|
-
try {
|
|
242
|
-
const res1 = await supertest(server).get('/temp-perm-test-dir');
|
|
243
|
-
expect(res1.status).toBe(200);
|
|
244
|
-
|
|
245
|
-
fs.chmodSync(tempDir, 0o000);
|
|
246
|
-
const res2 = await supertest(server).get('/temp-perm-test-dir');
|
|
247
|
-
expect([403, 500]).toContain(res2.status);
|
|
248
|
-
} finally {
|
|
249
|
-
try { fs.chmodSync(tempDir, 0o755); } catch { /* ignore */ }
|
|
250
|
-
if (fs.existsSync(tempDir)) fs.rmdirSync(tempDir);
|
|
251
|
-
server.close();
|
|
252
|
-
}
|
|
253
|
-
});
|
|
254
|
-
});
|
|
255
|
-
|
|
256
|
-
// ─── Content-Disposition ──────────────────────────────────────────────────────
|
|
257
|
-
|
|
258
|
-
describe('Bug Tests - Content-Disposition', () => {
|
|
259
|
-
let app;
|
|
260
|
-
let server;
|
|
261
|
-
|
|
262
|
-
beforeAll(() => {
|
|
263
|
-
app = new Koa();
|
|
264
|
-
app.use(koaClassicServer(rootDir));
|
|
265
|
-
server = app.listen();
|
|
266
|
-
});
|
|
267
|
-
|
|
268
|
-
afterAll(() => {
|
|
269
|
-
server.close();
|
|
270
|
-
});
|
|
271
|
-
|
|
272
|
-
test('FIXED: Filename with spaces is quoted in Content-Disposition', async () => {
|
|
273
|
-
const testFile = path.join(rootDir, 'file with spaces.txt');
|
|
274
|
-
fs.writeFileSync(testFile, 'test content');
|
|
275
|
-
|
|
276
|
-
try {
|
|
277
|
-
const res = await supertest(server).get('/file%20with%20spaces.txt');
|
|
278
|
-
const contentDisp = res.headers['content-disposition'];
|
|
279
|
-
// quoted-string form must wrap the filename in double quotes
|
|
280
|
-
expect(contentDisp).toMatch(/filename="file with spaces\.txt"/);
|
|
281
|
-
} finally {
|
|
282
|
-
if (fs.existsSync(testFile)) fs.unlinkSync(testFile);
|
|
283
|
-
}
|
|
284
|
-
});
|
|
285
|
-
|
|
286
|
-
test('FIXED: Filename with special chars has RFC 5987 extended form', async () => {
|
|
287
|
-
const testFile = path.join(rootDir, 'file with spaces & special.txt');
|
|
288
|
-
fs.writeFileSync(testFile, 'test content');
|
|
289
|
-
|
|
290
|
-
try {
|
|
291
|
-
const res = await supertest(server).get('/file%20with%20spaces%20%26%20special.txt');
|
|
292
|
-
const contentDisp = res.headers['content-disposition'];
|
|
293
|
-
// RFC 5987 extended form must be present with UTF-8 encoding prefix
|
|
294
|
-
expect(contentDisp).toMatch(/filename\*=UTF-8''/);
|
|
295
|
-
// The & must be percent-encoded as %26 in the extended form
|
|
296
|
-
expect(contentDisp).toContain('%26');
|
|
297
|
-
} finally {
|
|
298
|
-
if (fs.existsSync(testFile)) fs.unlinkSync(testFile);
|
|
299
|
-
}
|
|
300
|
-
});
|
|
301
|
-
|
|
302
|
-
test('FIXED: Filename with double-quote is safely escaped', async () => {
|
|
303
|
-
// Create file with a double-quote in its name (valid on Linux)
|
|
304
|
-
let testFile;
|
|
305
|
-
try {
|
|
306
|
-
testFile = path.join(rootDir, 'file"name.txt');
|
|
307
|
-
fs.writeFileSync(testFile, 'test');
|
|
308
|
-
} catch {
|
|
309
|
-
// Some filesystems disallow " in filenames — skip gracefully
|
|
310
|
-
return;
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
try {
|
|
314
|
-
const res = await supertest(server).get('/file%22name.txt');
|
|
315
|
-
const contentDisp = res.headers['content-disposition'];
|
|
316
|
-
// The " inside the quoted-string must be escaped as \"
|
|
317
|
-
expect(contentDisp).toMatch(/filename="file\\"name\.txt"/);
|
|
318
|
-
} finally {
|
|
319
|
-
if (fs.existsSync(testFile)) fs.unlinkSync(testFile);
|
|
320
|
-
}
|
|
321
|
-
});
|
|
322
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|