From 96061c6aa201869edfb31cefe8fc047b21c75ccd Mon Sep 17 00:00:00 2001 From: Martin Algesten Date: Fri, 28 Jun 2024 18:16:38 +0200 Subject: [PATCH] Refork frewsxcv/rust-chunked-transfer under MIT license --- src/chunked/{LICENSE => LICENSE-APACHE} | 0 src/chunked/LICENSE-MIT | 22 +++ src/chunked/decoder.rs | 20 +-- src/chunked/encoder.rs | 213 ------------------------ src/chunked/mod.rs | 17 -- 5 files changed, 24 insertions(+), 248 deletions(-) rename src/chunked/{LICENSE => LICENSE-APACHE} (100%) create mode 100644 src/chunked/LICENSE-MIT delete mode 100644 src/chunked/encoder.rs diff --git a/src/chunked/LICENSE b/src/chunked/LICENSE-APACHE similarity index 100% rename from src/chunked/LICENSE rename to src/chunked/LICENSE-APACHE diff --git a/src/chunked/LICENSE-MIT b/src/chunked/LICENSE-MIT new file mode 100644 index 00000000..892d6c7c --- /dev/null +++ b/src/chunked/LICENSE-MIT @@ -0,0 +1,22 @@ +The MIT License (MIT) + +Copyright (c) 2015 The tiny-http Contributors +Copyright (c) 2015 The rust-chunked-transfer Contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/src/chunked/decoder.rs b/src/chunked/decoder.rs index efeb0dcb..410a753d 100644 --- a/src/chunked/decoder.rs +++ b/src/chunked/decoder.rs @@ -1,18 +1,7 @@ // Copyright 2015 The tiny-http Contributors // Copyright 2015 The rust-chunked-transfer Contributors -// Forked into ureq, 2022, from https://github.com/frewsxcv/rust-chunked-transfer -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. +// Forked into ureq, 2024, from https://github.com/frewsxcv/rust-chunked-transfer +// Forked under dual MIT and Apache 2.0 license (see adjacent LICENSE-MIT and LICENSE-APACHE file) use std::error::Error; use std::fmt; @@ -57,11 +46,6 @@ where } } - /// Returns the remaining bytes left in the chunk being read. - pub fn remaining_chunks_size(&self) -> Option { - self.remaining_chunks_size - } - /// Unwraps the Decoder into its inner `Read` source. pub fn into_inner(self) -> R { self.source diff --git a/src/chunked/encoder.rs b/src/chunked/encoder.rs deleted file mode 100644 index 10d2e9e6..00000000 --- a/src/chunked/encoder.rs +++ /dev/null @@ -1,213 +0,0 @@ -// Copyright 2015 The tiny-http Contributors -// Copyright 2015 The rust-chunked-transfer Contributors -// Forked into ureq, 2022, from https://github.com/frewsxcv/rust-chunked-transfer -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -use std::io::Result as IoResult; -use std::io::Write; - -/// Splits the incoming data into HTTP chunks. -/// -/// # Example -/// -/// ```no_compile -/// use chunked_transfer::Encoder; -/// use std::io::Write; -/// -/// let mut decoded = "hello world"; -/// let mut encoded: Vec = vec![]; -/// -/// { -/// let mut encoder = Encoder::with_chunks_size(&mut encoded, 5); -/// encoder.write_all(decoded.as_bytes()); -/// } -/// -/// assert_eq!(encoded, b"5\r\nhello\r\n5\r\n worl\r\n1\r\nd\r\n0\r\n\r\n"); -/// ``` -pub struct Encoder -where - W: Write, -{ - // where to send the result - output: W, - - // size of each chunk - chunks_size: usize, - - // data waiting to be sent is stored here - // This will always be at least 6 bytes long. The first 6 bytes - // are reserved for the chunk size and \r\n. - buffer: Vec, - - // Flushes the internal buffer after each write. This might be useful - // if data should be sent immediately to downstream consumers - flush_after_write: bool, -} - -const MAX_CHUNK_SIZE: usize = std::u32::MAX as usize; -// This accounts for four hex digits (enough to hold a u32) plus two bytes -// for the \r\n -const MAX_HEADER_SIZE: usize = 6; - -impl Encoder -where - W: Write, -{ - pub fn new(output: W) -> Encoder { - Encoder::with_chunks_size(output, 8192) - } - - pub fn with_chunks_size(output: W, chunks: usize) -> Encoder { - let chunks_size = chunks.min(MAX_CHUNK_SIZE); - let mut encoder = Encoder { - output, - chunks_size, - buffer: vec![0; MAX_HEADER_SIZE], - flush_after_write: false, - }; - encoder.reset_buffer(); - encoder - } - - pub fn with_flush_after_write(output: W) -> Encoder { - let mut encoder = Encoder { - output, - chunks_size: 8192, - buffer: vec![0; MAX_HEADER_SIZE], - flush_after_write: true, - }; - encoder.reset_buffer(); - encoder - } - - fn reset_buffer(&mut self) { - // Reset buffer, still leaving space for the chunk size. That space - // will be populated once we know the size of the chunk. - self.buffer.truncate(MAX_HEADER_SIZE); - } - - fn is_buffer_empty(&self) -> bool { - self.buffer.len() == MAX_HEADER_SIZE - } - - fn buffer_len(&self) -> usize { - self.buffer.len() - MAX_HEADER_SIZE - } - - fn send(&mut self) -> IoResult<()> { - // Never send an empty buffer, because that would be interpreted - // as the end of the stream, which we indicate explicitly on drop. - if self.is_buffer_empty() { - return Ok(()); - } - // Prepend the length and \r\n to the buffer. - let prelude = format!("{:x}\r\n", self.buffer_len()); - let prelude = prelude.as_bytes(); - - // This should never happen because MAX_CHUNK_SIZE of u32::MAX - // can always be encoded in 4 hex bytes. - assert!( - prelude.len() <= MAX_HEADER_SIZE, - "invariant failed: prelude longer than MAX_HEADER_SIZE" - ); - - // Copy the prelude into the buffer. For small chunks, this won't necessarily - // take up all the space that was reserved for the prelude. - let offset = MAX_HEADER_SIZE - prelude.len(); - self.buffer[offset..MAX_HEADER_SIZE].clone_from_slice(prelude); - - // Append the chunk-finishing \r\n to the buffer. - self.buffer.write_all(b"\r\n")?; - - self.output.write_all(&self.buffer[offset..])?; - self.reset_buffer(); - - Ok(()) - } -} - -impl Write for Encoder -where - W: Write, -{ - fn write(&mut self, data: &[u8]) -> IoResult { - let remaining_buffer_space = self.chunks_size - self.buffer_len(); - let bytes_to_buffer = std::cmp::min(remaining_buffer_space, data.len()); - self.buffer.extend_from_slice(&data[0..bytes_to_buffer]); - let more_to_write: bool = bytes_to_buffer < data.len(); - if self.flush_after_write || more_to_write { - self.send()?; - } - - // If we didn't write the whole thing, keep working on it. - if more_to_write { - self.write_all(&data[bytes_to_buffer..])?; - } - Ok(data.len()) - } - - fn flush(&mut self) -> IoResult<()> { - self.send() - } -} - -impl Drop for Encoder -where - W: Write, -{ - fn drop(&mut self) { - self.flush().ok(); - write!(self.output, "0\r\n\r\n").ok(); - } -} - -#[cfg(test)] -mod test { - use super::Encoder; - use std::io; - use std::io::Write; - use std::str::from_utf8; - - #[test] - fn test() { - let mut source = io::Cursor::new("hello world".to_string().into_bytes()); - let mut dest: Vec = vec![]; - - { - let mut encoder = Encoder::with_chunks_size(dest.by_ref(), 5); - io::copy(&mut source, &mut encoder).unwrap(); - assert!(!encoder.is_buffer_empty()); - } - - let output = from_utf8(&dest).unwrap(); - - assert_eq!(output, "5\r\nhello\r\n5\r\n worl\r\n1\r\nd\r\n0\r\n\r\n"); - } - #[test] - fn flush_after_write() { - let mut source = io::Cursor::new("hello world".to_string().into_bytes()); - let mut dest: Vec = vec![]; - - { - let mut encoder = Encoder::with_flush_after_write(dest.by_ref()); - io::copy(&mut source, &mut encoder).unwrap(); - // The internal buffer has been flushed. - assert!(encoder.is_buffer_empty()); - } - - let output = from_utf8(&dest).unwrap(); - - assert_eq!(output, "b\r\nhello world\r\n0\r\n\r\n"); - } -} diff --git a/src/chunked/mod.rs b/src/chunked/mod.rs index 4402e3b4..c6e53470 100644 --- a/src/chunked/mod.rs +++ b/src/chunked/mod.rs @@ -1,20 +1,3 @@ -// Copyright 2015 The tiny-http Contributors -// Copyright 2015 The rust-chunked-transfer Contributors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. #![allow(dead_code, unused_imports)] mod decoder; pub use decoder::Decoder; - -mod encoder; -pub use encoder::Encoder;