dsl

package
v0.3.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 3, 2023 License: GPL-3.0 Imports: 21 Imported by: 0

Documentation

Overview

Package dsl contains a DSL for defining network experiments.

Design

The DSL is both internal and external. When you write code in terms of its primitives, such as TCPConnect and TLSHandshake, you compose a measurement pipeline consisting of multiple pipeline Stage. The composed pipeline is a toplevel Stage that runs all the underlying Stage performing the basic operations, such as TCPConnect and TLSHandshake. You can then run the composed pipeline by calling the Stage Run method and using a Runtime that fits your use case. Use a MeasurexliteRuntime if you need to collect Observations to create OONI measurements; use a MinimalRuntime otherwise.

You can also serialize the measurement pipeline to JSON by converting a Stage to a SerializableASTNode using the Stage ASTNode method. In turn, you can obtain a JSON serialization by calling the encoding/json.Marshal function on the SerializableASTNode. Then, you can parse the JSON using encoding/json.Unmarshal to obtain a LoadableASTNode. In turn, you can transform a LoadableASTNode to a RunnableASTNode by using the ASTLoader.Load method. The RunnableASTNode is a wrapper for a Stage that has a generic-typing interface (e.g., uses any) and performs type checking at runtime. By calling a RunnableASTNode Run method, you run the generic pipeline and obtain the same results you would have obtained had you called the original composed pipeline Stage Run method.

Design Goals

We designed this DSL for three reasons:

1. The internal DSL allows us to write code to generate the external DSL and, because the internal DSL code is also executable, we can run and test it directly and we can be confident that composition works because each Stage is bound to a specific input and output type and Go performs type checking.

2. The external DSL allows us to serve richer input to OONI Probes (e.g., we can serve measurement pipelines with specific options, including options that control the TLS and QUIC handshake, and we can combine multiple DNS lookup operations together). All in all, this functionality allows us to modify the implementation of simpler experiments such as Facebook Messenger using the OONI backend. In turn, this allows us to improve the implementation of experiments or fix small bugs (e.g., changes in the CA required by Signal) without releasing a new version of OONI Probe.

3. The external DSL also allows us to serve experimental nettests to OONI Probes that allow us to either perform A/B testing of nettests implementation or collect additional/follow-up measurements to understand censorship.

Because of the above requirements, the DSL is not Turing complete. The only operation it offers is that of composing together network measurement primitives using the Compose function and syntactic sugar such as Compose3, Compose4, and other composition functions. In addition, it also includes specialized composition operations such as DNSLookupParallel for performing DNS lookups in parallel and conversion operations such as MakeEndpointsForPort and NewEndpointPipeline that allow to compose DNS lookups and endpoint operations. In other words, all you can build with the DSL is a tree that you can visit to measure the internet. There are no loops and there are no conditional statements.

Writing filters

We additionally include functionality to register filtering functions in the implementation of experiments, to compute the test keys. The key feature enabling us to register filters is ASTLoader.RegisterCustomLoaderRule. Also, the IfFilterExists allows ignoring filters that a OONI Probe does not support during ASTLoader.Load. This functionality allows us to serve to probes ASTs including new filters that only new probes support. Older probes will honor the IfFilterExists Stage and replace unknow filters with the Identity Stage. This means that older probe would not compute some new top-level test keys but would otherwise collect the same Observations collected by new probes.

When writing filters you MUST remember the following:

1. ErrException indicates that something went very wrong (you can test for this class of errors using the IsErrException predicate);

2. ErrSkip indicates that a previous stage determined that subsequent stages should not run (you can use IsErrSkip for this class of errors);

3. ErrDNSLookup means a DNS lookup failed (you can use IsErrDNSLookup);

4. ErrTCPConnect indicates that TCP connect failed (you can use IsErrTCPConnect);

5. ErrTLSHandshake indicates a TLS handshake failure (use IsErrTLSHandshake);

6. ErrQUICHandshake relates to QUIC handhsake failures (use IsErrQUICHandshake);

7. ErrHTTPTransaction is an HTTP transaction error (use IsErrHTTPTransaction).

You SHOULD only flip test keys when the error you set corresponds to the operation for which you are filtering errors. For example, if you filter the results of a TLS handshake, your code SHOULD use IsErrTLSHandshake to ensure that the error you are witnessing has indeed been caused by a TLS handshake.

History

This package is an incremental evolution of the dslx design document where we added code to express the whole measurement pipeline using the DSL, rather than depending on imperative code to connect the DNS and the endpoints subpipelines. In turn, this new functionality allows us to serialize a measurement pipeline and serve it to the OONI Probes. The original motivation of making network experiments more intuitive and composable still holds.

Example (ExternalDSL)

This example shows how to use the internal DSL for measuring. We create a measurement pipeline using functions in the dsl package. Then, we serialize the pipeline to an AST, load the AST again, and finally execute the loaded AST.

package main

import (
	"context"
	"encoding/json"
	"fmt"
	"time"

	"github.com/apex/log"
	"github.com/ooni/2023-05-richer-input/pkg/dsl"
	"github.com/ooni/probe-engine/pkg/runtimex"
)

// newComplexMeasurementPipeline creates a complex measurement pipeline where we
// measure two domain names in parallel: www.example.com and www.example.org.
//
// The www.example.com measurement pipeline uses three DNS resolvers in parallel and
// measures HTTP, HTTPS, and HTTP3 endpoints generated from the DNS lookup results.
//
// The www.example.org pipeline is significantly simpler. It uses getaddrinfo for DNS
// lookups and only measures the HTTPS endpoints derived from DNS lookup results.
func newComplexMeasurementPipeline() dsl.Stage[*dsl.Void, *dsl.Void] {

	pipeline := dsl.RunStagesInParallel(

		dsl.Compose3(
			dsl.DomainName("www.example.com"),

			dsl.DNSLookupParallel(
				dsl.DNSLookupGetaddrinfo(),
				dsl.DNSLookupUDP("[2001:4860:4860::8844]:53"),
				dsl.DNSLookupUDP("8.8.4.4:53"),
			),

			dsl.MeasureMultipleEndpoints(

				dsl.Compose(
					dsl.MakeEndpointsForPort(80),
					dsl.NewEndpointPipeline(
						dsl.Compose4(
							dsl.TCPConnect(),
							dsl.HTTPConnectionTCP(),
							dsl.HTTPTransaction(),
							dsl.Discard[*dsl.HTTPResponse](),
						),
					),
				),

				dsl.Compose(
					dsl.MakeEndpointsForPort(443),
					dsl.NewEndpointPipeline(
						dsl.Compose5(
							dsl.TCPConnect(),
							dsl.TLSHandshake(),
							dsl.HTTPConnectionTLS(),
							dsl.HTTPTransaction(),
							dsl.Discard[*dsl.HTTPResponse](),
						),
					),
				),

				dsl.Compose(
					dsl.MakeEndpointsForPort(443),
					dsl.NewEndpointPipeline(
						dsl.Compose4(
							dsl.QUICHandshake(),
							dsl.HTTPConnectionQUIC(),
							dsl.HTTPTransaction(),
							dsl.Discard[*dsl.HTTPResponse](),
						),
					),
				),
			),
		),

		dsl.Compose4(
			dsl.DomainName("www.example.org"),

			dsl.DNSLookupGetaddrinfo(),

			dsl.MakeEndpointsForPort(443),

			dsl.NewEndpointPipeline(
				dsl.Compose5(
					dsl.TCPConnect(),
					dsl.TLSHandshake(),
					dsl.HTTPConnectionTLS(),
					dsl.HTTPTransaction(),
					dsl.Discard[*dsl.HTTPResponse](),
				),
			),
		),
	)

	return pipeline
}

func main() {
	// Create the measurement pipeline.
	pipeline := newComplexMeasurementPipeline()

	// Serialize the measurement pipeline AST to JSON.
	rawAST := runtimex.Try1(json.Marshal(pipeline.ASTNode()))

	// Typically, you would send the serialized AST to the probe via some OONI backend API
	// such as the future check-in v2 API. In this example, we keep it simple and just pretend
	// we received the raw AST from some OONI backend API.

	// Parse the serialized JSON into an AST.
	var loadable dsl.LoadableASTNode
	runtimex.Try0(json.Unmarshal(rawAST, &loadable))

	// Create a loader for loading the AST we just parsed.
	loader := dsl.NewASTLoader()

	// Convert the AST we just loaded into a runnable AST node.
	runnable := runtimex.Try1(loader.Load(&loadable))

	// Create a measurement runtime using measurexlite as the underlying
	// measurement library such that we also collect observations.
	rtx := dsl.NewMeasurexliteRuntime(log.Log, time.Now())

	// Create the void input for the pipeline. We need to cast the input to
	// a generic Maybe because there's dynamic type checking when running an
	// AST we loaded from the network.
	input := dsl.NewValue(&dsl.Void{}).AsGeneric()

	// Run the measurement pipeline. The [dsl.Try] function converts the pipeline result to
	// an error if and only if an exception occurred when executing the code. We return an
	// exception when some unexpected condition occurred when measuring (e.g., the pipeline
	// defines an invalid HTTP method and we cannot create an HTTP request).
	if err := dsl.Try(runnable.Run(context.Background(), rtx, input)); err != nil {
		log.WithError(err).Fatal("pipeline failed")
	}

	// Obtain observatins describing the performed measurement.
	observations := dsl.ReduceObservations(rtx.ExtractObservations()...)

	// Print the number of observations on the stdout.
	fmt.Printf(
		"%v %v %v %v %v %v",
		len(observations.NetworkEvents) > 0,
		len(observations.QUICHandshakes) > 0,
		len(observations.Queries) > 0,
		len(observations.Requests) > 0,
		len(observations.TCPConnect) > 0,
		len(observations.TLSHandshakes) > 0,
	)
}
Output:

true true true true true true
Example (InternalDSL)

This example shows how to use the internal DSL for measuring. We create a measurement pipeline using functions in the dsl package and then we run the pipeline.

package main

import (
	"context"
	"fmt"
	"time"

	"github.com/apex/log"
	"github.com/ooni/2023-05-richer-input/pkg/dsl"
)

// newComplexMeasurementPipeline creates a complex measurement pipeline where we
// measure two domain names in parallel: www.example.com and www.example.org.
//
// The www.example.com measurement pipeline uses three DNS resolvers in parallel and
// measures HTTP, HTTPS, and HTTP3 endpoints generated from the DNS lookup results.
//
// The www.example.org pipeline is significantly simpler. It uses getaddrinfo for DNS
// lookups and only measures the HTTPS endpoints derived from DNS lookup results.
func newComplexMeasurementPipeline() dsl.Stage[*dsl.Void, *dsl.Void] {

	pipeline := dsl.RunStagesInParallel(

		dsl.Compose3(
			dsl.DomainName("www.example.com"),

			dsl.DNSLookupParallel(
				dsl.DNSLookupGetaddrinfo(),
				dsl.DNSLookupUDP("[2001:4860:4860::8844]:53"),
				dsl.DNSLookupUDP("8.8.4.4:53"),
			),

			dsl.MeasureMultipleEndpoints(

				dsl.Compose(
					dsl.MakeEndpointsForPort(80),
					dsl.NewEndpointPipeline(
						dsl.Compose4(
							dsl.TCPConnect(),
							dsl.HTTPConnectionTCP(),
							dsl.HTTPTransaction(),
							dsl.Discard[*dsl.HTTPResponse](),
						),
					),
				),

				dsl.Compose(
					dsl.MakeEndpointsForPort(443),
					dsl.NewEndpointPipeline(
						dsl.Compose5(
							dsl.TCPConnect(),
							dsl.TLSHandshake(),
							dsl.HTTPConnectionTLS(),
							dsl.HTTPTransaction(),
							dsl.Discard[*dsl.HTTPResponse](),
						),
					),
				),

				dsl.Compose(
					dsl.MakeEndpointsForPort(443),
					dsl.NewEndpointPipeline(
						dsl.Compose4(
							dsl.QUICHandshake(),
							dsl.HTTPConnectionQUIC(),
							dsl.HTTPTransaction(),
							dsl.Discard[*dsl.HTTPResponse](),
						),
					),
				),
			),
		),

		dsl.Compose4(
			dsl.DomainName("www.example.org"),

			dsl.DNSLookupGetaddrinfo(),

			dsl.MakeEndpointsForPort(443),

			dsl.NewEndpointPipeline(
				dsl.Compose5(
					dsl.TCPConnect(),
					dsl.TLSHandshake(),
					dsl.HTTPConnectionTLS(),
					dsl.HTTPTransaction(),
					dsl.Discard[*dsl.HTTPResponse](),
				),
			),
		),
	)

	return pipeline
}

func main() {
	// Create the measurement pipeline.
	pipeline := newComplexMeasurementPipeline()

	// Create a measurement runtime using measurexlite as the underlying
	// measurement library such that we also collect observations.
	rtx := dsl.NewMeasurexliteRuntime(log.Log, time.Now())

	// Create the void input for the pipeline.
	input := dsl.NewValue(&dsl.Void{})

	// Run the measurement pipeline. The [dsl.Try] function converts the pipeline result to
	// an error if and only if an exception occurred when executing the code. We return an
	// exception when some unexpected condition occurred when measuring (e.g., the pipeline
	// defines an invalid HTTP method and we cannot create an HTTP request).
	if err := dsl.Try(pipeline.Run(context.Background(), rtx, input)); err != nil {
		log.WithError(err).Fatal("pipeline failed")
	}

	// Obtain observatins describing the performed measurement.
	observations := dsl.ReduceObservations(rtx.ExtractObservations()...)

	// Print the number of observations on the stdout.
	fmt.Printf(
		"%v %v %v %v %v %v",
		len(observations.NetworkEvents) > 0,
		len(observations.QUICHandshakes) > 0,
		len(observations.Queries) > 0,
		len(observations.Requests) > 0,
		len(observations.TCPConnect) > 0,
		len(observations.TLSHandshakes) > 0,
	)
}
Output:

true true true true true true

Index

Examples

Constants

This section is empty.

Variables

View Source
var ErrInvalidCert = errors.New("dsl: invalid PEM-encoded certificate")

ErrInvalidCert is returned when we encounter an invalid PEM-encoded certificate.

View Source
var ErrInvalidNumberOfChildren = errors.New("dsl: invalid number of children")

ErrInvalidNumberOfChildren indicates that the AST contains an invalid number of children.

View Source
var ErrNoSuchStage = errors.New("dsl: no such stage")

ErrNoSuchStage is returned when there's no such stage with the given name.

View Source
var ErrSkip = errors.New("dsl: skip this stage")

ErrSkip is a sentinel error indicating to a Stage that it should not run.

Functions

func AsSpecificMaybe

func AsSpecificMaybe[T any](v Maybe[any]) (Maybe[T], *ErrException)

AsSpecificMaybe converts a generic Maybe[any] to a specific Maybe[T].

func IsErrDNSLookup

func IsErrDNSLookup(err error) bool

IsErrDNSLookup returns true when an error is an ErrDNSLookup.

func IsErrException

func IsErrException(err error) bool

IsErrException returns true when an error is an ErrException.

func IsErrHTTPTransaction

func IsErrHTTPTransaction(err error) bool

IsErrHTTPTransaction returns true when an error is an ErrHTTPTransaction.

func IsErrQUICHandshake

func IsErrQUICHandshake(err error) bool

IsErrQUICHandshake returns true when an error is an ErrQUICHandshake.

func IsErrSkip

func IsErrSkip(err error) bool

IsErrSkip returns true when an error is an ErrSkip.

func IsErrTCPConnect

func IsErrTCPConnect(err error) bool

IsErrTCPConnect returns true when an error is an ErrTCPConnect.

func IsErrTLSHandshake

func IsErrTLSHandshake(err error) bool

IsErrTLSHandshake returns true when an error is an ErrTLSHandshake.

func ParallelRun

func ParallelRun[T any](ctx context.Context, parallelism int, workers ...Worker[T]) []T

ParallelRun runs the given functions using the given number of workers and returns a slice containing the result produced by each function. When the number of workers is zero or negative, this function will use a single worker.

func Try

func Try[T any](results Maybe[T]) error

Try inspects the results of running a pipeline and returns an error if the returned error is an ErrException, nil otherwise.

func ValidDomainNames

func ValidDomainNames(domains ...string) bool

ValidDomainNames returns whether the given list of domain names is valid.

func ValidEndpoints

func ValidEndpoints(endpoints ...string) bool

ValidEndpoints returns whether the given list of endpoints is valid.

func ValidIPAddrs

func ValidIPAddrs(addrs ...string) bool

ValidIPAddrs returns whether the given list contains valid IP addresses.

func ValidPorts

func ValidPorts(ports ...string) bool

ValidPorts returns true if the given ports are valid.

Types

type ASTLoader

type ASTLoader struct {
	// contains filtered or unexported fields
}

ASTLoader loads a LoadableASTNode and transforms it into a RunnableASTNode. The zero value of this struct is not ready to use; please, use the NewASTLoader factory.

func NewASTLoader

func NewASTLoader() *ASTLoader

NewASTLoader constructs a new ASTLoader and calls [ASTLoader.RegisterCustomLoadRule] for all the built-in ASTLoaderRule. There's a built-in ASTLoaderRule for each Stage defined by this package.

func (*ASTLoader) Load

func (al *ASTLoader) Load(node *LoadableASTNode) (RunnableASTNode, error)

Load loads a *LoadableASTNode producing the correspoinding *RunnableASTNode.

func (*ASTLoader) LoadChildren

func (al *ASTLoader) LoadChildren(node *LoadableASTNode) (out []RunnableASTNode, err error)

LoadChildren is a convenience function to load all the node's children when implementing an ASTLoaderRule.

func (*ASTLoader) LoadEmptyArguments

func (al *ASTLoader) LoadEmptyArguments(node *LoadableASTNode) error

LoadEmptyArguments is a convenience function for loading empty arguments when implementing an ASTLoaderRule.

func (*ASTLoader) RegisterCustomLoaderRule

func (al *ASTLoader) RegisterCustomLoaderRule(rule ASTLoaderRule)

RegisterCustomLoaderRule registers a custom ASTLoaderRule. Note that the NewASTLoader factory already registers all the built-in loader rules defined by this package.

func (*ASTLoader) RequireExactlyNumChildren

func (al *ASTLoader) RequireExactlyNumChildren(node *LoadableASTNode, num int) error

RequireExactlyNumChildren is a convenience function to validate the number of children when implementing an ASTLoaderRule.

type ASTLoaderRule

type ASTLoaderRule interface {
	Load(loader *ASTLoader, node *LoadableASTNode) (RunnableASTNode, error)
	StageName() string
}

ASTLoaderRule is a rule to load a *LoadableASTNode and convert it into a RunnableASTNode.

type DNSLookupResult

type DNSLookupResult struct {
	// Domain is the domain we tried to resolve.
	Domain string

	// Addresses contains resolved addresses (if any).
	Addresses []string
}

DNSLookupResult is the result of a DNS lookup operation.

type Endpoint

type Endpoint struct {
	// Address is the endpoint address consisting of an IP address
	// followed by ":" and by a port. When the address is an IPv6 address,
	// you MUST quote it using "[" and "]". The following strings
	//
	// - 8.8.8.8:53
	//
	// - [2001:4860:4860::8888]:53
	//
	// are valid UDP-resolver-endpoint addresses.
	Address string

	// Domain is the domain associated with the endpoint.
	Domain string
}

Endpoint is a network endpoint.

type ErrDNSLookup

type ErrDNSLookup struct {
	Err error
}

ErrDNSLookup wraps errors occurred during a DNS lookup operation.

func (*ErrDNSLookup) Error

func (exc *ErrDNSLookup) Error() string

Error implements error.

func (*ErrDNSLookup) Unwrap

func (exc *ErrDNSLookup) Unwrap() error

Unwrap supports errors.Unwrap.

type ErrException

type ErrException struct {
	Err error
}

ErrException indicates an exceptional condition occurred. For example, we cannot create an *http.Request because the URL is invalid. We use this wrapper error to distinguish between measurement errors and fundamental errors.

func NewErrException

func NewErrException(format string, v ...any) *ErrException

NewErrException creates a new exception with a formatted string as value.

func NewTypeErrException

func NewTypeErrException[Expected any](got any) *ErrException

NewTypeErrException creates a new exception for the given types.

func (*ErrException) Error

func (exc *ErrException) Error() string

Error implements error.

func (*ErrException) Unwrap

func (exc *ErrException) Unwrap() error

Unwrap supports errors.Unwrap.

type ErrHTTPTransaction

type ErrHTTPTransaction struct {
	Err error
}

ErrHTTPTransaction wraps errors occurred during an HTTP transaction operation.

func (*ErrHTTPTransaction) Error

func (exc *ErrHTTPTransaction) Error() string

Error implements error.

func (*ErrHTTPTransaction) Unwrap

func (exc *ErrHTTPTransaction) Unwrap() error

Unwrap supports errors.Unwrap.

type ErrInvalidAddressList

type ErrInvalidAddressList struct {
	Addresses []string
}

ErrInvalidAddressList indicates that an address list is invalid.

func (*ErrInvalidAddressList) Error

func (err *ErrInvalidAddressList) Error() string

Error implements error.

type ErrInvalidDomain

type ErrInvalidDomain struct {
	Domain string
}

ErrInvalidDomain indicates that a domain is invalid.

func (*ErrInvalidDomain) Error

func (err *ErrInvalidDomain) Error() string

Error implements error.

type ErrInvalidEndpoint

type ErrInvalidEndpoint struct {
	Endpoint string
}

ErrInvalidEndpoint indicates than an endpoint is invalid.

func (*ErrInvalidEndpoint) Error

func (err *ErrInvalidEndpoint) Error() string

Error implements error.

type ErrQUICHandshake

type ErrQUICHandshake struct {
	Err error
}

ErrQUICHandshake wraps errors occurred during a QUIC handshake operation.

func (*ErrQUICHandshake) Error

func (exc *ErrQUICHandshake) Error() string

Error implements error.

func (*ErrQUICHandshake) Unwrap

func (exc *ErrQUICHandshake) Unwrap() error

Unwrap supports errors.Unwrap.

type ErrTCPConnect

type ErrTCPConnect struct {
	Err error
}

ErrTCPConnect wraps errors occurred during a TCP connect operation.

func (*ErrTCPConnect) Error

func (exc *ErrTCPConnect) Error() string

Error implements error.

func (*ErrTCPConnect) Unwrap

func (exc *ErrTCPConnect) Unwrap() error

Unwrap supports errors.Unwrap.

type ErrTLSHandshake

type ErrTLSHandshake struct {
	Err error
}

ErrTLSHandshake wraps errors occurred during a TLS handshake operation.

func (*ErrTLSHandshake) Error

func (exc *ErrTLSHandshake) Error() string

Error implements error.

func (*ErrTLSHandshake) Unwrap

func (exc *ErrTLSHandshake) Unwrap() error

Unwrap supports errors.Unwrap.

type HTTPConnection

type HTTPConnection struct {
	// Address is the remote address.
	Address string

	// Domain is the domain we're measuring.
	Domain string

	// Network is the underlying con network ("tcp" or "udp").
	Network string

	// Scheme is the URL scheme to use.
	Scheme string

	// TLSNegotiatedProtocol is the OPTIONAL negotiated protocol (e.g., "h3").
	TLSNegotiatedProtocol string

	// Trace is the trace we're using.
	Trace Trace

	// Transport is the HTTP transport wrapping the underlying conn.
	Transport model.HTTPTransport
}

HTTPConnection is a connection usable by HTTP code.

type HTTPResponse

type HTTPResponse struct {
	// Address is the original endpoint address.
	Address string

	// Domain is the original domain.
	Domain string

	// Network is the original endpoint network.
	Network string

	// Request is the request we sent to the remote host.
	Request *http.Request

	// Response is the response.
	Response *http.Response

	// ResponseBodySnapshot is the body snapshot.
	ResponseBodySnapshot []byte
}

HTTPResponse is the result of performing an HTTP transaction.

type HTTPTransactionOption

type HTTPTransactionOption func(c *httpTransactionConfig)

HTTPTransactionOption is an option for configuring an HTTP transaction.

func HTTPTransactionOptionAccept

func HTTPTransactionOptionAccept(value string) HTTPTransactionOption

HTTPTransactionOptionAccept sets the Accept header.

func HTTPTransactionOptionAcceptLanguage

func HTTPTransactionOptionAcceptLanguage(value string) HTTPTransactionOption

HTTPTransactionOptionAcceptLanguage sets the Accept-Language header.

func HTTPTransactionOptionHost

func HTTPTransactionOptionHost(value string) HTTPTransactionOption

HTTPTransactionOptionHost sets the Host header.

func HTTPTransactionOptionMethod

func HTTPTransactionOptionMethod(value string) HTTPTransactionOption

HTTPTransactionOptionMethod sets the method.

func HTTPTransactionOptionReferer

func HTTPTransactionOptionReferer(value string) HTTPTransactionOption

HTTPTransactionOptionReferer sets the referer.

func HTTPTransactionOptionResponseBodySnapshotSize

func HTTPTransactionOptionResponseBodySnapshotSize(value int) HTTPTransactionOption

HTTPTransactionOptionResponseBodySnapshotSize sets the maximum response body snapshot size.

func HTTPTransactionOptionURLHost

func HTTPTransactionOptionURLHost(value string) HTTPTransactionOption

HTTPTransactionOptionURLHost sets the URL host.

func HTTPTransactionOptionURLPath

func HTTPTransactionOptionURLPath(value string) HTTPTransactionOption

HTTPTransactionOptionURLPath sets the URL path.

func HTTPTransactionOptionURLScheme

func HTTPTransactionOptionURLScheme(value string) HTTPTransactionOption

HTTPTransactionOptionURLScheme sets the URL scheme.

func HTTPTransactionOptionUserAgent

func HTTPTransactionOptionUserAgent(value string) HTTPTransactionOption

HTTPTransactionOptionUserAgent sets the User-Agent header.

type Identity

type Identity[T any] struct{}

Identity returns a filter that copies its input to its output. We define as filter a Stage where the input and output type are the same type.

func (*Identity[T]) ASTNode

func (*Identity[T]) ASTNode() *SerializableASTNode

ASTNode implements Stage.

func (*Identity[T]) Run

func (*Identity[T]) Run(ctx context.Context, rtx Runtime, input Maybe[T]) Maybe[T]

Run implements Stage.

type LoadableASTNode

type LoadableASTNode struct {
	// StageName is the name of the DSL stage to execute.
	StageName string `json:"stage_name"`

	// Arguments contains stage-specific arguments.
	Arguments json.RawMessage `json:"arguments"`

	// Children contains stage-specific children nodes.
	Children []*LoadableASTNode `json:"children"`
}

LoadableASTNode is the loadable representation of a SerializableASTNode.

type Maybe

type Maybe[T any] struct {
	Error error
	Value T
}

Maybe contains either value or an error.

func NewError

func NewError[T any](err error) Maybe[T]

NewError constructs a Maybe with the given error.

func NewValue

func NewValue[T any](value T) Maybe[T]

NewValue constructs a Maybe with the given value.

func (Maybe[T]) AsGeneric

func (m Maybe[T]) AsGeneric() Maybe[any]

AsGeneric converts a specific Maybe[T] to a generic Maybe[any].

type MeasurexliteRuntime

type MeasurexliteRuntime struct {
	// contains filtered or unexported fields
}

MeasurexliteRuntime is a Runtime using measurexlite to collect Observations.

func NewMeasurexliteRuntime

func NewMeasurexliteRuntime(logger model.Logger, zeroTime time.Time) *MeasurexliteRuntime

NewMeasurexliteRuntime creates a new MeasurexliteRuntime.

func (*MeasurexliteRuntime) Close

func (r *MeasurexliteRuntime) Close() error

Close implements Runtime.

func (*MeasurexliteRuntime) ExtractObservations

func (r *MeasurexliteRuntime) ExtractObservations() []*Observations

ExtractObservations removes the observations from the runtime and returns them. This method is safe to call from multiple goroutine contexts because locks a mutex.

func (*MeasurexliteRuntime) Logger

func (r *MeasurexliteRuntime) Logger() model.Logger

Logger implements Runtime.

func (*MeasurexliteRuntime) NewTrace

func (r *MeasurexliteRuntime) NewTrace() Trace

NewTrace implements Runtime.

func (*MeasurexliteRuntime) SaveObservations

func (r *MeasurexliteRuntime) SaveObservations(observations ...*Observations)

SaveObservations implements Runtime.

func (*MeasurexliteRuntime) TrackCloser

func (r *MeasurexliteRuntime) TrackCloser(conn io.Closer)

TrackCloser implements Runtime.

func (*MeasurexliteRuntime) TrackQUICConn

func (r *MeasurexliteRuntime) TrackQUICConn(conn quic.EarlyConnection)

TrackQUICConn implements Runtime.

type MinimalRuntime

type MinimalRuntime struct {
	// contains filtered or unexported fields
}

MinimalRuntime is a minimal Runtime. This Runtime mostly does not do anything but incrementing the Trace index and tracking connections so that they're closed by MinimalRuntime.Close. The zero value of this struct is not ready to use; construct using the NewMinimalRuntime factory function.

func NewMinimalRuntime

func NewMinimalRuntime(logger model.Logger) *MinimalRuntime

NewMinimalRuntime creates a minimal Runtime that increments Trace indexes and tracks connections.

func (*MinimalRuntime) Close

func (r *MinimalRuntime) Close() error

Close implements Runtime.

func (*MinimalRuntime) ExtractObservations

func (r *MinimalRuntime) ExtractObservations() []*Observations

ExtractObservations implements Trace.

func (*MinimalRuntime) Logger

func (r *MinimalRuntime) Logger() model.Logger

Logger implements Runtime.

func (*MinimalRuntime) NewTrace

func (r *MinimalRuntime) NewTrace() Trace

NewTrace implements Runtime.

func (*MinimalRuntime) SaveObservations

func (r *MinimalRuntime) SaveObservations(observations ...*Observations)

SaveObservations implements Runtime.

func (*MinimalRuntime) TrackCloser

func (r *MinimalRuntime) TrackCloser(conn io.Closer)

TrackCloser implements Runtime.

func (*MinimalRuntime) TrackQUICConn

func (r *MinimalRuntime) TrackQUICConn(conn quic.EarlyConnection)

TrackQUICConn implements Runtime.

type Observations

type Observations struct {
	// NetworkEvents contains I/O events.
	NetworkEvents []*model.ArchivalNetworkEvent `json:"network_events"`

	// Queries contains the DNS queries results.
	Queries []*model.ArchivalDNSLookupResult `json:"queries"`

	// Requests contains HTTP request results.
	Requests []*model.ArchivalHTTPRequestResult `json:"requests"`

	// TCPConnect contains the TCP connect results.
	TCPConnect []*model.ArchivalTCPConnectResult `json:"tcp_connect"`

	// TLSHandshakes contains the TLS handshakes results.
	TLSHandshakes []*model.ArchivalTLSOrQUICHandshakeResult `json:"tls_handshakes"`

	// QUICHandshakes contains the QUIC handshakes results.
	QUICHandshakes []*model.ArchivalTLSOrQUICHandshakeResult `json:"quic_handshakes"`
}

Observations contains measurement results grouped by type.

func NewObservations

func NewObservations() *Observations

NewObservations creates an empty set of Observations.

func ReduceObservations

func ReduceObservations(inputs ...*Observations) (output *Observations)

ReduceObservations reduces a list of observations to a single Observations.

func (*Observations) AsMap

func (obs *Observations) AsMap() map[string]any

AsMap returns a map from string to any containing the observations.

type QUICConnection

type QUICConnection struct {
	// Address is the endpoint address we're using.
	Address string

	// Conn is the established QUIC connection.
	Conn quic.EarlyConnection

	// Domain is the domain we're using.
	Domain string

	// TLSConfig is the TLS configuration we used.
	TLSConfig *tls.Config

	// TLSNegotiatedProtocol is the result of the ALPN negotiation.
	TLSNegotiatedProtocol string

	// Trace is the trace we're using.
	Trace Trace
}

QUICConnection is the results of a QUIC handshake.

type QUICHandshakeOption

type QUICHandshakeOption func(config *quicHandshakeConfig)

QUICHandshakeOption is an option for configuring the QUIC handshake.

func QUICHandshakeOptionALPN

func QUICHandshakeOptionALPN(value ...string) QUICHandshakeOption

QUICHandshakeOptionALPN configures the ALPN.

func QUICHandshakeOptionSNI

func QUICHandshakeOptionSNI(value string) QUICHandshakeOption

QUICHandshakeOptionSNI allows to configure the SNI.

func QUICHandshakeOptionSkipVerify

func QUICHandshakeOptionSkipVerify(value bool) QUICHandshakeOption

QUICHandshakeOptionSkipVerify allows to disable certificate verification.

func QUICHandshakeOptionX509Certs

func QUICHandshakeOptionX509Certs(value ...string) QUICHandshakeOption

QUICHandshakeOptionX509Certs allows to configure a custom root CA.

type RunnableASTNode

type RunnableASTNode interface {
	ASTNode() *SerializableASTNode
	Run(ctx context.Context, rtx Runtime, input Maybe[any]) Maybe[any]
}

RunnableASTNode is the runnable representation of a LoadableASTNode. It is functionally equivalent to a DSL Stage except that type checking happens at runtime.

type RunnableASTNodeStage

type RunnableASTNodeStage[A, B any] struct {
	N RunnableASTNode
}

RunnableASTNodeStage adapts a RunnableASTNode to be a Stage.

func (*RunnableASTNodeStage[A, B]) ASTNode

func (sx *RunnableASTNodeStage[A, B]) ASTNode() *SerializableASTNode

ASTNode implements Stage.

func (*RunnableASTNodeStage[A, B]) Run

func (sx *RunnableASTNodeStage[A, B]) Run(ctx context.Context, rtx Runtime, input Maybe[A]) Maybe[B]

Run implements Stage.

type Runtime

type Runtime interface {
	// ExtractObservations removes and returns the observations saved so far.
	ExtractObservations() []*Observations

	// Close closes all the closers tracker by the runtime.
	Close() error

	// NewTrace creates a new measurement trace.
	NewTrace() Trace

	// Logger returns the logger to use.
	Logger() model.Logger

	// SaveObservations saves the given observations into the runtime.
	SaveObservations(observations ...*Observations)

	// TrackCloser register the closer to be closed by Close.
	TrackCloser(io.Closer)

	// TrackQUICConn registers the given conn to be closed by Close.
	TrackQUICConn(quic.EarlyConnection)
}

Runtime is a runtime for running measurement pipelines.

type SerializableASTNode

type SerializableASTNode struct {
	// StageName is the name of the DSL stage to execute.
	StageName string `json:"stage_name"`

	// Arguments contains stage-specific arguments.
	Arguments any `json:"arguments"`

	// Children contains stage-specific children nodes.
	Children []*SerializableASTNode `json:"children"`
}

SerializableASTNode is the serializable representation of a Stage.

type Stage

type Stage[A, B any] interface {
	//ASTNode converts this stage to an ASTNode.
	ASTNode() *SerializableASTNode

	// Run runs the pipeline stage.
	Run(ctx context.Context, rtx Runtime, input Maybe[A]) Maybe[B]
}

Stage is a stage of a measurement pipeline.

func Compose

func Compose[A, B, C any](s1 Stage[A, B], s2 Stage[B, C]) Stage[A, C]

Compose composes two Stage together.

func Compose10

func Compose10[
	T0,
	T1,
	T2,
	T3,
	T4,
	T5,
	T6,
	T7,
	T8,
	T9,
	T10 any,
](
	s1 Stage[T0, T1],
	s2 Stage[T1, T2],
	s3 Stage[T2, T3],
	s4 Stage[T3, T4],
	s5 Stage[T4, T5],
	s6 Stage[T5, T6],
	s7 Stage[T6, T7],
	s8 Stage[T7, T8],
	s9 Stage[T8, T9],
	s10 Stage[T9, T10],
) Stage[T0, T10]

Compose10 composes 10 Stage together.

func Compose11

func Compose11[
	T0,
	T1,
	T2,
	T3,
	T4,
	T5,
	T6,
	T7,
	T8,
	T9,
	T10,
	T11 any,
](
	s1 Stage[T0, T1],
	s2 Stage[T1, T2],
	s3 Stage[T2, T3],
	s4 Stage[T3, T4],
	s5 Stage[T4, T5],
	s6 Stage[T5, T6],
	s7 Stage[T6, T7],
	s8 Stage[T7, T8],
	s9 Stage[T8, T9],
	s10 Stage[T9, T10],
	s11 Stage[T10, T11],
) Stage[T0, T11]

Compose11 composes 11 Stage together.

func Compose12

func Compose12[
	T0,
	T1,
	T2,
	T3,
	T4,
	T5,
	T6,
	T7,
	T8,
	T9,
	T10,
	T11,
	T12 any,
](
	s1 Stage[T0, T1],
	s2 Stage[T1, T2],
	s3 Stage[T2, T3],
	s4 Stage[T3, T4],
	s5 Stage[T4, T5],
	s6 Stage[T5, T6],
	s7 Stage[T6, T7],
	s8 Stage[T7, T8],
	s9 Stage[T8, T9],
	s10 Stage[T9, T10],
	s11 Stage[T10, T11],
	s12 Stage[T11, T12],
) Stage[T0, T12]

Compose12 composes 12 Stage together.

func Compose13

func Compose13[
	T0,
	T1,
	T2,
	T3,
	T4,
	T5,
	T6,
	T7,
	T8,
	T9,
	T10,
	T11,
	T12,
	T13 any,
](
	s1 Stage[T0, T1],
	s2 Stage[T1, T2],
	s3 Stage[T2, T3],
	s4 Stage[T3, T4],
	s5 Stage[T4, T5],
	s6 Stage[T5, T6],
	s7 Stage[T6, T7],
	s8 Stage[T7, T8],
	s9 Stage[T8, T9],
	s10 Stage[T9, T10],
	s11 Stage[T10, T11],
	s12 Stage[T11, T12],
	s13 Stage[T12, T13],
) Stage[T0, T13]

Compose13 composes 13 Stage together.

func Compose14

func Compose14[
	T0,
	T1,
	T2,
	T3,
	T4,
	T5,
	T6,
	T7,
	T8,
	T9,
	T10,
	T11,
	T12,
	T13,
	T14 any,
](
	s1 Stage[T0, T1],
	s2 Stage[T1, T2],
	s3 Stage[T2, T3],
	s4 Stage[T3, T4],
	s5 Stage[T4, T5],
	s6 Stage[T5, T6],
	s7 Stage[T6, T7],
	s8 Stage[T7, T8],
	s9 Stage[T8, T9],
	s10 Stage[T9, T10],
	s11 Stage[T10, T11],
	s12 Stage[T11, T12],
	s13 Stage[T12, T13],
	s14 Stage[T13, T14],
) Stage[T0, T14]

Compose14 composes 14 Stage together.

func Compose15

func Compose15[
	T0,
	T1,
	T2,
	T3,
	T4,
	T5,
	T6,
	T7,
	T8,
	T9,
	T10,
	T11,
	T12,
	T13,
	T14,
	T15 any,
](
	s1 Stage[T0, T1],
	s2 Stage[T1, T2],
	s3 Stage[T2, T3],
	s4 Stage[T3, T4],
	s5 Stage[T4, T5],
	s6 Stage[T5, T6],
	s7 Stage[T6, T7],
	s8 Stage[T7, T8],
	s9 Stage[T8, T9],
	s10 Stage[T9, T10],
	s11 Stage[T10, T11],
	s12 Stage[T11, T12],
	s13 Stage[T12, T13],
	s14 Stage[T13, T14],
	s15 Stage[T14, T15],
) Stage[T0, T15]

Compose15 composes 15 Stage together.

func Compose16

func Compose16[
	T0,
	T1,
	T2,
	T3,
	T4,
	T5,
	T6,
	T7,
	T8,
	T9,
	T10,
	T11,
	T12,
	T13,
	T14,
	T15,
	T16 any,
](
	s1 Stage[T0, T1],
	s2 Stage[T1, T2],
	s3 Stage[T2, T3],
	s4 Stage[T3, T4],
	s5 Stage[T4, T5],
	s6 Stage[T5, T6],
	s7 Stage[T6, T7],
	s8 Stage[T7, T8],
	s9 Stage[T8, T9],
	s10 Stage[T9, T10],
	s11 Stage[T10, T11],
	s12 Stage[T11, T12],
	s13 Stage[T12, T13],
	s14 Stage[T13, T14],
	s15 Stage[T14, T15],
	s16 Stage[T15, T16],
) Stage[T0, T16]

Compose16 composes 16 Stage together.

func Compose17

func Compose17[
	T0,
	T1,
	T2,
	T3,
	T4,
	T5,
	T6,
	T7,
	T8,
	T9,
	T10,
	T11,
	T12,
	T13,
	T14,
	T15,
	T16,
	T17 any,
](
	s1 Stage[T0, T1],
	s2 Stage[T1, T2],
	s3 Stage[T2, T3],
	s4 Stage[T3, T4],
	s5 Stage[T4, T5],
	s6 Stage[T5, T6],
	s7 Stage[T6, T7],
	s8 Stage[T7, T8],
	s9 Stage[T8, T9],
	s10 Stage[T9, T10],
	s11 Stage[T10, T11],
	s12 Stage[T11, T12],
	s13 Stage[T12, T13],
	s14 Stage[T13, T14],
	s15 Stage[T14, T15],
	s16 Stage[T15, T16],
	s17 Stage[T16, T17],
) Stage[T0, T17]

Compose17 composes 17 Stage together.

func Compose3

func Compose3[
	T0,
	T1,
	T2,
	T3 any,
](
	s1 Stage[T0, T1],
	s2 Stage[T1, T2],
	s3 Stage[T2, T3],
) Stage[T0, T3]

Compose3 composes 3 Stage together.

func Compose4

func Compose4[
	T0,
	T1,
	T2,
	T3,
	T4 any,
](
	s1 Stage[T0, T1],
	s2 Stage[T1, T2],
	s3 Stage[T2, T3],
	s4 Stage[T3, T4],
) Stage[T0, T4]

Compose4 composes 4 Stage together.

func Compose5

func Compose5[
	T0,
	T1,
	T2,
	T3,
	T4,
	T5 any,
](
	s1 Stage[T0, T1],
	s2 Stage[T1, T2],
	s3 Stage[T2, T3],
	s4 Stage[T3, T4],
	s5 Stage[T4, T5],
) Stage[T0, T5]

Compose5 composes 5 Stage together.

func Compose6

func Compose6[
	T0,
	T1,
	T2,
	T3,
	T4,
	T5,
	T6 any,
](
	s1 Stage[T0, T1],
	s2 Stage[T1, T2],
	s3 Stage[T2, T3],
	s4 Stage[T3, T4],
	s5 Stage[T4, T5],
	s6 Stage[T5, T6],
) Stage[T0, T6]

Compose6 composes 6 Stage together.

func Compose7

func Compose7[
	T0,
	T1,
	T2,
	T3,
	T4,
	T5,
	T6,
	T7 any,
](
	s1 Stage[T0, T1],
	s2 Stage[T1, T2],
	s3 Stage[T2, T3],
	s4 Stage[T3, T4],
	s5 Stage[T4, T5],
	s6 Stage[T5, T6],
	s7 Stage[T6, T7],
) Stage[T0, T7]

Compose7 composes 7 Stage together.

func Compose8

func Compose8[
	T0,
	T1,
	T2,
	T3,
	T4,
	T5,
	T6,
	T7,
	T8 any,
](
	s1 Stage[T0, T1],
	s2 Stage[T1, T2],
	s3 Stage[T2, T3],
	s4 Stage[T3, T4],
	s5 Stage[T4, T5],
	s6 Stage[T5, T6],
	s7 Stage[T6, T7],
	s8 Stage[T7, T8],
) Stage[T0, T8]

Compose8 composes 8 Stage together.

func Compose9

func Compose9[
	T0,
	T1,
	T2,
	T3,
	T4,
	T5,
	T6,
	T7,
	T8,
	T9 any,
](
	s1 Stage[T0, T1],
	s2 Stage[T1, T2],
	s3 Stage[T2, T3],
	s4 Stage[T3, T4],
	s5 Stage[T4, T5],
	s6 Stage[T5, T6],
	s7 Stage[T6, T7],
	s8 Stage[T7, T8],
	s9 Stage[T8, T9],
) Stage[T0, T9]

Compose9 composes 9 Stage together.

func DNSLookupGetaddrinfo

func DNSLookupGetaddrinfo() Stage[string, *DNSLookupResult]

DNSLookupGetaddrinfo returns a stage that performs DNS lookups using getaddrinfo.

This function returns an ErrDNSLookup if the error is a DNS lookup error. Remember to use the IsErrDNSLookup predicate when setting an experiment test keys.

func DNSLookupParallel

func DNSLookupParallel(stages ...Stage[string, *DNSLookupResult]) Stage[string, *DNSLookupResult]

DNSLookupParallel returns a stage that runs several DNS lookup stages in parallel using a pool of background goroutines. Note that this stage disregards the result of substages and returns an empty list of addresses when all the substages have failed.

func DNSLookupStatic

func DNSLookupStatic(addresses ...string) Stage[string, *DNSLookupResult]

DNSLookupStatic returns a stage that always returns the given IP addresses.

func DNSLookupUDP

func DNSLookupUDP(endpoint string) Stage[string, *DNSLookupResult]

DNSLookupUDP returns a stage that performs a DNS lookup using the given UDP resolver endpoint; use "ADDRESS:PORT" for IPv4 and "[ADDRESS]:PORT" for IPv6 endpoints.

This function returns an ErrDNSLookup if the error is a DNS lookup error. Remember to use the IsErrDNSLookup predicate when setting an experiment test keys.

func Discard

func Discard[T any]() Stage[T, *Void]

Discard returns a stage that discards its input value with type T. You need this stage to make sure your endpoint pipeline returns a *Void value.

func DomainName

func DomainName(value string) Stage[*Void, string]

DomainName returns a stage that returns the given domain name.

func HTTPConnectionQUIC

func HTTPConnectionQUIC() Stage[*QUICConnection, *HTTPConnection]

HTTPConnectionQUIC returns a stage that converts a QUIC connection to an HTTP connection.

func HTTPConnectionTCP

func HTTPConnectionTCP() Stage[*TCPConnection, *HTTPConnection]

HTTPConnectionTCP returns a stage that converts a TCP connection to an HTTP connection.

func HTTPConnectionTLS

func HTTPConnectionTLS() Stage[*TLSConnection, *HTTPConnection]

HTTPConnectionTLS returns a stage that converts a TLS connection to an HTTP connection.

func HTTPTransaction

func HTTPTransaction(options ...HTTPTransactionOption) Stage[*HTTPConnection, *HTTPResponse]

HTTPTransaction returns a stage that uses an HTTP connection to send an HTTP request and reads the response headers as well as a snapshot of the response body.

This function returns an ErrHTTPTransaction if the error is an HTTP transaction error. Remember to use the IsErrHTTPTransaction predicate when setting an experiment test keys.

func IfFilterExists

func IfFilterExists[T any](fx Stage[T, T]) Stage[T, T]

IfFilterExists wraps a filter such that probes interpreting the AST can compile the filter to an identity function if a filter with the given name does not exist. We define filter as a Stage where the input type and the output type are the same type. This functionality allows supporting old probes that do not support specific filters. Such probes will compile and execute the AST and run identity functions in place of the unsupported filters.

func MakeEndpointsForPort

func MakeEndpointsForPort(port uint16) Stage[*DNSLookupResult, []*Endpoint]

MakeEndpointsForPort returns a stage that converts the results of a DNS lookup to a list of transport layer endpoints ready to be measured using a dedicated pipeline.

func MeasureMultipleEndpoints

func MeasureMultipleEndpoints(stages ...Stage[*DNSLookupResult, *Void]) Stage[*DNSLookupResult, *Void]

MeasureMultipleEndpoints returns a stage that runs several endpoint measurement pipelines in parallel using a pool of background goroutines.

func NewEndpointPipeline

func NewEndpointPipeline(stage Stage[*Endpoint, *Void]) Stage[[]*Endpoint, *Void]

NewEndpointPipeline returns a stage that measures each endpoint given in input in parallel using a pool of background goroutines.

func QUICHandshake

func QUICHandshake(options ...QUICHandshakeOption) Stage[*Endpoint, *QUICConnection]

QUICHandshake returns a stage that performs a QUIC handshake.

This function returns an ErrQUICHandshake if the error is a QUIC handshake error. Remember to use the IsErrQUICHandshake predicate when setting an experiment test keys.

func RunStagesInParallel

func RunStagesInParallel(stages ...Stage[*Void, *Void]) Stage[*Void, *Void]

RunStagesInParallel returns a stage that runs the given stages in parallel using a pool of background goroutines.

func RunnableASTNodeListToStageList

func RunnableASTNodeListToStageList[A, B any](inputs ...RunnableASTNode) (outputs []Stage[A, B])

RunnableASTNodeListToStageList converts a list of RunnableASTNode to a list of Stage.

func TCPConnect

func TCPConnect() Stage[*Endpoint, *TCPConnection]

TCPConnect returns a stage that performs a TCP connect.

This function returns an ErrTCPConnect if the error is a TCP connect error. Remember to use the IsErrTCPConnect predicate when setting an experiment test keys.

func TLSHandshake

func TLSHandshake(options ...TLSHandshakeOption) Stage[*TCPConnection, *TLSConnection]

TLSHandshake returns a stage that performs a TLS handshake.

This function returns an ErrTLSHandshake if the error is a TLS handshake error. Remember to use the IsErrTLSHandshake predicate when setting an experiment test keys.

type StageRunnableASTNode

type StageRunnableASTNode[A, B any] struct {
	S Stage[A, B]
}

StageRunnableASTNode adapts a Stage to become a RunnableASTNode.

func (*StageRunnableASTNode[A, B]) ASTNode

func (n *StageRunnableASTNode[A, B]) ASTNode() *SerializableASTNode

ASTNode implements RunnableASTNode.

func (*StageRunnableASTNode[A, B]) Run

func (n *StageRunnableASTNode[A, B]) Run(ctx context.Context, rtx Runtime, input Maybe[any]) Maybe[any]

Run implements RunnableASTNode.

type TCPConnection

type TCPConnection struct {
	// Address is the endpoint address we're using.
	Address string

	// Conn is the established TCP connection.
	Conn net.Conn

	// Domain is the domain we're using.
	Domain string

	// Trace is the trace we're using.
	Trace Trace
}

TCPConnection is the result of performing a TCP connect operation.

type TLSConnection

type TLSConnection struct {
	// Address is the endpoint address we're using.
	Address string

	// Conn is the established TLS connection.
	Conn netxlite.TLSConn

	// Domain is the domain we're using.
	Domain string

	// TLSNegotiatedProtocol is the result of the ALPN negotiation.
	TLSNegotiatedProtocol string

	// Trace is the trace we're using.
	Trace Trace
}

TLSConnection is the result of performing a TLS handshake.

type TLSHandshakeOption

type TLSHandshakeOption func(config *tlsHandshakeConfig)

TLSHandshakeOption is an option for configuring the TLS handshake.

func TLSHandshakeOptionALPN

func TLSHandshakeOptionALPN(value ...string) TLSHandshakeOption

TLSHandshakeOptionALPN configures the ALPN.

func TLSHandshakeOptionSNI

func TLSHandshakeOptionSNI(value string) TLSHandshakeOption

TLSHandshakeOptionSNI allows to configure the SNI.

func TLSHandshakeOptionSkipVerify

func TLSHandshakeOptionSkipVerify(value bool) TLSHandshakeOption

TLSHandshakeOptionSkipVerify allows to disable certificate verification.

func TLSHandshakeOptionX509Certs

func TLSHandshakeOptionX509Certs(value ...string) TLSHandshakeOption

TLSHandshakeOptionX509Certs allows to configure a custom root CA.

type Trace

type Trace interface {
	// ExtractObservations removes and returns the observations saved so far.
	ExtractObservations() []*Observations

	// HTTPTransaction executes and measures an HTTP transaction. The n argument controls
	// the maximum response body snapshot size that we are willing to read.
	HTTPTransaction(c *HTTPConnection, r *http.Request, n int) (*http.Response, []byte, error)

	// Index is the unique index of this trace.
	Index() int64

	// NewDialerWithoutResolver creates a dialer not attached to any resolver.
	NewDialerWithoutResolver() model.Dialer

	// NewParallelUDPResolver creates an UDP resolver resolving A and AAAA in parallel.
	NewParallelUDPResolver(endpoint string) model.Resolver

	// NewQUICDialerWithoutResolver creates a QUIC dialer not using any resolver.
	NewQUICDialerWithoutResolver() model.QUICDialer

	// NewTLSHandshakerStdlib creates a TLS handshaker using the stdlib.
	NewTLSHandshakerStdlib() model.TLSHandshaker

	// NewStdlibResolver creates a resolver using the stdlib.
	NewStdlibResolver() model.Resolver
}

Trace traces measurement events and produces Observations.

type Void

type Void struct{}

Void is the empty data structure.

type Worker

type Worker[T any] interface {
	Produce(ctx context.Context) T
}

Worker produces a given result.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL