From af6e8b70b8261bb0c99ad094fe552ab92991620a Mon Sep 17 00:00:00 2001 From: appleboy Date: Sun, 30 Nov 2025 11:52:25 +0800 Subject: [PATCH 1/3] chore(deps): upgrade quic-go to v0.57.1 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix CVE-2025-59530 vulnerability (quic-go Crash Due to Premature HANDSHAKE_DONE Frame) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- go.mod | 4 ++-- go.sum | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/go.mod b/go.mod index 628ab4c5..58ec6fc9 100644 --- a/go.mod +++ b/go.mod @@ -12,7 +12,7 @@ require ( github.com/mattn/go-isatty v0.0.20 github.com/modern-go/reflect2 v1.0.2 github.com/pelletier/go-toml/v2 v2.2.4 - github.com/quic-go/quic-go v0.56.0 + github.com/quic-go/quic-go v0.57.1 github.com/stretchr/testify v1.11.1 github.com/ugorji/go/codec v1.3.1 golang.org/x/net v0.47.0 @@ -32,7 +32,7 @@ require ( github.com/leodido/go-urn v1.4.0 // indirect github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/quic-go/qpack v0.5.1 // indirect + github.com/quic-go/qpack v0.6.0 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect golang.org/x/arch v0.20.0 // indirect golang.org/x/crypto v0.45.0 // indirect diff --git a/go.sum b/go.sum index 90d5e526..bcdb4493 100644 --- a/go.sum +++ b/go.sum @@ -49,10 +49,10 @@ github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0 github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/quic-go/qpack v0.5.1 h1:giqksBPnT/HDtZ6VhtFKgoLOWmlyo9Ei6u9PqzIMbhI= -github.com/quic-go/qpack v0.5.1/go.mod h1:+PC4XFrEskIVkcLzpEkbLqq1uCoxPhQuvK5rH1ZgaEg= -github.com/quic-go/quic-go v0.56.0 h1:q/TW+OLismmXAehgFLczhCDTYB3bFmua4D9lsNBWxvY= -github.com/quic-go/quic-go v0.56.0/go.mod h1:9gx5KsFQtw2oZ6GZTyh+7YEvOxWCL9WZAepnHxgAo6c= +github.com/quic-go/qpack v0.6.0 h1:g7W+BMYynC1LbYLSqRt8PBg5Tgwxn214ZZR34VIOjz8= +github.com/quic-go/qpack v0.6.0/go.mod h1:lUpLKChi8njB4ty2bFLX2x4gzDqXwUpaO1DP9qMDZII= +github.com/quic-go/quic-go v0.57.1 h1:25KAAR9QR8KZrCZRThWMKVAwGoiHIrNbT72ULHTuI10= +github.com/quic-go/quic-go v0.57.1/go.mod h1:ly4QBAjHA2VhdnxhojRsCUOeJwKYg+taDlos92xb1+s= github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= From 583db590ec2a488ebcf7f8dc6232d11c7db62eac Mon Sep 17 00:00:00 2001 From: Milad Date: Sun, 30 Nov 2025 10:55:46 +0330 Subject: [PATCH 2/3] test(bytesconv): add tests for empty/nil cases (#4454) Co-authored-by: Bo-Yi Wu --- internal/bytesconv/bytesconv_test.go | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/internal/bytesconv/bytesconv_test.go b/internal/bytesconv/bytesconv_test.go index 4972ae70..60e28fb4 100644 --- a/internal/bytesconv/bytesconv_test.go +++ b/internal/bytesconv/bytesconv_test.go @@ -41,6 +41,15 @@ func TestBytesToString(t *testing.T) { } } +func TestBytesToStringEmpty(t *testing.T) { + if got := BytesToString([]byte{}); got != "" { + t.Fatalf("BytesToString([]byte{}) = %q; want empty string", got) + } + if got := BytesToString(nil); got != "" { + t.Fatalf("BytesToString(nil) = %q; want empty string", got) + } +} + const letterBytes = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" const ( letterIdxBits = 6 // 6 bits to represent a letter index @@ -78,6 +87,16 @@ func TestStringToBytes(t *testing.T) { } } +func TestStringToBytesEmpty(t *testing.T) { + b := StringToBytes("") + if len(b) != 0 { + t.Fatalf(`StringToBytes("") length = %d; want 0`, len(b)) + } + if !bytes.Equal(b, []byte("")) { + t.Fatalf(`StringToBytes("") = %v; want []byte("")`, b) + } +} + // go test -v -run=none -bench=^BenchmarkBytesConv -benchmem=true func BenchmarkBytesConvBytesToStrRaw(b *testing.B) { From f416d1e594a027063e73f66ac873a82113036fd8 Mon Sep 17 00:00:00 2001 From: Wayne Aki <111057868+Planckbaka@users.noreply.github.com> Date: Sun, 30 Nov 2025 15:38:07 +0800 Subject: [PATCH 3/3] test(gin): resolve race conditions in integration tests (#4453) - Implement TestRebuild404Handlers to verify 404 handler chain rebuilding when global middleware is added via Use() - Add waitForServerReady helper with exponential backoff to replace unreliable time.Sleep() calls in integration tests - Fix race conditions in TestRunEmpty, TestRunEmptyWithEnv, and TestRunWithPort by using proper server readiness checks - All tests now pass consistently with -race flag This addresses the empty test function and eliminates flaky test failures caused by insufficient wait times for server startup. Co-authored-by: Bo-Yi Wu --- gin_integration_test.go | 21 ++++++++++++--------- gin_test.go | 23 +++++++++++++++++++++++ test_helpers.go | 31 ++++++++++++++++++++++++++++++- 3 files changed, 65 insertions(+), 10 deletions(-) diff --git a/gin_integration_test.go b/gin_integration_test.go index e040993a..3ea5fe2f 100644 --- a/gin_integration_test.go +++ b/gin_integration_test.go @@ -70,9 +70,10 @@ func TestRunEmpty(t *testing.T) { router.GET("/example", func(c *Context) { c.String(http.StatusOK, "it worked") }) assert.NoError(t, router.Run()) }() - // have to wait for the goroutine to start and run the server - // otherwise the main thread will complete - time.Sleep(5 * time.Millisecond) + + // Wait for server to be ready with exponential backoff + err := waitForServerReady("http://localhost:8080/example", 10) + require.NoError(t, err, "server should start successfully") require.Error(t, router.Run(":8080")) testRequest(t, "http://localhost:8080/example") @@ -213,9 +214,10 @@ func TestRunEmptyWithEnv(t *testing.T) { router.GET("/example", func(c *Context) { c.String(http.StatusOK, "it worked") }) assert.NoError(t, router.Run()) }() - // have to wait for the goroutine to start and run the server - // otherwise the main thread will complete - time.Sleep(5 * time.Millisecond) + + // Wait for server to be ready with exponential backoff + err := waitForServerReady("http://localhost:3123/example", 10) + require.NoError(t, err, "server should start successfully") require.Error(t, router.Run(":3123")) testRequest(t, "http://localhost:3123/example") @@ -234,9 +236,10 @@ func TestRunWithPort(t *testing.T) { router.GET("/example", func(c *Context) { c.String(http.StatusOK, "it worked") }) assert.NoError(t, router.Run(":5150")) }() - // have to wait for the goroutine to start and run the server - // otherwise the main thread will complete - time.Sleep(5 * time.Millisecond) + + // Wait for server to be ready with exponential backoff + err := waitForServerReady("http://localhost:5150/example", 10) + require.NoError(t, err, "server should start successfully") require.Error(t, router.Run(":5150")) testRequest(t, "http://localhost:5150/example") diff --git a/gin_test.go b/gin_test.go index 21bf71d8..81343d88 100644 --- a/gin_test.go +++ b/gin_test.go @@ -545,6 +545,29 @@ func TestNoMethodWithoutGlobalHandlers(t *testing.T) { } func TestRebuild404Handlers(t *testing.T) { + var middleware0 HandlerFunc = func(c *Context) {} + var middleware1 HandlerFunc = func(c *Context) {} + + router := New() + + // Initially, allNoRoute should be nil + assert.Nil(t, router.allNoRoute) + + // Set NoRoute handlers + router.NoRoute(middleware0) + assert.Len(t, router.allNoRoute, 1) + assert.Len(t, router.noRoute, 1) + compareFunc(t, router.allNoRoute[0], middleware0) + + // Add Use middleware should trigger rebuild404Handlers + router.Use(middleware1) + assert.Len(t, router.allNoRoute, 2) + assert.Len(t, router.Handlers, 1) + assert.Len(t, router.noRoute, 1) + + // Global middleware should come first + compareFunc(t, router.allNoRoute[0], middleware1) + compareFunc(t, router.allNoRoute[1], middleware0) } func TestNoMethodWithGlobalHandlers(t *testing.T) { diff --git a/test_helpers.go b/test_helpers.go index a1a7c562..20d20032 100644 --- a/test_helpers.go +++ b/test_helpers.go @@ -4,7 +4,11 @@ package gin -import "net/http" +import ( + "fmt" + "net/http" + "time" +) // CreateTestContext returns a fresh Engine and a Context associated with it. // This is useful for tests that need to set up a new Gin engine instance @@ -29,3 +33,28 @@ func CreateTestContextOnly(w http.ResponseWriter, r *Engine) (c *Context) { c.writermem.reset(w) return } + +// waitForServerReady waits for a server to be ready by making HTTP requests +// with exponential backoff. This is more reliable than time.Sleep() for testing. +func waitForServerReady(url string, maxAttempts int) error { + client := &http.Client{ + Timeout: 100 * time.Millisecond, + } + + for i := 0; i < maxAttempts; i++ { + resp, err := client.Get(url) + if err == nil { + resp.Body.Close() + return nil + } + + // Exponential backoff: 10ms, 20ms, 40ms, 80ms, 160ms... + backoff := time.Duration(10*(1< 500*time.Millisecond { + backoff = 500 * time.Millisecond + } + time.Sleep(backoff) + } + + return fmt.Errorf("server at %s did not become ready after %d attempts", url, maxAttempts) +}