Skip to content

Commit f5e4784

Browse files
committed
feat: implement HTTP connection hijacking for gzipWriter
- Add imports for `bufio`, `errors`, `net`, and `net/http` - Ensure `gzipWriter` implements the `http.Hijacker` interface - Implement `Hijack` method for `gzipWriter` to allow taking over the connection from the HTTP server - Add `hijackableResponse` struct and methods to support hijacking in tests - Add `TestResponseWriterHijack` to test the hijacking functionality of `gzipWriter` Signed-off-by: appleboy <[email protected]>
1 parent 807284b commit f5e4784

File tree

2 files changed

+71
-0
lines changed

2 files changed

+71
-0
lines changed

gzip.go

+22
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
package gzip
22

33
import (
4+
"bufio"
45
"compress/gzip"
6+
"errors"
7+
"net"
8+
"net/http"
59

610
"github.com/gin-gonic/gin"
711
)
@@ -43,3 +47,21 @@ func (g *gzipWriter) WriteHeader(code int) {
4347
g.Header().Del("Content-Length")
4448
g.ResponseWriter.WriteHeader(code)
4549
}
50+
51+
// Ensure gzipWriter implements the http.Hijacker interface.
52+
// This will cause a compile-time error if gzipWriter does not implement all methods of the http.Hijacker interface.
53+
var _ http.Hijacker = (*gzipWriter)(nil)
54+
55+
// Hijack allows the caller to take over the connection from the HTTP server.
56+
// After a call to Hijack, the HTTP server library will not do anything else with the connection.
57+
// It becomes the caller's responsibility to manage and close the connection.
58+
//
59+
// It returns the underlying net.Conn, a buffered reader/writer for the connection, and an error
60+
// if the ResponseWriter does not support the Hijacker interface.
61+
func (g *gzipWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) {
62+
hijacker, ok := g.ResponseWriter.(http.Hijacker)
63+
if !ok {
64+
return nil, nil, errors.New("the ResponseWriter doesn't support the Hijacker interface")
65+
}
66+
return hijacker.Hijack()
67+
}

gzip_test.go

+49
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
package gzip
22

33
import (
4+
"bufio"
45
"bytes"
56
"compress/gzip"
67
"context"
78
"fmt"
89
"io"
10+
"net"
911
"net/http"
1012
"net/http/httptest"
1113
"net/http/httputil"
@@ -15,6 +17,7 @@ import (
1517

1618
"github.com/gin-gonic/gin"
1719
"github.com/stretchr/testify/assert"
20+
"github.com/stretchr/testify/require"
1821
)
1922

2023
const (
@@ -344,3 +347,49 @@ func TestCustomShouldCompressFn(t *testing.T) {
344347
assert.Equal(t, "19", w.Header().Get("Content-Length"))
345348
assert.Equal(t, testResponse, w.Body.String())
346349
}
350+
351+
type hijackableResponse struct {
352+
Hijacked bool
353+
header http.Header
354+
}
355+
356+
func newHijackableResponse() *hijackableResponse {
357+
return &hijackableResponse{header: make(http.Header)}
358+
}
359+
360+
func (h *hijackableResponse) Header() http.Header { return h.header }
361+
func (h *hijackableResponse) Write([]byte) (int, error) { return 0, nil }
362+
func (h *hijackableResponse) WriteHeader(int) {}
363+
func (h *hijackableResponse) Flush() {}
364+
func (h *hijackableResponse) Hijack() (net.Conn, *bufio.ReadWriter, error) {
365+
h.Hijacked = true
366+
return nil, nil, nil
367+
}
368+
369+
func TestResponseWriterHijack(t *testing.T) {
370+
req, _ := http.NewRequestWithContext(context.Background(), "GET", "/", nil)
371+
req.Header.Add(headerAcceptEncoding, "gzip")
372+
373+
router := gin.New()
374+
router.Use(Gzip(
375+
DefaultCompression,
376+
WithCustomShouldCompressFn(func(_ *gin.Context) bool {
377+
return false
378+
}),
379+
)).Use(gin.HandlerFunc(func(c *gin.Context) {
380+
hj, ok := c.Writer.(http.Hijacker)
381+
require.True(t, ok)
382+
383+
_, _, err := hj.Hijack()
384+
assert.Nil(t, err)
385+
c.Next()
386+
}))
387+
router.GET("/", func(c *gin.Context) {
388+
c.Header("Content-Length", strconv.Itoa(len(testResponse)))
389+
c.String(200, testResponse)
390+
})
391+
392+
hijackable := newHijackableResponse()
393+
router.ServeHTTP(hijackable, req)
394+
assert.True(t, hijackable.Hijacked)
395+
}

0 commit comments

Comments
 (0)