123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263 |
- package util
- import (
- "bytes"
- "errors"
- "io"
- "strings"
- )
- // PeekedReadCloser is a ReadCloser that allows peeking into a stream and buffering it in memory.
- // It can be instantiated using the Peek function. After a stream has been peeked, it can still be fully
- // read by reading the PeekedReadCloser. It first drained from the memory buffer, and then from the remaining
- // underlying reader.
- type PeekedReadCloser struct {
- PeekedBytes []byte
- LimitReached bool
- peeked io.Reader
- underlying io.ReadCloser
- closed bool
- }
- // Peek reads the underlying ReadCloser into memory up until the limit and returns a PeekedReadCloser.
- // It does not return an error if limit is reached. Instead, LimitReached will be set to true.
- func Peek(underlying io.ReadCloser, limit int) (*PeekedReadCloser, error) {
- if underlying == nil {
- underlying = io.NopCloser(strings.NewReader(""))
- }
- peeked := make([]byte, limit)
- read, err := io.ReadFull(underlying, peeked)
- if err != nil && !errors.Is(err, io.ErrUnexpectedEOF) && err != io.EOF {
- return nil, err
- }
- return &PeekedReadCloser{
- PeekedBytes: peeked[:read],
- LimitReached: read == limit,
- underlying: underlying,
- peeked: bytes.NewReader(peeked[:read]),
- closed: false,
- }, nil
- }
- // Read reads from the peeked bytes and then from the underlying stream
- func (r *PeekedReadCloser) Read(p []byte) (n int, err error) {
- if r.closed {
- return 0, io.EOF
- }
- n, err = r.peeked.Read(p)
- if errors.Is(err, io.EOF) {
- return r.underlying.Read(p)
- } else if err != nil {
- return 0, err
- }
- return
- }
- // Close closes the underlying stream
- func (r *PeekedReadCloser) Close() error {
- if r.closed {
- return io.EOF
- }
- r.closed = true
- return r.underlying.Close()
- }
|