diff --git a/internal/engine/session.go b/internal/engine/session.go index bcc0f7e070..dd62d42f24 100644 --- a/internal/engine/session.go +++ b/internal/engine/session.go @@ -197,11 +197,9 @@ func NewSession(ctx context.Context, config SessionConfig) (*Session, error) { Logger: sess.logger, ProxyURL: proxyURL, } - dialer := netxlite.NewDialerWithResolver(sess.logger, sess.resolver) - dialer = netxlite.MaybeWrapWithProxyDialer(dialer, proxyURL) - handshaker := netxlite.NewTLSHandshakerStdlib(sess.logger) - tlsDialer := netxlite.NewTLSDialer(dialer, handshaker) - txp := netxlite.NewHTTPTransport(sess.logger, dialer, tlsDialer) + txp := netxlite.NewHTTPTransportWithLoggerResolverAndOptionalProxyURL( + sess.logger, sess.resolver, sess.proxyURL, + ) txp = bytecounter.WrapHTTPTransport(txp, sess.byteCounter) sess.httpDefaultTransport = txp return sess, nil diff --git a/internal/netxlite/http.go b/internal/netxlite/http.go index 41969f7089..791d9f0fb8 100644 --- a/internal/netxlite/http.go +++ b/internal/netxlite/http.go @@ -9,6 +9,7 @@ import ( "errors" "net" "net/http" + "net/url" "time" oohttp "github.com/ooni/oohttp" @@ -105,6 +106,25 @@ func (txp *httpTransportConnectionsCloser) CloseIdleConnections() { txp.TLSDialer.CloseIdleConnections() } +// NewHTTPTransportWithLoggerResolverAndOptionalProxyURL creates HTTP transport using the +// given logger and resolver and an optional proxy URL. +// +// Arguments: +// +// - logger is the MANDATORY logger; +// +// - resolver is the MANDATORY resolver; +// +// - purl is the OPTIONAL proxy URL. +func NewHTTPTransportWithLoggerResolverAndOptionalProxyURL( + logger model.DebugLogger, resolver model.Resolver, purl *url.URL) model.HTTPTransport { + dialer := NewDialerWithResolver(logger, resolver) + dialer = MaybeWrapWithProxyDialer(dialer, purl) + handshaker := NewTLSHandshakerStdlib(logger) + tlsDialer := NewTLSDialer(dialer, handshaker) + return NewHTTPTransport(logger, dialer, tlsDialer) +} + // NewHTTPTransportWithResolver creates a new HTTP transport using // the stdlib for everything but the given resolver. func NewHTTPTransportWithResolver(logger model.DebugLogger, reso model.Resolver) model.HTTPTransport { diff --git a/internal/netxlite/http3.go b/internal/netxlite/http3.go index b5ab54664e..56d853df61 100644 --- a/internal/netxlite/http3.go +++ b/internal/netxlite/http3.go @@ -61,3 +61,12 @@ func NewHTTP3Transport( dialer: dialer, }) } + +// NewHTTP3TransportStdlib creates a new HTTPTransport using http3 that +// uses standard functionality for everything but the logger. +func NewHTTP3TransportStdlib(logger model.DebugLogger) model.HTTPTransport { + ql := NewQUICListener() + reso := NewStdlibResolver(logger) + qd := NewQUICDialerWithResolver(ql, logger, reso) + return NewHTTP3Transport(logger, qd, nil) +} diff --git a/internal/netxlite/http3_test.go b/internal/netxlite/http3_test.go index 6f212952f1..5a5b98177f 100644 --- a/internal/netxlite/http3_test.go +++ b/internal/netxlite/http3_test.go @@ -6,8 +6,8 @@ import ( "net/http" "testing" - "github.com/apex/log" "github.com/lucas-clemente/quic-go/http3" + "github.com/ooni/probe-cli/v3/internal/model" "github.com/ooni/probe-cli/v3/internal/model/mocks" nlmocks "github.com/ooni/probe-cli/v3/internal/netxlite/mocks" ) @@ -63,29 +63,41 @@ func TestHTTP3Transport(t *testing.T) { }) } +func verifyTypeChainForHTTP3(t *testing.T, txp model.HTTPTransport, + underlyingLogger model.DebugLogger, qd model.QUICDialer, config *tls.Config) { + logger := txp.(*httpTransportLogger) + if logger.Logger != underlyingLogger { + t.Fatal("invalid logger") + } + ew := logger.HTTPTransport.(*httpTransportErrWrapper) + h3txp := ew.HTTPTransport.(*http3Transport) + if qd != nil && h3txp.dialer != qd { + t.Fatal("invalid dialer") + } + h3 := h3txp.child.(*http3.RoundTripper) + if h3.Dial == nil { + t.Fatal("invalid Dial") + } + if !h3.DisableCompression { + t.Fatal("invalid DisableCompression") + } + if h3.TLSClientConfig != config { + t.Fatal("invalid TLSClientConfig") + } +} + func TestNewHTTP3Transport(t *testing.T) { t.Run("creates the correct type chain", func(t *testing.T) { qd := &mocks.QUICDialer{} config := &tls.Config{} - txp := NewHTTP3Transport(log.Log, qd, config) - logger := txp.(*httpTransportLogger) - if logger.Logger != log.Log { - t.Fatal("invalid logger") - } - ew := logger.HTTPTransport.(*httpTransportErrWrapper) - h3txp := ew.HTTPTransport.(*http3Transport) - if h3txp.dialer != qd { - t.Fatal("invalid dialer") - } - h3 := h3txp.child.(*http3.RoundTripper) - if h3.Dial == nil { - t.Fatal("invalid Dial") - } - if !h3.DisableCompression { - t.Fatal("invalid DisableCompression") - } - if h3.TLSClientConfig != config { - t.Fatal("invalid TLSClientConfig") - } + txp := NewHTTP3Transport(model.DiscardLogger, qd, config) + verifyTypeChainForHTTP3(t, txp, model.DiscardLogger, qd, config) + }) +} + +func TestNewHTTP3TransportStdlib(t *testing.T) { + t.Run("creates the correct type chain", func(t *testing.T) { + txp := NewHTTP3TransportStdlib(model.DiscardLogger) + verifyTypeChainForHTTP3(t, txp, model.DiscardLogger, nil, nil) }) } diff --git a/internal/netxlite/http_test.go b/internal/netxlite/http_test.go index 6c19f539ba..ace93de543 100644 --- a/internal/netxlite/http_test.go +++ b/internal/netxlite/http_test.go @@ -6,6 +6,7 @@ import ( "io" "net" "net/http" + "net/url" "strings" "testing" "time" @@ -16,6 +17,48 @@ import ( "github.com/ooni/probe-cli/v3/internal/model/mocks" ) +func TestNewHTTPTransportWithLoggerResolverAndOptionalProxyURL(t *testing.T) { + t.Run("without proxy URL", func(t *testing.T) { + logger := &mocks.Logger{} + resolver := &mocks.Resolver{} + txp := NewHTTPTransportWithLoggerResolverAndOptionalProxyURL(logger, resolver, nil) + txpLogger := txp.(*httpTransportLogger) + if txpLogger.Logger != logger { + t.Fatal("unexpected logger") + } + txpErrWrapper := txpLogger.HTTPTransport.(*httpTransportErrWrapper) + txpCc := txpErrWrapper.HTTPTransport.(*httpTransportConnectionsCloser) + dialer := txpCc.Dialer + dialerWithReadTimeout := dialer.(*httpDialerWithReadTimeout) + dialerLog := dialerWithReadTimeout.Dialer.(*dialerLogger) + dialerReso := dialerLog.Dialer.(*dialerResolver) + if dialerReso.Resolver != resolver { + t.Fatal("invalid resolver") + } + }) + + t.Run("with proxy URL", func(t *testing.T) { + URL := &url.URL{} + logger := &mocks.Logger{} + resolver := &mocks.Resolver{} + txp := NewHTTPTransportWithLoggerResolverAndOptionalProxyURL(logger, resolver, URL) + txpLogger := txp.(*httpTransportLogger) + if txpLogger.Logger != logger { + t.Fatal("unexpected logger") + } + txpErrWrapper := txpLogger.HTTPTransport.(*httpTransportErrWrapper) + txpCc := txpErrWrapper.HTTPTransport.(*httpTransportConnectionsCloser) + dialer := txpCc.Dialer + dialerWithReadTimeout := dialer.(*httpDialerWithReadTimeout) + dialerProxy := dialerWithReadTimeout.Dialer.(*proxyDialer) + dialerLog := dialerProxy.Dialer.(*dialerLogger) + dialerReso := dialerLog.Dialer.(*dialerResolver) + if dialerReso.Resolver != resolver { + t.Fatal("invalid resolver") + } + }) +} + func TestNewHTTPTransportWithResolver(t *testing.T) { expected := errors.New("mocked error") reso := &mocks.Resolver{