forked from vieter-v/vieter
100 lines
1.6 KiB
V
100 lines
1.6 KiB
V
module docker
|
|
|
|
import io
|
|
import util
|
|
import encoding.binary
|
|
import encoding.hex
|
|
|
|
struct ChunkedResponseReader {
|
|
mut:
|
|
reader io.Reader
|
|
// buf []u8
|
|
// offset int
|
|
// len int
|
|
bytes_left_in_chunk u64
|
|
end_of_stream bool
|
|
started bool
|
|
}
|
|
|
|
pub fn new_chunked_response_reader(reader io.Reader) &ChunkedResponseReader {
|
|
r := &ChunkedResponseReader{
|
|
reader: reader
|
|
}
|
|
|
|
return r
|
|
}
|
|
|
|
// We satisfy the io.Reader interface
|
|
pub fn (mut r ChunkedResponseReader) read(mut buf []u8) ?int {
|
|
if r.end_of_stream {
|
|
return none
|
|
}
|
|
|
|
if r.bytes_left_in_chunk == 0 {
|
|
r.bytes_left_in_chunk = r.read_chunk_size()?
|
|
|
|
if r.end_of_stream {
|
|
return none
|
|
}
|
|
}
|
|
|
|
mut c := 0
|
|
|
|
if buf.len > r.bytes_left_in_chunk {
|
|
c = r.reader.read(mut buf[..r.bytes_left_in_chunk])?
|
|
} else {
|
|
c = r.reader.read(mut buf)?
|
|
}
|
|
|
|
r.bytes_left_in_chunk -= u64(c)
|
|
|
|
return c
|
|
}
|
|
|
|
fn (mut r ChunkedResponseReader) read_chunk_size() ?u64 {
|
|
mut buf := []u8{len: 2}
|
|
mut res := []u8{}
|
|
|
|
if r.started {
|
|
// Each chunk ends with a `\r\n` which we want to skip first
|
|
r.reader.read(mut buf) ?
|
|
}
|
|
|
|
r.started = true
|
|
|
|
for {
|
|
c := r.reader.read(mut buf)?
|
|
res << buf[..c]
|
|
|
|
match_len := util.match_array_in_array(buf[..c], http_chunk_separator)
|
|
|
|
if match_len == http_chunk_separator.len {
|
|
break
|
|
}
|
|
|
|
if match_len > 0 {
|
|
mut buf2 := []u8{len: 2 - match_len}
|
|
c2 := r.reader.read(mut buf2)?
|
|
res << buf2[..c2]
|
|
|
|
if buf2 == http_chunk_separator[match_len..] {
|
|
break
|
|
}
|
|
}
|
|
}
|
|
|
|
mut num_data := hex.decode(res#[..-2].bytestr())?
|
|
|
|
for num_data.len < 8 {
|
|
num_data.insert(0, 0)
|
|
}
|
|
|
|
num := binary.big_endian_u64(num_data)
|
|
|
|
if num == 0 {
|
|
r.end_of_stream = true
|
|
}
|
|
|
|
return num
|
|
}
|