blob: c9afa34ddd5c6d9678e0e394c0ece0caf8bdaa15 [file] [edit]
package client
import (
"errors"
"io"
"net/http"
)
type hookTransport struct {
base http.RoundTripper
reqHooks []RequestHook
respHooks []ResponseHook
}
func (t *hookTransport) RoundTrip(req *http.Request) (*http.Response, error) {
if len(t.reqHooks) > 0 {
hookReq := req.Clone(req.Context())
if hookReq.Body != nil {
hookReq.Body = hookBody{}
}
if hookReq.GetBody != nil {
hookReq.GetBody = func() (io.ReadCloser, error) {
return hookBody{}, nil
}
}
for _, h := range t.reqHooks {
if err := h(hookReq); err != nil {
// The base transport never takes ownership, so close the original
// request body before returning the hook error.
if req.Body != nil {
_ = req.Body.Close()
}
return nil, err
}
}
// Restore the actual request body after the hooks have run. The
// modified request metadata is preserved on hookReq.
hookReq.Body = req.Body
hookReq.GetBody = req.GetBody
req = hookReq
}
resp, err := t.base.RoundTrip(req)
if err != nil {
return resp, err
}
if len(t.respHooks) > 0 {
hookResp := *resp
if hookResp.Body != nil {
hookResp.Body = hookBody{}
}
for _, h := range t.respHooks {
h(&hookResp)
}
}
return resp, nil
}
type hookBody struct{}
func (hookBody) Read([]byte) (int, error) {
return 0, errors.New("hooks must not read HTTP message body")
}
func (hookBody) Close() error { return nil }