Skip to content

Commit

Permalink
Additional log request handling.
Browse files Browse the repository at this point in the history
  • Loading branch information
smartyjohn committed Oct 6, 2023
1 parent 4bdcbd9 commit b6e339d
Show file tree
Hide file tree
Showing 2 changed files with 32 additions and 1 deletion.
8 changes: 7 additions & 1 deletion recovery_handler.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package httpserver

import (
"bytes"
"errors"
"fmt"
"net/http"
Expand Down Expand Up @@ -79,7 +80,12 @@ func (this *recoveryHandler) requestToString(request *http.Request) string {
}, strings.ReplaceAll(string(raw), "\r\n", "\n\t"))

if err != nil {
formatted += fmt.Sprintf(" [request formatting error: %s]", err)
// manually write out request info as it will not be returned on error (e.g. when Body is closed)
// [see implementation of DumpRequest]
b := new(bytes.Buffer)
_, _ = fmt.Fprintf(b, "%s %s HTTP/%d.%d\r\n", request.Method, request.RequestURI, request.ProtoMajor, request.ProtoMinor)
_ = request.Header.WriteSubset(b, nil)
formatted = fmt.Sprintf("%s [request formatting error: %s]", b.String(), err)
}

return fmt.Sprint("Recovered request: ", formatted)
Expand Down
25 changes: 25 additions & 0 deletions recovery_handler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"database/sql"
"errors"
"fmt"
"io"
"net/http"
"net/http/httptest"
"testing"
Expand Down Expand Up @@ -128,6 +129,22 @@ func (this *RecoveryHandlerFixture) TestInnerHandlerPanic_PostData_ReturnHTTP500
}
}

func (this *RecoveryHandlerFixture) TestInnerHandlerPanic_PostDataClosed_ReturnHTTP500() {
this.request = httptest.NewRequest("HEAD", "/", dummyReader{})

this.serveHTTPError = "panic value"
this.handler.ServeHTTP(this.response, this.request)

this.So(this.response.Code, should.Equal, 500)
this.So(this.panicRecoveredCount, should.Equal, 1)
this.So(this.panicRecoveredRequest, should.Equal, this.request)
if this.So(this.logged, should.HaveLength, 1) {
this.So(this.logged[0], should.StartWith, "[ERROR] Recovered panic: panic value")
this.So(this.logged[0], should.ContainSubstring, "closed pipe")
this.So(this.logged[0], should.ContainSubstring, "HEAD /")
}
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

func (this *RecoveryHandlerFixture) ServeHTTP(response http.ResponseWriter, request *http.Request) {
Expand All @@ -137,6 +154,9 @@ func (this *RecoveryHandlerFixture) ServeHTTP(response http.ResponseWriter, requ
if this.serveHTTPError != nil {
if request.Method == "POST" {
_, _ = request.Body.Read(make([]byte, 10)) //simulate partial read
} else if request.Method == "HEAD" {
_, _ = io.ReadAll(request.Body)
_ = request.Body.Close()
}
panic(this.serveHTTPError)
}
Expand All @@ -151,3 +171,8 @@ func (this *RecoveryHandlerFixture) PanicRecovered(request *http.Request, err an
func (this *RecoveryHandlerFixture) Printf(format string, args ...any) {
this.logged = append(this.logged, fmt.Sprintf(format, args...))
}

type dummyReader struct{}

func (d dummyReader) Close() error { return io.ErrClosedPipe }
func (d dummyReader) Read(_ []byte) (int, error) { return 0, io.EOF }

0 comments on commit b6e339d

Please sign in to comment.