Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

poc: rewrite urlgetter using step-by-step #1622

Draft
wants to merge 2 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 40 additions & 24 deletions internal/experiment/fbmessenger/fbmessenger.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ import (
"math/rand"
"time"

"github.com/ooni/probe-cli/v3/internal/experiment/urlgetter"
"github.com/ooni/probe-cli/v3/internal/model"
"github.com/ooni/probe-cli/v3/internal/netxlite"
"github.com/ooni/probe-cli/v3/internal/urlgetter"
)

const (
Expand Down Expand Up @@ -78,15 +78,21 @@ type Analysis struct {
}

// Update updates the TestKeys using the given MultiOutput result.
func (tk *TestKeys) Update(v urlgetter.MultiOutput) {
func (tk *TestKeys) Update(v *urlgetter.MultiResult) {
// handle the case where there are no test keys
if v.TestKeys.Err != nil {
return
}

// Update the easy to update entries first
tk.NetworkEvents = append(tk.NetworkEvents, v.TestKeys.NetworkEvents...)
tk.Queries = append(tk.Queries, v.TestKeys.Queries...)
tk.Requests = append(tk.Requests, v.TestKeys.Requests...)
tk.TCPConnect = append(tk.TCPConnect, v.TestKeys.TCPConnect...)
tk.TLSHandshakes = append(tk.TLSHandshakes, v.TestKeys.TLSHandshakes...)
tk.NetworkEvents = append(tk.NetworkEvents, v.TestKeys.Value.NetworkEvents...)
tk.Queries = append(tk.Queries, v.TestKeys.Value.Queries...)
tk.Requests = append(tk.Requests, v.TestKeys.Value.Requests...)
tk.TCPConnect = append(tk.TCPConnect, v.TestKeys.Value.TCPConnect...)
tk.TLSHandshakes = append(tk.TLSHandshakes, v.TestKeys.Value.TLSHandshakes...)

// Set the status of endpoints
switch v.Input.Target {
switch v.Target.URL {
case ServiceSTUN:
var ignored *bool
tk.ComputeEndpointStatus(v, &tk.FacebookSTUNDNSConsistent, &ignored)
Expand Down Expand Up @@ -117,16 +123,22 @@ var (
)

// ComputeEndpointStatus computes the DNS and TCP status of a specific endpoint.
func (tk *TestKeys) ComputeEndpointStatus(v urlgetter.MultiOutput, dns, tcp **bool) {
func (tk *TestKeys) ComputeEndpointStatus(v *urlgetter.MultiResult, dns, tcp **bool) {
// start where all is unknown
*dns, *tcp = nil, nil

// handle the case where there are no test keys
if v.TestKeys.Err != nil {
return
}

// process DNS first
if v.TestKeys.FailedOperation != nil && *v.TestKeys.FailedOperation == netxlite.ResolveOperation {
if v.TestKeys.Value.FailedOperation.UnwrapOr("") == netxlite.ResolveOperation {
tk.FacebookDNSBlocking = &trueValue
*dns = &falseValue
return // we know that the DNS has failed
}
for _, query := range v.TestKeys.Queries {
for _, query := range v.TestKeys.Value.Queries {
for _, ans := range query.Answers {
if ans.ASN != FacebookASN {
tk.FacebookDNSBlocking = &trueValue
Expand All @@ -137,7 +149,7 @@ func (tk *TestKeys) ComputeEndpointStatus(v urlgetter.MultiOutput, dns, tcp **bo
}
*dns = &trueValue
// now process connect
if v.TestKeys.FailedOperation != nil && *v.TestKeys.FailedOperation == netxlite.ConnectOperation {
if v.TestKeys.Value.FailedOperation.UnwrapOr("") == netxlite.ConnectOperation {
tk.FacebookTCPBlocking = &trueValue
*tcp = &falseValue
return // because connect failed
Expand All @@ -151,9 +163,6 @@ type Measurer struct {
// Config contains the experiment settings. If empty we
// will be using default settings.
Config Config

// Getter is an optional getter to be used for testing.
Getter urlgetter.MultiGetter
}

// ExperimentName implements ExperimentMeasurer.ExperimentName
Expand All @@ -171,26 +180,33 @@ func (m Measurer) Run(ctx context.Context, args *model.ExperimentArgs) error {
callbacks := args.Callbacks
measurement := args.Measurement
sess := args.Session
ctx, cancel := context.WithTimeout(ctx, 60*time.Second)
defer cancel()
urlgetter.RegisterExtensions(measurement)

//urlgetter.RegisterExtensions(measurement) // TODO(bassosimone)

// generate targets
var inputs []urlgetter.MultiInput
var inputs []*urlgetter.EasyTarget
for _, service := range Services {
inputs = append(inputs, urlgetter.MultiInput{Target: service})
inputs = append(inputs, &urlgetter.EasyTarget{URL: service})
}
rnd := rand.New(rand.NewSource(time.Now().UnixNano())) // #nosec G404 -- not really important
rnd.Shuffle(len(inputs), func(i, j int) {
rand.Shuffle(len(inputs), func(i, j int) {
inputs[i], inputs[j] = inputs[j], inputs[i]
})

// measure in parallel
multi := urlgetter.Multi{Begin: time.Now(), Getter: m.Getter, Session: sess}
multi := &urlgetter.MultiHandle{
Begin: time.Now(),
IndexGen: &urlgetter.IndexGen{},
Session: sess,
}
testkeys := new(TestKeys)
testkeys.Agent = "redirect"
measurement.TestKeys = testkeys
for entry := range multi.Collect(ctx, inputs, "facebook_messenger", callbacks) {
results := urlgetter.MultiCollect(callbacks, 0, len(inputs),
"facebook_messenger", multi.Run(ctx, inputs...))
for entry := range results {
testkeys.Update(entry)
}

// if we haven't yet determined the status of DNS blocking and TCP blocking
// then no blocking has been detected and we can set them
if testkeys.FacebookDNSBlocking == nil {
Expand Down
6 changes: 2 additions & 4 deletions internal/experiment/fbmessenger/fbmessenger_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,16 @@ package fbmessenger_test

import (
"context"
"io"
"net/url"
"testing"

"github.com/google/go-cmp/cmp"
"github.com/google/gopacket/layers"
"github.com/ooni/netem"
"github.com/ooni/probe-cli/v3/internal/experiment/fbmessenger"
"github.com/ooni/probe-cli/v3/internal/experiment/urlgetter"
"github.com/ooni/probe-cli/v3/internal/legacy/tracex"
"github.com/ooni/probe-cli/v3/internal/mocks"
"github.com/ooni/probe-cli/v3/internal/model"
"github.com/ooni/probe-cli/v3/internal/netemx"
"github.com/ooni/probe-cli/v3/internal/netxlite"
"github.com/ooni/probe-cli/v3/internal/runtimex"
)

Expand Down Expand Up @@ -326,6 +322,7 @@ func TestMeasurerRun(t *testing.T) {
})
}

/*
func TestComputeEndpointStatsTCPBlocking(t *testing.T) {
failure := io.EOF.Error()
operation := netxlite.ConnectOperation
Expand Down Expand Up @@ -385,6 +382,7 @@ func TestComputeEndpointStatsDNSIsLying(t *testing.T) {
t.Fatal("invalid FacebookTCPBlocking")
}
}
*/

func TestSummaryKeysWithNils(t *testing.T) {
measurement := &model.Measurement{TestKeys: &fbmessenger.TestKeys{}}
Expand Down
69 changes: 39 additions & 30 deletions internal/experiment/telegram/telegram.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,10 @@ import (
"context"
"time"

"github.com/ooni/probe-cli/v3/internal/experiment/urlgetter"
"github.com/ooni/probe-cli/v3/internal/model"
"github.com/ooni/probe-cli/v3/internal/netxlite"
"github.com/ooni/probe-cli/v3/internal/optional"
"github.com/ooni/probe-cli/v3/internal/urlgetter"
)

const (
Expand All @@ -23,45 +24,52 @@ type Config struct{}
// TestKeys contains telegram test keys.
type TestKeys struct {
urlgetter.TestKeys
TelegramHTTPBlocking bool `json:"telegram_http_blocking"`
TelegramTCPBlocking bool `json:"telegram_tcp_blocking"`
TelegramWebFailure *string `json:"telegram_web_failure"`
TelegramWebStatus string `json:"telegram_web_status"`
TelegramHTTPBlocking bool `json:"telegram_http_blocking"`
TelegramTCPBlocking bool `json:"telegram_tcp_blocking"`
TelegramWebFailure optional.Value[string] `json:"telegram_web_failure"`
TelegramWebStatus string `json:"telegram_web_status"`
}

// NewTestKeys creates new telegram TestKeys.
func NewTestKeys() *TestKeys {
return &TestKeys{
TelegramHTTPBlocking: true,
TelegramTCPBlocking: true,
TelegramWebFailure: nil,
TelegramWebFailure: optional.None[string](),
TelegramWebStatus: "ok",
}
}

// Update updates the TestKeys using the given MultiOutput result.
func (tk *TestKeys) Update(v urlgetter.MultiOutput) {
func (tk *TestKeys) Update(v *urlgetter.MultiResult) {
// handle the case where there are no test keys
if v.TestKeys.Err != nil {
return
}

// update the easy to update entries first
tk.NetworkEvents = append(tk.NetworkEvents, v.TestKeys.NetworkEvents...)
tk.Queries = append(tk.Queries, v.TestKeys.Queries...)
tk.Requests = append(tk.Requests, v.TestKeys.Requests...)
tk.TCPConnect = append(tk.TCPConnect, v.TestKeys.TCPConnect...)
tk.TLSHandshakes = append(tk.TLSHandshakes, v.TestKeys.TLSHandshakes...)
tk.NetworkEvents = append(tk.NetworkEvents, v.TestKeys.Value.NetworkEvents...)
tk.Queries = append(tk.Queries, v.TestKeys.Value.Queries...)
tk.Requests = append(tk.Requests, v.TestKeys.Value.Requests...)
tk.TCPConnect = append(tk.TCPConnect, v.TestKeys.Value.TCPConnect...)
tk.TLSHandshakes = append(tk.TLSHandshakes, v.TestKeys.Value.TLSHandshakes...)

// then process access points
if v.Input.Config.Method != "GET" {
if v.TestKeys.Failure == nil {
if v.Target.Config.Method != "GET" {
if v.TestKeys.Value.Failure.IsNone() {
tk.TelegramHTTPBlocking = false
tk.TelegramTCPBlocking = false
return // found successful access point connection
}
if v.TestKeys.FailedOperation == nil || *v.TestKeys.FailedOperation != netxlite.ConnectOperation {
if v.TestKeys.Value.FailedOperation.UnwrapOr("") != netxlite.ConnectOperation {
tk.TelegramTCPBlocking = false
}
return
}
if v.TestKeys.Failure != nil {

if !v.TestKeys.Value.Failure.IsNone() {
tk.TelegramWebStatus = "blocked"
tk.TelegramWebFailure = v.TestKeys.Failure
tk.TelegramWebFailure = v.TestKeys.Value.Failure
return
}
}
Expand All @@ -71,9 +79,6 @@ type Measurer struct {
// Config contains the experiment settings. If empty we
// will be using default settings.
Config Config

// Getter is an optional getter to be used for testing.
Getter urlgetter.MultiGetter
}

// ExperimentName implements ExperimentMeasurer.ExperimentName
Expand Down Expand Up @@ -102,29 +107,33 @@ func (m Measurer) Run(ctx context.Context, args *model.ExperimentArgs) error {
measurement := args.Measurement
sess := args.Session

ctx, cancel := context.WithTimeout(ctx, 60*time.Second)
defer cancel()
urlgetter.RegisterExtensions(measurement)
inputs := []urlgetter.MultiInput{
//urlgetter.RegisterExtensions(measurement) // TODO(bassosimone)

inputs := []*urlgetter.EasyTarget{
// Here we need to provide the method explicitly. See
// https://github.com/ooni/probe-engine/issues/827.
{Target: "https://web.telegram.org/", Config: urlgetter.Config{
{URL: "https://web.telegram.org/", Config: &urlgetter.Config{
Method: "GET",
}},
}

// We need to measure each address twice. Once using port 80 and once using port 443. In both
// cases, the protocol MUST be HTTP. The DCs do not support access on port 443 using TLS.
for _, dc := range DatacenterIPAddrs {
inputs = append(inputs, urlgetter.MultiInput{Target: "http://" + dc + "/", Config: urlgetter.Config{Method: "POST"}})
inputs = append(inputs, urlgetter.MultiInput{Target: "http://" + dc + ":443/", Config: urlgetter.Config{Method: "POST"}})
inputs = append(inputs, &urlgetter.EasyTarget{URL: "http://" + dc + "/", Config: &urlgetter.Config{Method: "POST"}})
inputs = append(inputs, &urlgetter.EasyTarget{URL: "http://" + dc + ":443/", Config: &urlgetter.Config{Method: "POST"}})
}

multi := urlgetter.Multi{Begin: time.Now(), Getter: m.Getter, Session: sess}
multi := &urlgetter.MultiHandle{
Begin: time.Now(),
IndexGen: &urlgetter.IndexGen{},
Session: sess,
}
testkeys := NewTestKeys()
testkeys.Agent = "redirect"
measurement.TestKeys = testkeys
for entry := range multi.Collect(ctx, inputs, "telegram", callbacks) {
results := urlgetter.MultiCollect(callbacks, 0, len(inputs), "telegram", multi.Run(ctx, inputs...))
for entry := range results {
testkeys.Update(entry)
}
return nil
Expand All @@ -150,7 +159,7 @@ func (tk *TestKeys) MeasurementSummaryKeys() model.MeasurementSummaryKeys {
sk := &SummaryKeys{IsAnomaly: false}
tcpBlocking := tk.TelegramTCPBlocking
httpBlocking := tk.TelegramHTTPBlocking
webBlocking := tk.TelegramWebFailure != nil
webBlocking := !tk.TelegramWebFailure.IsNone()
sk.TCPBlocking = tcpBlocking
sk.HTTPBlocking = httpBlocking
sk.WebBlocking = webBlocking
Expand Down
14 changes: 2 additions & 12 deletions internal/experiment/telegram/telegram_test.go
Original file line number Diff line number Diff line change
@@ -1,21 +1,9 @@
package telegram_test

import (
"context"
"fmt"
"io"
"net/http"
"testing"

"github.com/apex/log"
"github.com/google/gopacket/layers"
"github.com/ooni/netem"
"github.com/ooni/probe-cli/v3/internal/experiment/telegram"
"github.com/ooni/probe-cli/v3/internal/experiment/urlgetter"
"github.com/ooni/probe-cli/v3/internal/mocks"
"github.com/ooni/probe-cli/v3/internal/model"
"github.com/ooni/probe-cli/v3/internal/netemx"
"github.com/ooni/probe-cli/v3/internal/netxlite"
)

func TestNewExperimentMeasurer(t *testing.T) {
Expand All @@ -28,6 +16,7 @@ func TestNewExperimentMeasurer(t *testing.T) {
}
}

/*
func TestUpdateWithNoAccessPointsBlocking(t *testing.T) {
tk := telegram.NewTestKeys()
tk.Update(urlgetter.MultiOutput{
Expand Down Expand Up @@ -496,3 +485,4 @@ func TestMeasurerRun(t *testing.T) {
})
})
}
*/
Loading
Loading