deno.land / x / deno@v1.28.2 / ext / flash / chunked.rs
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273// Based on https://github.com/frewsxcv/rust-chunked-transfer/blob/5c08614458580f9e7a85124021006d83ce1ed6e9/src/decoder.rs// Copyright 2015 The tiny-http Contributors// Copyright 2015 The rust-chunked-transfer Contributors// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
use std::error::Error;use std::fmt;use std::io::Error as IoError;use std::io::ErrorKind;use std::io::Read;use std::io::Result as IoResult;
pub struct Decoder<R> { pub source: R,
// remaining size of the chunk being read // none if we are not in a chunk pub remaining_chunks_size: Option<usize>, pub end: bool,}
impl<R> Decoder<R>where R: Read,{ pub fn new(source: R, remaining_chunks_size: Option<usize>) -> Decoder<R> { Decoder { source, remaining_chunks_size, end: false, } }
fn read_chunk_size(&mut self) -> IoResult<usize> { let mut chunk_size_bytes = Vec::new(); let mut has_ext = false;
loop { let byte = match self.source.by_ref().bytes().next() { Some(b) => b?, None => { return Err(IoError::new(ErrorKind::InvalidInput, DecoderError)) } };
if byte == b'\r' { break; }
if byte == b';' { has_ext = true; break; }
chunk_size_bytes.push(byte); }
// Ignore extensions for now if has_ext { loop { let byte = match self.source.by_ref().bytes().next() { Some(b) => b?, None => { return Err(IoError::new(ErrorKind::InvalidInput, DecoderError)) } }; if byte == b'\r' { break; } } }
self.read_line_feed()?;
let chunk_size = String::from_utf8(chunk_size_bytes) .ok() .and_then(|c| usize::from_str_radix(c.trim(), 16).ok()) .ok_or_else(|| IoError::new(ErrorKind::InvalidInput, DecoderError))?;
Ok(chunk_size) }
fn read_carriage_return(&mut self) -> IoResult<()> { match self.source.by_ref().bytes().next() { Some(Ok(b'\r')) => Ok(()), _ => Err(IoError::new(ErrorKind::InvalidInput, DecoderError)), } }
fn read_line_feed(&mut self) -> IoResult<()> { match self.source.by_ref().bytes().next() { Some(Ok(b'\n')) => Ok(()), _ => Err(IoError::new(ErrorKind::InvalidInput, DecoderError)), } }}
impl<R> Read for Decoder<R>where R: Read,{ fn read(&mut self, buf: &mut [u8]) -> IoResult<usize> { let remaining_chunks_size = match self.remaining_chunks_size { Some(c) => c, None => { // first possibility: we are not in a chunk, so we'll attempt to determine // the chunks size let chunk_size = self.read_chunk_size()?;
// if the chunk size is 0, we are at EOF if chunk_size == 0 { self.read_carriage_return()?; self.read_line_feed()?; self.end = true; return Ok(0); }
chunk_size } };
// second possibility: we continue reading from a chunk if buf.len() < remaining_chunks_size { let read = self.source.read(buf)?; self.remaining_chunks_size = Some(remaining_chunks_size - read); return Ok(read); }
// third possibility: the read request goes further than the current chunk // we simply read until the end of the chunk and return let buf = &mut buf[..remaining_chunks_size]; let read = self.source.read(buf)?; self.remaining_chunks_size = if read == remaining_chunks_size { self.read_carriage_return()?; self.read_line_feed()?; None } else { Some(remaining_chunks_size - read) };
Ok(read) }}
#[derive(Debug, Copy, Clone)]struct DecoderError;
impl fmt::Display for DecoderError { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { write!(fmt, "Error while decoding chunks") }}
impl Error for DecoderError { fn description(&self) -> &str { "Error while decoding chunks" }}
#[cfg(test)]mod test { use super::Decoder; use std::io; use std::io::Read;
/// This unit test is taken from from Hyper /// https://github.com/hyperium/hyper /// Copyright (c) 2014 Sean McArthur #[test] fn test_read_chunk_size() { fn read(s: &str, expected: usize) { let mut decoded = Decoder::new(s.as_bytes(), None); let actual = decoded.read_chunk_size().unwrap(); assert_eq!(expected, actual); }
fn read_err(s: &str) { let mut decoded = Decoder::new(s.as_bytes(), None); let err_kind = decoded.read_chunk_size().unwrap_err().kind(); assert_eq!(err_kind, io::ErrorKind::InvalidInput); }
read("1\r\n", 1); read("01\r\n", 1); read("0\r\n", 0); read("00\r\n", 0); read("A\r\n", 10); read("a\r\n", 10); read("Ff\r\n", 255); read("Ff \r\n", 255); // Missing LF or CRLF read_err("F\rF"); read_err("F"); // Invalid hex digit read_err("X\r\n"); read_err("1X\r\n"); read_err("-\r\n"); read_err("-1\r\n"); // Acceptable (if not fully valid) extensions do not influence the size read("1;extension\r\n", 1); read("a;ext name=value\r\n", 10); read("1;extension;extension2\r\n", 1); read("1;;; ;\r\n", 1); read("2; extension...\r\n", 2); read("3 ; extension=123\r\n", 3); read("3 ;\r\n", 3); read("3 ; \r\n", 3); // Invalid extensions cause an error read_err("1 invalid extension\r\n"); read_err("1 A\r\n"); read_err("1;no CRLF"); }
#[test] fn test_valid_chunk_decode() { let source = io::Cursor::new( "3\r\nhel\r\nb\r\nlo world!!!\r\n0\r\n\r\n" .to_string() .into_bytes(), ); let mut decoded = Decoder::new(source, None);
let mut string = String::new(); decoded.read_to_string(&mut string).unwrap();
assert_eq!(string, "hello world!!!"); }
#[test] fn test_decode_zero_length() { let mut decoder = Decoder::new(b"0\r\n\r\n" as &[u8], None);
let mut decoded = String::new(); decoder.read_to_string(&mut decoded).unwrap();
assert_eq!(decoded, ""); }
#[test] fn test_decode_invalid_chunk_length() { let mut decoder = Decoder::new(b"m\r\n\r\n" as &[u8], None);
let mut decoded = String::new(); assert!(decoder.read_to_string(&mut decoded).is_err()); }
#[test] fn invalid_input1() { let source = io::Cursor::new( "2\r\nhel\r\nb\r\nlo world!!!\r\n0\r\n" .to_string() .into_bytes(), ); let mut decoded = Decoder::new(source, None);
let mut string = String::new(); assert!(decoded.read_to_string(&mut string).is_err()); }
#[test] fn invalid_input2() { let source = io::Cursor::new( "3\rhel\r\nb\r\nlo world!!!\r\n0\r\n" .to_string() .into_bytes(), ); let mut decoded = Decoder::new(source, None);
let mut string = String::new(); assert!(decoded.read_to_string(&mut string).is_err()); }}
Version Info