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) + } + } +}