Compare commits

...

4 Commits

Author SHA1 Message Date
Simone Basso 51b185b55a
feat(testingx): add HTTPHandlerResetWhileReadingBody (#1563)
Closes https://github.com/ooni/probe/issues/2714

Extracted from https://github.com/ooni/probe-cli/pull/1560

Part of https://github.com/ooni/probe/issues/2700
2024-04-23 13:43:29 +02:00
Simone Basso 6bd35a20be
feat(testingx): add log collector (#1562)
Closes https://github.com/ooni/probe/issues/2713.

We developed this diff in https://github.com/ooni/probe-cli/pull/1560,
which is work in the https://github.com/ooni/probe/issues/2700 context.
2024-04-23 12:23:15 +02:00
Simone Basso d12a3c2f3d
fix(gobash.yml): drop macos-latest checks (#1561)
Closes https://github.com/ooni/probe/issues/2712
2024-04-23 11:47:39 +02:00
dependabot[bot] d6d201d85e
chore(deps): bump golang.org/x/net from 0.22.0 to 0.23.0 (#1559)
Bumps [golang.org/x/net](https://github.com/golang/net) from 0.22.0 to
0.23.0.
<details>
<summary>Commits</summary>
<ul>
<li><a
href="c48da13158"><code>c48da13</code></a>
http2: fix TestServerContinuationFlood flakes</li>
<li><a
href="762b58d1cf"><code>762b58d</code></a>
http2: fix tipos in comment</li>
<li><a
href="ba872109ef"><code>ba87210</code></a>
http2: close connections when receiving too many headers</li>
<li><a
href="ebc8168ac8"><code>ebc8168</code></a>
all: fix some typos</li>
<li><a
href="3678185f8a"><code>3678185</code></a>
http2: make TestCanonicalHeaderCacheGrowth faster</li>
<li><a
href="448c44f928"><code>448c44f</code></a>
http2: remove clientTester</li>
<li><a
href="c7877ac421"><code>c7877ac</code></a>
http2: convert the remaining clientTester tests to testClientConn</li>
<li><a
href="d8870b0bf2"><code>d8870b0</code></a>
http2: use synthetic time in TestIdleConnTimeout</li>
<li><a
href="d73acffdc9"><code>d73acff</code></a>
http2: only set up deadline when Server.IdleTimeout is positive</li>
<li><a
href="89f602b7bb"><code>89f602b</code></a>
http2: validate client/outgoing trailers</li>
<li>Additional commits viewable in <a
href="https://github.com/golang/net/compare/v0.22.0...v0.23.0">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=golang.org/x/net&package-manager=go_modules&previous-version=0.22.0&new-version=0.23.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)
You can disable automated security fix PRs for this repo from the
[Security Alerts
page](https://github.com/ooni/probe-cli/network/alerts).

</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-04-22 17:27:53 +02:00
7 changed files with 204 additions and 12 deletions

View File

@ -31,7 +31,7 @@ jobs:
- "1.20"
- "1.21"
- "1.22"
system: [ubuntu-latest, macos-latest]
system: [ubuntu-latest]
runs-on: "${{ matrix.system }}"
steps:
- uses: actions/checkout@v3

2
go.mod
View File

@ -41,7 +41,7 @@ require (
gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/goptlib v1.5.0
gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/snowflake/v2 v2.6.1
golang.org/x/crypto v0.21.0
golang.org/x/net v0.22.0
golang.org/x/net v0.23.0
golang.org/x/sys v0.18.0
)

4
go.sum
View File

@ -654,8 +654,8 @@ golang.org/x/net v0.11.0/go.mod h1:2L/ixqYpgIVXmeoSA/4Lu7BzTG4KIyPIryS4IsOd1oQ=
golang.org/x/net v0.13.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA=
golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI=
golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
golang.org/x/net v0.22.0 h1:9sGLhx7iRIHEiX0oAJ3MRZMUCElJgy7Br1nO+AMN3Tc=
golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs=
golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=

View File

@ -6,8 +6,10 @@ import (
"net"
"net/http"
"net/url"
"time"
"github.com/ooni/netem"
"github.com/ooni/probe-cli/v3/internal/randx"
"github.com/ooni/probe-cli/v3/internal/runtimex"
)
@ -173,14 +175,7 @@ func HTTPHandlerTimeout() http.Handler {
}
func httpHandlerHijack(w http.ResponseWriter, r *http.Request, policy string) {
// Note:
//
// 1. we assume we can hihack the connection
//
// 2. Hijack won't fail the first time it's invoked
hijacker := w.(http.Hijacker)
conn, _ := runtimex.Try2(hijacker.Hijack())
conn := httpHijack(w)
defer conn.Close()
switch policy {
@ -194,3 +189,40 @@ func httpHandlerHijack(w http.ResponseWriter, r *http.Request, policy string) {
// nothing
}
}
// HTTPHandlerResetWhileReadingBody returns a handler that sends a
// connection reset by peer while the client is reading the body.
func HTTPHandlerResetWhileReadingBody() http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
conn := httpHijack(w)
defer conn.Close()
// write the HTTP response headers
conn.Write([]byte("HTTP/1.1 200 Ok\r\n"))
conn.Write([]byte("Content-Type: text/html\r\n"))
conn.Write([]byte("Content-Length: 65535\r\n"))
conn.Write([]byte("\r\n"))
// start writing the response
content := randx.Letters(32768)
conn.Write([]byte(content))
// sleep for half a second simulating something wrong
time.Sleep(500 * time.Millisecond)
// finally issue reset for the conn
tcpMaybeResetNetConn(conn)
})
}
// httpHijack is a convenience function to hijack the underlying connection.
func httpHijack(w http.ResponseWriter) net.Conn {
// Note:
//
// 1. we assume we can hihack the connection
//
// 2. Hijack won't fail the first time it's invoked
hijacker := w.(http.Hijacker)
conn, _ := runtimex.Try2(hijacker.Hijack())
return conn
}

View File

@ -498,3 +498,43 @@ func TestHTTPTestxWithNetem(t *testing.T) {
})
}
}
func TestHTTPHandlerResetWhileReadingBody(t *testing.T) {
// create a server for testing the given handler
server := testingx.MustNewHTTPServer(testingx.HTTPHandlerResetWhileReadingBody())
defer server.Close()
// create a suitable HTTP transport using netxlite
netx := &netxlite.Netx{Underlying: nil}
dialer := netx.NewDialerWithoutResolver(log.Log)
handshaker := netx.NewTLSHandshakerStdlib(log.Log)
tlsDialer := netxlite.NewTLSDialer(dialer, handshaker)
txp := netxlite.NewHTTPTransportWithOptions(log.Log, dialer, tlsDialer)
// create the request
req := runtimex.Try1(http.NewRequest("GET", server.URL, nil))
// perform the round trip
resp, err := txp.RoundTrip(req)
// we do not expect an error during the round trip
if err != nil {
t.Fatal(err)
}
// make sure we close the body
defer resp.Body.Close()
// start reading the response where we expect to see a RST
respbody, err := netxlite.ReadAllContext(req.Context(), resp.Body)
// verify we received a connection reset
if !errors.Is(err, netxlite.ECONNRESET) {
t.Fatal("expected ECONNRESET, got", err)
}
// make sure we've got no bytes
if len(respbody) != 0 {
t.Fatal("expected to see zero bytes here")
}
}

View File

@ -0,0 +1,87 @@
package testingx
import (
"fmt"
"sync"
"github.com/ooni/probe-cli/v3/internal/logmodel"
)
// Logger implements [logmodel.Logger] and collects all the log lines.
//
// The zero value of this struct is ready to use.
type Logger struct {
// debug contains debug lines.
debug []string
// info contains info lines.
info []string
// mu provides mutual exclusion.
mu sync.Mutex
// warning contains warning lines.
warning []string
}
var _ logmodel.Logger = &Logger{}
// Debug implements logmodel.Logger.
func (l *Logger) Debug(msg string) {
l.mu.Lock()
l.debug = append(l.debug, msg)
l.mu.Unlock()
}
// Debugf implements logmodel.Logger.
func (l *Logger) Debugf(format string, v ...interface{}) {
l.Debug(fmt.Sprintf(format, v...))
}
// Info implements logmodel.Logger.
func (l *Logger) Info(msg string) {
l.mu.Lock()
l.info = append(l.info, msg)
l.mu.Unlock()
}
// Infof implements logmodel.Logger.
func (l *Logger) Infof(format string, v ...interface{}) {
l.Info(fmt.Sprintf(format, v...))
}
// Warn implements logmodel.Logger.
func (l *Logger) Warn(msg string) {
l.mu.Lock()
l.warning = append(l.warning, msg)
l.mu.Unlock()
}
// Warnf implements logmodel.Logger.
func (l *Logger) Warnf(format string, v ...interface{}) {
l.Warn(fmt.Sprintf(format, v...))
}
// DebugLines returns a copy of the observed debug lines.
func (l *Logger) DebugLines() []string {
l.mu.Lock()
out := append([]string{}, l.debug...)
l.mu.Unlock()
return out
}
// InfoLines returns a copy of the observed info lines.
func (l *Logger) InfoLines() []string {
l.mu.Lock()
out := append([]string{}, l.info...)
l.mu.Unlock()
return out
}
// WarnLines returns a copy of the observed warn lines.
func (l *Logger) WarnLines() []string {
l.mu.Lock()
out := append([]string{}, l.warning...)
l.mu.Unlock()
return out
}

View File

@ -0,0 +1,33 @@
package testingx
import (
"testing"
"github.com/google/go-cmp/cmp"
)
func TestLogger(t *testing.T) {
logger := &Logger{}
logger.Debug("foobar")
logger.Debugf("foo%s", "baz")
expectDebug := []string{"foobar", "foobaz"}
logger.Info("barfoo")
logger.Infof("bar%s", "baz")
expectInfo := []string{"barfoo", "barbaz"}
logger.Warn("jarjar")
logger.Warnf("jar%s", "baz")
expectWarn := []string{"jarjar", "jarbaz"}
if diff := cmp.Diff(expectDebug, logger.DebugLines()); diff != "" {
t.Fatal(diff)
}
if diff := cmp.Diff(expectInfo, logger.InfoLines()); diff != "" {
t.Fatal(diff)
}
if diff := cmp.Diff(expectWarn, logger.WarnLines()); diff != "" {
t.Fatal(diff)
}
}