wrapContentDecompresser in response.go performs an exact (case-sensitive) map key lookup using the Content-Encoding header value (the content-coding token). However, RFC 9110 Section 8.4.1 specifies that content-coding values are case-insensitive:
Content-coding values are used to indicate an encoding transformation that has been
or can be applied to a representation. Content codings are case-insensitive.
This means a server returning Content-Encoding: BR, Br, or bR is valid per the spec, but resty returns ErrContentDecompresserNotFound because the decompresser was registered under lowercase "br".
Where
response.go lines 310-335 (v3branch):
func (r *Response) wrapContentDecompresser() error {
ce := r.Header().Get(hdrContentEncodingKey) // line 311: gets the content-coding
value (e.g. "BR")
if isStringEmpty(ce) {
return nil
}
if decFunc, f := r.Request.client.ContentDecompressers()[ce]; f { // line 316:exact map[string] lookup
// ...
} else {
return ErrContentDecompresserNotFound // line 331: reached when casing differs
}
return nil
}
Header.Get() returns the raw header value as-is. That value is then used as an exact key into the ContentDecompressers() map. Since AddContentDecompresser stores the key as provided (e.g. "br"), a response with Content-Encoding: BR won't match.
Reproduce
package main
import (
"fmt"
"io"
"net/http"
"net/http/httptest"
"resty.dev/v3"
)
func main() {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r
*http.Request) {
w.Header().Set("Content-Encoding", "BR") // uppercase — valid per RFC 911
w.WriteHeader(200)
w.Write([]byte("data"))
}))
defer server.Close()
client := resty.New()
client.AddContentDecompresser("br", func(body io.ReadCloser) (io.ReadCloser, erro
return body, nil // dummy decompresser
})
_, err := client.R().Get(server.URL)
fmt.Println(err) // "resty: content decoder not found"
}
Output:
resty: content decoder not found
Changing "BR" to "br" on the server side makes the error disappear, confirming the lookup is case-sensitive.
Example:
┌──────┬──────────────────┬─────────────────────────────────────────┐
│ Case │ Content-Encoding │ Result │
├──────┼──────────────────┼─────────────────────────────────────────┤
│ 1 │ br (lowercase) │ OK - no error │
├──────┼──────────────────┼─────────────────────────────────────────┤
│ 2 │ BR (uppercase) │ ERROR: resty: content decoder not found │
├──────┼──────────────────┼─────────────────────────────────────────┤
│ 3 │ Br (mixed) │ ERROR: resty: content decoder not found │
└──────┴──────────────────┴─────────────────────────────────────────┘
wrapContentDecompresserinresponse.goperforms an exact (case-sensitive) map key lookup using theContent-Encodingheader value (the content-coding token). However, RFC 9110 Section 8.4.1 specifies that content-coding values are case-insensitive:This means a server returning
Content-Encoding: BR,Br, orbRis valid per the spec, but resty returnsErrContentDecompresserNotFoundbecause the decompresser was registered under lowercase"br".Where
response.golines 310-335 (v3branch):Header.Get()returns the raw header value as-is. That value is then used as an exact key into theContentDecompressers()map. SinceAddContentDecompresserstores the key as provided (e.g."br"), a response withContent-Encoding: BRwon't match.Reproduce
Output:
Changing
"BR"to"br"on the server side makes the error disappear, confirming the lookup is case-sensitive.Example: