func drainBody(b io.ReadCloser) (r1, r2 io.ReadCloser, err error) {
var buf bytes.Buffer
if _, err = buf.ReadFrom(b); err != nil {
- return nil, nil, err
+ return nil, b, err
}
if err = b.Close(); err != nil {
- return nil, nil, err
+ return nil, b, err
}
return ioutil.NopCloser(&buf), ioutil.NopCloser(bytes.NewReader(buf.Bytes())), nil
}
return nil
}
-// DumpRequest returns the as-received wire representation of req, optionally
-// including the request body, for debugging. It is for use in servers; use
-// DumpRequestOut for client requests.
+// DumpRequest returns the given request in its HTTP/1.x wire
+// representation. It should only be used by servers to debug client
+// requests. The returned representation is an approximation only;
+// some details of the initial request are lost while parsing it into
+// an http.Request. In particular, the order and case of header field
+// names are lost. The order of values in multi-valued headers is kept
+// intact. HTTP/2 requests are dumped in HTTP/1.x form, not in their
+// original binary representations.
+//
+// If body is true, DumpRequest also returns the body. To do so, it
+// consumes req.Body and then replaces it with a new io.ReadCloser
+// that yields the same bytes. If DumpRequest returns an error,
+// the state of req is undefined.
//
-// DumpRequest is semantically a no-op, but in order to
-// dump the body, it reads the body data into memory and
-// changes req.Body to refer to the in-memory copy.
// The documentation for http.Request.Write details which fields
-// of req are used.
+// of req are included in the dump.
func DumpRequest(req *http.Request, body bool) (dump []byte, err error) {
save := req.Body
if !body || req.Body == nil {
} else {
save, req.Body, err = drainBody(req.Body)
if err != nil {
- return
+ return nil, err
}
}
} else {
save, resp.Body, err = drainBody(resp.Body)
if err != nil {
- return
+ return nil, err
}
}
err = resp.Write(&b)