feat: add CORS-aware ETag modes and configurable query parser options
Overview
This PR introduces two independent enhancements to Express.js that address long-standing issues with CDN caching and query string handling.
Changes Included
1. CORS-Aware ETag Generation (Fixes #5986)
Adds new ETag modes that include response headers in ETag calculation to prevent cache conflicts when serving content to multiple origins through CDNs.
New ETag modes:
-
'weak-cors': Weak ETag including Access-Control-Allow-Origin header -
'strong-cors': Strong ETag including Access-Control-Allow-Origin header
Problem solved: CDNs returning 304 Not Modified responses that omit CORS headers, causing browsers to apply cached CORS headers from different origins, resulting in CORS errors.
Usage: `app.set('etag', 'weak-cors');
app.use(function(req, res) { res.set('Access-Control-Allow-Origin', req.get('Origin')); res.send('content'); });`
Implementation:
- Extends
createETagGeneratorto acceptincludeHeadersoption - Updates
res.send()to pass response headers to ETag function - Maintains full backward compatibility with existing ETag modes
- Falls back to body-only hashing when CORS headers are not present
2. Configurable Query Parser Options (Fixes #5878)
Adds ability to configure qs library options when using the extended query parser, addressing silent parameter truncation and providing better security controls.
New API:
app.set('query parser', 'extended'); app.set('query parser options', { parameterLimit: 5000, // Increase from default 1000 arrayLimit: 50, // Increase from default 20 depth: 10, // Increase from default 5 allowPrototypes: false // Prevent prototype pollution });
Problem solved: Query strings exceeding the default 1000 parameter limit resulted in silent data loss. The default allowPrototypes: true setting poses a prototype pollution security risk.
Implementation:
-
compileQueryParsernow accepts optionalqsOptionsparameter -
createExtendedQueryParserfactory function replacesparseExtendedQueryString -
app.set('query parser options')triggers parser recompilation - Does not affect 'simple' parser mode
Backward Compatibility
Both features maintain full backward compatibility:
- Default behavior unchanged for both features
- Works without setting new options
- All existing tests pass (1269 total)
Test Coverage
-
CORS ETag tests: 13 new unit tests in
test/utils.js+ 10 integration tests intest/res.send.cors.js -
Query parser tests: 11 new tests in
test/req.query.options.js - Tests cover limits, security, edge cases, and backward compatibility
Security Considerations
The query parser feature helps prevent prototype pollution attacks by allowing developers to set allowPrototypes: false. The default remains true for backward compatibility, but documentation encourages the secure option.