mirror of
https://github.com/alist-org/gofakes3.git
synced 2024-08-14 19:38:30 +08:00
2077be77fb
The previous implementation expected inner.Read to always read until the end of the provided slice.
65 lines
1.3 KiB
Go
65 lines
1.3 KiB
Go
package gofakes3
|
|
|
|
import (
|
|
"fmt"
|
|
"io"
|
|
"io/ioutil"
|
|
)
|
|
|
|
type chunkedReader struct {
|
|
inner io.Reader
|
|
chunkRemain int
|
|
notFirstChunk bool
|
|
}
|
|
|
|
func newChunkedReader(inner io.Reader) *chunkedReader {
|
|
return &chunkedReader{
|
|
inner: inner,
|
|
chunkRemain: 0,
|
|
notFirstChunk: false,
|
|
}
|
|
}
|
|
|
|
func (r *chunkedReader) Read(p []byte) (n int, err error) {
|
|
sizeToRead := len(p)
|
|
for sizeToRead > 0 {
|
|
if r.chunkRemain > 0 {
|
|
// read until this chunk or sizeToRead ends
|
|
bytesToRead := sizeToRead
|
|
if sizeToRead > r.chunkRemain {
|
|
bytesToRead = r.chunkRemain
|
|
}
|
|
innerN, err := r.inner.Read(p[n : n+bytesToRead])
|
|
r.chunkRemain -= innerN
|
|
sizeToRead -= innerN
|
|
n += innerN
|
|
if err != nil {
|
|
return n, err
|
|
}
|
|
} else {
|
|
if !r.notFirstChunk {
|
|
// Is first chunk.
|
|
r.notFirstChunk = true
|
|
} else {
|
|
// skip last chunk's b"\r\n"
|
|
_, err = io.CopyN(ioutil.Discard, r.inner, 2)
|
|
if err != nil {
|
|
return n, err
|
|
}
|
|
}
|
|
// read next chunk header
|
|
chunkSize := 0
|
|
_, err = fmt.Fscanf(r.inner, "%x;", &chunkSize)
|
|
if err != nil {
|
|
return n, err
|
|
}
|
|
r.chunkRemain = chunkSize
|
|
_, err = io.CopyN(ioutil.Discard, r.inner, 16+64+2) // "chunk-signature=" + sizeOfHash + "\r\n"
|
|
if err != nil {
|
|
return n, err
|
|
}
|
|
}
|
|
}
|
|
return n, nil
|
|
}
|