From 00f8cfa3d3d52fe5181fd58181d47bdebf8b080e Mon Sep 17 00:00:00 2001 From: Burrup Lambert Date: Tue, 28 Jul 2026 15:10:20 +0100 Subject: [PATCH] fix: reset stale order on pooled headerSorter in SortedKeyValues headerSorter instances are pooled and shared between SortedKeyValuesBy and SortedKeyValues, but SortedKeyValues never cleared hs.order. A sorter previously used for an ordered sort would keep its order map and apply it to a later orderless sort, producing the wrong header order whenever the new header's lowercased keys collide with entries in the stale order map. Reset hs.order before sorting in SortedKeyValues and add a regression test. --- header.go | 4 ++++ header_test.go | 25 +++++++++++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/header.go b/header.go index b6481131..9561f97c 100644 --- a/header.go +++ b/header.go @@ -223,6 +223,10 @@ func (h Header) SortedKeyValues(exclude map[string]bool) (kvs []HeaderKeyValues, mutex.RUnlock() } hs.kvs = kvs + // Reset any order left on the sorter by a previous SortedKeyValuesBy + // call, otherwise a pooled sorter sorts by the stale order instead of + // lexicographically. + hs.order = nil sort.Sort(hs) return kvs, hs } diff --git a/header_test.go b/header_test.go index 3d9361bd..066950b5 100644 --- a/header_test.go +++ b/header_test.go @@ -359,3 +359,28 @@ func TestHTTP1HeaderOrder(t *testing.T) { t.Fatalf("got:\n%swant:\n%s", buf.String(), expected) } } + +func TestHeaderSorterPoolReuse(t *testing.T) { + // A sorter used by SortedKeyValuesBy keeps its order map. When it is + // pulled from the pool again by SortedKeyValues (no order), the stale + // order must not be used. + ordered := Header{ + "Zebra": {"1"}, + "Apple": {"2"}, + } + // Deliberately the reverse of lexicographic order. + _, hs := ordered.SortedKeyValuesBy(map[string]int{"zebra": 0, "apple": 1}, nil) + headerSorterPool.Put(hs) + + plain := Header{ + "Apple": {"1"}, + "Banana": {"2"}, + "Zebra": {"3"}, + } + kvs, _ := plain.SortedKeyValues(nil) + for i := 1; i < len(kvs); i++ { + if kvs[i-1].Key > kvs[i].Key { + t.Fatalf("keys not sorted lexicographically: %q before %q", kvs[i-1].Key, kvs[i].Key) + } + } +}