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
package/__tests__/ejs.test.js
DELETED
|
@@ -1,299 +0,0 @@
|
|
|
1
|
-
const Koa = require('koa');
|
|
2
|
-
const koaClassicServer = require('../index.cjs');
|
|
3
|
-
const supertest = require('supertest');
|
|
4
|
-
const path = require('path');
|
|
5
|
-
const fs = require('fs');
|
|
6
|
-
const ejs = require('ejs');
|
|
7
|
-
|
|
8
|
-
describe('EJS Template Engine Integration Tests', () => {
|
|
9
|
-
let app;
|
|
10
|
-
let server;
|
|
11
|
-
let request;
|
|
12
|
-
|
|
13
|
-
beforeAll(() => {
|
|
14
|
-
app = new Koa();
|
|
15
|
-
|
|
16
|
-
const rootDir = path.join(__dirname, 'publicWwwTest');
|
|
17
|
-
|
|
18
|
-
// Configure koaClassicServer with EJS template support
|
|
19
|
-
app.use(
|
|
20
|
-
koaClassicServer(rootDir, {
|
|
21
|
-
method: ['GET'],
|
|
22
|
-
dirListing: { enabled: true },
|
|
23
|
-
template: {
|
|
24
|
-
ext: ['ejs'],
|
|
25
|
-
render: async (ctx, next, filePath) => {
|
|
26
|
-
// Read the template file
|
|
27
|
-
const templateContent = await fs.promises.readFile(filePath, 'utf-8');
|
|
28
|
-
|
|
29
|
-
// Prepare data for different templates
|
|
30
|
-
const data = getTemplateData(filePath);
|
|
31
|
-
|
|
32
|
-
// Render with EJS
|
|
33
|
-
const html = ejs.render(templateContent, data);
|
|
34
|
-
|
|
35
|
-
ctx.type = 'text/html';
|
|
36
|
-
ctx.body = html;
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
})
|
|
40
|
-
);
|
|
41
|
-
|
|
42
|
-
server = app.listen();
|
|
43
|
-
request = supertest(server);
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
afterAll(() => {
|
|
47
|
-
if (server) {
|
|
48
|
-
server.close();
|
|
49
|
-
}
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
// Helper function to provide data for each template
|
|
53
|
-
function getTemplateData(filePath) {
|
|
54
|
-
const basename = path.basename(filePath, '.ejs');
|
|
55
|
-
|
|
56
|
-
const dataMap = {
|
|
57
|
-
'simple': {
|
|
58
|
-
title: 'Simple EJS Test',
|
|
59
|
-
heading: 'Hello from EJS',
|
|
60
|
-
message: 'This is a simple template test',
|
|
61
|
-
timestamp: '2025-11-18'
|
|
62
|
-
},
|
|
63
|
-
'with-loop': {
|
|
64
|
-
items: [
|
|
65
|
-
{ name: 'Item 1', value: 100 },
|
|
66
|
-
{ name: 'Item 2', value: 200 },
|
|
67
|
-
{ name: 'Item 3', value: 300 }
|
|
68
|
-
]
|
|
69
|
-
},
|
|
70
|
-
'with-conditional': {
|
|
71
|
-
isLoggedIn: true,
|
|
72
|
-
username: 'TestUser',
|
|
73
|
-
role: 'admin',
|
|
74
|
-
notifications: 5
|
|
75
|
-
},
|
|
76
|
-
'with-escaping': {
|
|
77
|
-
userInput: '<script>alert("XSS")</script>',
|
|
78
|
-
htmlContent: '<strong>Bold text</strong>',
|
|
79
|
-
safeText: 'Plain & safe text',
|
|
80
|
-
allowedHtml: '<em>Emphasized text</em>'
|
|
81
|
-
},
|
|
82
|
-
'complex': {
|
|
83
|
-
pageTitle: 'E-Commerce Products',
|
|
84
|
-
user: {
|
|
85
|
-
name: 'Mario Rossi'
|
|
86
|
-
},
|
|
87
|
-
products: [
|
|
88
|
-
{
|
|
89
|
-
id: 1,
|
|
90
|
-
name: 'Laptop',
|
|
91
|
-
description: 'High-performance laptop',
|
|
92
|
-
price: 999.99,
|
|
93
|
-
discount: 10,
|
|
94
|
-
inStock: true
|
|
95
|
-
},
|
|
96
|
-
{
|
|
97
|
-
id: 2,
|
|
98
|
-
name: 'Mouse',
|
|
99
|
-
description: 'Wireless mouse',
|
|
100
|
-
price: 29.99,
|
|
101
|
-
discount: 0,
|
|
102
|
-
inStock: true
|
|
103
|
-
},
|
|
104
|
-
{
|
|
105
|
-
id: 3,
|
|
106
|
-
name: 'Keyboard',
|
|
107
|
-
description: 'Mechanical keyboard',
|
|
108
|
-
price: 149.99,
|
|
109
|
-
discount: 15,
|
|
110
|
-
inStock: false
|
|
111
|
-
}
|
|
112
|
-
]
|
|
113
|
-
},
|
|
114
|
-
'testEjs': {
|
|
115
|
-
// For the existing test file
|
|
116
|
-
}
|
|
117
|
-
};
|
|
118
|
-
|
|
119
|
-
return dataMap[basename] || {};
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
describe('Simple Template - simple.ejs', () => {
|
|
123
|
-
test('Should render simple template with variables', async () => {
|
|
124
|
-
const response = await request.get('/ejs-templates/simple.ejs');
|
|
125
|
-
|
|
126
|
-
expect(response.status).toBe(200);
|
|
127
|
-
expect(response.type).toBe('text/html');
|
|
128
|
-
expect(response.text).toContain('Simple EJS Test');
|
|
129
|
-
expect(response.text).toContain('Hello from EJS');
|
|
130
|
-
expect(response.text).toContain('This is a simple template test');
|
|
131
|
-
expect(response.text).toContain('2025-11-18');
|
|
132
|
-
});
|
|
133
|
-
});
|
|
134
|
-
|
|
135
|
-
describe('Loop Template - with-loop.ejs', () => {
|
|
136
|
-
test('Should render template with forEach loop', async () => {
|
|
137
|
-
const response = await request.get('/ejs-templates/with-loop.ejs');
|
|
138
|
-
|
|
139
|
-
expect(response.status).toBe(200);
|
|
140
|
-
expect(response.text).toContain('Lista di Items');
|
|
141
|
-
expect(response.text).toContain('Item 1 - 100');
|
|
142
|
-
expect(response.text).toContain('Item 2 - 200');
|
|
143
|
-
expect(response.text).toContain('Item 3 - 300');
|
|
144
|
-
expect(response.text).toContain('Totale items: 3');
|
|
145
|
-
expect(response.text).toContain('data-index="0"');
|
|
146
|
-
expect(response.text).toContain('data-index="1"');
|
|
147
|
-
expect(response.text).toContain('data-index="2"');
|
|
148
|
-
});
|
|
149
|
-
});
|
|
150
|
-
|
|
151
|
-
describe('Conditional Template - with-conditional.ejs', () => {
|
|
152
|
-
test('Should render template with if/else conditionals (logged in)', async () => {
|
|
153
|
-
const response = await request.get('/ejs-templates/with-conditional.ejs');
|
|
154
|
-
|
|
155
|
-
expect(response.status).toBe(200);
|
|
156
|
-
expect(response.text).toContain('Benvenuto, TestUser!');
|
|
157
|
-
expect(response.text).toContain('Ruolo: admin');
|
|
158
|
-
expect(response.text).toContain('Hai 5 nuove notifiche');
|
|
159
|
-
// Should NOT contain guest panel
|
|
160
|
-
expect(response.text).not.toContain('Benvenuto, ospite!');
|
|
161
|
-
});
|
|
162
|
-
});
|
|
163
|
-
|
|
164
|
-
describe('Escaping Template - with-escaping.ejs', () => {
|
|
165
|
-
test('Should properly escape HTML in <%= %> tags', async () => {
|
|
166
|
-
const response = await request.get('/ejs-templates/with-escaping.ejs');
|
|
167
|
-
|
|
168
|
-
expect(response.status).toBe(200);
|
|
169
|
-
|
|
170
|
-
// HTML should be escaped (safe)
|
|
171
|
-
// Note: EJS uses " instead of " for quotes
|
|
172
|
-
expect(response.text).toContain('<script>alert("XSS")</script>');
|
|
173
|
-
|
|
174
|
-
// HTML should NOT be escaped (unsafe - unescaped output)
|
|
175
|
-
expect(response.text).toContain('<strong>Bold text</strong>');
|
|
176
|
-
|
|
177
|
-
// Safe text with & should be escaped
|
|
178
|
-
expect(response.text).toContain('Plain & safe text');
|
|
179
|
-
|
|
180
|
-
// Allowed HTML should be rendered
|
|
181
|
-
expect(response.text).toContain('<em>Emphasized text</em>');
|
|
182
|
-
});
|
|
183
|
-
|
|
184
|
-
test('Should protect against XSS attacks', async () => {
|
|
185
|
-
const response = await request.get('/ejs-templates/with-escaping.ejs');
|
|
186
|
-
|
|
187
|
-
// The escaped section should not contain executable script tags
|
|
188
|
-
const escapedSection = response.text.match(/<div class="escaped">[\s\S]*?<\/div>/)[0];
|
|
189
|
-
expect(escapedSection).not.toContain('<script>');
|
|
190
|
-
expect(escapedSection).toContain('<script>');
|
|
191
|
-
});
|
|
192
|
-
});
|
|
193
|
-
|
|
194
|
-
describe('Complex Template - complex.ejs', () => {
|
|
195
|
-
test('Should render complex template with all features', async () => {
|
|
196
|
-
const response = await request.get('/ejs-templates/complex.ejs');
|
|
197
|
-
|
|
198
|
-
expect(response.status).toBe(200);
|
|
199
|
-
|
|
200
|
-
// Page title
|
|
201
|
-
expect(response.text).toContain('E-Commerce Products');
|
|
202
|
-
|
|
203
|
-
// User greeting
|
|
204
|
-
expect(response.text).toContain('Ciao, Mario Rossi!');
|
|
205
|
-
|
|
206
|
-
// Products list
|
|
207
|
-
expect(response.text).toContain('Laptop');
|
|
208
|
-
expect(response.text).toContain('High-performance laptop');
|
|
209
|
-
expect(response.text).toContain('€999.99');
|
|
210
|
-
|
|
211
|
-
// Discount calculation
|
|
212
|
-
expect(response.text).toContain('Sconto: 10%');
|
|
213
|
-
expect(response.text).toContain('€899.99'); // 999.99 - 10%
|
|
214
|
-
|
|
215
|
-
// Mouse without discount
|
|
216
|
-
expect(response.text).toContain('Mouse');
|
|
217
|
-
expect(response.text).toContain('€29.99');
|
|
218
|
-
|
|
219
|
-
// Keyboard out of stock
|
|
220
|
-
expect(response.text).toContain('Keyboard');
|
|
221
|
-
expect(response.text).toContain('Non disponibile');
|
|
222
|
-
|
|
223
|
-
// Total count
|
|
224
|
-
expect(response.text).toContain('Totale prodotti: 3');
|
|
225
|
-
});
|
|
226
|
-
|
|
227
|
-
test('Should have correct product data attributes', async () => {
|
|
228
|
-
const response = await request.get('/ejs-templates/complex.ejs');
|
|
229
|
-
|
|
230
|
-
expect(response.text).toContain('data-id="1"');
|
|
231
|
-
expect(response.text).toContain('data-id="2"');
|
|
232
|
-
expect(response.text).toContain('data-id="3"');
|
|
233
|
-
});
|
|
234
|
-
|
|
235
|
-
test('Should show "Add to cart" button only for in-stock items', async () => {
|
|
236
|
-
const response = await request.get('/ejs-templates/complex.ejs');
|
|
237
|
-
|
|
238
|
-
// Count "Aggiungi al carrello" buttons - should be 2 (Laptop and Mouse)
|
|
239
|
-
const buttonMatches = response.text.match(/Aggiungi al carrello/g);
|
|
240
|
-
expect(buttonMatches).toHaveLength(2);
|
|
241
|
-
|
|
242
|
-
// Count "Non disponibile" - should be 1 (Keyboard)
|
|
243
|
-
const outOfStockMatches = response.text.match(/Non disponibile/g);
|
|
244
|
-
expect(outOfStockMatches).toHaveLength(1);
|
|
245
|
-
});
|
|
246
|
-
});
|
|
247
|
-
|
|
248
|
-
describe('Index Template - index.ejs', () => {
|
|
249
|
-
test('Should render index page with links', async () => {
|
|
250
|
-
const response = await request.get('/ejs-templates/index.ejs');
|
|
251
|
-
|
|
252
|
-
expect(response.status).toBe(200);
|
|
253
|
-
expect(response.text).toContain('Test Templates EJS');
|
|
254
|
-
expect(response.text).toContain('simple.ejs');
|
|
255
|
-
expect(response.text).toContain('with-loop.ejs');
|
|
256
|
-
expect(response.text).toContain('with-conditional.ejs');
|
|
257
|
-
expect(response.text).toContain('with-escaping.ejs');
|
|
258
|
-
expect(response.text).toContain('complex.ejs');
|
|
259
|
-
});
|
|
260
|
-
});
|
|
261
|
-
|
|
262
|
-
describe('Existing EJS file - testEjs.ejs', () => {
|
|
263
|
-
test('Should render existing testEjs.ejs file', async () => {
|
|
264
|
-
const response = await request.get('/cartella/sottocartella/provaEjs/testEjs.ejs');
|
|
265
|
-
|
|
266
|
-
expect(response.status).toBe(200);
|
|
267
|
-
expect(response.type).toBe('text/html');
|
|
268
|
-
expect(response.text).toContain('<h1>hello world</h1>');
|
|
269
|
-
});
|
|
270
|
-
});
|
|
271
|
-
|
|
272
|
-
describe('Error Handling', () => {
|
|
273
|
-
test('Should return 404 for non-existent .ejs file', async () => {
|
|
274
|
-
const response = await request.get('/ejs-templates/non-existent.ejs');
|
|
275
|
-
|
|
276
|
-
expect(response.status).toBe(404);
|
|
277
|
-
});
|
|
278
|
-
});
|
|
279
|
-
|
|
280
|
-
describe('Performance', () => {
|
|
281
|
-
test('Should render complex template in reasonable time', async () => {
|
|
282
|
-
const start = Date.now();
|
|
283
|
-
const response = await request.get('/ejs-templates/complex.ejs');
|
|
284
|
-
const duration = Date.now() - start;
|
|
285
|
-
|
|
286
|
-
expect(response.status).toBe(200);
|
|
287
|
-
expect(duration).toBeLessThan(100); // Should render in less than 100ms
|
|
288
|
-
});
|
|
289
|
-
|
|
290
|
-
test('Should render simple template very quickly', async () => {
|
|
291
|
-
const start = Date.now();
|
|
292
|
-
const response = await request.get('/ejs-templates/simple.ejs');
|
|
293
|
-
const duration = Date.now() - start;
|
|
294
|
-
|
|
295
|
-
expect(response.status).toBe(200);
|
|
296
|
-
expect(duration).toBeLessThan(50); // Should render in less than 50ms
|
|
297
|
-
});
|
|
298
|
-
});
|
|
299
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
dot dir file
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
acme
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
password
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
key data
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
secret data
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
regular
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
normal
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
NESTED_SECRET=nestedvalue
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
regular in subdir
|