ooni-probe-cli/internal/tutorial/measurex/chapter10/main.go

131 lines
3.5 KiB
Go

// -=-=- StartHere -=-=-
//
// # Chapter IX: Parallel DNS lookups
//
// The program we see here is _really_ similar to the one we
// discussed in the previous chapter. The main difference
// is the following: rather than performing DNS lookups
// sequentially, we call a function that runs through the
// list of resolvers and run them in parallel.
//
// Again, we are going to use low parallelism for the same
// rationale mentioned in chapter09.
//
// (This file is auto-generated. Do not edit it directly! To apply
// changes you need to modify `./internal/tutorial/measurex/chapter10/main.go`.)
//
// ## main.go
//
// The beginning of the program is pretty much the same.
//
// ```Go
package main
import (
"context"
"encoding/json"
"flag"
"fmt"
"net/url"
"time"
"github.com/ooni/probe-cli/v3/internal/measurex"
"github.com/ooni/probe-cli/v3/internal/runtimex"
)
type measurement struct {
DNS []*measurex.DNSMeasurement
Endpoints []*measurex.HTTPEndpointMeasurement
}
func print(v interface{}) {
data, err := json.Marshal(v)
runtimex.PanicOnError(err, "json.Marshal failed")
fmt.Printf("%s\n", string(data))
}
func main() {
URL := flag.String("url", "https://blog.cloudflare.com/", "URL to fetch")
timeout := flag.Duration("timeout", 60*time.Second, "timeout to use")
flag.Parse()
ctx, cancel := context.WithTimeout(context.Background(), *timeout)
defer cancel()
parsed, err := url.Parse(*URL)
runtimex.PanicOnError(err, "url.Parse failed")
mx := measurex.NewMeasurerWithDefaultSettings()
m := &measurement{}
// ```
//
// The bulk of the difference is here. We create
// a list of DNS resolvers. For each of them, we specify
// the type and the endpoint address. (There is no
// endpoint address for the system resolver, therefore
// we leave its address empty.)
//
// ```Go
resolvers := []*measurex.ResolverInfo{{
Network: measurex.ResolverUDP,
Address: "8.8.8.8:53",
}, {
Network: measurex.ResolverUDP,
Address: "8.8.4.4:53",
}, {
Network: measurex.ResolverUDP,
Address: "1.1.1.1:53",
}, {
Network: measurex.ResolverUDP,
Address: "1.0.0.1:53",
}, {
Network: measurex.ResolverSystem,
Address: "",
}}
// ```
//
// Then we call `LookupURLHostParallel`. This function runs
// the queries that make sense given the input URL using a
// pool of (currently three) background goroutines.
//
// When I say "queries that make sense", I mostly mean
// that we only query for HTTPSSvc when the input URL
// scheme is "https". Otherwise, if it's just "http", it
// does not make sense to send this query.
//
// ```Go
const parallelism = 3
for dns := range mx.LookupURLHostParallel(ctx, parallelism, parsed, resolvers...) {
m.DNS = append(m.DNS, dns)
}
// ```
//
// The rest of the program is exactly like in chapter09.
//
// ```Go
headers := measurex.NewHTTPRequestHeaderForMeasuring()
httpEndpoints, err := measurex.AllHTTPEndpointsForURL(parsed, headers, m.DNS...)
runtimex.PanicOnError(err, "cannot get all the HTTP endpoints")
cookies := measurex.NewCookieJar()
for epnt := range mx.HTTPEndpointGetParallel(ctx, parallelism, cookies, httpEndpoints...) {
m.Endpoints = append(m.Endpoints, epnt)
}
print(m)
}
// ```
//
// ## Running the example program
//
// Let us perform a vanilla run first:
//
// ```bash
// go run -race ./internal/tutorial/measurex/chapter10 | jq
// ```
//
// Take a look at the JSON output. Can you spot that
// DNS queries are run in parallel?
//
// ## Conclusion
//
// We have seen how to run parallel DNS queries.
//
// -=-=- StopHere -=-=-