koa-classic-server 2.0.0 → 2.1.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.
Files changed (45) hide show
  1. package/README.md +553 -127
  2. package/__tests__/directory-sorting-links.test.js +135 -0
  3. package/__tests__/ejs.test.js +299 -0
  4. package/__tests__/performance.test.js +75 -6
  5. package/__tests__/publicWwwTest/ejs-templates/complex.ejs +56 -0
  6. package/__tests__/publicWwwTest/ejs-templates/index.ejs +30 -0
  7. package/__tests__/publicWwwTest/ejs-templates/simple.ejs +13 -0
  8. package/__tests__/publicWwwTest/ejs-templates/with-conditional.ejs +28 -0
  9. package/__tests__/publicWwwTest/ejs-templates/with-escaping.ejs +26 -0
  10. package/__tests__/publicWwwTest/ejs-templates/with-loop.ejs +16 -0
  11. package/{scripts → __tests__}/setup-benchmark.js +1 -1
  12. package/docs/CODE_REVIEW.md +298 -0
  13. package/docs/FLOW_DIAGRAM.md +952 -0
  14. package/docs/template-engine/TEMPLATE_ENGINE_GUIDE.md +1734 -0
  15. package/docs/template-engine/esempi-incrementali.js +192 -0
  16. package/docs/template-engine/examples/esempio1-nessun-dato.ejs +12 -0
  17. package/docs/template-engine/examples/esempio2-una-variabile.ejs +11 -0
  18. package/docs/template-engine/examples/esempio3-piu-variabili.ejs +15 -0
  19. package/docs/template-engine/examples/esempio4-condizionale.ejs +18 -0
  20. package/docs/template-engine/examples/esempio5-loop.ejs +18 -0
  21. package/docs/template-engine/examples/index-esempi.html +181 -0
  22. package/docs/template-engine/examples/index.html +40 -0
  23. package/docs/template-engine/examples/test.ejs +64 -0
  24. package/index.cjs +186 -35
  25. package/package.json +9 -6
  26. package/CREATE_RELEASE.sh +0 -53
  27. package/publish-to-npm.sh +0 -65
  28. /package/{benchmark-results-baseline-v1.2.0.txt → __tests__/benchmark-results-baseline-v1.2.0.txt} +0 -0
  29. /package/{benchmark-results-optimized-v2.0.0.txt → __tests__/benchmark-results-optimized-v2.0.0.txt} +0 -0
  30. /package/{benchmark.js → __tests__/benchmark.js} +0 -0
  31. /package/{customTest → __tests__/customTest}/README.md +0 -0
  32. /package/{customTest → __tests__/customTest}/loadConfig.util.js +0 -0
  33. /package/{customTest → __tests__/customTest}/serversToLoad.util.js +0 -0
  34. /package/{demo-regex-index.js → __tests__/demo-regex-index.js} +0 -0
  35. /package/{test-regex-quick.js → __tests__/test-regex-quick.js} +0 -0
  36. /package/{BENCHMARKS.md → docs/BENCHMARKS.md} +0 -0
  37. /package/{CHANGELOG.md → docs/CHANGELOG.md} +0 -0
  38. /package/{DEBUG_REPORT.md → docs/DEBUG_REPORT.md} +0 -0
  39. /package/{DOCUMENTATION.md → docs/DOCUMENTATION.md} +0 -0
  40. /package/{EXAMPLES_INDEX_OPTION.md → docs/EXAMPLES_INDEX_OPTION.md} +0 -0
  41. /package/{INDEX_OPTION_PRIORITY.md → docs/INDEX_OPTION_PRIORITY.md} +0 -0
  42. /package/{OPTIMIZATION_HTTP_CACHING.md → docs/OPTIMIZATION_HTTP_CACHING.md} +0 -0
  43. /package/{PERFORMANCE_ANALYSIS.md → docs/PERFORMANCE_ANALYSIS.md} +0 -0
  44. /package/{PERFORMANCE_COMPARISON.md → docs/PERFORMANCE_COMPARISON.md} +0 -0
  45. /package/{noteExports.md → docs/noteExports.md} +0 -0
package/README.md CHANGED
@@ -1,48 +1,75 @@
1
1
  # koa-classic-server
2
2
 
3
- 🔒 **Secure Koa middleware for serving static files** with Apache-like directory listing, template engine support, and comprehensive security fixes.
3
+ 🚀 **Production-ready Koa middleware** for serving static files with Apache2-like directory listing, sortable columns, HTTP caching, template engine support, and enterprise-grade security.
4
4
 
5
5
  [![npm version](https://img.shields.io/npm/v/koa-classic-server.svg)](https://www.npmjs.com/package/koa-classic-server)
6
6
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
7
- [![Tests](https://img.shields.io/badge/tests-71%20passing-brightgreen.svg)]()
7
+ [![Tests](https://img.shields.io/badge/tests-153%20passing-brightgreen.svg)]()
8
8
 
9
- ## ⚠️ Version 1.2.0 - Critical Security Update
9
+ ---
10
+
11
+ ## 🎉 Version 2.1.2 - Production Release
12
+
13
+ Version 2.1.2 is a **major production release** featuring performance optimizations, enhanced directory listing, and critical bug fixes.
14
+
15
+ ### What's New in 2.1.2
10
16
 
11
- Version 1.2.0 includes **critical security fixes** for path traversal vulnerabilities and other important improvements. **Upgrade immediately** if you're using version 1.1.0 or earlier.
17
+ **Sortable Directory Columns** - Click Name/Type/Size to sort (Apache2-like)
18
+ ✅ **Navigation Bug Fixed** - Directory navigation now works correctly after sorting
19
+ ✅ **File Size Display** - Human-readable file sizes (B, KB, MB, GB, TB)
20
+ ✅ **HTTP Caching** - 80-95% bandwidth reduction with ETag and Last-Modified
21
+ ✅ **Async/Await** - Non-blocking I/O for high performance
22
+ ✅ **153 Tests Passing** - Comprehensive test coverage
23
+ ✅ **Flow Documentation** - Complete execution flow diagrams
24
+ ✅ **Code Review** - Standardized operators and best practices
12
25
 
13
- ### What's New in 1.2.0
26
+ ### What's New in 2.0
14
27
 
15
- ✅ **Fixed Path Traversal Vulnerability** - No more unauthorized file access
16
- ✅ **Proper HTTP 404 Status Codes** - Standards-compliant error handling
17
- ✅ **Template Error Handling** - No more server crashes
18
- ✅ **XSS Protection** - HTML escaping in directory listings
19
- ✅ **Race Condition Fixes** - Robust file access
20
- ✅ **71 Tests Passing** - Comprehensive test coverage
28
+ ✅ **Performance Optimizations** - 50-70% faster directory listings
29
+ ✅ **Enhanced Index Option** - Array format with RegExp support
30
+ ✅ **Template Engine Guide** - Complete documentation with examples
31
+ ✅ **Security Hardened** - Path traversal, XSS, race condition fixes
21
32
 
22
- [See full changelog](./CHANGELOG.md)
33
+ [See full changelog](./docs/CHANGELOG.md)
34
+
35
+ ---
23
36
 
24
37
  ## Features
25
38
 
26
- koa-classic-server is a middleware for serving static files from a directory with Apache 2-like behavior. The contents of a folder on the server will be shown remotely and if you want to access a file, click on it.
39
+ **koa-classic-server** is a high-performance middleware for serving static files with Apache2-like behavior, making file browsing intuitive and powerful.
27
40
 
28
- **Key Features:**
41
+ ### Core Features
29
42
 
30
- - 🗂️ **Directory Listing** - Apache-style browseable directories
31
- - 📄 **Static File Serving** - Automatic MIME type detection
32
- - 🎨 **Template Engine Support** - Integrate EJS, Pug, Handlebars, etc.
33
- - 🔒 **Security** - Path traversal protection, XSS prevention
34
- - ⚙️ **Configurable** - URL prefixes, reserved paths, index files
35
- - 🧪 **Well-Tested** - 71 tests with security coverage
43
+ - 🗂️ **Apache2-like Directory Listing** - Sortable columns (Name, Type, Size)
44
+ - 📄 **Static File Serving** - Automatic MIME type detection with streaming
45
+ - 📊 **Sortable Columns** - Click headers to sort ascending/descending
46
+ - 📏 **File Sizes** - Human-readable display (B, KB, MB, GB, TB)
47
+ - **HTTP Caching** - ETag, Last-Modified, 304 responses
48
+ - 🎨 **Template Engine Support** - EJS, Pug, Handlebars, Nunjucks, etc.
49
+ - 🔒 **Enterprise Security** - Path traversal, XSS, race condition protection
50
+ - ⚙️ **Highly Configurable** - URL prefixes, reserved paths, index files
51
+ - 🚀 **High Performance** - Async/await, non-blocking I/O, optimized algorithms
52
+ - 🧪 **Well-Tested** - 153 passing tests with comprehensive coverage
36
53
  - 📦 **Dual Module Support** - CommonJS and ES Modules
37
54
 
55
+ ---
56
+
38
57
  ## Installation
39
58
 
40
59
  ```bash
41
60
  npm install koa-classic-server
42
61
  ```
43
62
 
63
+ **Requirements:**
64
+ - Node.js >= 12.0.0
65
+ - Koa >= 2.0.0
66
+
67
+ ---
68
+
44
69
  ## Quick Start
45
70
 
71
+ ### Basic Usage
72
+
46
73
  ```javascript
47
74
  const Koa = require('koa');
48
75
  const koaClassicServer = require('koa-classic-server');
@@ -56,9 +83,30 @@ app.listen(3000);
56
83
  console.log('Server running on http://localhost:3000');
57
84
  ```
58
85
 
59
- ## Usage
86
+ ### With Options
87
+
88
+ ```javascript
89
+ const Koa = require('koa');
90
+ const koaClassicServer = require('koa-classic-server');
91
+
92
+ const app = new Koa();
93
+
94
+ app.use(koaClassicServer(__dirname + '/public', {
95
+ showDirContents: true,
96
+ index: ['index.html', 'index.htm'],
97
+ urlPrefix: '/static',
98
+ cacheMaxAge: 3600,
99
+ enableCaching: true
100
+ }));
101
+
102
+ app.listen(3000);
103
+ ```
104
+
105
+ ---
106
+
107
+ ## Complete Usage Guide
60
108
 
61
- ### Import
109
+ ### 1. Import
62
110
 
63
111
  ```javascript
64
112
  // CommonJS
@@ -68,9 +116,9 @@ const koaClassicServer = require('koa-classic-server');
68
116
  import koaClassicServer from 'koa-classic-server';
69
117
  ```
70
118
 
71
- ### Basic Examples
119
+ ### 2. Basic File Server
72
120
 
73
- #### Example 1: Simple File Server
121
+ Serve static files from a directory:
74
122
 
75
123
  ```javascript
76
124
  const Koa = require('koa');
@@ -80,55 +128,183 @@ const app = new Koa();
80
128
 
81
129
  app.use(koaClassicServer(__dirname + '/public', {
82
130
  showDirContents: true,
83
- index: ['index.html'] // Array format (recommended)
131
+ index: ['index.html']
84
132
  }));
85
133
 
86
134
  app.listen(3000);
87
135
  ```
88
136
 
89
- #### Example 2: With URL Prefix
137
+ **What it does:**
138
+ - Serves files from `/public` directory
139
+ - Shows directory listing when accessing folders
140
+ - Looks for `index.html` in directories
141
+ - Sortable columns (Name, Type, Size)
142
+ - File sizes displayed in human-readable format
90
143
 
91
- ```javascript
92
- const Koa = require('koa');
93
- const koaClassicServer = require('koa-classic-server');
144
+ ### 3. With URL Prefix
94
145
 
95
- const app = new Koa();
146
+ Serve files under a specific URL path:
96
147
 
97
- // Files accessible under /static
98
- // e.g., http://localhost:3000/static/image.png
99
- app.use(koaClassicServer(__dirname + '/public', {
148
+ ```javascript
149
+ app.use(koaClassicServer(__dirname + '/assets', {
100
150
  urlPrefix: '/static',
101
151
  showDirContents: true
102
152
  }));
153
+ ```
103
154
 
104
- app.listen(3000);
155
+ **Result:**
156
+ - `http://localhost:3000/static/image.png` → serves `/assets/image.png`
157
+ - `http://localhost:3000/static/` → shows `/assets` directory listing
158
+
159
+ ### 4. With Reserved Paths
160
+
161
+ Protect specific directories from being accessed:
162
+
163
+ ```javascript
164
+ app.use(koaClassicServer(__dirname + '/www', {
165
+ urlsReserved: ['/admin', '/config', '/.git', '/node_modules']
166
+ }));
105
167
  ```
106
168
 
107
- #### Example 3: With Template Engine (EJS)
169
+ **Result:**
170
+ - `/admin/*` → passed to next middleware (not served)
171
+ - `/config/*` → protected
172
+ - Other paths → served normally
173
+
174
+ ### 5. With Template Engine (EJS)
175
+
176
+ Dynamically render templates with data:
177
+
178
+ ```javascript
179
+ const ejs = require('ejs');
180
+
181
+ app.use(koaClassicServer(__dirname + '/views', {
182
+ template: {
183
+ ext: ['ejs', 'html.ejs'],
184
+ render: async (ctx, next, filePath) => {
185
+ const data = {
186
+ title: 'My App',
187
+ user: ctx.state.user || { name: 'Guest' },
188
+ items: ['Item 1', 'Item 2', 'Item 3'],
189
+ timestamp: new Date().toISOString()
190
+ };
191
+
192
+ ctx.body = await ejs.renderFile(filePath, data);
193
+ ctx.type = 'text/html';
194
+ }
195
+ }
196
+ }));
197
+ ```
198
+
199
+ **Template example (`views/dashboard.ejs`):**
200
+ ```html
201
+ <!DOCTYPE html>
202
+ <html>
203
+ <head>
204
+ <title><%= title %></title>
205
+ </head>
206
+ <body>
207
+ <h1>Welcome, <%= user.name %>!</h1>
208
+ <ul>
209
+ <% items.forEach(item => { %>
210
+ <li><%= item %></li>
211
+ <% }); %>
212
+ </ul>
213
+ <p>Generated at: <%= timestamp %></p>
214
+ </body>
215
+ </html>
216
+ ```
217
+
218
+ **See complete guide:** [Template Engine Documentation →](./docs/template-engine/TEMPLATE_ENGINE_GUIDE.md)
219
+
220
+ ### 6. With HTTP Caching
221
+
222
+ Enable aggressive caching for static files:
223
+
224
+ ```javascript
225
+ app.use(koaClassicServer(__dirname + '/public', {
226
+ enableCaching: true, // Enable ETag and Last-Modified
227
+ cacheMaxAge: 86400, // Cache for 24 hours (in seconds)
228
+ }));
229
+ ```
230
+
231
+ **Benefits:**
232
+ - 80-95% bandwidth reduction
233
+ - 304 Not Modified responses for unchanged files
234
+ - Faster page loads for returning visitors
235
+
236
+ **See details:** [HTTP Caching Optimization →](./docs/OPTIMIZATION_HTTP_CACHING.md)
237
+
238
+ ### 7. Multiple Index Files with Priority
239
+
240
+ Search for multiple index files with custom order:
241
+
242
+ ```javascript
243
+ app.use(koaClassicServer(__dirname + '/public', {
244
+ index: [
245
+ 'index.html', // First priority
246
+ 'index.htm', // Second priority
247
+ /index\.[eE][jJ][sS]/, // Third: index.ejs (case-insensitive)
248
+ 'default.html' // Last priority
249
+ ]
250
+ }));
251
+ ```
252
+
253
+ **See details:** [Index Option Priority →](./docs/INDEX_OPTION_PRIORITY.md)
254
+
255
+ ### 8. Complete Production Example
256
+
257
+ Real-world configuration for production:
108
258
 
109
259
  ```javascript
110
260
  const Koa = require('koa');
111
261
  const koaClassicServer = require('koa-classic-server');
112
262
  const ejs = require('ejs');
263
+ const path = require('path');
113
264
 
114
265
  const app = new Koa();
115
266
 
116
- app.use(koaClassicServer(__dirname + '/views', {
267
+ // Serve static assets with caching
268
+ app.use(koaClassicServer(path.join(__dirname, 'public'), {
269
+ method: ['GET', 'HEAD'],
270
+ showDirContents: false, // Disable directory listing in production
271
+ index: ['index.html', 'index.htm'],
272
+ urlPrefix: '/assets',
273
+ urlsReserved: ['/admin', '/api', '/.git'],
274
+ enableCaching: true,
275
+ cacheMaxAge: 86400, // 24 hours
276
+ }));
277
+
278
+ // Serve dynamic templates
279
+ app.use(koaClassicServer(path.join(__dirname, 'views'), {
280
+ showDirContents: false,
117
281
  template: {
282
+ ext: ['ejs'],
118
283
  render: async (ctx, next, filePath) => {
119
- ctx.body = await ejs.renderFile(filePath, {
120
- title: 'My App',
121
- user: ctx.state.user
122
- });
123
- },
124
- ext: ['ejs', 'html']
284
+ const data = {
285
+ env: process.env.NODE_ENV,
286
+ user: ctx.state.user,
287
+ config: ctx.state.config
288
+ };
289
+
290
+ try {
291
+ ctx.body = await ejs.renderFile(filePath, data);
292
+ ctx.type = 'text/html';
293
+ } catch (error) {
294
+ console.error('Template error:', error);
295
+ ctx.status = 500;
296
+ ctx.body = 'Internal Server Error';
297
+ }
298
+ }
125
299
  }
126
300
  }));
127
301
 
128
302
  app.listen(3000);
129
303
  ```
130
304
 
131
- ## API
305
+ ---
306
+
307
+ ## API Reference
132
308
 
133
309
  ### koaClassicServer(rootDir, options)
134
310
 
@@ -136,56 +312,54 @@ Creates a Koa middleware for serving static files.
136
312
 
137
313
  **Parameters:**
138
314
 
139
- - `rootDir` (String, required): Absolute path to the directory containing static files
140
- - `options` (Object, optional): Configuration options
315
+ - **`rootDir`** (String, required): Absolute path to the directory containing files
316
+ - **`options`** (Object, optional): Configuration options
141
317
 
142
318
  **Returns:** Koa middleware function
143
319
 
144
- ## Options
320
+ ### Options
145
321
 
146
322
  ```javascript
147
- const options = {
323
+ {
148
324
  // HTTP methods allowed (default: ['GET'])
149
325
  method: ['GET', 'HEAD'],
150
326
 
151
327
  // Show directory contents (default: true)
152
328
  showDirContents: true,
153
329
 
154
- // Index file configuration (default: [])
155
- // RECOMMENDED: Use array format (string format is deprecated)
156
- // Formats:
157
- // - Array of strings: ['index.html', 'index.htm', 'default.html']
158
- // - Array of RegExp: [/index\.html/i] (case-insensitive)
159
- // - Mixed array: ['index.html', /INDEX\.HTM/i]
160
- // Priority: First match wins (array order determines search priority)
161
- //
162
- // DEPRECATED: String format 'index.html' still works but will be removed
163
- // in future versions. Please use array format: ['index.html']
164
- //
165
- // See INDEX_OPTION_PRIORITY.md for detailed behavior documentation
166
- index: ['index.html'],
330
+ // Index file configuration
331
+ // Array format (recommended):
332
+ // - Strings: exact matches ['index.html', 'default.html']
333
+ // - RegExp: pattern matches [/index\.html/i]
334
+ // - Mixed: ['index.html', /INDEX\.HTM/i]
335
+ // Priority determined by array order (first match wins)
336
+ // See docs/INDEX_OPTION_PRIORITY.md for details
337
+ index: ['index.html', 'index.htm'],
167
338
 
168
339
  // URL path prefix (default: '')
169
- // Files will be served under this prefix
340
+ // Files served under this prefix
170
341
  urlPrefix: '/static',
171
342
 
172
343
  // Reserved paths (default: [])
173
- // These directories won't be accessible
174
- // Note: Only works for first-level directories
175
- urlsReserved: ['/admin', '/private'],
344
+ // First-level directories passed to next middleware
345
+ urlsReserved: ['/admin', '/api', '/.git'],
176
346
 
177
347
  // Template engine configuration
178
348
  template: {
179
349
  // Template rendering function
180
350
  render: async (ctx, next, filePath) => {
181
351
  // Your rendering logic
182
- ctx.body = await yourTemplateEngine.render(filePath, data);
352
+ ctx.body = await yourEngine.render(filePath, data);
183
353
  },
184
354
 
185
- // File extensions to process with template.render
355
+ // File extensions to process
186
356
  ext: ['ejs', 'pug', 'hbs']
187
- }
188
- };
357
+ },
358
+
359
+ // HTTP caching configuration
360
+ enableCaching: true, // Enable ETag & Last-Modified (default: true)
361
+ cacheMaxAge: 3600, // Cache-Control max-age in seconds (default: 3600 = 1 hour)
362
+ }
189
363
  ```
190
364
 
191
365
  ### Options Details
@@ -194,131 +368,383 @@ const options = {
194
368
  |--------|------|---------|-------------|
195
369
  | `method` | Array | `['GET']` | Allowed HTTP methods |
196
370
  | `showDirContents` | Boolean | `true` | Show directory listing |
197
- | `index` | String | `''` | Index file name |
371
+ | `index` | Array/String | `[]` | Index file patterns (array format recommended) |
198
372
  | `urlPrefix` | String | `''` | URL path prefix |
199
- | `urlsReserved` | Array | `[]` | Reserved directory paths |
373
+ | `urlsReserved` | Array | `[]` | Reserved directory paths (first-level only) |
200
374
  | `template.render` | Function | `undefined` | Template rendering function |
201
375
  | `template.ext` | Array | `[]` | Extensions for template rendering |
376
+ | `enableCaching` | Boolean | `true` | Enable HTTP caching headers |
377
+ | `cacheMaxAge` | Number | `3600` | Cache duration in seconds |
378
+
379
+ ---
380
+
381
+ ## Directory Listing Features
382
+
383
+ ### Sortable Columns
384
+
385
+ Click on column headers to sort:
386
+
387
+ - **Name** - Alphabetical sorting (A-Z or Z-A)
388
+ - **Type** - Sort by MIME type (directories always first)
389
+ - **Size** - Sort by file size (directories always first)
390
+
391
+ Visual indicators:
392
+ - **↑** - Ascending order
393
+ - **↓** - Descending order
394
+
395
+ ### File Size Display
396
+
397
+ Human-readable format:
398
+ - `1.5 KB` - Kilobytes
399
+ - `2.3 MB` - Megabytes
400
+ - `1.2 GB` - Gigabytes
401
+ - `-` - Directories (no size)
402
+
403
+ ### Navigation
404
+
405
+ - **Click folder name** - Enter directory
406
+ - **Click file name** - Download/view file
407
+ - **Parent Directory** - Go up one level
408
+
409
+ ---
202
410
 
203
411
  ## Security
204
412
 
205
- ### Path Traversal Protection
413
+ ### Built-in Protection
414
+
415
+ koa-classic-server includes enterprise-grade security:
416
+
417
+ #### 1. Path Traversal Protection
206
418
 
207
- koa-classic-server 1.2.0 protects against path traversal attacks:
419
+ Prevents access to files outside `rootDir`:
208
420
 
209
421
  ```javascript
210
- // ❌ These requests are blocked (return 403 Forbidden)
211
- GET /../../../etc/passwd
212
- GET /../config/database.yml
213
- GET /%2e%2e%2fpackage.json
422
+ // ❌ Blocked requests
423
+ GET /../../../etc/passwd → 403 Forbidden
424
+ GET /../config/database.yml → 403 Forbidden
425
+ GET /%2e%2e%2fpackage.json → 403 Forbidden
214
426
  ```
215
427
 
216
- ### Protected Directories
428
+ #### 2. XSS Protection
217
429
 
218
- Use `urlsReserved` to protect sensitive directories:
430
+ All filenames and paths are HTML-escaped:
219
431
 
220
432
  ```javascript
221
- app.use(koaClassicServer(__dirname + '/www', {
222
- urlsReserved: ['/config', '/private', '/.git', '/node_modules']
433
+ // Malicious filename: <script>alert('xss')</script>.txt
434
+ // Displayed as: &lt;script&gt;alert('xss')&lt;/script&gt;.txt
435
+ // ✅ Safe - script doesn't execute
436
+ ```
437
+
438
+ #### 3. Reserved URLs
439
+
440
+ Protect sensitive directories:
441
+
442
+ ```javascript
443
+ app.use(koaClassicServer(__dirname, {
444
+ urlsReserved: ['/admin', '/config', '/.git', '/node_modules']
223
445
  }));
224
446
  ```
225
447
 
226
- ### XSS Protection
448
+ #### 4. Race Condition Protection
227
449
 
228
- All filenames and paths in directory listings are HTML-escaped to prevent XSS attacks.
450
+ File access is verified before streaming:
229
451
 
230
- ## Error Handling
452
+ ```javascript
453
+ // File deleted between check and access?
454
+ // ✅ Returns 404 instead of crashing
455
+ ```
456
+
457
+ **See full security audit:** [Security Tests →](./__tests__/security.test.js)
231
458
 
232
- koa-classic-server properly handles errors:
459
+ ---
233
460
 
234
- - **404** - File/directory not found
235
- - **403** - Forbidden (path traversal attempts, reserved directories)
236
- - **500** - Template rendering errors, file access errors
461
+ ## Performance
462
+
463
+ ### Optimizations
464
+
465
+ Version 2.x includes major performance improvements:
466
+
467
+ - **Async/Await** - Non-blocking I/O, event loop never blocked
468
+ - **Array Join** - 30-40% less memory vs string concatenation
469
+ - **HTTP Caching** - 80-95% bandwidth reduction
470
+ - **Single stat() Call** - No double file system access
471
+ - **Streaming** - Large files streamed efficiently
472
+
473
+ ### Benchmarks
474
+
475
+ Performance results on directory with 1,000 files:
476
+
477
+ ```
478
+ Before (v1.x): ~350ms per request
479
+ After (v2.x): ~190ms per request
480
+ Improvement: 46% faster
481
+ ```
482
+
483
+ **See detailed benchmarks:** [Performance Analysis →](./docs/PERFORMANCE_ANALYSIS.md)
484
+
485
+ ---
237
486
 
238
487
  ## Testing
239
488
 
489
+ Run the comprehensive test suite:
490
+
240
491
  ```bash
241
492
  # Run all tests
242
493
  npm test
243
494
 
244
495
  # Run security tests only
245
496
  npm run test:security
497
+
498
+ # Run performance benchmarks
499
+ npm run test:performance
246
500
  ```
247
501
 
248
- ## Middleware Behavior
502
+ **Test Coverage:**
503
+ - ✅ 153 tests passing
504
+ - ✅ Security tests (path traversal, XSS, race conditions)
505
+ - ✅ EJS template integration tests
506
+ - ✅ Index option tests (strings, arrays, RegExp)
507
+ - ✅ Performance benchmarks
508
+ - ✅ Directory sorting tests
249
509
 
250
- ### Directory Handling
510
+ ---
251
511
 
252
- 1. If `index` file exists → serve index file
253
- 2. If `showDirContents: true` → show directory listing
254
- 3. If `showDirContents: false` → return 404
512
+ ## Complete Documentation
255
513
 
256
- ### File Handling
514
+ ### Core Documentation
257
515
 
258
- 1. Check if file extension matches `template.ext`
259
- 2. If yes call `template.render()`
260
- 3. If no serve static file with appropriate MIME type
516
+ - **[DOCUMENTATION.md](./docs/DOCUMENTATION.md)** - Complete API reference and usage guide
517
+ - **[FLOW_DIAGRAM.md](./docs/FLOW_DIAGRAM.md)** - Visual flow diagrams and code execution paths
518
+ - **[CHANGELOG.md](./docs/CHANGELOG.md)** - Version history and release notes
261
519
 
262
- ### Reserved URLs
520
+ ### Template Engine
263
521
 
264
- Requests to reserved paths are passed to the next middleware.
522
+ - **[TEMPLATE_ENGINE_GUIDE.md](./docs/template-engine/TEMPLATE_ENGINE_GUIDE.md)** - Complete guide to template engine integration
523
+ - Progressive examples (simple to enterprise)
524
+ - EJS, Pug, Handlebars, Nunjucks support
525
+ - Best practices and troubleshooting
265
526
 
266
- ## Migration from 1.1.0
527
+ ### Configuration
267
528
 
268
- Upgrading is simple! No code changes required:
529
+ - **[INDEX_OPTION_PRIORITY.md](./docs/INDEX_OPTION_PRIORITY.md)** - Detailed priority behavior for `index` option
530
+ - String vs Array vs RegExp formats
531
+ - Priority order examples
532
+ - Migration guide from v1.x
269
533
 
270
- ```bash
271
- npm update koa-classic-server
534
+ - **[EXAMPLES_INDEX_OPTION.md](./docs/EXAMPLES_INDEX_OPTION.md)** - 10 practical examples of `index` option with RegExp
535
+ - Case-insensitive matching
536
+ - Multiple extensions
537
+ - Complex patterns
538
+
539
+ ### Performance
540
+
541
+ - **[PERFORMANCE_ANALYSIS.md](./docs/PERFORMANCE_ANALYSIS.md)** - Performance optimization analysis
542
+ - Before/after comparisons
543
+ - Memory usage analysis
544
+ - Bottleneck identification
545
+
546
+ - **[PERFORMANCE_COMPARISON.md](./docs/PERFORMANCE_COMPARISON.md)** - Detailed performance benchmarks
547
+ - Request latency
548
+ - Throughput metrics
549
+ - Concurrent request handling
550
+
551
+ - **[OPTIMIZATION_HTTP_CACHING.md](./docs/OPTIMIZATION_HTTP_CACHING.md)** - HTTP caching implementation details
552
+ - ETag generation
553
+ - Last-Modified headers
554
+ - 304 Not Modified responses
555
+
556
+ - **[BENCHMARKS.md](./docs/BENCHMARKS.md)** - Benchmark results and methodology
557
+
558
+ ### Code Quality
559
+
560
+ - **[CODE_REVIEW.md](./docs/CODE_REVIEW.md)** - Code quality analysis and review
561
+ - Security audit
562
+ - Best practices
563
+ - Standardization improvements
564
+
565
+ - **[DEBUG_REPORT.md](./docs/DEBUG_REPORT.md)** - Known limitations and debugging info
566
+ - Reserved URLs behavior
567
+ - Edge cases
568
+ - Troubleshooting tips
569
+
570
+ ---
571
+
572
+ ## Migration Guide
573
+
574
+ ### From v1.x to v2.x
575
+
576
+ **Breaking Changes:**
577
+ - `index` option: String format deprecated (still works), use array format
578
+
579
+ **Migration:**
580
+
581
+ ```javascript
582
+ // v1.x (deprecated)
583
+ {
584
+ index: 'index.html'
585
+ }
586
+
587
+ // v2.x (recommended)
588
+ {
589
+ index: ['index.html']
590
+ }
272
591
  ```
273
592
 
274
- **What changed:**
275
- - 404 status codes now correct (was 200)
276
- - Path traversal blocked (was allowed)
277
- - Template errors return 500 (was crash)
593
+ **New Features:**
594
+ - HTTP caching (enabled by default)
595
+ - Sortable directory columns
596
+ - File size display
597
+ - Enhanced index option with RegExp
278
598
 
279
- See [CHANGELOG.md](./CHANGELOG.md) for detailed information.
599
+ **See full migration guide:** [CHANGELOG.md](./docs/CHANGELOG.md)
280
600
 
281
- ## Complete Documentation
601
+ ---
602
+
603
+ ## Examples
604
+
605
+ ### Example 1: Simple Static Server
606
+
607
+ ```javascript
608
+ const Koa = require('koa');
609
+ const koaClassicServer = require('koa-classic-server');
610
+
611
+ const app = new Koa();
612
+ app.use(koaClassicServer(__dirname + '/public'));
613
+ app.listen(3000);
614
+ ```
615
+
616
+ ### Example 2: Multi-Directory Server
617
+
618
+ ```javascript
619
+ const Koa = require('koa');
620
+ const koaClassicServer = require('koa-classic-server');
621
+
622
+ const app = new Koa();
623
+
624
+ // Serve static assets
625
+ app.use(koaClassicServer(__dirname + '/public', {
626
+ urlPrefix: '/static',
627
+ showDirContents: false
628
+ }));
629
+
630
+ // Serve user uploads
631
+ app.use(koaClassicServer(__dirname + '/uploads', {
632
+ urlPrefix: '/files',
633
+ showDirContents: true
634
+ }));
282
635
 
283
- For complete documentation with all features, examples, troubleshooting, and best practices, see:
636
+ app.listen(3000);
637
+ ```
284
638
 
285
- - **[DOCUMENTATION.md](./DOCUMENTATION.md)** - Complete API reference and usage guide
286
- - **[INDEX_OPTION_PRIORITY.md](./INDEX_OPTION_PRIORITY.md)** - Detailed priority behavior for `index` option (string, array, RegExp)
287
- - **[EXAMPLES_INDEX_OPTION.md](./EXAMPLES_INDEX_OPTION.md)** - 10 practical examples of `index` option with RegExp
288
- - **[PERFORMANCE_ANALYSIS.md](./PERFORMANCE_ANALYSIS.md)** - Performance optimization analysis
289
- - **[PERFORMANCE_COMPARISON.md](./PERFORMANCE_COMPARISON.md)** - Before/after performance benchmarks
639
+ ### Example 3: Development Server with Templates
640
+
641
+ ```javascript
642
+ const Koa = require('koa');
643
+ const koaClassicServer = require('koa-classic-server');
644
+ const ejs = require('ejs');
645
+
646
+ const app = new Koa();
647
+
648
+ // Development mode - show directories
649
+ app.use(koaClassicServer(__dirname + '/src', {
650
+ showDirContents: true,
651
+ template: {
652
+ ext: ['ejs'],
653
+ render: async (ctx, next, filePath) => {
654
+ ctx.body = await ejs.renderFile(filePath, {
655
+ dev: true,
656
+ timestamp: Date.now()
657
+ });
658
+ ctx.type = 'text/html';
659
+ }
660
+ }
661
+ }));
662
+
663
+ app.listen(3000);
664
+ ```
665
+
666
+ ---
667
+
668
+ ## Troubleshooting
669
+
670
+ ### Common Issues
671
+
672
+ **Issue: 404 errors for all files**
673
+
674
+ Check that `rootDir` is an absolute path:
675
+
676
+ ```javascript
677
+ // ❌ Wrong (relative path)
678
+ koaClassicServer('./public')
679
+
680
+ // ✅ Correct (absolute path)
681
+ koaClassicServer(__dirname + '/public')
682
+ koaClassicServer(path.join(__dirname, 'public'))
683
+ ```
684
+
685
+ **Issue: Reserved URLs not working**
686
+
687
+ Reserved URLs only work for first-level directories:
688
+
689
+ ```javascript
690
+ urlsReserved: ['/admin'] // ✅ Blocks /admin/*
691
+ urlsReserved: ['/admin/users'] // ❌ Doesn't work (nested)
692
+ ```
693
+
694
+ **Issue: Directory sorting not working**
695
+
696
+ Make sure you're accessing directories without query params initially. The sorting is applied when you click headers.
697
+
698
+ **See full troubleshooting:** [DEBUG_REPORT.md](./docs/DEBUG_REPORT.md)
699
+
700
+ ---
290
701
 
291
702
  ## Contributing
292
703
 
293
- Contributions are welcome! Please feel free to submit a Pull Request.
704
+ Contributions are welcome! Please:
705
+
706
+ 1. Fork the repository
707
+ 2. Create a feature branch
708
+ 3. Add tests for new functionality
709
+ 4. Ensure all tests pass (`npm test`)
710
+ 5. Submit a pull request
711
+
712
+ ---
294
713
 
295
714
  ## Known Limitations
296
715
 
297
716
  - Reserved URLs only work for first-level directories
298
- - Single index file name (no fallback array)
717
+ - Template rendering is synchronous per request
299
718
 
300
- See [DEBUG_REPORT.md](./DEBUG_REPORT.md) for technical details.
719
+ See [DEBUG_REPORT.md](./docs/DEBUG_REPORT.md) for technical details.
720
+
721
+ ---
301
722
 
302
723
  ## License
303
724
 
304
- MIT
725
+ MIT License - see LICENSE file for details
726
+
727
+ ---
305
728
 
306
729
  ## Author
307
730
 
308
731
  Italo Paesano
309
732
 
310
- ## Changelog
311
-
312
- See [CHANGELOG.md](./CHANGELOG.md)
733
+ ---
313
734
 
314
735
  ## Links
315
736
 
316
- - [Full Documentation](./DOCUMENTATION.md)
317
- - [Debug Report](./DEBUG_REPORT.md)
318
- - [Changelog](./CHANGELOG.md)
319
- - [Repository](https://github.com/italopaesano/koa-classic-server)
320
- - [npm Package](https://www.npmjs.com/package/koa-classic-server)
737
+ - **[npm Package](https://www.npmjs.com/package/koa-classic-server)** - Official npm package
738
+ - **[GitHub Repository](https://github.com/italopaesano/koa-classic-server)** - Source code
739
+ - **[Issue Tracker](https://github.com/italopaesano/koa-classic-server/issues)** - Report bugs
740
+ - **[Full Documentation](./docs/DOCUMENTATION.md)** - Complete reference
741
+
742
+ ---
743
+
744
+ ## Changelog
745
+
746
+ See [CHANGELOG.md](./docs/CHANGELOG.md) for version history.
321
747
 
322
748
  ---
323
749
 
324
- **⚠️ Security Notice:** Version 1.2.0 fixes critical vulnerabilities. Update immediately if using 1.1.0 or earlier.
750
+ **⚠️ Security Notice:** Always use the latest version for security updates and bug fixes.