diff --git a/backend/app/cmd/avatar_test.go b/backend/app/cmd/avatar_test.go index 3d84fa62..551ed6d7 100644 --- a/backend/app/cmd/avatar_test.go +++ b/backend/app/cmd/avatar_test.go @@ -21,6 +21,7 @@ func TestAvatar_Execute(t *testing.T) { _, err := p.ParseArgs([]string{"--src.type=fs", "--src.fs.path=/tmp/ava-test", "--dst.type=bolt", "--dst.bolt.file=/tmp/ava-test.db"}) require.NoError(t, err) + defer os.Remove("/tmp/ava-test.db") err = cmd.Execute(nil) assert.NoError(t, err) @@ -31,6 +32,7 @@ func TestAvatar_Execute(t *testing.T) { _, err = p.ParseArgs([]string{"--src.type=fs", "--src.fs.path=/tmp/ava-test", "--dst.type=bolt", "--dst.bolt.file=/tmp/ava-test2.db"}) require.NoError(t, err) + defer os.Remove("/tmp/ava-test2.db") err = cmd.Execute(nil) assert.Error(t, err, "failed blah") } diff --git a/backend/app/cmd/backup.go b/backend/app/cmd/backup.go index 7f8c6748..d6a77d54 100644 --- a/backend/app/cmd/backup.go +++ b/backend/app/cmd/backup.go @@ -37,6 +37,7 @@ func (ec *BackupCommand) Execute(_ []string) error { // prepare http client and request client := http.Client{} + defer client.CloseIdleConnections() ctx, cancel := context.WithTimeout(context.Background(), ec.Timeout) defer cancel() exportURL := fmt.Sprintf("%s/api/v1/admin/export?mode=file&site=%s", ec.RemarkURL, ec.Site) diff --git a/backend/app/cmd/cleanup.go b/backend/app/cmd/cleanup.go index 4409977a..dd9f9f7e 100644 --- a/backend/app/cmd/cleanup.go +++ b/backend/app/cmd/cleanup.go @@ -130,6 +130,7 @@ func (cc *CleanupCommand) postsInRange(fromS, toS string) ([]store.PostInfo, err func (cc *CleanupCommand) listPosts() ([]store.PostInfo, error) { listURL := fmt.Sprintf("%s/api/v1/list?site=%s&limit=10000", cc.RemarkURL, cc.Site) client := http.Client{Timeout: 30 * time.Second} + defer client.CloseIdleConnections() r, err := client.Get(listURL) if err != nil { return nil, fmt.Errorf("get request failed for list of posts, site %s: %w", cc.Site, err) @@ -155,8 +156,9 @@ func (cc *CleanupCommand) listComments(postURL string) ([]store.Comment, error) var err error // handle 429 error from limiter + client := http.Client{Timeout: 30 * time.Second} + defer client.CloseIdleConnections() for { - client := http.Client{Timeout: 30 * time.Second} r, err = client.Get(commentsURL) if err != nil { return nil, fmt.Errorf("get request failed for comments, %s: %w", postURL, err) @@ -187,7 +189,7 @@ func (cc *CleanupCommand) listComments(postURL string) ([]store.Comment, error) } // deleteComment with DELETE /admin/comment/{id}?site=siteID&url=post-url -func (cc *CleanupCommand) deleteComment(c store.Comment) error { +func (cc *CleanupCommand) deleteComment(c store.Comment) error { //nolint:dupl // not worth combining deleteURL := fmt.Sprintf("%s/api/v1/admin/comment/%s?site=%s&url=%s&format=plain", cc.RemarkURL, c.ID, cc.Site, c.Locator.URL) req, err := http.NewRequest("DELETE", deleteURL, http.NoBody) if err != nil { @@ -196,6 +198,7 @@ func (cc *CleanupCommand) deleteComment(c store.Comment) error { req.SetBasicAuth("admin", cc.AdminPasswd) client := http.Client{} + defer client.CloseIdleConnections() r, err := client.Do(req) if err != nil { return fmt.Errorf("delete request failed for comment %s, %s: %w", c.ID, c.Locator.URL, err) @@ -208,7 +211,7 @@ func (cc *CleanupCommand) deleteComment(c store.Comment) error { } // setTitle with PUT /admin/title/{id}?site=siteID&url=post-url -func (cc *CleanupCommand) setTitle(c store.Comment) error { +func (cc *CleanupCommand) setTitle(c store.Comment) error { //nolint:dupl // not worth combining titleURL := fmt.Sprintf("%s/api/v1/admin/title/%s?site=%s&url=%s&format=plain", cc.RemarkURL, c.ID, cc.Site, c.Locator.URL) req, err := http.NewRequest("PUT", titleURL, http.NoBody) if err != nil { @@ -217,6 +220,7 @@ func (cc *CleanupCommand) setTitle(c store.Comment) error { req.SetBasicAuth("admin", cc.AdminPasswd) client := http.Client{} + defer client.CloseIdleConnections() r, err := client.Do(req) if err != nil { return fmt.Errorf("title request failed for comment %s, %s: %w", c.ID, c.Locator.URL, err) diff --git a/backend/app/cmd/import.go b/backend/app/cmd/import.go index 3626d9ad..c7e3e7a4 100644 --- a/backend/app/cmd/import.go +++ b/backend/app/cmd/import.go @@ -34,6 +34,7 @@ func (ic *ImportCommand) Execute(_ []string) error { } client := http.Client{} + defer client.CloseIdleConnections() ctx, cancel := context.WithTimeout(context.Background(), ic.Timeout) defer cancel() importURL := fmt.Sprintf("%s/api/v1/admin/import?site=%s&provider=%s", ic.RemarkURL, ic.Site, ic.Provider) diff --git a/backend/app/cmd/remap.go b/backend/app/cmd/remap.go index 31acb8fe..3f30403b 100644 --- a/backend/app/cmd/remap.go +++ b/backend/app/cmd/remap.go @@ -32,6 +32,7 @@ func (rc *RemapCommand) Execute(_ []string) error { } client := http.Client{} + defer client.CloseIdleConnections() ctx, cancel := context.WithTimeout(context.Background(), rc.Timeout) defer cancel() remapURL := fmt.Sprintf("%s/api/v1/admin/remap?site=%s", rc.RemarkURL, rc.Site) diff --git a/backend/app/main_test.go b/backend/app/main_test.go index 6d90dbe5..dc383767 100644 --- a/backend/app/main_test.go +++ b/backend/app/main_test.go @@ -142,6 +142,7 @@ func chooseRandomUnusedPort() (port int) { func waitForHTTPServerStart(port int) { // wait for up to 10 seconds for server to start before returning it client := http.Client{Timeout: time.Second} + defer client.CloseIdleConnections() for i := 0; i < 100; i++ { time.Sleep(time.Millisecond * 100) if resp, err := client.Get(fmt.Sprintf("http://localhost:%d", port)); err == nil { diff --git a/backend/app/rest/api/admin_test.go b/backend/app/rest/api/admin_test.go index 8664959a..57e6e9b8 100644 --- a/backend/app/rest/api/admin_test.go +++ b/backend/app/rest/api/admin_test.go @@ -219,6 +219,7 @@ func TestAdmin_Pin(t *testing.T) { pin := func(val int) int { client := http.Client{} + defer client.CloseIdleConnections() req, err := http.NewRequest(http.MethodPut, fmt.Sprintf("%s/api/v1/admin/pin/%s?site=remark42&url=https://radio-t.com/blah&pin=%d", ts.URL, id1, val), http.NoBody) assert.NoError(t, err) @@ -719,6 +720,7 @@ func TestAdmin_DeleteMeRequest(t *testing.T) { assert.NoError(t, err) client := http.Client{} + defer client.CloseIdleConnections() req, err := http.NewRequest(http.MethodGet, fmt.Sprintf("%s/api/v1/admin/deleteme?token=%s", ts.URL, tkn), http.NoBody) assert.NoError(t, err) @@ -752,6 +754,7 @@ func TestAdmin_DeleteMeRequestFailed(t *testing.T) { // try with bad token client := http.Client{} + defer client.CloseIdleConnections() req, err := http.NewRequest(http.MethodGet, fmt.Sprintf("%s/api/v1/admin/deleteme?token=%s", ts.URL, "bad token"), http.NoBody) assert.NoError(t, err) req.SetBasicAuth("admin", "password") diff --git a/backend/app/rest/api/migrator_test.go b/backend/app/rest/api/migrator_test.go index 0dba5505..d3cd4e44 100644 --- a/backend/app/rest/api/migrator_test.go +++ b/backend/app/rest/api/migrator_test.go @@ -34,6 +34,7 @@ func TestMigrator_Import(t *testing.T) { "votes":{},"time":"2018-04-30T01:37:00.861387771-05:00"}`) client := &http.Client{Timeout: 1 * time.Second} + defer client.CloseIdleConnections() req, err := http.NewRequest("POST", ts.URL+"/api/v1/admin/import?site=remark42&provider=native", r) require.NoError(t, err) req.SetBasicAuth("admin", "password") @@ -92,6 +93,7 @@ func TestMigrator_ImportFromWP(t *testing.T) { r := strings.NewReader(strings.Replace(xmlTestWP, "'", "`", -1)) client := &http.Client{Timeout: 1 * time.Second} + defer client.CloseIdleConnections() req, err := http.NewRequest("POST", ts.URL+"/api/v1/admin/import?site=remark42&provider=wordpress", r) assert.NoError(t, err) req.Header.Add("Content-Type", "application/xml; charset=utf-8") @@ -120,6 +122,7 @@ func TestMigrator_ImportFromCommento(t *testing.T) { "provider":"sso:example.com","joinDate":"2021-03-19T19:27:25.954285Z","isModerator":false}]}`) client := &http.Client{Timeout: 1 * time.Second} + defer client.CloseIdleConnections() req, err := http.NewRequest("POST", ts.URL+"/api/v1/admin/import?site=remark42&provider=commento", r) assert.NoError(t, err) req.Header.Add("Content-Type", "application/json; charset=utf-8") @@ -150,6 +153,7 @@ func TestMigrator_ImportRejected(t *testing.T) { "votes":{},"time":"2018-04-30T01:37:00.861387771-05:00"}`) client := &http.Client{Timeout: 1 * time.Second} + defer client.CloseIdleConnections() req, err := http.NewRequest("POST", ts.URL+"/api/v1/admin/import?site=remark42&provider=native&secret=XYZ", r) assert.NoError(t, err) resp, err := client.Do(req) @@ -172,6 +176,7 @@ func TestMigrator_ImportDouble(t *testing.T) { } r := strings.NewReader(`{"version":1}` + strings.Join(recs, "\n")) // reader with 10k records client := &http.Client{Timeout: 1 * time.Second} + defer client.CloseIdleConnections() req, err := http.NewRequest("POST", ts.URL+"/api/v1/admin/import?site=remark42&provider=native", r) require.NoError(t, err) req.SetBasicAuth("admin", "password") @@ -182,6 +187,7 @@ func TestMigrator_ImportDouble(t *testing.T) { assert.Equal(t, http.StatusAccepted, resp.StatusCode) client = &http.Client{Timeout: 5 * time.Second} + defer client.CloseIdleConnections() req, err = http.NewRequest("POST", ts.URL+"/api/v1/admin/import?site=remark42&provider=native", r) require.NoError(t, err) req.SetBasicAuth("admin", "password") @@ -208,6 +214,7 @@ func TestMigrator_ImportWaitExpired(t *testing.T) { } r := strings.NewReader(`{"version":1}` + strings.Join(recs, "\n")) // reader with `nRecs` records client := &http.Client{Timeout: 5 * time.Second} + defer client.CloseIdleConnections() req, err := http.NewRequest("POST", ts.URL+"/api/v1/admin/import?site=remark42&provider=native", r) require.NoError(t, err) req.SetBasicAuth("admin", "password") @@ -218,6 +225,7 @@ func TestMigrator_ImportWaitExpired(t *testing.T) { assert.Equal(t, http.StatusAccepted, resp.StatusCode) client = &http.Client{Timeout: 5 * time.Second} + defer client.CloseIdleConnections() req, err = http.NewRequest("GET", ts.URL+"/api/v1/admin/wait?site=remark42&timeout=5ms", http.NoBody) require.NoError(t, err) req.SetBasicAuth("admin", "password") @@ -245,6 +253,7 @@ func TestMigrator_Export(t *testing.T) { // import comments first client := &http.Client{Timeout: 1 * time.Second} + defer client.CloseIdleConnections() req, err := http.NewRequest("POST", ts.URL+"/api/v1/admin/import?site=remark42&provider=native", r) require.NoError(t, err) req.SetBasicAuth("admin", "password") @@ -387,6 +396,7 @@ func TestMigrator_RemapReject(t *testing.T) { // without admin credentials client := &http.Client{Timeout: 1 * time.Second} + defer client.CloseIdleConnections() rules := strings.NewReader(`https://remark42.com/* https://www.remark42.com/*`) req, err := http.NewRequest("POST", ts.URL+"/api/v1/admin/remap?site=remark42", rules) require.NoError(t, err) @@ -398,6 +408,7 @@ func TestMigrator_RemapReject(t *testing.T) { func waitForMigrationCompletion(t *testing.T, ts *httptest.Server) { client := &http.Client{Timeout: 10 * time.Second} + defer client.CloseIdleConnections() req, err := http.NewRequest("GET", ts.URL+"/api/v1/admin/wait?site=remark42", http.NoBody) require.NoError(t, err) req.SetBasicAuth("admin", "password") diff --git a/backend/app/rest/api/rest_private_test.go b/backend/app/rest/api/rest_private_test.go index 3347e78d..a0138610 100644 --- a/backend/app/rest/api/rest_private_test.go +++ b/backend/app/rest/api/rest_private_test.go @@ -154,6 +154,7 @@ func TestRest_CreateRejected(t *testing.T) { // try with wrong aud client := &http.Client{Timeout: 5 * time.Second} + defer client.CloseIdleConnections() req, err := http.NewRequest("POST", ts.URL+"/api/v1/comment", strings.NewReader(body)) require.NoError(t, err) req.Header.Add("X-JWT", devTokenBadAud) @@ -250,6 +251,7 @@ func TestRest_Update(t *testing.T) { id := addComment(t, c1, ts) client := http.Client{} + defer client.CloseIdleConnections() req, err := http.NewRequest(http.MethodPut, ts.URL+"/api/v1/comment/"+id+"?site=remark42&url=https://radio-t.com/blah1", strings.NewReader(`{"text":"updated text", "summary":"my edit"}`)) assert.NoError(t, err) @@ -303,6 +305,7 @@ func TestRest_UpdateDelete(t *testing.T) { // delete a comment client := http.Client{} + defer client.CloseIdleConnections() req, err := http.NewRequest(http.MethodPut, ts.URL+"/api/v1/comment/"+id+"?site=remark42&url=https://radio-t.com/blah1", strings.NewReader(`{"delete": true, "summary":"removed by user"}`)) require.NoError(t, err) @@ -355,6 +358,7 @@ func TestRest_UpdateNotOwner(t *testing.T) { assert.NoError(t, err) client := http.Client{} + defer client.CloseIdleConnections() req, err := http.NewRequest(http.MethodPut, ts.URL+"/api/v1/comment/"+id1+ "?site=remark42&url=https://radio-t.com/blah1", strings.NewReader(`{"text":"updated text", "summary":"my edit"}`)) assert.NoError(t, err) @@ -368,6 +372,7 @@ func TestRest_UpdateNotOwner(t *testing.T) { assert.Equal(t, `{"code":3,"details":"can not edit comments for other users","error":"rejected"}`+"\n", string(body)) client = http.Client{} + defer client.CloseIdleConnections() req, err = http.NewRequest(http.MethodPut, ts.URL+"/api/v1/comment/"+id1+ "?site=remark42&url=https://radio-t.com/blah1", strings.NewReader(`ERRR "text":"updated text", "summary":"my"}`)) assert.NoError(t, err) @@ -387,6 +392,7 @@ func TestRest_UpdateWrongAud(t *testing.T) { id := addComment(t, c1, ts) client := http.Client{} + defer client.CloseIdleConnections() req, err := http.NewRequest(http.MethodPut, ts.URL+"/api/v1/comment/"+id+"?site=remark42&url=https://radio-t.com/blah1", strings.NewReader(`{"text":"updated text", "summary":"my edit"}`)) assert.NoError(t, err) @@ -406,6 +412,7 @@ func TestRest_UpdateWithRestrictedWords(t *testing.T) { id := addComment(t, c1, ts) client := http.Client{} + defer client.CloseIdleConnections() req, err := http.NewRequest(http.MethodPut, ts.URL+"/api/v1/comment/"+id+"?site=remark42&url=https://radio-t.com/blah1", strings.NewReader(`{"text":"What the duck is that?", "summary":"my edit"}`)) assert.NoError(t, err) @@ -437,6 +444,7 @@ func TestRest_Vote(t *testing.T) { vote := func(val int) int { client := http.Client{} + defer client.CloseIdleConnections() req, err := http.NewRequest(http.MethodPut, fmt.Sprintf("%s/api/v1/vote/%s?site=remark42&url=https://radio-t.com/blah&vote=%d", ts.URL, id1, val), http.NoBody) assert.NoError(t, err) @@ -526,6 +534,7 @@ func TestRest_AnonVote(t *testing.T) { vote := func(val int) int { client := http.Client{} + defer client.CloseIdleConnections() req, err := http.NewRequest(http.MethodPut, fmt.Sprintf("%s/api/v1/vote/%s?site=remark42&url=https://radio-t.com/blah&vote=%d", ts.URL, id1, val), http.NoBody) assert.NoError(t, err) @@ -538,6 +547,7 @@ func TestRest_AnonVote(t *testing.T) { getWithAnonAuth := func(url string) (body string, code int) { client := &http.Client{Timeout: 5 * time.Second} + defer client.CloseIdleConnections() req, err := http.NewRequest("GET", url, http.NoBody) require.NoError(t, err) req.Header.Add("X-JWT", anonToken) @@ -628,6 +638,7 @@ func TestRest_EmailAndTelegram(t *testing.T) { {description: "set user telegram, token is good", url: "/api/v1/telegram/subscribe?site=remark42&tkn=good_token", method: http.MethodGet, responseCode: http.StatusOK}, } client := http.Client{} + defer client.CloseIdleConnections() for _, x := range testData { x := x t.Run(x.description, func(t *testing.T) { @@ -663,6 +674,7 @@ func TestRest_EmailNotification(t *testing.T) { defer srv.privRest.notifyService.Close() client := http.Client{} + defer client.CloseIdleConnections() // create new comment from dev user req, err := http.NewRequest("POST", ts.URL+"/api/v1/comment", strings.NewReader( @@ -808,6 +820,7 @@ func TestRest_TelegramNotification(t *testing.T) { defer srv.privRest.notifyService.Close() client := http.Client{} + defer client.CloseIdleConnections() // create new comment from dev user req, err := http.NewRequest("POST", ts.URL+"/api/v1/comment", strings.NewReader( @@ -1014,6 +1027,7 @@ func TestRest_UserAllData(t *testing.T) { require.NoError(t, err) client := &http.Client{Timeout: 1 * time.Second} + defer client.CloseIdleConnections() req, err := http.NewRequest("GET", ts.URL+"/api/v1/userdata?site=remark42", http.NoBody) require.NoError(t, err) req.Header.Add("X-JWT", devToken) @@ -1066,6 +1080,7 @@ func TestRest_UserAllDataManyComments(t *testing.T) { require.NoError(t, err) } client := &http.Client{Timeout: 1 * time.Second} + defer client.CloseIdleConnections() req, err := http.NewRequest("GET", ts.URL+"/api/v1/userdata?site=remark42", http.NoBody) require.NoError(t, err) req.Header.Add("X-JWT", devToken) @@ -1090,6 +1105,7 @@ func TestRest_DeleteMe(t *testing.T) { defer teardown() client := http.Client{} + defer client.CloseIdleConnections() req, err := http.NewRequest(http.MethodPost, fmt.Sprintf("%s/api/v1/deleteme?site=remark42", ts.URL), http.NoBody) assert.NoError(t, err) req.Header.Add("X-JWT", devToken) @@ -1136,6 +1152,7 @@ func TestRest_SavePictureCtrl(t *testing.T) { require.NoError(t, bodyWriter.Close()) client := http.Client{} + defer client.CloseIdleConnections() req, err := http.NewRequest(http.MethodPost, fmt.Sprintf("%s/api/v1/picture", ts.URL), bodyBuf) require.NoError(t, err) req.Header.Add("Content-Type", contentType) @@ -1227,6 +1244,7 @@ func TestRest_CreateWithPictures(t *testing.T) { contentType := bodyWriter.FormDataContentType() require.NoError(t, bodyWriter.Close()) client := http.Client{} + defer client.CloseIdleConnections() req, err := http.NewRequest(http.MethodPost, fmt.Sprintf("%s/api/v1/picture", ts.URL), bodyBuf) require.NoError(t, err) req.Header.Add("Content-Type", contentType) diff --git a/backend/app/rest/api/rest_public_test.go b/backend/app/rest/api/rest_public_test.go index ea8eb1d3..8bfa0f50 100644 --- a/backend/app/rest/api/rest_public_test.go +++ b/backend/app/rest/api/rest_public_test.go @@ -269,6 +269,7 @@ func TestRest_FindReadOnly(t *testing.T) { // set post to read-only client := http.Client{} + defer client.CloseIdleConnections() req, err := http.NewRequest(http.MethodPut, fmt.Sprintf("%s/api/v1/admin/readonly?site=remark42&url=https://radio-t.com/blah1&ro=1", ts.URL), http.NoBody) assert.NoError(t, err) diff --git a/backend/app/rest/api/rest_test.go b/backend/app/rest/api/rest_test.go index a504c827..6a24eb57 100644 --- a/backend/app/rest/api/rest_test.go +++ b/backend/app/rest/api/rest_test.go @@ -146,6 +146,7 @@ func TestRest_RunStaticSSLMode(t *testing.T) { TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, }, } + defer client.CloseIdleConnections() resp, err := client.Get(fmt.Sprintf("http://localhost:%d/blah?param=1", port)) require.NoError(t, err) @@ -190,6 +191,7 @@ func TestRest_RunAutocertModeHTTPOnly(t *testing.T) { return http.ErrUseLastResponse }, } + defer client.CloseIdleConnections() resp, err := client.Get(fmt.Sprintf("http://localhost:%d/blah?param=1", port)) require.NoError(t, err) @@ -509,6 +511,7 @@ func get(t *testing.T, url string) (response string, statusCode int) { func sendReq(_ *testing.T, r *http.Request, tkn string) (*http.Response, error) { client := http.Client{Timeout: 5 * time.Second} + defer client.CloseIdleConnections() if tkn != "" { r.Header.Set("X-JWT", tkn) } @@ -517,6 +520,7 @@ func sendReq(_ *testing.T, r *http.Request, tkn string) (*http.Response, error) func getWithDevAuth(t *testing.T, url string) (body string, code int) { client := &http.Client{Timeout: 5 * time.Second} + defer client.CloseIdleConnections() req, err := http.NewRequest("GET", url, http.NoBody) require.NoError(t, err) req.Header.Add("X-JWT", devToken) @@ -530,6 +534,7 @@ func getWithDevAuth(t *testing.T, url string) (body string, code int) { func getWithAdminAuth(t *testing.T, url string) (response string, statusCode int) { client := &http.Client{Timeout: 5 * time.Second} + defer client.CloseIdleConnections() req, err := http.NewRequest("GET", url, http.NoBody) require.NoError(t, err) req.SetBasicAuth("admin", "password") @@ -542,6 +547,7 @@ func getWithAdminAuth(t *testing.T, url string) (response string, statusCode int } func post(t *testing.T, url, body string) (*http.Response, error) { client := &http.Client{Timeout: 5 * time.Second} + defer client.CloseIdleConnections() req, err := http.NewRequest("POST", url, strings.NewReader(body)) assert.NoError(t, err) req.SetBasicAuth("admin", "password") @@ -553,6 +559,7 @@ func addComment(t *testing.T, c store.Comment, ts *httptest.Server) string { require.NoError(t, err, "can't marshal comment %+v", c) client := &http.Client{Timeout: 5 * time.Second} + defer client.CloseIdleConnections() req, err := http.NewRequest("POST", ts.URL+"/api/v1/comment", bytes.NewBuffer(b)) require.NoError(t, err) req.Header.Add("X-JWT", devToken) diff --git a/backend/app/rest/api/ssl_test.go b/backend/app/rest/api/ssl_test.go index e9fe4f6b..fcf6b7c7 100644 --- a/backend/app/rest/api/ssl_test.go +++ b/backend/app/rest/api/ssl_test.go @@ -30,6 +30,7 @@ func TestSSL_Redirect(t *testing.T) { TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, }, } + defer client.CloseIdleConnections() // check http to https redirect response resp, err := client.Get(ts.URL + "/blah?param=1") @@ -59,6 +60,7 @@ func TestSSL_ACME_HTTPChallengeRouter(t *testing.T) { return http.ErrUseLastResponse }, } + defer client.CloseIdleConnections() // check http to https redirect response resp, err := client.Get(ts.URL + "/blah?param=1") diff --git a/backend/app/rest/proxy/image.go b/backend/app/rest/proxy/image.go index be6ce9e5..e9c3b1d6 100644 --- a/backend/app/rest/proxy/image.go +++ b/backend/app/rest/proxy/image.go @@ -145,6 +145,7 @@ func (p Image) downloadImage(ctx context.Context, imgURL string) ([]byte, error) defer cancel() client := http.Client{Timeout: 30 * time.Second} + defer client.CloseIdleConnections() var resp *http.Response err := repeater.NewDefault(5, time.Second).Do(ctx, func() error { var e error diff --git a/backend/app/store/engine/remote.go b/backend/app/store/engine/remote.go index 7c3c84f6..2ebee809 100644 --- a/backend/app/store/engine/remote.go +++ b/backend/app/store/engine/remote.go @@ -112,5 +112,6 @@ func (r *RPC) Delete(req DeleteRequest) error { // Close storage engine func (r *RPC) Close() error { _, err := r.Call("store.close") + r.Client.Client.CloseIdleConnections() return err } diff --git a/backend/app/store/service/title.go b/backend/app/store/service/title.go index 01b6a127..f3039390 100644 --- a/backend/app/store/service/title.go +++ b/backend/app/store/service/title.go @@ -40,6 +40,7 @@ func NewTitleExtractor(client http.Client) *TitleExtractor { // Get page for url and return title func (t *TitleExtractor) Get(url string) (string, error) { client := http.Client{Timeout: t.client.Timeout, Transport: t.client.Transport} + defer client.CloseIdleConnections() b, err := t.cache.Get(url, func() (interface{}, error) { resp, err := client.Get(url) if err != nil { @@ -72,6 +73,7 @@ func (t *TitleExtractor) Get(url string) (string, error) { // Close title extractor func (t *TitleExtractor) Close() error { + t.client.CloseIdleConnections() return t.cache.Close() }