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 }