prometheus / prometheus/common
cloneRequest does not copy the header, so round trippers mutate the caller's request
Nobody has claimed this yet.
- Dominant language
- Go
- Stars
- 295
- Forks
- 367
- Avg merge
- 2d 10h
- Merged PRs (30d)
- 18
Description
cloneRequest in config/http_config.go intends a deep copy of the header but does not make one:
r2 := new(http.Request)
*r2 = *r
// Deep copy of the Header.
maps.Copy(r.Header, r2.Header)
After *r2 = *r, r2.Header is the same map as r.Header, so maps.Copy copies it onto itself. The clone shares the caller's header map.
Every round tripper that touches headers is affected, since they all clone first and then modify. headersRoundTripper uses Header.Add, so a reused request gains another copy of every configured header on each round trip. It grows without bound until the server rejects it — a downstream report in Alloy (grafana/alloy#7016) shows ~1000 identical X-Api-Key lines in one request and scrapes failing with 431.
There is a second effect: Header.Set on the clone of a request built without a header panics with assignment to entry in nil map, because the shared nil map is never replaced.
Introduced in 56870db ("Modernize Go"), which replaced the manual copy loop:
- r2.Header = make(http.Header)
- for k, s := range r.Header {
- r2.Header[k] = s
- }
+ maps.Copy(r.Header, r2.Header)
The arguments are also the wrong way round, but swapping them is not enough — the clone needs its own map.
Fix in #982.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start in config/http_config.go at cloneRequest and inspect the round trippers that clone and modify headers. Verify that cloned requests do not mutate the caller's headers, repeated round trips do not duplicate configured headers, and setting a header on a request without headers does not panic.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- go
- Domain
- networking
- Issue type
- Bug
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 85/100