From dce71a047493d72fc211020047eda1b41fdeeafa Mon Sep 17 00:00:00 2001 From: Claudio Netto Date: Wed, 8 Feb 2023 19:01:01 -0300 Subject: [PATCH] fix(web/api): preventing panic by closing the flusher writer --- api/v1alpha1/zz_generated.deepcopy.go | 5 --- pkg/web/log.go | 48 +++++++++++++++++++++------ 2 files changed, 37 insertions(+), 16 deletions(-) diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index ce50785ed..f6a57b52f 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -15,8 +15,6 @@ import ( runtime "k8s.io/apimachinery/pkg/runtime" ) - - // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *AllowedUpstream) DeepCopyInto(out *AllowedUpstream) { *out = *in @@ -216,8 +214,6 @@ func (in *Location) DeepCopy() *Location { return out } - - // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *NginxConfig) DeepCopyInto(out *NginxConfig) { *out = *in @@ -658,7 +654,6 @@ func (in *RpaasPlanSpec) DeepCopy() *RpaasPlanSpec { return out } - // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *TLSSessionResumption) DeepCopyInto(out *TLSSessionResumption) { *out = *in diff --git a/pkg/web/log.go b/pkg/web/log.go index 3454bcd63..19f9d8f48 100644 --- a/pkg/web/log.go +++ b/pkg/web/log.go @@ -5,7 +5,7 @@ package web import ( - "fmt" + "errors" "io" "net/http" "strconv" @@ -16,27 +16,50 @@ import ( ) type flushWriter struct { - sync.Mutex - io.Writer + w io.Writer + m sync.Mutex + closed bool } func (fw *flushWriter) Write(p []byte) (int, error) { - fw.Lock() - defer fw.Unlock() + fw.m.Lock() + defer fw.m.Unlock() - n, err := fmt.Fprintln(fw.Writer, string(p)) + if fw.closed { + return 0, nil + } + + if fw.w == nil { + return 0, errors.New("no writer available") + } + + n, err := fw.w.Write(p) if err != nil { - return n, err + return 0, err + } + + if n < len(p) { + return 0, io.ErrShortWrite } - if f, ok := fw.Writer.(http.Flusher); ok { + fw.w.Write([]byte{'\n'}) // carrier return + + if f, ok := fw.w.(http.Flusher); ok { f.Flush() } return n, nil } -func extractLogArgs(c echo.Context) rpaas.LogArgs { +func (fw *flushWriter) Close() { + fw.m.Lock() + defer fw.m.Unlock() + + fw.closed = true + fw.w = io.Discard +} + +func extractLogArgs(c echo.Context, w io.Writer) rpaas.LogArgs { params := c.Request().URL.Query() var lines *int64 @@ -53,7 +76,7 @@ func extractLogArgs(c echo.Context) rpaas.LogArgs { color, _ := strconv.ParseBool(params.Get("color")) return rpaas.LogArgs{ - Stdout: &flushWriter{Writer: c.Response().Writer}, + Stdout: w, Stderr: io.Discard, Pod: params.Get("pod"), Container: params.Get("container"), @@ -70,5 +93,8 @@ func log(c echo.Context) error { return err } - return manager.Log(c.Request().Context(), c.Param("instance"), extractLogArgs(c)) + w := &flushWriter{w: c.Response()} + defer w.Close() + + return manager.Log(c.Request().Context(), c.Param("instance"), extractLogArgs(c, w)) }