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 ¶
- Variables
- func AsSpecificMaybe[T any](v Maybe[any]) (Maybe[T], *ErrException)
- func IsErrDNSLookup(err error) bool
- func IsErrException(err error) bool
- func IsErrHTTPTransaction(err error) bool
- func IsErrQUICHandshake(err error) bool
- func IsErrSkip(err error) bool
- func IsErrTCPConnect(err error) bool
- func IsErrTLSHandshake(err error) bool
- func ParallelRun[T any](ctx context.Context, parallelism int, workers ...Worker[T]) []T
- func Try[T any](results Maybe[T]) error
- func ValidDomainNames(domains ...string) bool
- func ValidEndpoints(endpoints ...string) bool
- func ValidIPAddrs(addrs ...string) bool
- func ValidPorts(ports ...string) bool
- type ASTLoader
- func (al *ASTLoader) Load(node *LoadableASTNode) (RunnableASTNode, error)
- func (al *ASTLoader) LoadChildren(node *LoadableASTNode) (out []RunnableASTNode, err error)
- func (al *ASTLoader) LoadEmptyArguments(node *LoadableASTNode) error
- func (al *ASTLoader) RegisterCustomLoaderRule(rule ASTLoaderRule)
- func (al *ASTLoader) RequireExactlyNumChildren(node *LoadableASTNode, num int) error
- type ASTLoaderRule
- type DNSLookupResult
- type Endpoint
- type ErrDNSLookup
- type ErrException
- type ErrHTTPTransaction
- type ErrInvalidAddressList
- type ErrInvalidDomain
- type ErrInvalidEndpoint
- type ErrQUICHandshake
- type ErrTCPConnect
- type ErrTLSHandshake
- type HTTPConnection
- type HTTPResponse
- type HTTPTransactionOption
- func HTTPTransactionOptionAccept(value string) HTTPTransactionOption
- func HTTPTransactionOptionAcceptLanguage(value string) HTTPTransactionOption
- func HTTPTransactionOptionHost(value string) HTTPTransactionOption
- func HTTPTransactionOptionMethod(value string) HTTPTransactionOption
- func HTTPTransactionOptionReferer(value string) HTTPTransactionOption
- func HTTPTransactionOptionResponseBodySnapshotSize(value int) HTTPTransactionOption
- func HTTPTransactionOptionURLHost(value string) HTTPTransactionOption
- func HTTPTransactionOptionURLPath(value string) HTTPTransactionOption
- func HTTPTransactionOptionURLScheme(value string) HTTPTransactionOption
- func HTTPTransactionOptionUserAgent(value string) HTTPTransactionOption
- type Identity
- type LoadableASTNode
- type Maybe
- type MeasurexliteRuntime
- func (r *MeasurexliteRuntime) Close() error
- func (r *MeasurexliteRuntime) ExtractObservations() []*Observations
- func (r *MeasurexliteRuntime) Logger() model.Logger
- func (r *MeasurexliteRuntime) NewTrace() Trace
- func (r *MeasurexliteRuntime) SaveObservations(observations ...*Observations)
- func (r *MeasurexliteRuntime) TrackCloser(conn io.Closer)
- func (r *MeasurexliteRuntime) TrackQUICConn(conn quic.EarlyConnection)
- type MinimalRuntime
- func (r *MinimalRuntime) Close() error
- func (r *MinimalRuntime) ExtractObservations() []*Observations
- func (r *MinimalRuntime) Logger() model.Logger
- func (r *MinimalRuntime) NewTrace() Trace
- func (r *MinimalRuntime) SaveObservations(observations ...*Observations)
- func (r *MinimalRuntime) TrackCloser(conn io.Closer)
- func (r *MinimalRuntime) TrackQUICConn(conn quic.EarlyConnection)
- type Observations
- type QUICConnection
- type QUICHandshakeOption
- type RunnableASTNode
- type RunnableASTNodeStage
- type Runtime
- type SerializableASTNode
- type Stage
- func Compose[A, B, C any](s1 Stage[A, B], s2 Stage[B, C]) Stage[A, C]
- 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], ...) Stage[T0, T10]
- 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], ...) Stage[T0, T11]
- 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], ...) Stage[T0, T12]
- 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], ...) Stage[T0, T13]
- 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], ...) Stage[T0, T14]
- 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], ...) Stage[T0, T15]
- 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], ...) Stage[T0, T16]
- func Compose17[...](s1 Stage[T0, T1], s2 Stage[T1, T2], s3 Stage[T2, T3], s4 Stage[T3, T4], ...) Stage[T0, T17]
- func Compose3[T0, T1, T2, T3 any](s1 Stage[T0, T1], s2 Stage[T1, T2], s3 Stage[T2, T3]) Stage[T0, T3]
- 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]
- 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], ...) Stage[T0, T5]
- 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], ...) Stage[T0, T6]
- 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], ...) Stage[T0, T7]
- 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], ...) Stage[T0, T8]
- 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], ...) Stage[T0, T9]
- func DNSLookupGetaddrinfo() Stage[string, *DNSLookupResult]
- func DNSLookupParallel(stages ...Stage[string, *DNSLookupResult]) Stage[string, *DNSLookupResult]
- func DNSLookupStatic(addresses ...string) Stage[string, *DNSLookupResult]
- func DNSLookupUDP(endpoint string) Stage[string, *DNSLookupResult]
- func Discard[T any]() Stage[T, *Void]
- func DomainName(value string) Stage[*Void, string]
- func HTTPConnectionQUIC() Stage[*QUICConnection, *HTTPConnection]
- func HTTPConnectionTCP() Stage[*TCPConnection, *HTTPConnection]
- func HTTPConnectionTLS() Stage[*TLSConnection, *HTTPConnection]
- func HTTPTransaction(options ...HTTPTransactionOption) Stage[*HTTPConnection, *HTTPResponse]
- func IfFilterExists[T any](fx Stage[T, T]) Stage[T, T]
- func MakeEndpointsForPort(port uint16) Stage[*DNSLookupResult, []*Endpoint]
- func MeasureMultipleEndpoints(stages ...Stage[*DNSLookupResult, *Void]) Stage[*DNSLookupResult, *Void]
- func NewEndpointPipeline(stage Stage[*Endpoint, *Void]) Stage[[]*Endpoint, *Void]
- func QUICHandshake(options ...QUICHandshakeOption) Stage[*Endpoint, *QUICConnection]
- func RunStagesInParallel(stages ...Stage[*Void, *Void]) Stage[*Void, *Void]
- func RunnableASTNodeListToStageList[A, B any](inputs ...RunnableASTNode) (outputs []Stage[A, B])
- func TCPConnect() Stage[*Endpoint, *TCPConnection]
- func TLSHandshake(options ...TLSHandshakeOption) Stage[*TCPConnection, *TLSConnection]
- type StageRunnableASTNode
- type TCPConnection
- type TLSConnection
- type TLSHandshakeOption
- type Trace
- type Void
- type Worker
Examples ¶
Constants ¶
This section is empty.
Variables ¶
var ErrInvalidCert = errors.New("dsl: invalid PEM-encoded certificate")
ErrInvalidCert is returned when we encounter an invalid PEM-encoded certificate.
var ErrInvalidNumberOfChildren = errors.New("dsl: invalid number of children")
ErrInvalidNumberOfChildren indicates that the AST contains an invalid number of children.
var ErrNoSuchStage = errors.New("dsl: no such stage")
ErrNoSuchStage is returned when there's no such stage with the given name.
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 ¶
IsErrDNSLookup returns true when an error is an ErrDNSLookup.
func IsErrException ¶
IsErrException returns true when an error is an ErrException.
func IsErrHTTPTransaction ¶
IsErrHTTPTransaction returns true when an error is an ErrHTTPTransaction.
func IsErrQUICHandshake ¶
IsErrQUICHandshake returns true when an error is an ErrQUICHandshake.
func IsErrTCPConnect ¶
IsErrTCPConnect returns true when an error is an ErrTCPConnect.
func IsErrTLSHandshake ¶
IsErrTLSHandshake returns true when an error is an ErrTLSHandshake.
func ParallelRun ¶
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 ¶
Try inspects the results of running a pipeline and returns an error if the returned error is an ErrException, nil otherwise.
func ValidDomainNames ¶
ValidDomainNames returns whether the given list of domain names is valid.
func ValidEndpoints ¶
ValidEndpoints returns whether the given list of endpoints is valid.
func ValidIPAddrs ¶
ValidIPAddrs returns whether the given list contains valid IP addresses.
func ValidPorts ¶
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) 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) 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) 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) 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.
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 ¶
Maybe contains either value or an error.
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) 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.
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 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 ¶
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 ¶
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 ¶
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 ¶
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 ¶
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 ¶
StageRunnableASTNode adapts a Stage to become a RunnableASTNode.
func (*StageRunnableASTNode[A, B]) ASTNode ¶
func (n *StageRunnableASTNode[A, B]) ASTNode() *SerializableASTNode
ASTNode 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.
Source Files ¶
- ast.go
- compose.go
- discard.go
- dnsdomain.go
- dnsgetaddrinfo.go
- dnsmodel.go
- dnsparallel.go
- dnsstatic.go
- dnsudp.go
- doc.go
- endpointmake.go
- endpointmodel.go
- endpointmultiple.go
- endpointpipeline.go
- exception.go
- filter.go
- httpcore.go
- httpmodel.go
- httpquic.go
- httptcp.go
- httptls.go
- identity.go
- maybe.go
- measurexlite.go
- observations.go
- operation.go
- parallel.go
- quichandshake.go
- quicmodel.go
- runtime.go
- skip.go
- stage.go
- tcpconnect.go
- tcpmodel.go
- tlshandshake.go
- tlsmodel.go
- trace.go
- trycatch.go
- validate.go
- void.go
- worker.go