github.com/karrick/gorill@v1.10.3/escrowReader.go (about)

     1  package gorill
     2  
     3  import (
     4  	"bytes"
     5  	"io"
     6  )
     7  
     8  // EscrowReader is a structure that mimics the io.ReadCloser interface, yet
     9  // already has all the payload bytes stored in memory along with any read error
    10  // that took place while reading the payload. The benefit of using it is that
    11  // other code may re-read the payload without an additional penalty, as the
    12  // bytes are already buffered in memory.
    13  type EscrowReader struct {
    14  	// off holds the offset into the buffer that Read will return bytes from.
    15  	off int64
    16  
    17  	// cerr holds any error that occurred whiel closing the data source.
    18  	cerr error
    19  
    20  	// rerr holds any error that occurred while reading the data source.
    21  	rerr error
    22  
    23  	buf []byte // payload holds the request body payload.
    24  }
    25  
    26  // NewEscrowReader reads and consumes all the data from the specified
    27  // io.ReadCloser into either a new bytes.Buffer or a specified bytes.Buffer,
    28  // then returns an io.ReadCloser that allows the data to be read multiple
    29  // times. It always closes the provided io.ReadCloser.
    30  //
    31  // It does not return any errors during instantiation, because any read error
    32  // encountered will be returned after the last byte is read from the provided
    33  // io.ReadCloser. Likewise any close error will be returned by the structure's
    34  // Close method.
    35  //
    36  //     func someHandler(w http.ResponseWriter, r *http.Request) {
    37  //         // Get a scratch buffer for the example. For production code, consider using
    38  //         // a free-list of buffers, such as https://github.com/karrick/gobp
    39  //         bb := new(bytes.Buffer)
    40  //         r.Body = NewEscrowReader(r.Body, bb)
    41  //         // ...
    42  //     }
    43  func NewEscrowReader(iorc io.ReadCloser, bb *bytes.Buffer) *EscrowReader {
    44  	if bb == nil {
    45  		bb = new(bytes.Buffer)
    46  	}
    47  	_, rerr := bb.ReadFrom(iorc)
    48  	if rerr == nil {
    49  		// Mimic expected behavior of returning io.EOF when there are no bytes
    50  		// remaining to be read.
    51  		rerr = io.EOF
    52  	}
    53  	cerr := iorc.Close()
    54  	return &EscrowReader{buf: bb.Bytes(), cerr: cerr, rerr: rerr}
    55  }
    56  
    57  // Bytes returns the slice of bytes read from the original data source.
    58  func (er *EscrowReader) Bytes() []byte { return er.buf }
    59  
    60  // Close returns the error that took place when closing the original
    61  // io.ReadCloser. Under normal circumstances it will be nil.
    62  func (er *EscrowReader) Close() error { return er.cerr }
    63  
    64  // Err returns the error encountered while reading from the source io.ReadCloser
    65  // if not io.EOF; otherwise it returns the error encountered while closing it.
    66  // This method comes in handy when you know you have an EscrowReader, and you
    67  // want to know whether the entire payload was slurped in.
    68  //
    69  //     func example(iorc io.ReadCloser) ([]byte, error) {
    70  //         if er, ok := iorc.(*gorill.EscrowReader); ok {
    71  //             return er.Bytes(), er.Err()
    72  //         }
    73  //     }
    74  func (er *EscrowReader) Err() error {
    75  	// An error encountered while reading has more context than an error
    76  	// encountered while closing.
    77  	if er.rerr != io.EOF {
    78  		return er.rerr
    79  	}
    80  	return er.cerr
    81  }
    82  
    83  // Read reads up to len(p) bytes into p. It returns the number of bytes read (0
    84  // <= n <= len(p)) and any error encountered. Even if Read returns n < len(p),
    85  // it may use all of p as scratch space during the call.  If some data is
    86  // available but not len(p) bytes, Read conventionally returns what is available
    87  // instead of waiting for more.
    88  //
    89  // When there are no more bytes to be read from the buffer, it will return any
    90  // error encountered when reading the original io.ReadCloser data source. That
    91  // error value is normally nil, but could be any other error other than io.EOF.
    92  func (er *EscrowReader) Read(b []byte) (int, error) {
    93  	if er.off >= int64(len(er.buf)) {
    94  		// Once everything has been read, any further reads return the error
    95  		// that was recorded when slurping in the original data source.
    96  		return 0, er.rerr
    97  	}
    98  	n := copy(b, er.buf[er.off:])
    99  	er.off += int64(n)
   100  	return n, nil
   101  }
   102  
   103  // Reset will cause the next Read to read from the beginning of the buffer.
   104  func (er *EscrowReader) Reset() {
   105  	er.off = 0
   106  }
   107  
   108  // WriteTo writes the entire buffer contents to w, and returns the number of
   109  // bytes written along with any error.
   110  func (er *EscrowReader) WriteTo(w io.Writer) (int64, error) {
   111  	var n int64
   112  	if len(er.buf) > 0 {
   113  		nw, err := w.Write(er.buf)
   114  		n = int64(nw)
   115  		if err == nil && nw != len(er.buf) {
   116  			// While io.Writer function is supposed to write all the bytes or
   117  			// return an error describing why, protect against a misbehaving
   118  			// writer that writes fewer bytes than requested and returns no
   119  			// error.
   120  			return n, io.ErrShortWrite
   121  		}
   122  		return n, err
   123  	}
   124  	return n, nil
   125  }