diff --git a/README.md b/README.md index 1a3c195..77cdaf7 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ [![](https://godoc.org/github.com/nathany/looper?status.svg)](http://godoc.org/github.com/bnkamalesh/webgo) [![](https://awesome.re/mentioned-badge.svg)](https://github.com/avelino/awesome-go#web-frameworks) -# WebGo v7.0.1 +# WebGo v7.0.4 WebGo is a minimalistic router for [Go](https://golang.org) to build web applications (server side) with no 3rd party dependencies. WebGo will always be Go standard library compliant; with the HTTP handlers having the same signature as [http.HandlerFunc](https://golang.org/pkg/net/http/#HandlerFunc). diff --git a/config_test.go b/config_test.go index 5da1aea..c4d53f1 100644 --- a/config_test.go +++ b/config_test.go @@ -16,7 +16,7 @@ func TestConfig_LoadInvalid(t *testing.T) { cfg := &Config{} cfg.Load("") str := tl.out.String() - want := "open : no such file or directoryunexpected end of JSON inputPort number not provided or is invalid (should be between 0 - 65535)" + want := "open : no such file or directoryunexpected end of JSON inputport number not provided or is invalid (should be between 0 - 65535)" got := str if got != want { t.Errorf( diff --git a/errors.go b/errors.go index 0ebeff3..ea5f0cf 100644 --- a/errors.go +++ b/errors.go @@ -9,7 +9,7 @@ import ( var ( // ErrInvalidPort is the error returned when the port number provided in the config file is invalid - ErrInvalidPort = errors.New("Port number not provided or is invalid (should be between 0 - 65535)") + ErrInvalidPort = errors.New("port number not provided or is invalid (should be between 0 - 65535)") lh *logHandler ) @@ -71,7 +71,7 @@ func (lh *logHandler) Warn(data ...interface{}) { lh.warn.Println(data...) } -// Error prints log of severity 2 +// Error prints log of severity 2 func (lh *logHandler) Error(data ...interface{}) { if lh.err == nil { return diff --git a/responses.go b/responses.go index 3449684..081fa05 100644 --- a/responses.go +++ b/responses.go @@ -7,6 +7,10 @@ import ( "net/http" ) +var ( + jsonErrPayload = []byte{} +) + // ErrorData used to render the error page type ErrorData struct { ErrCode int @@ -69,14 +73,15 @@ func SendResponse(w http.ResponseWriter, data interface{}, rCode int) { w = crwAsserter(w, rCode) w.Header().Add(HeaderContentType, JSONContentType) err := json.NewEncoder(w).Encode(dOutput{Data: data, Status: rCode}) - if err != nil { - /* - In case of encoding error, send "internal server error" and - log the actual error. - */ - R500(w, ErrInternalServer) - LOGHANDLER.Error(err) + if err == nil { + return } + + // assuming the error was related to JSON encoding, so reattempting to respond + // with a static payload. This could still fail in case of network write or other error(s) + w = crwAsserter(w, http.StatusInternalServerError) + _, _ = w.Write(jsonErrPayload) + LOGHANDLER.Error(err) } // SendError is used to respond to any request with an error @@ -84,14 +89,15 @@ func SendError(w http.ResponseWriter, data interface{}, rCode int) { w = crwAsserter(w, rCode) w.Header().Add(HeaderContentType, JSONContentType) err := json.NewEncoder(w).Encode(errOutput{data, rCode}) - if err != nil { - /* - In case of encoding error, send "internal server error" and - log the actual error. - */ - R500(w, ErrInternalServer) - LOGHANDLER.Error(err) + if err == nil { + return } + + // assuming the error was related to JSON encoding, so reattempting to respond + // with a static payload. This could still fail in case of network write or other error(s) + w = crwAsserter(w, http.StatusInternalServerError) + _, _ = w.Write(jsonErrPayload) + LOGHANDLER.Error(err) } // Render is used for rendering templates (HTML) diff --git a/router.go b/router.go index 84574a7..91950c7 100644 --- a/router.go +++ b/router.go @@ -3,6 +3,7 @@ package webgo import ( "bufio" "context" + "encoding/json" "errors" "fmt" "net" @@ -14,13 +15,21 @@ import ( // responsewriter used type httpResponseWriter interface { http.ResponseWriter - http.CloseNotifier //nolint http.Flusher http.Hijacker http.Pusher } func init() { + var err error + jsonErrPayload, err = json.Marshal(errOutput{ + Errors: ErrInternalServer, + Status: http.StatusInternalServerError, + }) + if err != nil { + panic(err) + } + // ensure the custom response writer implements all the required functions crw := &customResponseWriter{} _ = httpResponseWriter(crw) @@ -93,14 +102,6 @@ func (crw *customResponseWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) { return nil, nil, errors.New("unable to create hijacker") } -// CloseNotify implements the http.CloseNotifier interface -func (crw *customResponseWriter) CloseNotify() <-chan bool { //nolint - if n, ok := crw.ResponseWriter.(http.CloseNotifier); ok { //nolint - return n.CloseNotify() - } - return nil -} - func (crw *customResponseWriter) Push(target string, opts *http.PushOptions) error { if n, ok := crw.ResponseWriter.(http.Pusher); ok { return n.Push(target, opts)