d0da224a2a
See https://github.com/ooni/probe/issues/2184 While there, rename `runtimex.PanicIfFalse` to `runtimex.Assert` (it was about time...)
304 lines
8.0 KiB
Go
304 lines
8.0 KiB
Go
package tracex
|
|
|
|
//
|
|
// All the possible events
|
|
//
|
|
|
|
import (
|
|
"errors"
|
|
"net/http"
|
|
"time"
|
|
|
|
"github.com/ooni/probe-cli/v3/internal/netxlite"
|
|
"github.com/ooni/probe-cli/v3/internal/runtimex"
|
|
)
|
|
|
|
// FailureStr is the string representation of an error. The empty
|
|
// string represents the absence of any error.
|
|
type FailureStr string
|
|
|
|
// NewFailureStr creates a FailureStr from an error. If the error is not
|
|
// already an ErrWrapper, it's converted to an ErrWrapper. If the ErrWrapper's
|
|
// Failure is not empty, we return that. Otherwise we return a string
|
|
// indicating that an ErrWrapper has an empty failure (should not happen).
|
|
func NewFailureStr(err error) FailureStr {
|
|
if err == nil {
|
|
return ""
|
|
}
|
|
// The following code guarantees that the error is always wrapped even
|
|
// when we could not actually hit our code that does the wrapping. A case
|
|
// in which this could happen is with context deadline for HTTP when you
|
|
// have wrapped the underlying dialers but not the Transport.
|
|
var errWrapper *netxlite.ErrWrapper
|
|
if !errors.As(err, &errWrapper) {
|
|
err := netxlite.NewTopLevelGenericErrWrapper(err)
|
|
couldConvert := errors.As(err, &errWrapper)
|
|
runtimex.Assert(couldConvert, "we should have an ErrWrapper here")
|
|
}
|
|
s := errWrapper.Failure
|
|
if s == "" {
|
|
s = "unknown_failure: errWrapper.Failure is empty"
|
|
}
|
|
return FailureStr(s)
|
|
}
|
|
|
|
// IsNil returns whether this FailureStr is nil. Technically speaking, the
|
|
// failure cannot be nil, but an empty string is equivalent to nil after
|
|
// we convert using ToFailure(). Also, this type is often called Err, Error,
|
|
// or Failure. So, the resulting code actually reads correct.
|
|
func (fs FailureStr) IsNil() bool {
|
|
return fs == ""
|
|
}
|
|
|
|
// IsNotNil is the opposite of IsNil. Technically speaking, the
|
|
// failure cannot be nil, but an empty string is equivalent to nil after
|
|
// we convert using ToFailure(). Also, this type is often called Err, Error,
|
|
// or Failure. So, the resulting code actually reads correct.
|
|
func (fs FailureStr) IsNotNil() bool {
|
|
return !fs.IsNil()
|
|
}
|
|
|
|
// ToFailure converts a FailureStr to a OONI failure (i.e., a string
|
|
// on error and nil in case of success).
|
|
func (fs FailureStr) ToFailure() (out *string) {
|
|
if fs != "" {
|
|
s := string(fs)
|
|
out = &s
|
|
}
|
|
return
|
|
}
|
|
|
|
// Event is one of the events within a trace.
|
|
type Event interface {
|
|
// Value returns the event value
|
|
Value() *EventValue
|
|
|
|
// Name returns the event name
|
|
Name() string
|
|
}
|
|
|
|
// EventTLSHandshakeStart is the beginning of the TLS handshake.
|
|
type EventTLSHandshakeStart struct {
|
|
V *EventValue
|
|
}
|
|
|
|
func (ev *EventTLSHandshakeStart) Value() *EventValue {
|
|
return ev.V
|
|
}
|
|
|
|
func (ev *EventTLSHandshakeStart) Name() string {
|
|
return "tls_handshake_start"
|
|
}
|
|
|
|
// EventTLSHandshakeDone is the end of the TLS handshake.
|
|
type EventTLSHandshakeDone struct {
|
|
V *EventValue
|
|
}
|
|
|
|
func (ev *EventTLSHandshakeDone) Value() *EventValue {
|
|
return ev.V
|
|
}
|
|
|
|
func (ev *EventTLSHandshakeDone) Name() string {
|
|
return "tls_handshake_done"
|
|
}
|
|
|
|
// EventResolveStart is the beginning of a DNS lookup operation.
|
|
type EventResolveStart struct {
|
|
V *EventValue
|
|
}
|
|
|
|
func (ev *EventResolveStart) Value() *EventValue {
|
|
return ev.V
|
|
}
|
|
|
|
func (ev *EventResolveStart) Name() string {
|
|
return "resolve_start"
|
|
}
|
|
|
|
// EventResolveDone is the end of a DNS lookup operation.
|
|
type EventResolveDone struct {
|
|
V *EventValue
|
|
}
|
|
|
|
func (ev *EventResolveDone) Value() *EventValue {
|
|
return ev.V
|
|
}
|
|
|
|
func (ev *EventResolveDone) Name() string {
|
|
return "resolve_done"
|
|
}
|
|
|
|
// EventDNSRoundTripStart is the start of a DNS round trip.
|
|
type EventDNSRoundTripStart struct {
|
|
V *EventValue
|
|
}
|
|
|
|
func (ev *EventDNSRoundTripStart) Value() *EventValue {
|
|
return ev.V
|
|
}
|
|
|
|
func (ev *EventDNSRoundTripStart) Name() string {
|
|
return "dns_round_trip_start"
|
|
}
|
|
|
|
// EventDNSRoundTripDone is the end of a DNS round trip.
|
|
type EventDNSRoundTripDone struct {
|
|
V *EventValue
|
|
}
|
|
|
|
func (ev *EventDNSRoundTripDone) Value() *EventValue {
|
|
return ev.V
|
|
}
|
|
|
|
func (ev *EventDNSRoundTripDone) Name() string {
|
|
return "dns_round_trip_done"
|
|
}
|
|
|
|
// EventQUICHandshakeStart is the start of a QUIC handshake.
|
|
type EventQUICHandshakeStart struct {
|
|
V *EventValue
|
|
}
|
|
|
|
func (ev *EventQUICHandshakeStart) Value() *EventValue {
|
|
return ev.V
|
|
}
|
|
|
|
func (ev *EventQUICHandshakeStart) Name() string {
|
|
return "quic_handshake_start"
|
|
}
|
|
|
|
// EventQUICHandshakeDone is the end of a QUIC handshake.
|
|
type EventQUICHandshakeDone struct {
|
|
V *EventValue
|
|
}
|
|
|
|
func (ev *EventQUICHandshakeDone) Value() *EventValue {
|
|
return ev.V
|
|
}
|
|
|
|
func (ev *EventQUICHandshakeDone) Name() string {
|
|
return "quic_handshake_done"
|
|
}
|
|
|
|
// EventWriteToOperation summarizes the WriteTo operation.
|
|
type EventWriteToOperation struct {
|
|
V *EventValue
|
|
}
|
|
|
|
func (ev *EventWriteToOperation) Value() *EventValue {
|
|
return ev.V
|
|
}
|
|
|
|
func (ev *EventWriteToOperation) Name() string {
|
|
return netxlite.WriteToOperation
|
|
}
|
|
|
|
// EventReadFromOperation summarizes the ReadFrom operation.
|
|
type EventReadFromOperation struct {
|
|
V *EventValue
|
|
}
|
|
|
|
func (ev *EventReadFromOperation) Value() *EventValue {
|
|
return ev.V
|
|
}
|
|
|
|
func (ev *EventReadFromOperation) Name() string {
|
|
return netxlite.ReadFromOperation
|
|
}
|
|
|
|
// EventHTTPTransactionStart is the beginning of an HTTP transaction.
|
|
type EventHTTPTransactionStart struct {
|
|
V *EventValue
|
|
}
|
|
|
|
func (ev *EventHTTPTransactionStart) Value() *EventValue {
|
|
return ev.V
|
|
}
|
|
|
|
func (ev *EventHTTPTransactionStart) Name() string {
|
|
return "http_transaction_start"
|
|
}
|
|
|
|
// EventHTTPTransactionDone is the end of an HTTP transaction.
|
|
type EventHTTPTransactionDone struct {
|
|
V *EventValue
|
|
}
|
|
|
|
func (ev *EventHTTPTransactionDone) Value() *EventValue {
|
|
return ev.V
|
|
}
|
|
|
|
func (ev *EventHTTPTransactionDone) Name() string {
|
|
return "http_transaction_done"
|
|
}
|
|
|
|
// EventConnectOperation contains information about the connect operation.
|
|
type EventConnectOperation struct {
|
|
V *EventValue
|
|
}
|
|
|
|
func (ev *EventConnectOperation) Value() *EventValue {
|
|
return ev.V
|
|
}
|
|
|
|
func (ev *EventConnectOperation) Name() string {
|
|
return netxlite.ConnectOperation
|
|
}
|
|
|
|
// EventReadOperation contains information about a read operation.
|
|
type EventReadOperation struct {
|
|
V *EventValue
|
|
}
|
|
|
|
func (ev *EventReadOperation) Value() *EventValue {
|
|
return ev.V
|
|
}
|
|
|
|
func (ev *EventReadOperation) Name() string {
|
|
return netxlite.ReadOperation
|
|
}
|
|
|
|
// EventWriteOperation contains information about a write operation.
|
|
type EventWriteOperation struct {
|
|
V *EventValue
|
|
}
|
|
|
|
func (ev *EventWriteOperation) Value() *EventValue {
|
|
return ev.V
|
|
}
|
|
|
|
func (ev *EventWriteOperation) Name() string {
|
|
return netxlite.WriteOperation
|
|
}
|
|
|
|
// Event is one of the events within a trace
|
|
type EventValue struct {
|
|
Addresses []string `json:",omitempty"`
|
|
Address string `json:",omitempty"`
|
|
DNSQuery []byte `json:",omitempty"`
|
|
DNSResponse []byte `json:",omitempty"`
|
|
Data []byte `json:",omitempty"`
|
|
Duration time.Duration `json:",omitempty"`
|
|
Err FailureStr `json:",omitempty"`
|
|
HTTPMethod string `json:",omitempty"`
|
|
HTTPRequestHeaders http.Header `json:",omitempty"`
|
|
HTTPResponseHeaders http.Header `json:",omitempty"`
|
|
HTTPResponseBody []byte `json:",omitempty"`
|
|
HTTPResponseBodyIsTruncated bool `json:",omitempty"`
|
|
HTTPStatusCode int `json:",omitempty"`
|
|
HTTPURL string `json:",omitempty"`
|
|
Hostname string `json:",omitempty"`
|
|
NoTLSVerify bool `json:",omitempty"`
|
|
NumBytes int `json:",omitempty"`
|
|
Proto string `json:",omitempty"`
|
|
TLSServerName string `json:",omitempty"`
|
|
TLSCipherSuite string `json:",omitempty"`
|
|
TLSNegotiatedProto string `json:",omitempty"`
|
|
TLSNextProtos []string `json:",omitempty"`
|
|
TLSPeerCerts [][]byte `json:",omitempty"`
|
|
TLSVersion string `json:",omitempty"`
|
|
Time time.Time `json:",omitempty"`
|
|
Transport string `json:",omitempty"`
|
|
}
|