Skip to content

Commit 050ff1f

Browse files
committed
refactor: improve cache key generation by escaping key delimiters and normalizing method names
1 parent b7913fb commit 050ff1f

3 files changed

Lines changed: 12 additions & 9 deletions

File tree

middleware/cache/cache.go

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1332,12 +1332,12 @@ func canonicalQueryString(uri *fasthttp.URI) string {
13321332
// Pre-scan query string to detect excessive parameters before expensive parsing.
13331333
// This prevents DoS via url.ParseQuery allocating large maps/slices.
13341334
if len(query) > maxQueryBufferSize {
1335-
return boundKeySegment(query)
1335+
return boundKeySegment(escapeKeyDelimiters(query))
13361336
}
13371337

13381338
// Fast path: single key=value pair needs no parsing or sorting
13391339
if strings.IndexByte(query, '&') < 0 {
1340-
return boundKeySegment(query)
1340+
return boundKeySegment(escapeKeyDelimiters(query))
13411341
}
13421342

13431343
// Quick count of potential parameters (ampersands + 1)
@@ -1347,22 +1347,22 @@ func canonicalQueryString(uri *fasthttp.URI) string {
13471347
paramCount++
13481348
if paramCount > maxQueryParams {
13491349
// Too many parameters detected, hash without parsing
1350-
return boundKeySegment(query)
1350+
return boundKeySegment(escapeKeyDelimiters(query))
13511351
}
13521352
}
13531353
}
13541354

13551355
parsed, err := url.ParseQuery(query)
13561356
if err != nil {
1357-
return boundKeySegment(query)
1357+
return boundKeySegment(escapeKeyDelimiters(query))
13581358
}
13591359

13601360
// Double-check actual parameter count after parsing
13611361
actualCount := 0
13621362
for _, values := range parsed {
13631363
actualCount += len(values)
13641364
if actualCount > maxQueryParams {
1365-
return boundKeySegment(query)
1365+
return boundKeySegment(escapeKeyDelimiters(query))
13661366
}
13671367
}
13681368

@@ -1399,7 +1399,7 @@ func canonicalQueryString(uri *fasthttp.URI) string {
13991399
*bufPtr = buf
14001400
keyBufferPool.Put(bufPtr)
14011401
}
1402-
return boundKeySegment(query)
1402+
return boundKeySegment(escapeKeyDelimiters(query))
14031403
}
14041404

14051405
buf = append(buf, escapedKey...)

middleware/cache/cache_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5451,7 +5451,7 @@ func Test_hasDirective(t *testing.T) {
54515451
{"at start", "no-cache, max-age=0", "no-cache", true},
54525452
{"at end", "public, no-cache", "no-cache", true},
54535453
{"not present", "public, max-age=0", "no-cache", false},
5454-
{"partial match (truncated)", "no-cach", "no-cache", false}, // cspell:disable-line -- intentionally truncated directive
5454+
{"shorter token does not match", "no-catch", "no-cache", false},
54555455
{"substring of longer token", "no-cache-extended", "no-cache", false},
54565456

54575457
// Trailing whitespace (#4143)

middleware/cache/config.go

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -169,10 +169,13 @@ func configDefault(config ...Config) Config {
169169
cfg.Methods = ConfigDefault.Methods
170170
} else {
171171
// Normalize method names to uppercase (HTTP methods are case-sensitive
172-
// and c.Method() returns uppercase, e.g. "GET" not "get")
172+
// and c.Method() returns uppercase, e.g. "GET" not "get").
173+
// Copy first to avoid mutating the caller's slice.
174+
normalized := make([]string, len(cfg.Methods))
173175
for i, m := range cfg.Methods {
174-
cfg.Methods[i] = utilsstrings.ToUpper(m)
176+
normalized[i] = utilsstrings.ToUpper(m)
175177
}
178+
cfg.Methods = normalized
176179
}
177180
if cfg.KeyGenerator == nil {
178181
cfg.KeyGenerator = func(c fiber.Ctx) string {

0 commit comments

Comments
 (0)