Brotli,
}
+//a cursor turning EOF into blocking errors
+#[derive(Debug)]
+struct BlockingCursor {
+ pub cursor: Cursor<Vec<u8>>,
+}
+
+impl BlockingCursor {
+ fn new() -> BlockingCursor {
+ BlockingCursor {
+ cursor: Cursor::new(Vec::with_capacity(ENCODING_CHUNK_SIZE)),
+ }
+ }
+ pub fn set_position(&mut self, pos: u64) {
+ self.cursor.set_position(pos)
+ }
+ fn position(&self) -> u64 {
+ self.cursor.position()
+ }
+ pub fn get_ref(&self) -> &Vec<u8> {
+ self.cursor.get_ref()
+ }
+}
+
+// we need to implement this as flate2 and brotli crates
+// will read from this object
+impl Write for BlockingCursor {
+ fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
+ //use the cursor, except it turns eof into blocking error
+ let r = self.cursor.write(buf);
+ match r {
+ Err(ref err) => {
+ if err.kind() == std::io::ErrorKind::UnexpectedEof {
+ return Err(std::io::ErrorKind::WouldBlock.into());
+ }
+ }
+ Ok(0) => {
+ //regular EOF turned into blocking error
+ return Err(std::io::ErrorKind::WouldBlock.into());
+ }
+ Ok(_n) => {}
+ }
+ r
+ }
+
+ fn flush(&mut self) -> std::io::Result<()> {
+ Ok(())
+ }
+}
+
/// The outer decompressor tracks the number of callbacks and time spent
/// decompressing.
pub(crate) struct Decompressor {
/// Trait that represents the decompression writers (gzip, deflate, etc.) and
/// methods needed to write to a temporary buffer.
-pub(crate) trait BufWriter: Write {
+trait BufWriter: Write {
/// Get a mutable reference to the buffer.
- fn get_mut(&mut self) -> Option<&mut Cursor<Box<[u8]>>>;
+ fn get_mut(&mut self) -> Option<&mut BlockingCursor>;
/// Notify end of data.
- fn finish(self: Box<Self>) -> std::io::Result<Cursor<Box<[u8]>>>;
+ fn finish(self: Box<Self>) -> std::io::Result<BlockingCursor>;
/// Attempt to finish this output stream, writing out final chunks of data.
fn try_finish(&mut self) -> std::io::Result<()>;
}
/// A BufWriter that doesn't consume any data.
///
/// This should be used exclusively with passthrough mode.
-struct NullBufWriter(Cursor<Box<[u8]>>);
+struct NullBufWriter(BlockingCursor);
impl Write for NullBufWriter {
fn write(&mut self, _: &[u8]) -> std::io::Result<usize> {
}
impl BufWriter for NullBufWriter {
- fn get_mut(&mut self) -> Option<&mut Cursor<Box<[u8]>>> {
+ fn get_mut(&mut self) -> Option<&mut BlockingCursor> {
Some(&mut self.0)
}
- fn finish(self: Box<Self>) -> std::io::Result<Cursor<Box<[u8]>>> {
+ fn finish(self: Box<Self>) -> std::io::Result<BlockingCursor> {
Ok(self.0)
}
buffer: Vec<u8>,
flags: u8,
xlen: u16,
- inner: flate2::write::DeflateDecoder<Cursor<Box<[u8]>>>,
+ inner: flate2::write::DeflateDecoder<BlockingCursor>,
state: GzState,
}
impl GzipBufWriter {
- fn new(buf: Cursor<Box<[u8]>>) -> Self {
+ fn new(buf: BlockingCursor) -> Self {
GzipBufWriter {
buffer: Vec::with_capacity(10),
flags: 0,
}
impl BufWriter for GzipBufWriter {
- fn get_mut(&mut self) -> Option<&mut Cursor<Box<[u8]>>> {
+ fn get_mut(&mut self) -> Option<&mut BlockingCursor> {
Some(self.inner.get_mut())
}
- fn finish(self: Box<Self>) -> std::io::Result<Cursor<Box<[u8]>>> {
+ fn finish(self: Box<Self>) -> std::io::Result<BlockingCursor> {
self.inner.finish()
}
}
/// Simple wrapper around a deflate implementation
-struct DeflateBufWriter(flate2::write::DeflateDecoder<Cursor<Box<[u8]>>>);
+struct DeflateBufWriter(flate2::write::DeflateDecoder<BlockingCursor>);
impl Write for DeflateBufWriter {
fn write(&mut self, data: &[u8]) -> std::io::Result<usize> {
}
impl BufWriter for DeflateBufWriter {
- fn get_mut(&mut self) -> Option<&mut Cursor<Box<[u8]>>> {
+ fn get_mut(&mut self) -> Option<&mut BlockingCursor> {
Some(self.0.get_mut())
}
- fn finish(self: Box<Self>) -> std::io::Result<Cursor<Box<[u8]>>> {
+ fn finish(self: Box<Self>) -> std::io::Result<BlockingCursor> {
self.0.finish()
}
}
/// Simple wrapper around a zlib implementation
-struct ZlibBufWriter(flate2::write::ZlibDecoder<Cursor<Box<[u8]>>>);
+struct ZlibBufWriter(flate2::write::ZlibDecoder<BlockingCursor>);
impl Write for ZlibBufWriter {
fn write(&mut self, data: &[u8]) -> std::io::Result<usize> {
}
impl BufWriter for ZlibBufWriter {
- fn get_mut(&mut self) -> Option<&mut Cursor<Box<[u8]>>> {
+ fn get_mut(&mut self) -> Option<&mut BlockingCursor> {
Some(self.0.get_mut())
}
- fn finish(self: Box<Self>) -> std::io::Result<Cursor<Box<[u8]>>> {
+ fn finish(self: Box<Self>) -> std::io::Result<BlockingCursor> {
self.0.finish()
}
}
/// Simple wrapper around an lzma implementation
-struct LzmaBufWriter(lzma_rs::decompress::Stream<Cursor<Box<[u8]>>>);
+struct LzmaBufWriter(lzma_rs::decompress::Stream<BlockingCursor>);
impl Write for LzmaBufWriter {
fn write(&mut self, data: &[u8]) -> std::io::Result<usize> {
}
impl BufWriter for LzmaBufWriter {
- fn get_mut(&mut self) -> Option<&mut Cursor<Box<[u8]>>> {
+ fn get_mut(&mut self) -> Option<&mut BlockingCursor> {
self.0.get_output_mut()
}
- fn finish(self: Box<Self>) -> std::io::Result<Cursor<Box<[u8]>>> {
+ fn finish(self: Box<Self>) -> std::io::Result<BlockingCursor> {
self.0.finish().map_err(|e| match e {
lzma_rs::error::Error::IoError(e) => e,
lzma_rs::error::Error::HeaderTooShort(e) => {
}
/// Simple wrapper around an lzma implementation
-struct BrotliBufWriter(brotli::DecompressorWriter<Cursor<Box<[u8]>>>);
+struct BrotliBufWriter(brotli::DecompressorWriter<BlockingCursor>);
impl Write for BrotliBufWriter {
fn write(&mut self, data: &[u8]) -> std::io::Result<usize> {
}
impl BufWriter for BrotliBufWriter {
- fn get_mut(&mut self) -> Option<&mut Cursor<Box<[u8]>>> {
+ fn get_mut(&mut self) -> Option<&mut BlockingCursor> {
Some(self.0.get_mut())
}
- fn finish(self: Box<Self>) -> std::io::Result<Cursor<Box<[u8]>>> {
+ fn finish(self: Box<Self>) -> std::io::Result<BlockingCursor> {
self.0
.into_inner()
.map_err(|_e| std::io::Error::new(std::io::ErrorKind::Other, "brotli"))
fn writer(
encoding: HtpContentEncoding, options: &Options,
) -> std::io::Result<(Box<dyn BufWriter>, bool)> {
- let buf = Cursor::new(Box::new([0u8; ENCODING_CHUNK_SIZE]) as Box<[u8]>);
+ let buf = BlockingCursor::new();
match encoding {
HtpContentEncoding::Gzip => Ok((Box::new(GzipBufWriter::new(buf)), false)),
fn test_gz_header() {
// No flags or other bits
let input = b"\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\x00";
- let buf = Cursor::new(Box::new([0u8; ENCODING_CHUNK_SIZE]) as Box<[u8]>);
+ let buf = BlockingCursor::new();
let mut gzw = GzipBufWriter::new(buf);
assert_eq!(gzw.write(input).unwrap(), input.len());
assert_eq!(gzw.state, GzState::AfterHeader);
// Just CRC
let input = b"\x1f\x8b\x08\x02\x00\x00\x00\x00\x00\x00\x11\x22";
- let buf = Cursor::new(Box::new([0u8; ENCODING_CHUNK_SIZE]) as Box<[u8]>);
+ let buf = BlockingCursor::new();
let mut gzw = GzipBufWriter::new(buf);
assert_eq!(gzw.write(input).unwrap(), input.len());
assert_eq!(gzw.state, GzState::AfterHeader);
// Just extra
let input = b"\x1f\x8b\x08\x04\x00\x00\x00\x00\x00\x00\x04\x00abcd";
- let buf = Cursor::new(Box::new([0u8; ENCODING_CHUNK_SIZE]) as Box<[u8]>);
+ let buf = BlockingCursor::new();
let mut gzw = GzipBufWriter::new(buf);
assert_eq!(gzw.write(input).unwrap(), input.len());
assert_eq!(gzw.state, GzState::AfterHeader);
// Just filename
let input = b"\x1f\x8b\x08\x08\x00\x00\x00\x00\x00\x00variable\x00";
- let buf = Cursor::new(Box::new([0u8; ENCODING_CHUNK_SIZE]) as Box<[u8]>);
+ let buf = BlockingCursor::new();
let mut gzw = GzipBufWriter::new(buf);
assert_eq!(gzw.write(input).unwrap(), input.len());
assert_eq!(gzw.state, GzState::AfterHeader);
// Just comment
let input = b"\x1f\x8b\x08\x10\x00\x00\x00\x00\x00\x00also variable\x00";
- let buf = Cursor::new(Box::new([0u8; ENCODING_CHUNK_SIZE]) as Box<[u8]>);
+ let buf = BlockingCursor::new();
let mut gzw = GzipBufWriter::new(buf);
assert_eq!(gzw.write(input).unwrap(), input.len());
assert_eq!(gzw.state, GzState::AfterHeader);
// Extra and Filename
let input = b"\x1f\x8b\x08\x0c\x00\x00\x00\x00\x00\x00\x05\x00extrafilename\x00";
- let buf = Cursor::new(Box::new([0u8; ENCODING_CHUNK_SIZE]) as Box<[u8]>);
+ let buf = BlockingCursor::new();
let mut gzw = GzipBufWriter::new(buf);
assert_eq!(gzw.write(input).unwrap(), input.len());
assert_eq!(gzw.state, GzState::AfterHeader);
// Extra and Comment and CRC
let input = b"\x1f\x8b\x08\x16\x00\x00\x00\x00\x00\x00\x05\x00extracomment\x00\x34\x12";
- let buf = Cursor::new(Box::new([0u8; ENCODING_CHUNK_SIZE]) as Box<[u8]>);
+ let buf = BlockingCursor::new();
let mut gzw = GzipBufWriter::new(buf);
assert_eq!(gzw.write(input).unwrap(), input.len());
assert_eq!(gzw.state, GzState::AfterHeader);
// Filename and Comment
let input = b"\x1f\x8b\x08\x18\x00\x00\x00\x00\x00\x00filename\x00comment\x00";
- let buf = Cursor::new(Box::new([0u8; ENCODING_CHUNK_SIZE]) as Box<[u8]>);
+ let buf = BlockingCursor::new();
let mut gzw = GzipBufWriter::new(buf);
assert_eq!(gzw.write(input).unwrap(), input.len());
assert_eq!(gzw.state, GzState::AfterHeader);
// Extra Filename and Comment and CRC
let input =
b"\x1f\x8b\x08\x1e\x00\x00\x00\x00\x00\x00\x05\x00extrafilename\x00comment\x00\x34\x12";
- let buf = Cursor::new(Box::new([0u8; ENCODING_CHUNK_SIZE]) as Box<[u8]>);
+ let buf = BlockingCursor::new();
let mut gzw = GzipBufWriter::new(buf);
assert_eq!(gzw.write(input).unwrap(), input.len());
assert_eq!(gzw.state, GzState::AfterHeader);
// Too short
let input = b"\x1f\x8b\x08\x1e\x00\x00\x00\x00\x00\x00\x05\x00extrafilename\x00comment\x00\x34";
- let buf = Cursor::new(Box::new([0u8; ENCODING_CHUNK_SIZE]) as Box<[u8]>);
+ let buf = BlockingCursor::new();
let mut gzw = GzipBufWriter::new(buf);
assert_eq!(gzw.write(input).unwrap(), input.len() - 1);
assert_eq!(gzw.state, GzState::Crc);
assert_eq!(gzw.write(input).unwrap(), input.len());
assert_eq!(gzw.state, GzState::AfterHeader);
let input = b"\x1f\x8b\x08\x01\x00\x00\x00\x00\x00";
- let buf = Cursor::new(Box::new([0u8; ENCODING_CHUNK_SIZE]) as Box<[u8]>);
+ let buf = BlockingCursor::new();
let mut gzw = GzipBufWriter::new(buf);
assert_eq!(gzw.write(input).unwrap(), input.len());
assert_eq!(gzw.state, GzState::Start);