///| A bounded collector for one HTTP body. IPP has no outer message-length field;
///|
/// finish must be called at HTTP EOF, not when a 0x03 byte appears in a document.
pub struct MessageCollector {
limits : DecodeLimits
buffer : @buffer.Buffer
mut closed : Bool
}
///|
pub fn MessageCollector::new(
limits? : DecodeLimits = DecodeLimits::defaults(),
) -> MessageCollector raise IppError {
limits.validate()
if limits.max_message_bytes > 2147483647 - limits.max_document_bytes {
raise Invalid("combined collector limits exceed integer range")
}
{ limits, buffer: @buffer.Buffer(), closed: false, }
}
///|
pub fn MessageCollector::feed(
self : MessageCollector,
chunk : Bytes,
) -> Unit raise IppError {
if self.closed {
raise Invalid("collector is already finished")
}
let maximum = self.limits.max_message_bytes + self.limits.max_document_bytes
if chunk.length() > maximum - self.buffer.length() {
raise Limit("HTTP body bytes")
}
self.buffer.write_bytes(chunk)
}
///|
pub fn MessageCollector::length(self : MessageCollector) -> Int {
self.buffer.length()
}
///|
pub fn MessageCollector::finish(
self : MessageCollector,
) -> Message raise IppError {
if self.closed {
raise Invalid("collector is already finished")
}
self.closed = true
decode(self.buffer.to_bytes(), limits=self.limits)
}
///| A hex dump reports offsets independently of UTF-8 decoding, including binary
///|
/// document bytes. The output limit prevents an accidental multi-megabyte log.
pub fn hex_dump(
bytes : Bytes,
maximum? : Int = 1024,
width? : Int = 16,
) -> String raise IppError {
if maximum < 0 || maximum > 1048576 || width < 1 || width > 64 {
raise Invalid("invalid hex dump limits")
}
let output = StringBuilder()
let count = if bytes.length() < maximum { bytes.length() } else { maximum }
let mut offset = 0
while offset < count {
let address = offset.reinterpret_as_uint().to_string(radix=16)
for pad = address.length(); pad < 8; pad = pad + 1 {
output.write_string("0")
}
output.write_string(address)
output.write_string(" ")
let end = if count - offset < width { count } else { offset + width }
for index = offset; index < offset + width; index = index + 1 {
if index < end {
output.write_string(
bytes_to_hex(bytes.exact_view(start=index, end=index + 1).to_owned()),
)
} else {
output.write_string(" ")
}
output.write_string(" ")
}
output.write_string(" |")
for index = offset; index < end; index = index + 1 {
let byte = bytes[index].to_int()
if byte >= 32 && byte <= 126 {
output.write_char(byte.to_char().unwrap())
} else {
output.write_string(".")
}
}
output.write_string("|\n")
offset = end
}
if count < bytes.length() {
output.write_string("... \{bytes.length() - count} bytes omitted\n")
}
output.to_string()
}