diff --git a/gin.go b/gin.go
index 9bd4c46af6..b54dbd8a62 100644
--- a/gin.go
+++ b/gin.go
@@ -16,6 +16,8 @@ import (
"github.com/gin-gonic/gin/internal/bytesconv"
"github.com/gin-gonic/gin/render"
+ "golang.org/x/net/http2"
+ "golang.org/x/net/http2/h2c"
)
const defaultMultipartMemory = 32 << 20 // 32 MB
@@ -141,6 +143,9 @@ type Engine struct {
// method call.
MaxMultipartMemory int64
+ // Enable h2c support.
+ UseH2C bool
+
delims render.Delims
secureJSONPrefix string
HTMLRender render.HTMLRender
@@ -207,6 +212,15 @@ func Default() *Engine {
return engine
}
+func (engine *Engine) Handler() http.Handler {
+ if !engine.UseH2C {
+ return engine
+ }
+
+ h2s := &http2.Server{}
+ return h2c.NewHandler(engine, h2s)
+}
+
func (engine *Engine) allocateContext() *Context {
v := make(Params, 0, engine.maxParams)
skippedNodes := make([]skippedNode, 0, engine.maxSections)
@@ -361,7 +375,7 @@ func (engine *Engine) Run(addr ...string) (err error) {
address := resolveAddress(addr)
debugPrint("Listening and serving HTTP on %s\n", address)
- err = http.ListenAndServe(address, engine)
+ err = http.ListenAndServe(address, engine.Handler())
return
}
@@ -480,7 +494,7 @@ func (engine *Engine) RunTLS(addr, certFile, keyFile string) (err error) {
"Please check https://pkg.go.dev/github.com/gin-gonic/gin#readme-don-t-trust-all-proxies for details.")
}
- err = http.ListenAndServeTLS(addr, certFile, keyFile, engine)
+ err = http.ListenAndServeTLS(addr, certFile, keyFile, engine.Handler())
return
}
@@ -503,7 +517,7 @@ func (engine *Engine) RunUnix(file string) (err error) {
defer listener.Close()
defer os.Remove(file)
- err = http.Serve(listener, engine)
+ err = http.Serve(listener, engine.Handler())
return
}
@@ -540,7 +554,7 @@ func (engine *Engine) RunListener(listener net.Listener) (err error) {
"Please check https://pkg.go.dev/github.com/gin-gonic/gin#readme-don-t-trust-all-proxies for details.")
}
- err = http.Serve(listener, engine)
+ err = http.Serve(listener, engine.Handler())
return
}
diff --git a/gin_test.go b/gin_test.go
index 0aece61d16..629a109b2d 100644
--- a/gin_test.go
+++ b/gin_test.go
@@ -19,6 +19,7 @@ import (
"time"
"github.com/stretchr/testify/assert"
+ "golang.org/x/net/http2"
)
func formatAsDate(t time.Time) string {
@@ -79,6 +80,39 @@ func TestLoadHTMLGlobDebugMode(t *testing.T) {
assert.Equal(t, "Hello world
", string(resp))
}
+func TestH2c(t *testing.T) {
+ ln, err := net.Listen("tcp", "127.0.0.1:0")
+ if err != nil {
+ fmt.Println(err)
+ }
+ r := Default()
+ r.UseH2C = true
+ r.GET("/", func(c *Context) {
+ c.String(200, "Hello world
")
+ })
+ go http.Serve(ln, r.Handler())
+ defer ln.Close()
+
+ url := "http://" + ln.Addr().String() + "/"
+
+ http := 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 := http.Get(url)
+ if err != nil {
+ fmt.Println(err)
+ }
+
+ resp, _ := ioutil.ReadAll(res.Body)
+ assert.Equal(t, "Hello world
", string(resp))
+}
+
func TestLoadHTMLGlobTestMode(t *testing.T) {
ts := setupHTMLFiles(
t,
diff --git a/go.mod b/go.mod
index b088f26bb9..b59e590728 100644
--- a/go.mod
+++ b/go.mod
@@ -10,6 +10,7 @@ require (
github.com/mattn/go-isatty v0.0.14
github.com/stretchr/testify v1.7.0
github.com/ugorji/go/codec v1.2.6
+ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110
google.golang.org/protobuf v1.27.1
gopkg.in/yaml.v2 v2.4.0
)
diff --git a/go.sum b/go.sum
index 59efbf75d0..c01ba52431 100644
--- a/go.sum
+++ b/go.sum
@@ -53,6 +53,7 @@ github.com/ugorji/go/codec v1.2.6 h1:7kbGefxLoDBuYXOms4yD7223OpNMMPNPZxXk5TvFcyQ
github.com/ugorji/go/codec v1.2.6/go.mod h1:V6TCNZ4PHqoHGFZuSG1W8nrCzzdgA2DozYxWFFpvxTw=
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97 h1:/UOmuWzQfxxo9UtlXMwuQU8CMgg1eZXqTRwkSQJWKOI=
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
+golang.org/x/net v0.0.0-20210226172049-e18ecbb05110 h1:qWPm9rbaAMKs8Bq/9LRpbMqxWRVUAQwMI9fVrssnTfw=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=