From 47a03c7cf23e41bb45193ab400ad01c89b1c89a2 Mon Sep 17 00:00:00 2001 From: Abhiyan Khanal Date: Sat, 7 Mar 2026 17:10:04 +0545 Subject: [PATCH] feat(engine): add H2CConfig to allow configuring h2c http2.Server Co-Authored-By: Claude Opus 4.6 --- gin.go | 8 ++++++++ gin_test.go | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+) diff --git a/gin.go b/gin.go index 2e033bf3..f29a8757 100644 --- a/gin.go +++ b/gin.go @@ -169,6 +169,11 @@ type Engine struct { // UseH2C enable h2c support. UseH2C bool + // H2CConfig optionally specifies the http2.Server configuration used for h2c connections. + // If nil, a default &http2.Server{} is used. Set this to configure options such as + // MaxConcurrentStreams, IdleTimeout, etc. + H2CConfig *http2.Server + // ContextWithFallback enable fallback Context.Deadline(), Context.Done(), Context.Err() and Context.Value() when Context.Request.Context() is not nil. ContextWithFallback bool @@ -246,6 +251,9 @@ func (engine *Engine) Handler() http.Handler { } h2s := &http2.Server{} + if engine.H2CConfig != nil { + h2s = engine.H2CConfig + } return h2c.NewHandler(engine, h2s) } diff --git a/gin_test.go b/gin_test.go index 43c9494d..55764a4b 100644 --- a/gin_test.go +++ b/gin_test.go @@ -120,6 +120,55 @@ func TestH2c(t *testing.T) { assert.Equal(t, "

Hello world

", string(resp)) } +func TestH2CHandlerDefaultConfig(t *testing.T) { + r := Default() + r.UseH2C = true + handler := r.Handler() + // When UseH2C is true and H2CConfig is nil, Handler() should return an h2c handler (not the engine itself). + assert.NotEqual(t, r, handler) +} + +func TestH2CHandlerWithCustomConfig(t *testing.T) { + ln, err := net.Listen("tcp", localhostIP+":0") + if err != nil { + t.Error(err) + } + r := Default() + r.UseH2C = true + r.H2CConfig = &http2.Server{ + IdleTimeout: 60 * time.Second, + } + r.GET("/", func(c *Context) { + c.String(200, "

Hello world

") + }) + go func() { + err := http.Serve(ln, r.Handler()) + if err != nil { + t.Log(err) + } + }() + defer ln.Close() + + url := "http://" + ln.Addr().String() + "/" + + httpClient := http.Client{ + Transport: &http2.Transport{ + AllowHTTP: true, + DialTLS: func(netw, addr string, cfg *tls.Config) (net.Conn, error) { + return net.Dial(netw, addr) + }, + }, + } + + res, err := httpClient.Get(url) + if err != nil { + t.Error(err) + } + + resp, _ := io.ReadAll(res.Body) + assert.Equal(t, "

Hello world

", string(resp)) +} + func TestLoadHTMLGlobTestMode(t *testing.T) { ts := setupHTMLFiles( t,