ooni-probe-cli/internal/engine/legacy/netx/oldhttptransport/bodytracer.go
Simone Basso c74c94d616
cleanup: remove ConnID, DialID, TransactionID (#395)
We are not using them anymore. The only nettest still using the
legacy netx implementation is tor, for which setting these fields
is useless, because it performs each measurement into a separate
goroutine. Hence, let us start removing this part of the legacy
netx codebase, which is hampering progress in other areas.

Occurred to me while doing testing for the recent changes in
error mapping (https://github.com/ooni/probe/issues/1505).
2021-06-23 13:36:45 +02:00

78 lines
2.0 KiB
Go

package oldhttptransport
import (
"io"
"net/http"
"time"
"github.com/ooni/probe-cli/v3/internal/engine/legacy/netx/modelx"
)
// BodyTracer performs single HTTP transactions and emits
// measurement events as they happen.
type BodyTracer struct {
Transport http.RoundTripper
}
// NewBodyTracer creates a new Transport.
func NewBodyTracer(roundTripper http.RoundTripper) *BodyTracer {
return &BodyTracer{Transport: roundTripper}
}
// RoundTrip executes a single HTTP transaction, returning
// a Response for the provided Request.
func (t *BodyTracer) RoundTrip(req *http.Request) (resp *http.Response, err error) {
resp, err = t.Transport.RoundTrip(req)
if err != nil {
return
}
// "The http Client and Transport guarantee that Body is always
// non-nil, even on responses without a body or responses with
// a zero-length body." (from the docs)
resp.Body = &bodyWrapper{
ReadCloser: resp.Body,
root: modelx.ContextMeasurementRootOrDefault(req.Context()),
}
return
}
// CloseIdleConnections closes the idle connections.
func (t *BodyTracer) CloseIdleConnections() {
// Adapted from net/http code
type closeIdler interface {
CloseIdleConnections()
}
if tr, ok := t.Transport.(closeIdler); ok {
tr.CloseIdleConnections()
}
}
type bodyWrapper struct {
io.ReadCloser
root *modelx.MeasurementRoot
}
func (bw *bodyWrapper) Read(b []byte) (n int, err error) {
n, err = bw.ReadCloser.Read(b)
bw.root.Handler.OnMeasurement(modelx.Measurement{
HTTPResponseBodyPart: &modelx.HTTPResponseBodyPartEvent{
// "Read reads up to len(p) bytes into p. It returns the number of
// bytes read (0 <= n <= len(p)) and any error encountered."
Data: b[:n],
Error: err,
DurationSinceBeginning: time.Since(bw.root.Beginning),
},
})
return
}
func (bw *bodyWrapper) Close() (err error) {
err = bw.ReadCloser.Close()
bw.root.Handler.OnMeasurement(modelx.Measurement{
HTTPResponseDone: &modelx.HTTPResponseDoneEvent{
DurationSinceBeginning: time.Since(bw.root.Beginning),
},
})
return
}