From 0f494fd756b1af6176e50d436258dad0455d2a95 Mon Sep 17 00:00:00 2001 From: bensynapse <118375461+bensynapse@users.noreply.github.com> Date: Sun, 11 Oct 2026 08:13:34 +0300 Subject: [PATCH] close response bodies after loading compressed HTML --- query.go | 15 +++----- query_http_test.go | 94 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 100 insertions(+), 9 deletions(-) create mode 100644 query_http_test.go diff --git a/query.go b/query.go index ab22207..cb8b337 100644 --- a/query.go +++ b/query.go @@ -97,12 +97,12 @@ func LoadURL(url string) (*html.Node, error) { // LoadURLWithCustomClient loads the HTML document from the specified URL. Default enabling gzip on a HTTP request. // Custom HTTP Client. -func LoadURLWithClient(url string, client *http.Client)(*html.Node, error){ +func LoadURLWithClient(url string, client *http.Client) (*html.Node, error) { req, err := http.NewRequest("GET", url, nil) if err != nil { return nil, err } - if client == nil{ + if client == nil { client = http.DefaultClient } // Enable gzip compression. @@ -111,13 +111,8 @@ func LoadURLWithClient(url string, client *http.Client)(*html.Node, error){ if err != nil { return nil, err } - var reader io.ReadCloser - - defer func() { - if reader != nil { - reader.Close() - } - }() + defer resp.Body.Close() + var reader io.Reader encoding := resp.Header.Get("Content-Encoding") switch encoding { case "gzip": @@ -125,12 +120,14 @@ func LoadURLWithClient(url string, client *http.Client)(*html.Node, error){ if err != nil { return nil, err } + defer gzipReader.Close() reader = gzipReader case "deflate": zlibReader, err := zlib.NewReader(resp.Body) if err != nil { return nil, err } + defer zlibReader.Close() reader = zlibReader case "": reader = resp.Body diff --git a/query_http_test.go b/query_http_test.go new file mode 100644 index 0000000..0e588c0 --- /dev/null +++ b/query_http_test.go @@ -0,0 +1,94 @@ +package htmlquery + +import ( + "bytes" + "compress/gzip" + "compress/zlib" + "io" + "net/http" + "testing" +) + +type trackedResponseBody struct { + io.Reader + closes int +} + +func (b *trackedResponseBody) Close() error { + b.closes++ + return nil +} + +type responseTransport func(*http.Request) (*http.Response, error) + +func (f responseTransport) RoundTrip(req *http.Request) (*http.Response, error) { + return f(req) +} + +type failedResponseReader struct{} + +func (failedResponseReader) Read([]byte) (int, error) { + return 0, io.ErrClosedPipe +} + +func TestLoadURLWithClientClosesResponseBody(t *testing.T) { + const document = "