Summary
Request.Marshal() does not round-trip a request faithfully. Two distinct facets:
Facet A: Marshal() destroys the original body (non-idempotent)
In Marshal(), the body is read with io.ReadAll(r.Body) but never restored:
if r.Body != nil {
body, err = io.ReadAll(r.Body)
...
}
After Marshal() returns, r.Body is fully consumed. As a result:
- Calling
Marshal() a second time produces a request with an empty body.
- Calling
Do() or Retry() after a Marshal() sends an empty body.
Facet B: ProxyURL and ResponseCharacterEncoding are silently dropped
The internal serializableRequest struct omits ProxyURL and ResponseCharacterEncoding, so Marshal() -> UnmarshalRequest() loses them. ResponseCharacterEncoding is a user-set, pre-fetch field consumed by fixCharset; losing it on a queued or persisted request changes behavior (silently falls back to auto-detect).
Reproduction
- Marshal the same request twice -> the second result has
"Body":"".
- Set
ProxyURL / ResponseCharacterEncoding, Marshal then UnmarshalRequest -> both come back empty.
Fix
Restore r.Body after reading, and add ProxyURL + ResponseCharacterEncoding to serializableRequest (populated in Marshal, restored in UnmarshalRequest). PR incoming.
Summary
Request.Marshal()does not round-trip a request faithfully. Two distinct facets:Facet A: Marshal() destroys the original body (non-idempotent)
In
Marshal(), the body is read withio.ReadAll(r.Body)but never restored:After
Marshal()returns,r.Bodyis fully consumed. As a result:Marshal()a second time produces a request with an empty body.Do()orRetry()after aMarshal()sends an empty body.Facet B: ProxyURL and ResponseCharacterEncoding are silently dropped
The internal
serializableRequeststruct omitsProxyURLandResponseCharacterEncoding, soMarshal()->UnmarshalRequest()loses them.ResponseCharacterEncodingis a user-set, pre-fetch field consumed byfixCharset; losing it on a queued or persisted request changes behavior (silently falls back to auto-detect).Reproduction
"Body":"".ProxyURL/ResponseCharacterEncoding, Marshal then UnmarshalRequest -> both come back empty.Fix
Restore
r.Bodyafter reading, and addProxyURL+ResponseCharacterEncodingtoserializableRequest(populated inMarshal, restored inUnmarshalRequest). PR incoming.