fix(measurex): use same keys of the OONI data format (#572)
This change should simplify the pipeline's job. Reference issue: https://github.com/ooni/probe/issues/1817. I previously dismissed this possibility, but now it seems clear it is simpler to have a very tabular data format internally and to convert such a format to OONI's data format when serializing. The OONI data format is what the pipeline expects, but processing is easier with a more linear/tabular format.
This commit is contained in:
parent
6f90d29bfa
commit
aa27bbe33f
35 changed files with 1539 additions and 993 deletions
|
|
@ -1,8 +1,11 @@
|
|||
package measurex
|
||||
|
||||
import (
|
||||
"net"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
//
|
||||
|
|
@ -11,6 +14,10 @@ import (
|
|||
// This file defines helpers to serialize to the OONI data format.
|
||||
//
|
||||
|
||||
//
|
||||
// BinaryData
|
||||
//
|
||||
|
||||
// ArchivalBinaryData is the archival format for binary data.
|
||||
type ArchivalBinaryData struct {
|
||||
Data []byte `json:"data"`
|
||||
|
|
@ -29,6 +36,130 @@ func NewArchivalBinaryData(data []byte) (out *ArchivalBinaryData) {
|
|||
return
|
||||
}
|
||||
|
||||
//
|
||||
// NetworkEvent
|
||||
//
|
||||
|
||||
// ArchivalNetworkEvent is the OONI data format representation
|
||||
// of a network event according to df-008-netevents.
|
||||
type ArchivalNetworkEvent struct {
|
||||
// JSON names compatible with df-008-netevents
|
||||
RemoteAddr string `json:"address"`
|
||||
Failure *string `json:"failure"`
|
||||
Count int `json:"num_bytes,omitempty"`
|
||||
Operation string `json:"operation"`
|
||||
Network string `json:"proto"`
|
||||
Finished float64 `json:"t"`
|
||||
Started float64 `json:"started"`
|
||||
|
||||
// Names that are not part of the spec.
|
||||
Oddity Oddity `json:"oddity"`
|
||||
}
|
||||
|
||||
// NewArchivalNetworkEvent converts a network event to its archival format.
|
||||
func NewArchivalNetworkEvent(in *NetworkEvent) *ArchivalNetworkEvent {
|
||||
return &ArchivalNetworkEvent{
|
||||
RemoteAddr: in.RemoteAddr,
|
||||
Failure: in.Failure,
|
||||
Count: in.Count,
|
||||
Operation: in.Operation,
|
||||
Network: in.Network,
|
||||
Finished: in.Finished,
|
||||
Started: in.Started,
|
||||
Oddity: in.Oddity,
|
||||
}
|
||||
}
|
||||
|
||||
// NewArchivalNetworkEventList converts a list of NetworkEvent
|
||||
// to a list of ArchivalNetworkEvent.
|
||||
func NewArchivalNetworkEventList(in []*NetworkEvent) (out []*ArchivalNetworkEvent) {
|
||||
for _, ev := range in {
|
||||
out = append(out, NewArchivalNetworkEvent(ev))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
//
|
||||
// DNSRoundTripEvent
|
||||
//
|
||||
|
||||
// ArchivalDNSRoundTripEvent is the OONI data format representation
|
||||
// of a DNS round trip, which is currently not specified.
|
||||
//
|
||||
// We are trying to use names compatible with the names currently
|
||||
// used by other specifications we currently use.
|
||||
type ArchivalDNSRoundTripEvent struct {
|
||||
Network string `json:"engine"`
|
||||
Address string `json:"resolver_address"`
|
||||
Query *ArchivalBinaryData `json:"raw_query"`
|
||||
Started float64 `json:"started"`
|
||||
Finished float64 `json:"t"`
|
||||
Failure *string `json:"failure"`
|
||||
Reply *ArchivalBinaryData `json:"raw_reply"`
|
||||
}
|
||||
|
||||
// NewArchivalDNSRoundTripEvent converts a DNSRoundTripEvent into is archival format.
|
||||
func NewArchivalDNSRoundTripEvent(in *DNSRoundTripEvent) *ArchivalDNSRoundTripEvent {
|
||||
return &ArchivalDNSRoundTripEvent{
|
||||
Network: in.Network,
|
||||
Address: in.Address,
|
||||
Query: NewArchivalBinaryData(in.Query),
|
||||
Started: in.Started,
|
||||
Finished: in.Finished,
|
||||
Failure: in.Failure,
|
||||
Reply: NewArchivalBinaryData(in.Reply),
|
||||
}
|
||||
}
|
||||
|
||||
// NewArchivalDNSRoundTripEventList converts a DNSRoundTripEvent
|
||||
// list to the corresponding archival format.
|
||||
func NewArchivalDNSRoundTripEventList(in []*DNSRoundTripEvent) (out []*ArchivalDNSRoundTripEvent) {
|
||||
for _, ev := range in {
|
||||
out = append(out, NewArchivalDNSRoundTripEvent(ev))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
//
|
||||
// HTTPRoundTrip
|
||||
//
|
||||
|
||||
// ArchivalHTTPRequest is the archival format of an HTTP
|
||||
// request according to df-001-http.md.
|
||||
type ArchivalHTTPRequest struct {
|
||||
Method string `json:"method"`
|
||||
URL string `json:"url"`
|
||||
Headers ArchivalHeaders `json:"headers"`
|
||||
}
|
||||
|
||||
// ArchivalHTTPResponse is the archival format of an HTTP
|
||||
// response according to df-001-http.md.
|
||||
type ArchivalHTTPResponse struct {
|
||||
// Names consistent with df-001-http.md
|
||||
Code int64 `json:"code"`
|
||||
Headers ArchivalHeaders `json:"headers"`
|
||||
Body *ArchivalBinaryData `json:"body"`
|
||||
BodyIsTruncated bool `json:"body_is_truncated"`
|
||||
|
||||
// Fields not part of the spec
|
||||
BodyLength int64 `json:"x_body_length"`
|
||||
BodyIsUTF8 bool `json:"x_body_is_utf8"`
|
||||
}
|
||||
|
||||
// ArchivalHTTPRoundTripEvent is the archival format of an
|
||||
// HTTP response according to df-001-http.md.
|
||||
type ArchivalHTTPRoundTripEvent struct {
|
||||
// JSON names following the df-001-httpt data format.
|
||||
Failure *string `json:"failure"`
|
||||
Request *HTTPRequest `json:"request"`
|
||||
Response *HTTPResponse `json:"response"`
|
||||
Finished float64 `json:"t"`
|
||||
Started float64 `json:"started"`
|
||||
|
||||
// Names not in the specification
|
||||
Oddity Oddity `json:"oddity"`
|
||||
}
|
||||
|
||||
// ArchivalHeaders is a list of HTTP headers.
|
||||
type ArchivalHeaders map[string]string
|
||||
|
||||
|
|
@ -54,6 +185,64 @@ func NewArchivalHeaders(in http.Header) (out ArchivalHeaders) {
|
|||
return
|
||||
}
|
||||
|
||||
// NewArchivalHTTPRoundTripEvent converts an HTTPRoundTrip to its archival format.
|
||||
func NewArchivalHTTPRoundTripEvent(in *HTTPRoundTripEvent) *ArchivalHTTPRoundTripEvent {
|
||||
return &ArchivalHTTPRoundTripEvent{
|
||||
Failure: in.Failure,
|
||||
Request: &HTTPRequest{
|
||||
Method: in.Method,
|
||||
URL: in.URL,
|
||||
Headers: NewArchivalHeaders(in.RequestHeaders),
|
||||
},
|
||||
Response: &HTTPResponse{
|
||||
Code: in.StatusCode,
|
||||
Headers: NewArchivalHeaders(in.ResponseHeaders),
|
||||
Body: NewArchivalBinaryData(in.ResponseBody),
|
||||
BodyLength: in.ResponseBodyLength,
|
||||
BodyIsTruncated: in.ResponseBodyIsTruncated,
|
||||
BodyIsUTF8: in.ResponseBodyIsUTF8,
|
||||
},
|
||||
Finished: in.Finished,
|
||||
Started: in.Started,
|
||||
Oddity: in.Oddity,
|
||||
}
|
||||
}
|
||||
|
||||
// NewArchivalHTTPRoundTripEventList converts a list of
|
||||
// HTTPRoundTripEvent to a list of ArchivalRoundTripEvent.
|
||||
func NewArchivalHTTPRoundTripEventList(in []*HTTPRoundTripEvent) (out []*ArchivalHTTPRoundTripEvent) {
|
||||
for _, ev := range in {
|
||||
out = append(out, NewArchivalHTTPRoundTripEvent(ev))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
//
|
||||
// QUICTLSHandshakeEvent
|
||||
//
|
||||
|
||||
// ArchivalQUICTLSHandshakeEvent is the archival data format for a
|
||||
// QUIC or TLS handshake event according to df-006-tlshandshake.
|
||||
type ArchivalQUICTLSHandshakeEvent struct {
|
||||
// JSON names compatible with df-006-tlshandshake
|
||||
CipherSuite string `json:"cipher_suite"`
|
||||
Failure *string `json:"failure"`
|
||||
NegotiatedProto string `json:"negotiated_proto"`
|
||||
TLSVersion string `json:"tls_version"`
|
||||
PeerCerts []*ArchivalBinaryData `json:"peer_certificates"`
|
||||
Finished float64 `json:"t"`
|
||||
|
||||
// JSON names that are consistent with the
|
||||
// spirit of the spec but are not in it
|
||||
RemoteAddr string `json:"address"`
|
||||
SNI string `json:"server_name"` // used in prod
|
||||
ALPN []string `json:"alpn"`
|
||||
SkipVerify bool `json:"no_tls_verify"` // used in prod
|
||||
Oddity Oddity `json:"oddity"`
|
||||
Network string `json:"proto"`
|
||||
Started float64 `json:"started"`
|
||||
}
|
||||
|
||||
// NewArchivalTLSCertList builds a new []ArchivalBinaryData
|
||||
// from a list of raw x509 certificates data.
|
||||
func NewArchivalTLSCerts(in [][]byte) (out []*ArchivalBinaryData) {
|
||||
|
|
@ -66,13 +255,341 @@ func NewArchivalTLSCerts(in [][]byte) (out []*ArchivalBinaryData) {
|
|||
return
|
||||
}
|
||||
|
||||
// NewArchivalFailure creates an archival failure from an error. We
|
||||
// cannot round trip an error using JSON, so we serialize to this
|
||||
// intermediate format that is a sort of Optional<string>.
|
||||
func NewArchivalFailure(err error) *string {
|
||||
if err == nil {
|
||||
return nil
|
||||
// NewArchivalQUICTLSHandshakeEvent converts a QUICTLSHandshakeEvent
|
||||
// to its archival data format.
|
||||
func NewArchivalQUICTLSHandshakeEvent(in *QUICTLSHandshakeEvent) *ArchivalQUICTLSHandshakeEvent {
|
||||
return &ArchivalQUICTLSHandshakeEvent{
|
||||
CipherSuite: in.CipherSuite,
|
||||
Failure: in.Failure,
|
||||
NegotiatedProto: in.NegotiatedProto,
|
||||
TLSVersion: in.TLSVersion,
|
||||
PeerCerts: NewArchivalTLSCerts(in.PeerCerts),
|
||||
Finished: in.Finished,
|
||||
RemoteAddr: in.RemoteAddr,
|
||||
SNI: in.SNI,
|
||||
ALPN: in.ALPN,
|
||||
SkipVerify: in.SkipVerify,
|
||||
Oddity: in.Oddity,
|
||||
Network: in.Network,
|
||||
Started: in.Started,
|
||||
}
|
||||
s := err.Error()
|
||||
return &s
|
||||
}
|
||||
|
||||
// NewArchivalQUICTLSHandshakeEventList converts a list of
|
||||
// QUICTLSHandshakeEvent to a list of ArchivalQUICTLSHandshakeEvent.
|
||||
func NewArchivalQUICTLSHandshakeEventList(in []*QUICTLSHandshakeEvent) (out []*ArchivalQUICTLSHandshakeEvent) {
|
||||
for _, ev := range in {
|
||||
out = append(out, NewArchivalQUICTLSHandshakeEvent(ev))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
//
|
||||
// DNSLookup
|
||||
//
|
||||
|
||||
// ArchivalDNSLookupAnswer is the archival format of a
|
||||
// DNS lookup answer according to df-002-dnst.
|
||||
type ArchivalDNSLookupAnswer struct {
|
||||
// JSON names compatible with df-002-dnst's spec
|
||||
Type string `json:"answer_type"`
|
||||
IPv4 string `json:"ipv4,omitempty"`
|
||||
IPv6 string `json:"ivp6,omitempty"`
|
||||
|
||||
// Names not part of the spec.
|
||||
ALPN string `json:"alpn,omitempty"`
|
||||
}
|
||||
|
||||
// ArchivalDNSLookupEvent is the archival data format
|
||||
// of a DNS lookup according to df-002-dnst.
|
||||
type ArchivalDNSLookupEvent struct {
|
||||
// fields inside df-002-dnst
|
||||
Answers []ArchivalDNSLookupAnswer `json:"answers"`
|
||||
Network string `json:"engine"`
|
||||
Failure *string `json:"failure"`
|
||||
Domain string `json:"hostname"`
|
||||
QueryType string `json:"query_type"`
|
||||
Address string `json:"resolver_address"`
|
||||
Finished float64 `json:"t"`
|
||||
|
||||
// Names not part of the spec.
|
||||
Started float64 `json:"started"`
|
||||
Oddity Oddity `json:"oddity"`
|
||||
}
|
||||
|
||||
// NewArchivalDNSLookupAnswers creates a list of ArchivalDNSLookupAnswer.
|
||||
func NewArchivalDNSLookupAnswers(in *DNSLookupEvent) (out []ArchivalDNSLookupAnswer) {
|
||||
for _, ip := range in.A {
|
||||
out = append(out, ArchivalDNSLookupAnswer{
|
||||
Type: "A",
|
||||
IPv4: ip,
|
||||
})
|
||||
}
|
||||
for _, ip := range in.AAAA {
|
||||
out = append(out, ArchivalDNSLookupAnswer{
|
||||
Type: "AAAA",
|
||||
IPv6: ip,
|
||||
})
|
||||
}
|
||||
for _, alpn := range in.ALPN {
|
||||
out = append(out, ArchivalDNSLookupAnswer{
|
||||
Type: "ALPN",
|
||||
ALPN: alpn,
|
||||
})
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// NewArchivalDNSLookupEvent converts a DNSLookupEvent
|
||||
// to its archival representation.
|
||||
func NewArchivalDNSLookupEvent(in *DNSLookupEvent) *ArchivalDNSLookupEvent {
|
||||
return &ArchivalDNSLookupEvent{
|
||||
Answers: NewArchivalDNSLookupAnswers(in),
|
||||
Network: in.Network,
|
||||
Failure: in.Failure,
|
||||
Domain: in.Domain,
|
||||
QueryType: in.QueryType,
|
||||
Address: in.Address,
|
||||
Finished: in.Finished,
|
||||
Started: in.Started,
|
||||
Oddity: in.Oddity,
|
||||
}
|
||||
}
|
||||
|
||||
// NewArchivalDNSLookupEventList converts a list of DNSLookupEvent
|
||||
// to a list of ArchivalDNSLookupEvent.
|
||||
func NewArchivalDNSLookupEventList(in []*DNSLookupEvent) (out []*ArchivalDNSLookupEvent) {
|
||||
for _, ev := range in {
|
||||
out = append(out, NewArchivalDNSLookupEvent(ev))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
//
|
||||
// TCPConnect
|
||||
//
|
||||
|
||||
// ArchivalTCPConnect is the archival form of TCP connect
|
||||
// events in compliance with df-005-tcpconnect.
|
||||
type ArchivalTCPConnect struct {
|
||||
// Names part of the spec.
|
||||
IP string `json:"ip"`
|
||||
Port int64 `json:"port"`
|
||||
Finished float64 `json:"t"`
|
||||
Status *ArchivalTCPConnectStatus `json:"status"`
|
||||
|
||||
// Names not part of the spec.
|
||||
Started float64 `json:"started"`
|
||||
Oddity Oddity `json:"oddity"`
|
||||
}
|
||||
|
||||
// ArchivalTCPConnectStatus contains the status of a TCP connect.
|
||||
type ArchivalTCPConnectStatus struct {
|
||||
Blocked bool `json:"blocked"`
|
||||
Failure *string `json:"failure"`
|
||||
Success bool `json:"success"`
|
||||
}
|
||||
|
||||
// NewArchivalTCPConnect converts a NetworkEvent to an ArchivalTCPConnect.
|
||||
func NewArchivalTCPConnect(in *NetworkEvent) *ArchivalTCPConnect {
|
||||
// We ignore errors because values come from Go code that
|
||||
// emits correct serialization of TCP/UDP addresses.
|
||||
addr, port, _ := net.SplitHostPort(in.RemoteAddr)
|
||||
portnum, _ := strconv.Atoi(port)
|
||||
return &ArchivalTCPConnect{
|
||||
IP: addr,
|
||||
Port: int64(portnum),
|
||||
Finished: in.Finished,
|
||||
Status: &ArchivalTCPConnectStatus{
|
||||
Blocked: in.Failure != nil,
|
||||
Failure: in.Failure,
|
||||
Success: in.Failure == nil,
|
||||
},
|
||||
Started: in.Started,
|
||||
Oddity: in.Oddity,
|
||||
}
|
||||
}
|
||||
|
||||
// NewArchivalTCPConnectList converts a list of NetworkEvent
|
||||
// to a list of ArchivalTCPConnect. In doing that, the code
|
||||
// only considers "connect" events using the TCP protocol.
|
||||
func NewArchivalTCPConnectList(in []*NetworkEvent) (out []*ArchivalTCPConnect) {
|
||||
for _, ev := range in {
|
||||
if ev.Operation != "connect" {
|
||||
continue
|
||||
}
|
||||
switch ev.Network {
|
||||
case "tcp", "tcp4", "tcp6":
|
||||
out = append(out, NewArchivalTCPConnect(ev))
|
||||
default:
|
||||
// nothing
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
//
|
||||
// URLMeasurement
|
||||
//
|
||||
|
||||
// ArchivalURLMeasurement is the archival representation of URLMeasurement
|
||||
type ArchivalURLMeasurement struct {
|
||||
URL string `json:"url"`
|
||||
DNS []*ArchivalDNSMeasurement `json:"dns"`
|
||||
Endpoints []*ArchivalHTTPEndpointMeasurement `json:"endpoints"`
|
||||
TH *ArchivalTHMeasurement `json:"th"`
|
||||
TotalRuntime time.Duration `json:"x_total_runtime"`
|
||||
DNSRuntime time.Duration `json:"x_dns_runtime"`
|
||||
THRuntime time.Duration `json:"x_th_runtime"`
|
||||
EpntsRuntime time.Duration `json:"x_epnts_runtime"`
|
||||
}
|
||||
|
||||
// NewArchivalURLMeasurement creates the archival representation
|
||||
// of an URLMeasurement data structure.
|
||||
func NewArchivalURLMeasurement(in *URLMeasurement) *ArchivalURLMeasurement {
|
||||
return &ArchivalURLMeasurement{
|
||||
URL: in.URL,
|
||||
DNS: NewArchivalDNSMeasurementList(in.DNS),
|
||||
Endpoints: NewArchivalHTTPEndpointMeasurementList(in.Endpoints),
|
||||
TH: NewArchivalTHMeasurement(in.TH),
|
||||
TotalRuntime: in.TotalRuntime,
|
||||
DNSRuntime: in.DNSRuntime,
|
||||
THRuntime: in.THRuntime,
|
||||
EpntsRuntime: in.EpntsRuntime,
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// EndpointMeasurement
|
||||
//
|
||||
|
||||
// ArchivalEndpointMeasurement is the archival representation of EndpointMeasurement.
|
||||
type ArchivalEndpointMeasurement struct {
|
||||
// Network is the network of this endpoint.
|
||||
Network EndpointNetwork `json:"network"`
|
||||
|
||||
// Address is the address of this endpoint.
|
||||
Address string `json:"address"`
|
||||
|
||||
// An EndpointMeasurement is a Measurement.
|
||||
*ArchivalMeasurement
|
||||
}
|
||||
|
||||
// NewArchivalEndpointMeasurement converts an EndpointMeasurement
|
||||
// to the corresponding archival data format.
|
||||
func NewArchivalEndpointMeasurement(in *EndpointMeasurement) *ArchivalEndpointMeasurement {
|
||||
return &ArchivalEndpointMeasurement{
|
||||
Network: in.Network,
|
||||
Address: in.Address,
|
||||
ArchivalMeasurement: NewArchivalMeasurement(in.Measurement),
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// THMeasurement
|
||||
//
|
||||
|
||||
// ArchivalTHMeasurement is the archival representation of THMeasurement.
|
||||
type ArchivalTHMeasurement struct {
|
||||
DNS []*ArchivalDNSMeasurement `json:"dns"`
|
||||
Endpoints []*ArchivalHTTPEndpointMeasurement `json:"endpoints"`
|
||||
}
|
||||
|
||||
// NewArchivalTHMeasurement creates the archival representation of THMeasurement.
|
||||
func NewArchivalTHMeasurement(in *THMeasurement) *ArchivalTHMeasurement {
|
||||
return &ArchivalTHMeasurement{
|
||||
DNS: NewArchivalDNSMeasurementList(in.DNS),
|
||||
Endpoints: NewArchivalHTTPEndpointMeasurementList(in.Endpoints),
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// DNSMeasurement
|
||||
//
|
||||
|
||||
// ArchivalDNSMeasurement is the archival representation of DNSMeasurement.
|
||||
type ArchivalDNSMeasurement struct {
|
||||
Domain string `json:"domain"`
|
||||
*ArchivalMeasurement
|
||||
}
|
||||
|
||||
// NewArchivalDNSMeasurement converts a DNSMeasurement to an ArchivalDNSMeasurement.
|
||||
func NewArchivalDNSMeasurement(in *DNSMeasurement) *ArchivalDNSMeasurement {
|
||||
return &ArchivalDNSMeasurement{
|
||||
Domain: in.Domain,
|
||||
ArchivalMeasurement: NewArchivalMeasurement(in.Measurement),
|
||||
}
|
||||
}
|
||||
|
||||
// NewArchivalDNSMeasurementList converts a list of DNSMeasurement
|
||||
// to a list of ArchivalDNSMeasurement.
|
||||
func NewArchivalDNSMeasurementList(in []*DNSMeasurement) (out []*ArchivalDNSMeasurement) {
|
||||
for _, m := range in {
|
||||
out = append(out, NewArchivalDNSMeasurement(m))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
//
|
||||
// HTTPEndpointMeasurement
|
||||
//
|
||||
|
||||
// ArchivalHTTPEndpointMeasurement is the archival representation
|
||||
// of an HTTPEndpointMeasurement.
|
||||
type ArchivalHTTPEndpointMeasurement struct {
|
||||
URL string `json:"url"`
|
||||
Network EndpointNetwork `json:"network"`
|
||||
Address string `json:"address"`
|
||||
*ArchivalMeasurement
|
||||
}
|
||||
|
||||
// NewArchivalHTTPEndpointMeasurement converts an HTTPEndpointMeasurement
|
||||
// to an ArchivalHTTPEndpointMeasurement.
|
||||
func NewArchivalHTTPEndpointMeasurement(in *HTTPEndpointMeasurement) *ArchivalHTTPEndpointMeasurement {
|
||||
return &ArchivalHTTPEndpointMeasurement{
|
||||
URL: in.URL,
|
||||
Network: in.Network,
|
||||
Address: in.Address,
|
||||
ArchivalMeasurement: NewArchivalMeasurement(in.Measurement),
|
||||
}
|
||||
}
|
||||
|
||||
// NewArchivalHTTPEndpointMeasurementList converts a list of HTTPEndpointMeasurement
|
||||
// to a list of ArchivalHTTPEndpointMeasurement.
|
||||
func NewArchivalHTTPEndpointMeasurementList(in []*HTTPEndpointMeasurement) (out []*ArchivalHTTPEndpointMeasurement) {
|
||||
for _, m := range in {
|
||||
out = append(out, NewArchivalHTTPEndpointMeasurement(m))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
//
|
||||
// Measurement
|
||||
//
|
||||
|
||||
// ArchivalMeasurement is the archival representation of a Measurement.
|
||||
type ArchivalMeasurement struct {
|
||||
NetworkEvents []*ArchivalNetworkEvent `json:"network_events,omitempty"`
|
||||
DNSEvents []*ArchivalDNSRoundTripEvent `json:"dns_events,omitempty"`
|
||||
Queries []*ArchivalDNSLookupEvent `json:"queries,omitempty"`
|
||||
TCPConnect []*ArchivalTCPConnect `json:"tcp_connect,omitempty"`
|
||||
TLSHandshakes []*ArchivalQUICTLSHandshakeEvent `json:"tls_handshakes,omitempty"`
|
||||
QUICHandshakes []*ArchivalQUICTLSHandshakeEvent `json:"quic_handshakes,omitempty"`
|
||||
Requests []*ArchivalHTTPRoundTripEvent `json:"requests,omitempty"`
|
||||
}
|
||||
|
||||
// NewArchivalMeasurement converts a Measurement to ArchivalMeasurement.
|
||||
func NewArchivalMeasurement(in *Measurement) *ArchivalMeasurement {
|
||||
out := &ArchivalMeasurement{
|
||||
NetworkEvents: NewArchivalNetworkEventList(in.ReadWrite),
|
||||
DNSEvents: NewArchivalDNSRoundTripEventList(in.DNSRoundTrip),
|
||||
Queries: nil, // done below
|
||||
TCPConnect: NewArchivalTCPConnectList(in.Connect),
|
||||
TLSHandshakes: NewArchivalQUICTLSHandshakeEventList(in.TLSHandshake),
|
||||
QUICHandshakes: NewArchivalQUICTLSHandshakeEventList(in.QUICHandshake),
|
||||
Requests: NewArchivalHTTPRoundTripEventList(in.HTTPRoundTrip),
|
||||
}
|
||||
out.Queries = append(out.Queries, NewArchivalDNSLookupEventList(in.LookupHost)...)
|
||||
out.Queries = append(out.Queries, NewArchivalDNSLookupEventList(in.LookupHTTPSSvc)...)
|
||||
return out
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue