ooni-probe-cli/internal/measurex/utils.go
Simone Basso 399d2f65da
feat(measurex): refactored measurement library (#528)
This commit introduce a measurement library that consists of
refactored code from earlier websteps experiments.

I am not going to add tests for the time being, because this library
is still a bit in flux, as we finalize websteps.

I will soon though commit documentation explaining in detail how
to use it, which currrently is at https://github.com/ooni/probe-cli/pull/506
and adds a new directory to internal/tutorial.

The core idea of this measurement library is to allow two
measurement modes:

1. tracing, which is what we're currently doing now, and the
tutorial shows how we can rewrite the measurement part of web
connectivity with measurex using less code. Under a tracing
approach, we construct a normal http.Client that however has
tracing configured, we gather events for resolve, connect, TLS
handshake, QUIC handshake, HTTP round trip, etc. and then we
try to make sense of what happened from the events stream;

2. step-by-step, which is what websteps does, and basically
means that after each operation you immediately write into
a Measurement structure its results and immediately draw the
conclusions on what seems odd (which later may become an
anomaly if we see what the test helper measured).

This library is also such that it produces a data format
compatible with the current OONI spec.

This work is part of https://github.com/ooni/probe/issues/1733.
2021-09-30 01:24:08 +02:00

89 lines
2.1 KiB
Go

package measurex
import (
"errors"
"net"
"net/url"
)
//
// Utils
//
// This is where we put free functions.
//
// ALPNForHTTPEndpoint selects the correct ALPN for an HTTP endpoint
// given the network. On failure, we return a nil list.
func ALPNForHTTPEndpoint(network EndpointNetwork) []string {
switch network {
case NetworkQUIC:
return []string{"h3"}
case NetworkTCP:
return []string{"h2", "http/1.1"}
default:
return nil
}
}
// addrStringIfNotNil returns the string of the given addr
// unless the addr is nil, in which case it returns an empty string.
func addrStringIfNotNil(addr net.Addr) (out string) {
if addr != nil {
out = addr.String()
}
return
}
// ErrCannotDeterminePortFromURL indicates that we could not determine
// the correct port from the URL authority and scheme.
var ErrCannotDeterminePortFromURL = errors.New("cannot determine port from URL")
// PortFromURL returns the port determined from the URL or an error.
func PortFromURL(URL *url.URL) (string, error) {
switch {
case URL.Port() != "":
return URL.Port(), nil
case URL.Scheme == "https":
return "443", nil
case URL.Scheme == "http":
return "80", nil
default:
return "", ErrCannotDeterminePortFromURL
}
}
// removeDuplicateEndpoints removes duplicate endpoints from a list of endpoints.
func removeDuplicateEndpoints(epnts ...*Endpoint) (out []*Endpoint) {
duplicates := make(map[string]*Endpoint)
for _, epnt := range epnts {
duplicates[epnt.String()] = epnt
}
for _, epnt := range duplicates {
out = append(out, epnt)
}
return
}
// removeDuplicateHTTPEndpoints removes duplicate endpoints from a list of endpoints.
func removeDuplicateHTTPEndpoints(epnts ...*HTTPEndpoint) (out []*HTTPEndpoint) {
duplicates := make(map[string]*HTTPEndpoint)
for _, epnt := range epnts {
duplicates[epnt.String()] = epnt
}
for _, epnt := range duplicates {
out = append(out, epnt)
}
return
}
// HTTPEndpointsToEndpoints convers HTTPEndpoints to Endpoints
func HTTPEndpointsToEndpoints(in []*HTTPEndpoint) (out []*Endpoint) {
for _, epnt := range in {
out = append(out, &Endpoint{
Network: epnt.Network,
Address: epnt.Address,
})
}
return
}