package httputils import ( "bytes" "errors" "io" "net/http" "strings" ) // implementations copied from stdlib // errNoBody is a sentinel error value used by failureToReadBody so we // can detect that the lack of body was intentional. var errNoBody = errors.New("sentinel error value") // failureToReadBody is an io.ReadCloser that just returns errNoBody on // Read. It's swapped in when we don't actually want to consume // the body, but need a non-nil one, and want to distinguish the // error from reading the dummy body. type failureToReadBody struct{} func (failureToReadBody) Read([]byte) (int, error) { return 0, errNoBody } func (failureToReadBody) Close() error { return nil } // emptyBody is an instance of empty reader. var emptyBody = io.NopCloser(strings.NewReader("")) // drainBody reads all of b to memory and then returns two equivalent // ReadClosers yielding the same bytes. // // It returns an error if the initial slurp of all bytes fails. It does not attempt // to make the returned ReadClosers have identical error-matching behavior. func drainBody(b io.ReadCloser) (r1, r2 io.ReadCloser, err error) { if b == nil || b == http.NoBody { // No copying needed. Preserve the magic sentinel meaning of NoBody. return http.NoBody, http.NoBody, nil } var buf bytes.Buffer if _, err = buf.ReadFrom(b); err != nil { return nil, b, err } if err = b.Close(); err != nil { return nil, b, err } return io.NopCloser(&buf), io.NopCloser(bytes.NewReader(buf.Bytes())), nil }