From 4e6f86bade597dc167c68d75889ab3e7d29201a4 Mon Sep 17 00:00:00 2001 From: jadidbourbaki Date: Sat, 30 Mar 2024 20:17:40 -0400 Subject: [PATCH 1/7] Making eTags a header not a trailer --- admin.go | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/admin.go b/admin.go index c6151d11415..1f5abcbdb8f 100644 --- a/admin.go +++ b/admin.go @@ -958,13 +958,14 @@ func handleConfig(w http.ResponseWriter, r *http.Request) error { switch r.Method { case http.MethodGet: w.Header().Set("Content-Type", "application/json") - // Set the ETag as a trailer header. - // The alternative is to write the config to a buffer, and - // then hash that. - w.Header().Set("Trailer", "ETag") - hash := etagHasher() - configWriter := io.MultiWriter(w, hash) + + // Read the config into a buffer instead of writing directory to + // the response writer, as we want to set the ETag as the header, + // not the trailer header + var buf bytes.Buffer + + configWriter := io.MultiWriter(&buf, hash) err := readConfig(r.URL.Path, configWriter) if err != nil { return APIError{HTTPStatus: http.StatusBadRequest, Err: err} @@ -973,6 +974,7 @@ func handleConfig(w http.ResponseWriter, r *http.Request) error { // we could consider setting up a sync.Pool for the summed // hashes to reduce GC pressure. w.Header().Set("Etag", makeEtag(r.URL.Path, hash)) + w.Write(buf.Bytes()) return nil From 539221f6af0072b433a22d64a6e7507499377ae7 Mon Sep 17 00:00:00 2001 From: jadidbourbaki Date: Sat, 30 Mar 2024 20:27:18 -0400 Subject: [PATCH 2/7] Checked the write --- admin.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/admin.go b/admin.go index 1f5abcbdb8f..26a5dc41ed9 100644 --- a/admin.go +++ b/admin.go @@ -974,7 +974,10 @@ func handleConfig(w http.ResponseWriter, r *http.Request) error { // we could consider setting up a sync.Pool for the summed // hashes to reduce GC pressure. w.Header().Set("Etag", makeEtag(r.URL.Path, hash)) - w.Write(buf.Bytes()) + _, err = w.Write(buf.Bytes()) + if err != nil { + return APIError{HTTPStatus: http.StatusBadRequest, Err: err} + } return nil From 9ec205ecd8685884fb6b308fc82b1236fb2617f7 Mon Sep 17 00:00:00 2001 From: jadidbourbaki Date: Sat, 30 Mar 2024 20:51:22 -0400 Subject: [PATCH 3/7] Fixed typo --- admin.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/admin.go b/admin.go index 26a5dc41ed9..6a8b1fb793e 100644 --- a/admin.go +++ b/admin.go @@ -960,7 +960,7 @@ func handleConfig(w http.ResponseWriter, r *http.Request) error { w.Header().Set("Content-Type", "application/json") hash := etagHasher() - // Read the config into a buffer instead of writing directory to + // Read the config into a buffer instead of writing directly to // the response writer, as we want to set the ETag as the header, // not the trailer header var buf bytes.Buffer From 398436ce1264bebf824789aa53a99a0c9f60490f Mon Sep 17 00:00:00 2001 From: jadidbourbaki Date: Sat, 30 Mar 2024 20:57:56 -0400 Subject: [PATCH 4/7] Corrected comment --- admin.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/admin.go b/admin.go index 6a8b1fb793e..6b708400cdc 100644 --- a/admin.go +++ b/admin.go @@ -962,7 +962,7 @@ func handleConfig(w http.ResponseWriter, r *http.Request) error { // Read the config into a buffer instead of writing directly to // the response writer, as we want to set the ETag as the header, - // not the trailer header + // not the trailer. var buf bytes.Buffer configWriter := io.MultiWriter(&buf, hash) From 9d6cf415233bde81a875c05fbf501088bbfd276b Mon Sep 17 00:00:00 2001 From: jadidbourbaki Date: Mon, 1 Apr 2024 17:14:10 -0400 Subject: [PATCH 5/7] Added sync Pool --- admin.go | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/admin.go b/admin.go index 6b708400cdc..4d47681fd05 100644 --- a/admin.go +++ b/admin.go @@ -954,6 +954,14 @@ func makeEtag(path string, hash hash.Hash) string { return fmt.Sprintf(`"%s %x"`, path, hash.Sum(nil)) } +// This buffer pool is used to keep buffers for +// reading the config file during eTag header generation +var bufferPool = sync.Pool{ + New: func() interface{} { + return new(bytes.Buffer) + }, +} + func handleConfig(w http.ResponseWriter, r *http.Request) error { switch r.Method { case http.MethodGet: @@ -963,9 +971,9 @@ func handleConfig(w http.ResponseWriter, r *http.Request) error { // Read the config into a buffer instead of writing directly to // the response writer, as we want to set the ETag as the header, // not the trailer. - var buf bytes.Buffer + buf := bufferPool.Get().(*bytes.Buffer) - configWriter := io.MultiWriter(&buf, hash) + configWriter := io.MultiWriter(buf, hash) err := readConfig(r.URL.Path, configWriter) if err != nil { return APIError{HTTPStatus: http.StatusBadRequest, Err: err} @@ -979,6 +987,9 @@ func handleConfig(w http.ResponseWriter, r *http.Request) error { return APIError{HTTPStatus: http.StatusBadRequest, Err: err} } + buf.Reset() + bufferPool.Put(buf) + return nil case http.MethodPost, From 0844a7bf424297e0fa22cc37d4f3513afaba9710 Mon Sep 17 00:00:00 2001 From: jadidbourbaki Date: Mon, 1 Apr 2024 20:41:38 -0400 Subject: [PATCH 6/7] Changed control flow of buffer reset / putting and changed error code --- admin.go | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/admin.go b/admin.go index 4d47681fd05..3917b509f8a 100644 --- a/admin.go +++ b/admin.go @@ -972,6 +972,8 @@ func handleConfig(w http.ResponseWriter, r *http.Request) error { // the response writer, as we want to set the ETag as the header, // not the trailer. buf := bufferPool.Get().(*bytes.Buffer) + buf.Reset() + defer bufferPool.Put(buf) configWriter := io.MultiWriter(buf, hash) err := readConfig(r.URL.Path, configWriter) @@ -984,12 +986,9 @@ func handleConfig(w http.ResponseWriter, r *http.Request) error { w.Header().Set("Etag", makeEtag(r.URL.Path, hash)) _, err = w.Write(buf.Bytes()) if err != nil { - return APIError{HTTPStatus: http.StatusBadRequest, Err: err} + return APIError{HTTPStatus: http.StatusInternalServerError, Err: err} } - buf.Reset() - bufferPool.Put(buf) - return nil case http.MethodPost, From a83ac95dc1e4d33e71cdcb6cc5bdff2c8400e41c Mon Sep 17 00:00:00 2001 From: jadidbourbaki Date: Tue, 2 Apr 2024 02:59:29 -0400 Subject: [PATCH 7/7] Switched from interface{} to any in bufferPool --- admin.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/admin.go b/admin.go index 3917b509f8a..13d24084dab 100644 --- a/admin.go +++ b/admin.go @@ -957,7 +957,7 @@ func makeEtag(path string, hash hash.Hash) string { // This buffer pool is used to keep buffers for // reading the config file during eTag header generation var bufferPool = sync.Pool{ - New: func() interface{} { + New: func() any { return new(bytes.Buffer) }, }