koa-classic-server 3.0.1 → 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.
Files changed (106) hide show
  1. package/README.md +44 -120
  2. package/index.cjs +200 -21
  3. package/package.json +10 -5
  4. package/.github/workflows/npm-publish.yml +0 -98
  5. package/CLAUDE.md +0 -101
  6. package/__tests__/benchmark-results-baseline-v1.2.0.txt +0 -354
  7. package/__tests__/benchmark-results-optimized-v2.0.0.txt +0 -354
  8. package/__tests__/benchmark-results-v3.0.0.txt +0 -372
  9. package/__tests__/benchmark.js +0 -239
  10. package/__tests__/caching-headers.test.js +0 -556
  11. package/__tests__/compression-fixtures/data.json +0 -1
  12. package/__tests__/compression-fixtures/large.txt +0 -1
  13. package/__tests__/compression-fixtures/small.txt +0 -1
  14. package/__tests__/compression.test.js +0 -284
  15. package/__tests__/customTest/README.md +0 -6
  16. package/__tests__/customTest/loadConfig.util.js +0 -41
  17. package/__tests__/customTest/serversToLoad.util.js +0 -93
  18. package/__tests__/demo-regex-index.js +0 -140
  19. package/__tests__/deprecation-warnings.test.js +0 -105
  20. package/__tests__/directory-sorting-links.test.js +0 -135
  21. package/__tests__/dt-unknown.test.js +0 -635
  22. package/__tests__/ejs.test.js +0 -299
  23. package/__tests__/head-method.test.js +0 -160
  24. package/__tests__/hidden-fixtures/.dot-dir/inside.txt +0 -1
  25. package/__tests__/hidden-fixtures/.env +0 -2
  26. package/__tests__/hidden-fixtures/.well-known/acme-challenge.txt +0 -1
  27. package/__tests__/hidden-fixtures/config/secrets/password.txt +0 -1
  28. package/__tests__/hidden-fixtures/data.key +0 -1
  29. package/__tests__/hidden-fixtures/file.secret +0 -1
  30. package/__tests__/hidden-fixtures/index.html +0 -1
  31. package/__tests__/hidden-fixtures/normal.txt +0 -1
  32. package/__tests__/hidden-fixtures/subdir/.env +0 -1
  33. package/__tests__/hidden-fixtures/subdir/regular.txt +0 -1
  34. package/__tests__/hidden-option.test.js +0 -407
  35. package/__tests__/hideExtension.test.js +0 -607
  36. package/__tests__/index-option.test.js +0 -449
  37. package/__tests__/index.test.js +0 -345
  38. package/__tests__/listing.test.js +0 -437
  39. package/__tests__/logger.test.js +0 -232
  40. package/__tests__/performance.test.js +0 -370
  41. package/__tests__/publicWwwTest/cartella/sottocartella/ciao.html +0 -11
  42. package/__tests__/publicWwwTest/cartella/sottocartella/provaEjs/testEjs.ejs +0 -11
  43. package/__tests__/publicWwwTest/cartella vuota con spazi nel nome/file con spazio nel nome .txt +0 -1
  44. package/__tests__/publicWwwTest/cartella vuota con spazi nel nome /file con spazio nel nome .txt +0 -1
  45. package/__tests__/publicWwwTest/ejs-templates/complex.ejs +0 -56
  46. package/__tests__/publicWwwTest/ejs-templates/index.ejs +0 -30
  47. package/__tests__/publicWwwTest/ejs-templates/simple.ejs +0 -13
  48. package/__tests__/publicWwwTest/ejs-templates/with-conditional.ejs +0 -28
  49. package/__tests__/publicWwwTest/ejs-templates/with-escaping.ejs +0 -26
  50. package/__tests__/publicWwwTest/ejs-templates/with-loop.ejs +0 -16
  51. package/__tests__/publicWwwTest/hideext-test/about/index.html +0 -1
  52. package/__tests__/publicWwwTest/hideext-test/about.EJS +0 -1
  53. package/__tests__/publicWwwTest/hideext-test/about.ejs +0 -2
  54. package/__tests__/publicWwwTest/hideext-test/blog/articolo.ejs +0 -2
  55. package/__tests__/publicWwwTest/hideext-test/conflict-test/pagina +0 -1
  56. package/__tests__/publicWwwTest/hideext-test/conflict-test/pagina.ejs +0 -1
  57. package/__tests__/publicWwwTest/hideext-test/file.ejs.bak +0 -1
  58. package/__tests__/publicWwwTest/hideext-test/index.ejs +0 -2
  59. package/__tests__/publicWwwTest/hideext-test/photo.txt +0 -1
  60. package/__tests__/publicWwwTest/hideext-test/sezione/index.ejs +0 -1
  61. package/__tests__/publicWwwTest/hideext-test/style.css +0 -1
  62. package/__tests__/publicWwwTest/ile_vuoto.txt +0 -0
  63. package/__tests__/publicWwwTest/index.html +0 -11
  64. package/__tests__/publicWwwTest/prova file .txt +0 -2
  65. package/__tests__/publicWwwTest/semplicetxt.txt +0 -1
  66. package/__tests__/publicWwwTest/test-page.html +0 -1
  67. package/__tests__/publicWwwTest/test.txt +0 -1
  68. package/__tests__/range-fixtures/sample.txt +0 -1
  69. package/__tests__/range.test.js +0 -223
  70. package/__tests__/security-headers.test.js +0 -165
  71. package/__tests__/security.test.js +0 -322
  72. package/__tests__/server-cache-fixtures/large.txt +0 -1
  73. package/__tests__/server-cache-fixtures/small.txt +0 -1
  74. package/__tests__/server-cache.test.js +0 -594
  75. package/__tests__/setup-benchmark.js +0 -178
  76. package/__tests__/symlink.test.js +0 -441
  77. package/__tests__/template-timeout.test.js +0 -321
  78. package/__tests__/test-regex-quick.js +0 -158
  79. package/__tests__/useOriginalUrl.test.js +0 -213
  80. package/docs/ACTION_PLAN.md +0 -293
  81. package/docs/BENCHMARKS.md +0 -317
  82. package/docs/CHANGELOG.md +0 -906
  83. package/docs/CODE_REVIEW.md +0 -300
  84. package/docs/DEBUG_REPORT.md +0 -593
  85. package/docs/DOCUMENTATION.md +0 -1864
  86. package/docs/EXAMPLES_INDEX_OPTION.md +0 -395
  87. package/docs/FLOW_DIAGRAM.md +0 -954
  88. package/docs/INDEX_OPTION_PRIORITY.md +0 -527
  89. package/docs/OPTIMIZATION_HTTP_CACHING.md +0 -689
  90. package/docs/OPTIMIZATION_ROADMAP_for_V3.md +0 -864
  91. package/docs/PERFORMANCE_ANALYSIS.md +0 -839
  92. package/docs/PERFORMANCE_COMPARISON.md +0 -388
  93. package/docs/noteExports.md +0 -148
  94. package/docs/security_improvement_for_V3.md +0 -421
  95. package/docs/template-engine/TEMPLATE_ENGINE_GUIDE.md +0 -1734
  96. package/docs/template-engine/esempi-incrementali.js +0 -192
  97. package/docs/template-engine/examples/esempio1-nessun-dato.ejs +0 -12
  98. package/docs/template-engine/examples/esempio2-una-variabile.ejs +0 -11
  99. package/docs/template-engine/examples/esempio3-piu-variabili.ejs +0 -15
  100. package/docs/template-engine/examples/esempio4-condizionale.ejs +0 -18
  101. package/docs/template-engine/examples/esempio5-loop.ejs +0 -18
  102. package/docs/template-engine/examples/index-esempi.html +0 -181
  103. package/docs/template-engine/examples/index.html +0 -40
  104. package/docs/template-engine/examples/test.ejs +0 -64
  105. package/eslint.config.mjs +0 -17
  106. package/jest.config.js +0 -18
@@ -1,556 +0,0 @@
1
- /**
2
- * HTTP Caching Headers Test
3
- *
4
- * Tests to verify correct caching behavior:
5
- * - When browserCacheEnabled: true -> proper cache headers
6
- * - When browserCacheEnabled: false -> anti-cache headers
7
- */
8
-
9
- const Koa = require('koa');
10
- const supertest = require('supertest');
11
- const koaClassicServer = require('../index.cjs');
12
- const path = require('path');
13
- const fs = require('fs');
14
-
15
- const TEST_DIR = path.join(__dirname, 'test-caching-headers');
16
-
17
- describe('HTTP Caching Headers', () => {
18
- beforeAll(() => {
19
- // Create test directory and file
20
- if (!fs.existsSync(TEST_DIR)) {
21
- fs.mkdirSync(TEST_DIR, { recursive: true });
22
- }
23
- fs.writeFileSync(path.join(TEST_DIR, 'test.txt'), 'Test content for caching');
24
- });
25
-
26
- afterAll(() => {
27
- // Cleanup
28
- if (fs.existsSync(TEST_DIR)) {
29
- fs.rmSync(TEST_DIR, { recursive: true, force: true });
30
- }
31
- });
32
-
33
- describe('When caching is DISABLED (browserCacheEnabled: false)', () => {
34
- let app;
35
- let server;
36
- let request;
37
-
38
- beforeAll(() => {
39
- app = new Koa();
40
- app.use(koaClassicServer(TEST_DIR, {
41
- browserCacheEnabled: false
42
- }));
43
- server = app.listen();
44
- request = supertest(server);
45
- });
46
-
47
- afterAll(() => {
48
- server.close();
49
- });
50
-
51
- test('Should return anti-cache headers', async () => {
52
- const res = await request.get('/test.txt');
53
-
54
- expect(res.status).toBe(200);
55
-
56
- // Verify anti-cache headers are present
57
- expect(res.headers['cache-control']).toBe('no-cache, no-store, must-revalidate');
58
- expect(res.headers['pragma']).toBe('no-cache');
59
- expect(res.headers['expires']).toBe('0');
60
-
61
- // Verify caching headers are NOT present
62
- expect(res.headers['etag']).toBeUndefined();
63
- expect(res.headers['last-modified']).toBeUndefined();
64
- });
65
-
66
- test('Should NOT return 304 even with If-None-Match header', async () => {
67
- // First request to get potential ETag (should not exist)
68
- const res1 = await request.get('/test.txt');
69
- expect(res1.status).toBe(200);
70
-
71
- // Second request with If-None-Match (should still return 200)
72
- const res2 = await request
73
- .get('/test.txt')
74
- .set('If-None-Match', '"fake-etag"');
75
-
76
- expect(res2.status).toBe(200);
77
- expect(res2.text).toBe('Test content for caching');
78
- });
79
-
80
- test('Should NOT return 304 even with If-Modified-Since header', async () => {
81
- const futureDate = new Date(Date.now() + 86400000).toUTCString();
82
-
83
- const res = await request
84
- .get('/test.txt')
85
- .set('If-Modified-Since', futureDate);
86
-
87
- expect(res.status).toBe(200);
88
- expect(res.text).toBe('Test content for caching');
89
- });
90
- });
91
-
92
- describe('When caching is ENABLED (browserCacheEnabled: true)', () => {
93
- let app;
94
- let server;
95
- let request;
96
-
97
- beforeAll(() => {
98
- app = new Koa();
99
- app.use(koaClassicServer(TEST_DIR, {
100
- browserCacheEnabled: true,
101
- browserCacheMaxAge: 3600
102
- }));
103
- server = app.listen();
104
- request = supertest(server);
105
- });
106
-
107
- afterAll(() => {
108
- server.close();
109
- });
110
-
111
- test('Should return proper cache headers', async () => {
112
- const res = await request.get('/test.txt');
113
-
114
- expect(res.status).toBe(200);
115
-
116
- // Verify cache headers are present
117
- expect(res.headers['cache-control']).toBe('public, max-age=3600, must-revalidate');
118
- expect(res.headers['etag']).toBeDefined();
119
- expect(res.headers['last-modified']).toBeDefined();
120
-
121
- // Verify anti-cache headers are NOT present
122
- expect(res.headers['pragma']).toBeUndefined();
123
- expect(res.headers['expires']).not.toBe('0');
124
- });
125
-
126
- test('Should return 304 with matching ETag', async () => {
127
- // First request to get ETag
128
- const res1 = await request.get('/test.txt');
129
- expect(res1.status).toBe(200);
130
- const etag = res1.headers['etag'];
131
- expect(etag).toBeDefined();
132
-
133
- // Second request with If-None-Match
134
- const res2 = await request
135
- .get('/test.txt')
136
- .set('If-None-Match', etag);
137
-
138
- expect(res2.status).toBe(304);
139
- expect(res2.text).toBe('');
140
- });
141
-
142
- test('Should return 304 with If-Modified-Since (not modified)', async () => {
143
- // Get file stats and add 1 second to ensure it's after file mtime
144
- const stats = fs.statSync(path.join(TEST_DIR, 'test.txt'));
145
- const futureDate = new Date(stats.mtime.getTime() + 1000).toUTCString();
146
-
147
- // Request with If-Modified-Since header (1 second in future)
148
- const res = await request
149
- .get('/test.txt')
150
- .set('If-Modified-Since', futureDate);
151
-
152
- expect(res.status).toBe(304);
153
- expect(res.text).toBe('');
154
- });
155
-
156
- test('Should return 200 with If-Modified-Since (file modified)', async () => {
157
- // Use a date in the past
158
- const pastDate = new Date(Date.now() - 86400000).toUTCString();
159
-
160
- const res = await request
161
- .get('/test.txt')
162
- .set('If-Modified-Since', pastDate);
163
-
164
- expect(res.status).toBe(200);
165
- expect(res.text).toBe('Test content for caching');
166
- });
167
- });
168
-
169
- describe('Default behavior (caching disabled by default)', () => {
170
- let app;
171
- let server;
172
- let request;
173
-
174
- beforeAll(() => {
175
- app = new Koa();
176
- // No options provided - should default to browserCacheEnabled: false
177
- app.use(koaClassicServer(TEST_DIR));
178
- server = app.listen();
179
- request = supertest(server);
180
- });
181
-
182
- afterAll(() => {
183
- server.close();
184
- });
185
-
186
- test('Should have anti-cache headers by default', async () => {
187
- const res = await request.get('/test.txt');
188
-
189
- expect(res.status).toBe(200);
190
- expect(res.headers['cache-control']).toBe('no-cache, no-store, must-revalidate');
191
- expect(res.headers['pragma']).toBe('no-cache');
192
- expect(res.headers['expires']).toBe('0');
193
- });
194
- });
195
-
196
- describe('Custom browserCacheMaxAge values', () => {
197
- test('Should respect custom browserCacheMaxAge: 7200', async () => {
198
- const app = new Koa();
199
- app.use(koaClassicServer(TEST_DIR, {
200
- browserCacheEnabled: true,
201
- browserCacheMaxAge: 7200
202
- }));
203
- const server = app.listen();
204
- const request = supertest(server);
205
-
206
- const res = await request.get('/test.txt');
207
-
208
- expect(res.status).toBe(200);
209
- expect(res.headers['cache-control']).toBe('public, max-age=7200, must-revalidate');
210
-
211
- server.close();
212
- });
213
-
214
- test('Should respect custom browserCacheMaxAge: 0 (no browser cache)', async () => {
215
- const app = new Koa();
216
- app.use(koaClassicServer(TEST_DIR, {
217
- browserCacheEnabled: true,
218
- browserCacheMaxAge: 0
219
- }));
220
- const server = app.listen();
221
- const request = supertest(server);
222
-
223
- const res = await request.get('/test.txt');
224
-
225
- expect(res.status).toBe(200);
226
- expect(res.headers['cache-control']).toBe('public, max-age=0, must-revalidate');
227
- // Should still have ETag for validation
228
- expect(res.headers['etag']).toBeDefined();
229
-
230
- server.close();
231
- });
232
-
233
- test('Should respect custom browserCacheMaxAge: 86400 (1 day)', async () => {
234
- const app = new Koa();
235
- app.use(koaClassicServer(TEST_DIR, {
236
- browserCacheEnabled: true,
237
- browserCacheMaxAge: 86400
238
- }));
239
- const server = app.listen();
240
- const request = supertest(server);
241
-
242
- const res = await request.get('/test.txt');
243
-
244
- expect(res.status).toBe(200);
245
- expect(res.headers['cache-control']).toBe('public, max-age=86400, must-revalidate');
246
-
247
- server.close();
248
- });
249
- });
250
-
251
- describe('ETag generation and validation', () => {
252
- test('ETag should change when file is modified', async () => {
253
- const testFile = path.join(TEST_DIR, 'dynamic-test.txt');
254
- fs.writeFileSync(testFile, 'Original content');
255
-
256
- const app = new Koa();
257
- app.use(koaClassicServer(TEST_DIR, {
258
- browserCacheEnabled: true
259
- }));
260
- const server = app.listen();
261
- const request = supertest(server);
262
-
263
- // First request
264
- const res1 = await request.get('/dynamic-test.txt');
265
- expect(res1.status).toBe(200);
266
- const etag1 = res1.headers['etag'];
267
- expect(etag1).toBeDefined();
268
-
269
- // Wait 10ms to ensure different mtime
270
- await new Promise(resolve => setTimeout(resolve, 10));
271
-
272
- // Modify file
273
- fs.writeFileSync(testFile, 'Modified content - different');
274
-
275
- // Second request - ETag should be different
276
- const res2 = await request.get('/dynamic-test.txt');
277
- expect(res2.status).toBe(200);
278
- const etag2 = res2.headers['etag'];
279
- expect(etag2).toBeDefined();
280
- expect(etag2).not.toBe(etag1);
281
-
282
- // Cleanup
283
- fs.unlinkSync(testFile);
284
- server.close();
285
- });
286
-
287
- test('ETag should change when file size changes', async () => {
288
- const testFile = path.join(TEST_DIR, 'size-test.txt');
289
- fs.writeFileSync(testFile, 'Short');
290
-
291
- const app = new Koa();
292
- app.use(koaClassicServer(TEST_DIR, {
293
- browserCacheEnabled: true
294
- }));
295
- const server = app.listen();
296
- const request = supertest(server);
297
-
298
- // First request
299
- const res1 = await request.get('/size-test.txt');
300
- const etag1 = res1.headers['etag'];
301
-
302
- // Wait and change file size
303
- await new Promise(resolve => setTimeout(resolve, 10));
304
- fs.writeFileSync(testFile, 'Much longer content here');
305
-
306
- // Second request
307
- const res2 = await request.get('/size-test.txt');
308
- const etag2 = res2.headers['etag'];
309
-
310
- expect(etag2).not.toBe(etag1);
311
-
312
- fs.unlinkSync(testFile);
313
- server.close();
314
- });
315
- });
316
-
317
- describe('Bandwidth savings with 304 responses', () => {
318
- test('304 response should have no body', async () => {
319
- const app = new Koa();
320
- app.use(koaClassicServer(TEST_DIR, {
321
- browserCacheEnabled: true
322
- }));
323
- const server = app.listen();
324
- const request = supertest(server);
325
-
326
- // First request
327
- const res1 = await request.get('/test.txt');
328
- expect(res1.status).toBe(200);
329
- expect(res1.text).toBe('Test content for caching');
330
- const bodySize1 = res1.text.length;
331
-
332
- // Second request with ETag
333
- const res2 = await request
334
- .get('/test.txt')
335
- .set('If-None-Match', res1.headers['etag']);
336
-
337
- expect(res2.status).toBe(304);
338
- expect(res2.text).toBe('');
339
- expect(res2.text.length).toBe(0);
340
-
341
- // Verify bandwidth saving
342
- expect(bodySize1).toBeGreaterThan(0);
343
- expect(res2.text.length).toBe(0);
344
-
345
- server.close();
346
- });
347
-
348
- test('Should save bandwidth on multiple 304 responses', async () => {
349
- const app = new Koa();
350
- app.use(koaClassicServer(TEST_DIR, {
351
- browserCacheEnabled: true
352
- }));
353
- const server = app.listen();
354
- const request = supertest(server);
355
-
356
- // First request
357
- const res1 = await request.get('/test.txt');
358
- const etag = res1.headers['etag'];
359
- const originalSize = res1.text.length;
360
-
361
- // Make 10 cached requests
362
- let totalBytesSaved = 0;
363
- for (let i = 0; i < 10; i++) {
364
- const res = await request
365
- .get('/test.txt')
366
- .set('If-None-Match', etag);
367
-
368
- expect(res.status).toBe(304);
369
- totalBytesSaved += originalSize;
370
- }
371
-
372
- expect(totalBytesSaved).toBeGreaterThan(0);
373
-
374
- server.close();
375
- });
376
- });
377
-
378
- describe('Caching with different MIME types', () => {
379
- beforeAll(() => {
380
- // Create files with different types
381
- fs.writeFileSync(path.join(TEST_DIR, 'test.html'), '<html><body>Test</body></html>');
382
- fs.writeFileSync(path.join(TEST_DIR, 'test.json'), '{"test": "data"}');
383
- fs.writeFileSync(path.join(TEST_DIR, 'test.css'), 'body { color: red; }');
384
- fs.writeFileSync(path.join(TEST_DIR, 'test.js'), 'console.log("test");');
385
- });
386
-
387
- afterAll(() => {
388
- fs.unlinkSync(path.join(TEST_DIR, 'test.html'));
389
- fs.unlinkSync(path.join(TEST_DIR, 'test.json'));
390
- fs.unlinkSync(path.join(TEST_DIR, 'test.css'));
391
- fs.unlinkSync(path.join(TEST_DIR, 'test.js'));
392
- });
393
-
394
- test('HTML files should have cache headers', async () => {
395
- const app = new Koa();
396
- app.use(koaClassicServer(TEST_DIR, {
397
- browserCacheEnabled: true
398
- }));
399
- const server = app.listen();
400
- const request = supertest(server);
401
-
402
- const res = await request.get('/test.html');
403
- expect(res.status).toBe(200);
404
- expect(res.headers['etag']).toBeDefined();
405
- expect(res.headers['cache-control']).toContain('public');
406
- expect(res.headers['content-type']).toContain('text/html');
407
-
408
- server.close();
409
- });
410
-
411
- test('JSON files should have cache headers', async () => {
412
- const app = new Koa();
413
- app.use(koaClassicServer(TEST_DIR, {
414
- browserCacheEnabled: true
415
- }));
416
- const server = app.listen();
417
- const request = supertest(server);
418
-
419
- const res = await request.get('/test.json');
420
- expect(res.status).toBe(200);
421
- expect(res.headers['etag']).toBeDefined();
422
- expect(res.headers['content-type']).toContain('application/json');
423
-
424
- server.close();
425
- });
426
-
427
- test('CSS files should have cache headers', async () => {
428
- const app = new Koa();
429
- app.use(koaClassicServer(TEST_DIR, {
430
- browserCacheEnabled: true
431
- }));
432
- const server = app.listen();
433
- const request = supertest(server);
434
-
435
- const res = await request.get('/test.css');
436
- expect(res.status).toBe(200);
437
- expect(res.headers['etag']).toBeDefined();
438
- expect(res.headers['content-type']).toContain('text/css');
439
-
440
- server.close();
441
- });
442
-
443
- test('JavaScript files should have cache headers', async () => {
444
- const app = new Koa();
445
- app.use(koaClassicServer(TEST_DIR, {
446
- browserCacheEnabled: true
447
- }));
448
- const server = app.listen();
449
- const request = supertest(server);
450
-
451
- const res = await request.get('/test.js');
452
- expect(res.status).toBe(200);
453
- expect(res.headers['etag']).toBeDefined();
454
- expect(res.headers['content-type']).toContain('javascript');
455
-
456
- server.close();
457
- });
458
- });
459
-
460
- describe('Caching does not interfere with template rendering', () => {
461
- test('Template files should not get cache headers during rendering', async () => {
462
- const testFile = path.join(TEST_DIR, 'test-template.ejs');
463
- fs.writeFileSync(testFile, '<html><body><%= name %></body></html>');
464
-
465
- let renderCalled = false;
466
-
467
- const app = new Koa();
468
- app.use(koaClassicServer(TEST_DIR, {
469
- browserCacheEnabled: true,
470
- browserCacheMaxAge: 3600,
471
- template: {
472
- ext: ['ejs'],
473
- render: async (ctx, next, filePath) => {
474
- renderCalled = true;
475
- ctx.body = '<html><body>Rendered</body></html>';
476
- ctx.type = 'text/html';
477
- }
478
- }
479
- }));
480
- const server = app.listen();
481
- const request = supertest(server);
482
-
483
- const res = await request.get('/test-template.ejs');
484
-
485
- expect(res.status).toBe(200);
486
- expect(renderCalled).toBe(true);
487
- expect(res.text).toBe('<html><body>Rendered</body></html>');
488
-
489
- // Template rendering happens before caching logic,
490
- // so cache headers should not be added by koaClassicServer
491
- // (the template renderer controls caching)
492
-
493
- fs.unlinkSync(testFile);
494
- server.close();
495
- });
496
- });
497
-
498
- describe('Concurrent requests with caching', () => {
499
- test('Multiple concurrent requests should handle caching correctly', async () => {
500
- const app = new Koa();
501
- app.use(koaClassicServer(TEST_DIR, {
502
- browserCacheEnabled: true
503
- }));
504
- const server = app.listen();
505
- const request = supertest(server);
506
-
507
- // Make 5 concurrent requests
508
- const promises = Array.from({ length: 5 }, () =>
509
- request.get('/test.txt')
510
- );
511
-
512
- const results = await Promise.all(promises);
513
-
514
- // All should succeed
515
- results.forEach(res => {
516
- expect(res.status).toBe(200);
517
- expect(res.headers['etag']).toBeDefined();
518
- });
519
-
520
- // All ETags should be identical (same file)
521
- const etags = results.map(r => r.headers['etag']);
522
- const uniqueEtags = new Set(etags);
523
- expect(uniqueEtags.size).toBe(1);
524
-
525
- server.close();
526
- });
527
-
528
- test('Concurrent 304 responses should work correctly', async () => {
529
- const app = new Koa();
530
- app.use(koaClassicServer(TEST_DIR, {
531
- browserCacheEnabled: true
532
- }));
533
- const server = app.listen();
534
- const request = supertest(server);
535
-
536
- // First request to get ETag
537
- const initial = await request.get('/test.txt');
538
- const etag = initial.headers['etag'];
539
-
540
- // Make 5 concurrent cached requests
541
- const promises = Array.from({ length: 5 }, () =>
542
- request.get('/test.txt').set('If-None-Match', etag)
543
- );
544
-
545
- const results = await Promise.all(promises);
546
-
547
- // All should return 304
548
- results.forEach(res => {
549
- expect(res.status).toBe(304);
550
- expect(res.text).toBe('');
551
- });
552
-
553
- server.close();
554
- });
555
- });
556
- });
@@ -1 +0,0 @@
1
- {"key":"value"}
@@ -1 +0,0 @@
1
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
@@ -1 +0,0 @@
1
- tiny