Skip to content
Permalink
Browse files

Recover from panic in body write (#687)

* Recover from panic in body stream write

* CR + Add tests
  • Loading branch information...
Bobochka authored and erikdubbelboer committed Nov 6, 2019
1 parent 87c4546 commit 70223a183c44d77b3362f263cef6cfa45650c5a5
Showing with 74 additions and 2 deletions.
  1. +13 −2 http.go
  2. +61 −0 http_test.go
15 http.go
@@ -1462,8 +1462,19 @@ func (req *Request) writeBodyStream(w *bufio.Writer) error {
return err
}

func (resp *Response) writeBodyStream(w *bufio.Writer, sendBody bool) error {
var err error
// ErrBodyStreamWritePanic is returned when panic happens during writing body stream.
type ErrBodyStreamWritePanic struct {
error
}

func (resp *Response) writeBodyStream(w *bufio.Writer, sendBody bool) (err error) {
defer func() {
if r := recover(); r != nil {
err = &ErrBodyStreamWritePanic{
error: fmt.Errorf("panic while writing body stream: %+v", r),
}
}
}()

contentLength := resp.Header.ContentLength()
if contentLength < 0 {
@@ -2189,3 +2189,64 @@ func TestResponseImmediateHeaderFlushChunked(t *testing.T) {

<-waitForIt
}

type ErroneousBodyStream struct {
errOnRead bool
errOnClose bool
}

func (ebs *ErroneousBodyStream) Read(p []byte) (n int, err error) {
if ebs.errOnRead {
panic("reading erroneous body stream")
}
return 0, io.EOF
}

func (ebs *ErroneousBodyStream) Close() error {
if ebs.errOnClose {
panic("closing erroneous body stream")
}
return nil
}

func TestResponseBodyStreamErrorOnPanicDuringRead(t *testing.T) {
t.Parallel()
var resp Response
var w bytes.Buffer
bw := bufio.NewWriter(&w)

ebs := &ErroneousBodyStream{errOnRead: true, errOnClose: false}
resp.SetBodyStream(ebs, 42)
err := resp.Write(bw)
if err == nil {
t.Fatalf("expected error when writing response.")
}
e, ok := err.(*ErrBodyStreamWritePanic)
if !ok {
t.Fatalf("expected error struct to be *ErrBodyStreamWritePanic, got: %+v.", e)
}
if e.Error() != "panic while writing body stream: reading erroneous body stream" {
t.Fatalf("unexpected error value, got: %+v.", e.Error())
}
}

func TestResponseBodyStreamErrorOnPanicDuringClose(t *testing.T) {
t.Parallel()
var resp Response
var w bytes.Buffer
bw := bufio.NewWriter(&w)

ebs := &ErroneousBodyStream{errOnRead: false, errOnClose: true}
resp.SetBodyStream(ebs, 42)
err := resp.Write(bw)
if err == nil {
t.Fatalf("expected error when writing response.")
}
e, ok := err.(*ErrBodyStreamWritePanic)
if !ok {
t.Fatalf("expected error struct to be *ErrBodyStreamWritePanic, got: %+v.", e)
}
if e.Error() != "panic while writing body stream: closing erroneous body stream" {
t.Fatalf("unexpected error value, got: %+v.", e.Error())
}
}

0 comments on commit 70223a1

Please sign in to comment.
You can’t perform that action at this time.