diff --git a/api.go b/api.go index 9ab6b6b2..9ed065f6 100644 --- a/api.go +++ b/api.go @@ -38,7 +38,13 @@ func (h *Headscale) KeyHandler( ) { writer.Header().Set("Content-Type", "text/plain; charset=utf-8") writer.WriteHeader(http.StatusOK) - writer.Write([]byte(MachinePublicKeyStripPrefix(h.privateKey.Public()))) + _, err := writer.Write([]byte(MachinePublicKeyStripPrefix(h.privateKey.Public()))) + if err != nil { + log.Error(). + Caller(). + Err(err). + Msg("Failed to write response") + } } type registerWebAPITemplateConfig struct { @@ -72,7 +78,13 @@ func (h *Headscale) RegisterWebAPI( if machineKeyStr == "" { writer.Header().Set("Content-Type", "text/plain; charset=utf-8") writer.WriteHeader(http.StatusBadRequest) - writer.Write([]byte("Wrong params")) + _, err := writer.Write([]byte("Wrong params")) + if err != nil { + log.Error(). + Caller(). + Err(err). + Msg("Failed to write response") + } return } @@ -87,14 +99,26 @@ func (h *Headscale) RegisterWebAPI( Msg("Could not render register web API template") writer.Header().Set("Content-Type", "text/plain; charset=utf-8") writer.WriteHeader(http.StatusInternalServerError) - writer.Write([]byte("Could not render register web API template")) + _, err = writer.Write([]byte("Could not render register web API template")) + if err != nil { + log.Error(). + Caller(). + Err(err). + Msg("Failed to write response") + } return } writer.Header().Set("Content-Type", "text/html; charset=utf-8") writer.WriteHeader(http.StatusOK) - writer.Write(content.Bytes()) + _, err := writer.Write(content.Bytes()) + if err != nil { + log.Error(). + Caller(). + Err(err). + Msg("Failed to write response") + } } // RegistrationHandler handles the actual registration process of a machine @@ -407,7 +431,13 @@ func (h *Headscale) handleMachineLogOut( writer.Header().Set("Content-Type", "application/json; charset=utf-8") writer.WriteHeader(http.StatusOK) - writer.Write(respBody) + _, err = writer.Write(respBody) + if err != nil { + log.Error(). + Caller(). + Err(err). + Msg("Failed to write response") + } } func (h *Headscale) handleMachineValidRegistration( @@ -445,7 +475,13 @@ func (h *Headscale) handleMachineValidRegistration( writer.Header().Set("Content-Type", "application/json; charset=utf-8") writer.WriteHeader(http.StatusOK) - writer.Write(respBody) + _, err = writer.Write(respBody) + if err != nil { + log.Error(). + Caller(). + Err(err). + Msg("Failed to write response") + } } func (h *Headscale) handleMachineExpired( @@ -493,7 +529,13 @@ func (h *Headscale) handleMachineExpired( writer.Header().Set("Content-Type", "application/json; charset=utf-8") writer.WriteHeader(http.StatusOK) - writer.Write(respBody) + _, err = writer.Write(respBody) + if err != nil { + log.Error(). + Caller(). + Err(err). + Msg("Failed to write response") + } } func (h *Headscale) handleMachineRefreshKey( @@ -535,7 +577,13 @@ func (h *Headscale) handleMachineRefreshKey( writer.Header().Set("Content-Type", "application/json; charset=utf-8") writer.WriteHeader(http.StatusOK) - writer.Write(respBody) + _, err = writer.Write(respBody) + if err != nil { + log.Error(). + Caller(). + Err(err). + Msg("Failed to write response") + } } func (h *Headscale) handleMachineRegistrationNew( @@ -574,7 +622,13 @@ func (h *Headscale) handleMachineRegistrationNew( writer.Header().Set("Content-Type", "application/json; charset=utf-8") writer.WriteHeader(http.StatusOK) - writer.Write(respBody) + _, err = writer.Write(respBody) + if err != nil { + log.Error(). + Caller(). + Err(err). + Msg("Failed to write response") + } } // TODO: check if any locks are needed around IP allocation. @@ -618,7 +672,13 @@ func (h *Headscale) handleAuthKey( writer.Header().Set("Content-Type", "application/json; charset=utf-8") writer.WriteHeader(http.StatusUnauthorized) - writer.Write(respBody) + _, err = writer.Write(respBody) + if err != nil { + log.Error(). + Caller(). + Err(err). + Msg("Failed to write response") + } log.Error(). Caller(). @@ -721,7 +781,14 @@ func (h *Headscale) handleAuthKey( Inc() writer.Header().Set("Content-Type", "application/json; charset=utf-8") writer.WriteHeader(http.StatusOK) - writer.Write(respBody) + _, err = writer.Write(respBody) + if err != nil { + log.Error(). + Caller(). + Err(err). + Msg("Failed to write response") + } + log.Info(). Str("func", "handleAuthKey"). Str("machine", registerRequest.Hostinfo.Hostname). diff --git a/app.go b/app.go index c3c626e5..e4e69105 100644 --- a/app.go +++ b/app.go @@ -348,7 +348,13 @@ func (h *Headscale) httpAuthenticationMiddleware(next http.Handler) http.Handler Str("client_address", req.RemoteAddr). Msg(`missing "Bearer " prefix in "Authorization" header`) writer.WriteHeader(http.StatusUnauthorized) - writer.Write([]byte("Unauthorized")) + _, err := writer.Write([]byte("Unauthorized")) + if err != nil { + log.Error(). + Caller(). + Err(err). + Msg("Failed to write response") + } return } @@ -362,7 +368,13 @@ func (h *Headscale) httpAuthenticationMiddleware(next http.Handler) http.Handler Msg("failed to validate token") writer.WriteHeader(http.StatusInternalServerError) - writer.Write([]byte("Unauthorized")) + _, err := writer.Write([]byte("Unauthorized")) + if err != nil { + log.Error(). + Caller(). + Err(err). + Msg("Failed to write response") + } return } @@ -373,7 +385,13 @@ func (h *Headscale) httpAuthenticationMiddleware(next http.Handler) http.Handler Msg("invalid token") writer.WriteHeader(http.StatusUnauthorized) - writer.Write([]byte("Unauthorized")) + _, err := writer.Write([]byte("Unauthorized")) + if err != nil { + log.Error(). + Caller(). + Err(err). + Msg("Failed to write response") + } return } @@ -409,7 +427,13 @@ func (h *Headscale) createRouter(grpcMux *runtime.ServeMux) *mux.Router { "/health", func(writer http.ResponseWriter, req *http.Request) { writer.WriteHeader(http.StatusOK) - writer.Write([]byte("{\"healthy\": \"ok\"}")) + _, err := writer.Write([]byte("{\"healthy\": \"ok\"}")) + if err != nil { + log.Error(). + Caller(). + Err(err). + Msg("Failed to write response") + } }).Methods(http.MethodGet) router.HandleFunc("/key", h.KeyHandler).Methods(http.MethodGet) diff --git a/derp_server.go b/derp_server.go index fb0acba0..098ca53e 100644 --- a/derp_server.go +++ b/derp_server.go @@ -105,7 +105,13 @@ func (h *Headscale) DERPHandler( } writer.Header().Set("Content-Type", "text/plain") writer.WriteHeader(http.StatusUpgradeRequired) - writer.Write([]byte("DERP requires connection upgrade")) + _, err := writer.Write([]byte("DERP requires connection upgrade")) + if err != nil { + log.Error(). + Caller(). + Err(err). + Msg("Failed to write response") + } return } @@ -117,7 +123,13 @@ func (h *Headscale) DERPHandler( log.Error().Caller().Msg("DERP requires Hijacker interface from Gin") writer.Header().Set("Content-Type", "text/plain") writer.WriteHeader(http.StatusInternalServerError) - writer.Write([]byte("HTTP does not support general TCP support")) + _, err := writer.Write([]byte("HTTP does not support general TCP support")) + if err != nil { + log.Error(). + Caller(). + Err(err). + Msg("Failed to write response") + } return } @@ -127,7 +139,13 @@ func (h *Headscale) DERPHandler( log.Error().Caller().Err(err).Msgf("Hijack failed") writer.Header().Set("Content-Type", "text/plain") writer.WriteHeader(http.StatusInternalServerError) - writer.Write([]byte("HTTP does not support general TCP support")) + _, err = writer.Write([]byte("HTTP does not support general TCP support")) + if err != nil { + log.Error(). + Caller(). + Err(err). + Msg("Failed to write response") + } return } @@ -160,7 +178,13 @@ func (h *Headscale) DERPProbeHandler( writer.WriteHeader(http.StatusOK) default: writer.WriteHeader(http.StatusMethodNotAllowed) - writer.Write([]byte("bogus probe method")) + _, err := writer.Write([]byte("bogus probe method")) + if err != nil { + log.Error(). + Caller(). + Err(err). + Msg("Failed to write response") + } } } @@ -196,7 +220,13 @@ func (h *Headscale) DERPBootstrapDNSHandler( } writer.Header().Set("Content-Type", "application/json") writer.WriteHeader(http.StatusOK) - json.NewEncoder(writer).Encode(dnsEntries) + err := json.NewEncoder(writer).Encode(dnsEntries) + if err != nil { + log.Error(). + Caller(). + Err(err). + Msg("Failed to write response") + } } // ServeSTUN starts a STUN server on the configured addr. diff --git a/oidc.go b/oidc.go index 171d4f80..09365a4d 100644 --- a/oidc.go +++ b/oidc.go @@ -142,7 +142,13 @@ func (h *Headscale) OIDCCallback( if code == "" || state == "" { writer.Header().Set("Content-Type", "text/plain; charset=utf-8") writer.WriteHeader(http.StatusBadRequest) - writer.Write([]byte("Wrong params")) + _, err := writer.Write([]byte("Wrong params")) + if err != nil { + log.Error(). + Caller(). + Err(err). + Msg("Failed to write response") + } return } @@ -155,7 +161,13 @@ func (h *Headscale) OIDCCallback( Msg("Could not exchange code for token") writer.Header().Set("Content-Type", "text/plain; charset=utf-8") writer.WriteHeader(http.StatusBadRequest) - writer.Write([]byte("Could not exchange code for token")) + _, err := writer.Write([]byte("Could not exchange code for token")) + if err != nil { + log.Error(). + Caller(). + Err(err). + Msg("Failed to write response") + } return } @@ -170,7 +182,13 @@ func (h *Headscale) OIDCCallback( if !rawIDTokenOK { writer.Header().Set("Content-Type", "text/plain; charset=utf-8") writer.WriteHeader(http.StatusBadRequest) - writer.Write([]byte("Could not extract ID Token")) + _, err := writer.Write([]byte("Could not extract ID Token")) + if err != nil { + log.Error(). + Caller(). + Err(err). + Msg("Failed to write response") + } return } @@ -185,7 +203,13 @@ func (h *Headscale) OIDCCallback( Msg("failed to verify id token") writer.Header().Set("Content-Type", "text/plain; charset=utf-8") writer.WriteHeader(http.StatusBadRequest) - writer.Write([]byte("Failed to verify id token")) + _, err := writer.Write([]byte("Failed to verify id token")) + if err != nil { + log.Error(). + Caller(). + Err(err). + Msg("Failed to write response") + } return } @@ -206,7 +230,13 @@ func (h *Headscale) OIDCCallback( Msg("Failed to decode id token claims") writer.Header().Set("Content-Type", "text/plain; charset=utf-8") writer.WriteHeader(http.StatusBadRequest) - writer.Write([]byte("Failed to decode id token claims")) + _, err := writer.Write([]byte("Failed to decode id token claims")) + if err != nil { + log.Error(). + Caller(). + Err(err). + Msg("Failed to write response") + } return } @@ -218,7 +248,13 @@ func (h *Headscale) OIDCCallback( log.Error().Msg("authenticated principal does not match any allowed domain") writer.Header().Set("Content-Type", "text/plain; charset=utf-8") writer.WriteHeader(http.StatusBadRequest) - writer.Write([]byte("unauthorized principal (domain mismatch)")) + _, err := writer.Write([]byte("unauthorized principal (domain mismatch)")) + if err != nil { + log.Error(). + Caller(). + Err(err). + Msg("Failed to write response") + } return } @@ -230,7 +266,13 @@ func (h *Headscale) OIDCCallback( log.Error().Msg("authenticated principal does not match any allowed user") writer.Header().Set("Content-Type", "text/plain; charset=utf-8") writer.WriteHeader(http.StatusBadRequest) - writer.Write([]byte("unauthorized principal (user mismatch)")) + _, err := writer.Write([]byte("unauthorized principal (user mismatch)")) + if err != nil { + log.Error(). + Caller(). + Err(err). + Msg("Failed to write response") + } return } @@ -243,7 +285,13 @@ func (h *Headscale) OIDCCallback( Msg("requested machine state key expired before authorisation completed") writer.Header().Set("Content-Type", "text/plain; charset=utf-8") writer.WriteHeader(http.StatusBadRequest) - writer.Write([]byte("state has expired")) + _, err := writer.Write([]byte("state has expired")) + if err != nil { + log.Error(). + Caller(). + Err(err). + Msg("Failed to write response") + } return } @@ -259,7 +307,13 @@ func (h *Headscale) OIDCCallback( Msg("could not parse machine public key") writer.Header().Set("Content-Type", "text/plain; charset=utf-8") writer.WriteHeader(http.StatusBadRequest) - writer.Write([]byte("could not parse public key")) + _, err := writer.Write([]byte("could not parse public key")) + if err != nil { + log.Error(). + Caller(). + Err(err). + Msg("Failed to write response") + } return } @@ -268,7 +322,13 @@ func (h *Headscale) OIDCCallback( log.Error().Msg("could not get machine key from cache") writer.Header().Set("Content-Type", "text/plain; charset=utf-8") writer.WriteHeader(http.StatusInternalServerError) - writer.Write([]byte("could not get machine key from cache")) + _, err := writer.Write([]byte("could not get machine key from cache")) + if err != nil { + log.Error(). + Caller(). + Err(err). + Msg("Failed to write response") + } return } @@ -300,14 +360,26 @@ func (h *Headscale) OIDCCallback( writer.Header().Set("Content-Type", "text/plain; charset=utf-8") writer.WriteHeader(http.StatusInternalServerError) - writer.Write([]byte("Could not render OIDC callback template")) + _, err := writer.Write([]byte("Could not render OIDC callback template")) + if err != nil { + log.Error(). + Caller(). + Err(err). + Msg("Failed to write response") + } return } writer.Header().Set("Content-Type", "text/html; charset=utf-8") writer.WriteHeader(http.StatusOK) - writer.Write(content.Bytes()) + _, err := writer.Write(content.Bytes()) + if err != nil { + log.Error(). + Caller(). + Err(err). + Msg("Failed to write response") + } return } @@ -320,7 +392,13 @@ func (h *Headscale) OIDCCallback( log.Error().Err(err).Caller().Msgf("couldn't normalize email") writer.Header().Set("Content-Type", "text/plain; charset=utf-8") writer.WriteHeader(http.StatusInternalServerError) - writer.Write([]byte("couldn't normalize email")) + _, err := writer.Write([]byte("couldn't normalize email")) + if err != nil { + log.Error(). + Caller(). + Err(err). + Msg("Failed to write response") + } return } @@ -339,7 +417,13 @@ func (h *Headscale) OIDCCallback( Msgf("could not create new namespace '%s'", namespaceName) writer.Header().Set("Content-Type", "text/plain; charset=utf-8") writer.WriteHeader(http.StatusInternalServerError) - writer.Write([]byte("could not create namespace")) + _, err := writer.Write([]byte("could not create namespace")) + if err != nil { + log.Error(). + Caller(). + Err(err). + Msg("Failed to write response") + } return } @@ -351,7 +435,13 @@ func (h *Headscale) OIDCCallback( Msg("could not find or create namespace") writer.Header().Set("Content-Type", "text/plain; charset=utf-8") writer.WriteHeader(http.StatusInternalServerError) - writer.Write([]byte("could not find or create namespace")) + _, err := writer.Write([]byte("could not find or create namespace")) + if err != nil { + log.Error(). + Caller(). + Err(err). + Msg("Failed to write response") + } return } @@ -370,7 +460,13 @@ func (h *Headscale) OIDCCallback( Msg("could not register machine") writer.Header().Set("Content-Type", "text/plain; charset=utf-8") writer.WriteHeader(http.StatusInternalServerError) - writer.Write([]byte("could not register machine")) + _, err := writer.Write([]byte("could not register machine")) + if err != nil { + log.Error(). + Caller(). + Err(err). + Msg("Failed to write response") + } return } @@ -388,12 +484,24 @@ func (h *Headscale) OIDCCallback( writer.Header().Set("Content-Type", "text/plain; charset=utf-8") writer.WriteHeader(http.StatusInternalServerError) - writer.Write([]byte("Could not render OIDC callback template")) + _, err := writer.Write([]byte("Could not render OIDC callback template")) + if err != nil { + log.Error(). + Caller(). + Err(err). + Msg("Failed to write response") + } return } writer.Header().Set("Content-Type", "text/html; charset=utf-8") writer.WriteHeader(http.StatusOK) - writer.Write(content.Bytes()) + _, err = writer.Write(content.Bytes()) + if err != nil { + log.Error(). + Caller(). + Err(err). + Msg("Failed to write response") + } } diff --git a/platform_config.go b/platform_config.go index 4aa58ec4..6bb195c7 100644 --- a/platform_config.go +++ b/platform_config.go @@ -69,14 +69,26 @@ REG ADD "HKLM\Software\Tailscale IPN" /v LoginURL /t REG_SZ /d "{{.URL}}" writer.Header().Set("Content-Type", "text/plain; charset=utf-8") writer.WriteHeader(http.StatusInternalServerError) - writer.Write([]byte("Could not render Windows index template")) + _, err := writer.Write([]byte("Could not render Windows index template")) + if err != nil { + log.Error(). + Caller(). + Err(err). + Msg("Failed to write response") + } return } writer.Header().Set("Content-Type", "text/html; charset=utf-8") writer.WriteHeader(http.StatusOK) - writer.Write(payload.Bytes()) + _, err := writer.Write(payload.Bytes()) + if err != nil { + log.Error(). + Caller(). + Err(err). + Msg("Failed to write response") + } } // WindowsRegConfig generates and serves a .reg file configured with the Headscale server address. @@ -97,14 +109,26 @@ func (h *Headscale) WindowsRegConfig( writer.Header().Set("Content-Type", "text/plain; charset=utf-8") writer.WriteHeader(http.StatusInternalServerError) - writer.Write([]byte("Could not render Windows registry template")) + _, err := writer.Write([]byte("Could not render Windows registry template")) + if err != nil { + log.Error(). + Caller(). + Err(err). + Msg("Failed to write response") + } return } writer.Header().Set("Content-Type", "text/x-ms-regedit; charset=utf-8") writer.WriteHeader(http.StatusOK) - writer.Write(content.Bytes()) + _, err := writer.Write(content.Bytes()) + if err != nil { + log.Error(). + Caller(). + Err(err). + Msg("Failed to write response") + } } // AppleConfigMessage shows a simple message in the browser to point the user to the iOS/MacOS profile and instructions for how to install it. @@ -175,14 +199,26 @@ func (h *Headscale) AppleConfigMessage( writer.Header().Set("Content-Type", "text/plain; charset=utf-8") writer.WriteHeader(http.StatusInternalServerError) - writer.Write([]byte("Could not render Apple index template")) + _, err := writer.Write([]byte("Could not render Apple index template")) + if err != nil { + log.Error(). + Caller(). + Err(err). + Msg("Failed to write response") + } return } writer.Header().Set("Content-Type", "text/html; charset=utf-8") writer.WriteHeader(http.StatusOK) - writer.Write(payload.Bytes()) + _, err := writer.Write(payload.Bytes()) + if err != nil { + log.Error(). + Caller(). + Err(err). + Msg("Failed to write response") + } } func (h *Headscale) ApplePlatformConfig( @@ -209,7 +245,13 @@ func (h *Headscale) ApplePlatformConfig( writer.Header().Set("Content-Type", "text/plain; charset=utf-8") writer.WriteHeader(http.StatusInternalServerError) - writer.Write([]byte("Failed to create UUID")) + _, err := writer.Write([]byte("Failed to create UUID")) + if err != nil { + log.Error(). + Caller(). + Err(err). + Msg("Failed to write response") + } return } @@ -223,7 +265,13 @@ func (h *Headscale) ApplePlatformConfig( writer.Header().Set("Content-Type", "text/plain; charset=utf-8") writer.WriteHeader(http.StatusInternalServerError) - writer.Write([]byte("Failed to create content UUID")) + _, err := writer.Write([]byte("Failed to create content UUID")) + if err != nil { + log.Error(). + Caller(). + Err(err). + Msg("Failed to write response") + } return } @@ -245,7 +293,13 @@ func (h *Headscale) ApplePlatformConfig( writer.Header().Set("Content-Type", "text/plain; charset=utf-8") writer.WriteHeader(http.StatusInternalServerError) - writer.Write([]byte("Could not render Apple macOS template")) + _, err := writer.Write([]byte("Could not render Apple macOS template")) + if err != nil { + log.Error(). + Caller(). + Err(err). + Msg("Failed to write response") + } return } @@ -258,14 +312,26 @@ func (h *Headscale) ApplePlatformConfig( writer.Header().Set("Content-Type", "text/plain; charset=utf-8") writer.WriteHeader(http.StatusInternalServerError) - writer.Write([]byte("Could not render Apple iOS template")) + _, err := writer.Write([]byte("Could not render Apple iOS template")) + if err != nil { + log.Error(). + Caller(). + Err(err). + Msg("Failed to write response") + } return } default: writer.Header().Set("Content-Type", "text/plain; charset=utf-8") writer.WriteHeader(http.StatusBadRequest) - writer.Write([]byte("Invalid platform, only ios and macos is supported")) + _, err := writer.Write([]byte("Invalid platform, only ios and macos is supported")) + if err != nil { + log.Error(). + Caller(). + Err(err). + Msg("Failed to write response") + } return } @@ -285,14 +351,26 @@ func (h *Headscale) ApplePlatformConfig( writer.Header().Set("Content-Type", "text/plain; charset=utf-8") writer.WriteHeader(http.StatusInternalServerError) - writer.Write([]byte("Could not render Apple platform template")) + _, err := writer.Write([]byte("Could not render Apple platform template")) + if err != nil { + log.Error(). + Caller(). + Err(err). + Msg("Failed to write response") + } return } writer.Header().Set("Content-Type", "application/x-apple-aspen-config; charset=utf-8") writer.WriteHeader(http.StatusOK) - writer.Write(content.Bytes()) + _, err = writer.Write(content.Bytes()) + if err != nil { + log.Error(). + Caller(). + Err(err). + Msg("Failed to write response") + } } type WindowsRegistryConfig struct { diff --git a/poll.go b/poll.go index 6a06c2fe..72e293a5 100644 --- a/poll.go +++ b/poll.go @@ -179,7 +179,13 @@ func (h *Headscale) PollNetMapHandler( writer.Header().Set("Content-Type", "application/json; charset=utf-8") writer.WriteHeader(http.StatusOK) - writer.Write(data) + _, err := writer.Write(data) + if err != nil { + log.Error(). + Caller(). + Err(err). + Msg("Failed to write response") + } return } @@ -213,7 +219,13 @@ func (h *Headscale) PollNetMapHandler( Msg("Client sent endpoint update and is ok with a response without peer list") writer.Header().Set("Content-Type", "application/json; charset=utf-8") writer.WriteHeader(http.StatusOK) - writer.Write(data) + _, err := writer.Write(data) + if err != nil { + log.Error(). + Caller(). + Err(err). + Msg("Failed to write response") + } // It sounds like we should update the nodes when we have received a endpoint update // even tho the comments in the tailscale code dont explicitly say so. updateRequestsFromNode.WithLabelValues(machine.Namespace.Name, machine.Hostname, "endpoint-update"). diff --git a/swagger.go b/swagger.go index 082117d4..588b42ab 100644 --- a/swagger.go +++ b/swagger.go @@ -57,14 +57,26 @@ func SwaggerUI( writer.Header().Set("Content-Type", "text/plain; charset=utf-8") writer.WriteHeader(http.StatusInternalServerError) - writer.Write([]byte("Could not render Swagger")) + _, err := writer.Write([]byte("Could not render Swagger")) + if err != nil { + log.Error(). + Caller(). + Err(err). + Msg("Failed to write response") + } return } writer.Header().Set("Content-Type", "text/html; charset=utf-8") writer.WriteHeader(http.StatusOK) - writer.Write(payload.Bytes()) + _, err := writer.Write(payload.Bytes()) + if err != nil { + log.Error(). + Caller(). + Err(err). + Msg("Failed to write response") + } } func SwaggerAPIv1( @@ -73,5 +85,10 @@ func SwaggerAPIv1( ) { writer.Header().Set("Content-Type", "application/json; charset=utf-88") writer.WriteHeader(http.StatusOK) - writer.Write(apiV1JSON) + if _, err := writer.Write(apiV1JSON); err != nil { + log.Error(). + Caller(). + Err(err). + Msg("Failed to write response") + } }