uhttp_body_bytes/lib.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195
//! This crate provides an iterator that yields the bytes in an HTTP request body. In
//! particular, it provides convenience for the use case where data is read directly from
//! a `TcpStream` into a fixed-size buffer and, after the first read, the buffer contains
//! the request headers as well as some initial chunk of the request body.
//!
//! This iterator can yield the bytes in that partial chunk, then reuse the entire buffer
//! to read further body chunks and yield the bytes from those. The result can be fed, for
//! example, into a byte-based parser such as
//! [serde_json::from_iter](https://docs.serde.rs/serde_json/de/fn.from_iter.html).
//!
//! ## Example
//!
//! ```rust
//! use uhttp_body_bytes::BodyBytes;
//! use std::io::{Cursor, Read};
//!
//! // Create a sample POST request with json payload.
//! let request = b"POST / HTTP/1.1\r\nHost: w3.org\r\n\r\n{\"k\": 42}";
//! let mut stream = Cursor::new(&request[..]);
//!
//! // Simulate reading request-line/headers and partial body into a fixed-size buffer.
//! let mut buf = [0; 36];
//! let nbytes = stream.read(&mut buf[..]).unwrap();
//! assert_eq!(nbytes, 36);
//! assert_eq!(&buf[..], &b"POST / HTTP/1.1\r\nHost: w3.org\r\n\r\n{\"k"[..]);
//!
//! // Process the headers (up to byte 33.)
//! // [...]
//! let body_start = 33;
//!
//! // Start reading body after end of headers.
//! let mut bytes = BodyBytes::new(stream, &mut buf[..], body_start, nbytes);
//! assert_eq!(bytes.next().unwrap().unwrap(), b'{');
//! assert_eq!(bytes.next().unwrap().unwrap(), b'"');
//! assert_eq!(bytes.next().unwrap().unwrap(), b'k');
//! assert_eq!(bytes.next().unwrap().unwrap(), b'"');
//! assert_eq!(bytes.next().unwrap().unwrap(), b':');
//! assert_eq!(bytes.next().unwrap().unwrap(), b' ');
//! assert_eq!(bytes.next().unwrap().unwrap(), b'4');
//! assert_eq!(bytes.next().unwrap().unwrap(), b'2');
//! assert_eq!(bytes.next().unwrap().unwrap(), b'}');
//! assert!(bytes.next().is_none());
//! ```
use std::io::Read;
/// Iterator over bytes in a stream using a slice buffer.
#[derive(PartialEq, Eq, Hash, Debug)]
pub struct BodyBytes<'a, R: Read> {
/// Underlying stream to buffer and read bytes from.
stream: R,
/// Buffer for writing TCP chunks into and reading bytes out of.
buf: &'a mut [u8],
/// Byte position in buffer to read next.
pos: usize,
/// Total number of valid bytes in buffer.
len: usize,
}
impl<'a, R: Read> BodyBytes<'a, R> {
/// Create a new `BodyBytes` to read chunks from the given stream into the given
/// buffer and iterate over the bytes in each chunk.
///
/// Before reading the first chunk from the stream, any remaining bytes in the given
/// buffer are iterated over starting at the given position out of the given length.
pub fn new(stream: R, buf: &'a mut [u8], start: usize, len: usize) -> Self {
BodyBytes {
buf: buf,
stream: stream,
pos: start,
len: len,
}
}
}
impl<'a, R: Read> Iterator for BodyBytes<'a, R> {
type Item = std::io::Result<u8>;
fn next(&mut self) -> Option<Self::Item> {
if self.pos == self.len {
let len = match self.stream.read(self.buf) {
Ok(l) => l,
Err(e) => return Some(Err(e)),
};
if len == 0 {
return None;
}
self.pos = 0;
self.len = len;
}
let b = self.buf[self.pos];
self.pos += 1;
Some(Ok(b))
}
}
#[cfg(test)]
mod test {
use super::*;
use std::io::Cursor;
#[test]
fn test_body_bytes() {
let stream = b"dy text";
let mut buf = [b'#'; 25];
(&mut buf[..]).copy_from_slice(b"GET / HTTP/1.1\r\n\r\nsome bo");
let mut r = BodyBytes::new(Cursor::new(&stream[..]), &mut buf[..], 18, 25);
assert_eq!(r.next().unwrap().unwrap(), b's');
assert_eq!(r.next().unwrap().unwrap(), b'o');
assert_eq!(r.next().unwrap().unwrap(), b'm');
assert_eq!(r.next().unwrap().unwrap(), b'e');
assert_eq!(r.next().unwrap().unwrap(), b' ');
assert_eq!(r.next().unwrap().unwrap(), b'b');
assert_eq!(r.next().unwrap().unwrap(), b'o');
assert_eq!(r.next().unwrap().unwrap(), b'd');
assert_eq!(r.next().unwrap().unwrap(), b'y');
assert_eq!(r.next().unwrap().unwrap(), b' ');
assert_eq!(r.next().unwrap().unwrap(), b't');
assert_eq!(r.next().unwrap().unwrap(), b'e');
assert_eq!(r.next().unwrap().unwrap(), b'x');
assert_eq!(r.next().unwrap().unwrap(), b't');
assert!(r.next().is_none());
let stream = b"abcdef";
let mut buf = [b'#'; 4];
let mut r = BodyBytes::new(Cursor::new(&stream[..]), &mut buf[..], 4, 4);
assert_eq!(r.next().unwrap().unwrap(), b'a');
assert_eq!(r.next().unwrap().unwrap(), b'b');
assert_eq!(r.next().unwrap().unwrap(), b'c');
assert_eq!(r.next().unwrap().unwrap(), b'd');
assert_eq!(r.next().unwrap().unwrap(), b'e');
assert_eq!(r.next().unwrap().unwrap(), b'f');
assert!(r.next().is_none());
let stream = b"cdefgh";
let mut buf = [b'#'; 4];
(&mut buf[..2]).copy_from_slice(b"ab");
let mut r = BodyBytes::new(Cursor::new(&stream[..]), &mut buf[..], 0, 2);
assert_eq!(r.next().unwrap().unwrap(), b'a');
assert_eq!(r.next().unwrap().unwrap(), b'b');
assert_eq!(r.next().unwrap().unwrap(), b'c');
assert_eq!(r.next().unwrap().unwrap(), b'd');
assert_eq!(r.next().unwrap().unwrap(), b'e');
assert_eq!(r.next().unwrap().unwrap(), b'f');
assert_eq!(r.next().unwrap().unwrap(), b'g');
assert_eq!(r.next().unwrap().unwrap(), b'h');
assert!(r.next().is_none());
let stream = b" text";
let mut buf = [b'#'; 25];
(&mut buf[..22]).copy_from_slice(b"GET / HTTP/1.1\r\n\r\nsome");
let mut r = BodyBytes::new(Cursor::new(&stream[..]), &mut buf[..], 18, 22);
assert_eq!(r.next().unwrap().unwrap(), b's');
assert_eq!(r.next().unwrap().unwrap(), b'o');
assert_eq!(r.next().unwrap().unwrap(), b'm');
assert_eq!(r.next().unwrap().unwrap(), b'e');
assert_eq!(r.next().unwrap().unwrap(), b' ');
assert_eq!(r.next().unwrap().unwrap(), b't');
assert_eq!(r.next().unwrap().unwrap(), b'e');
assert_eq!(r.next().unwrap().unwrap(), b'x');
assert_eq!(r.next().unwrap().unwrap(), b't');
assert!(r.next().is_none());
let stream = b"efghijklm";
let mut buf = [b'#'; 4];
(&mut buf[..]).copy_from_slice(b"abcd");
let mut r = BodyBytes::new(Cursor::new(&stream[..]), &mut buf[..], 2, 4);
assert_eq!(r.next().unwrap().unwrap(), b'c');
assert_eq!(r.next().unwrap().unwrap(), b'd');
assert_eq!(r.next().unwrap().unwrap(), b'e');
assert_eq!(r.next().unwrap().unwrap(), b'f');
assert_eq!(r.next().unwrap().unwrap(), b'g');
assert_eq!(r.next().unwrap().unwrap(), b'h');
assert_eq!(r.next().unwrap().unwrap(), b'i');
assert_eq!(r.next().unwrap().unwrap(), b'j');
assert_eq!(r.next().unwrap().unwrap(), b'k');
assert_eq!(r.next().unwrap().unwrap(), b'l');
assert_eq!(r.next().unwrap().unwrap(), b'm');
assert!(r.next().is_none());
}
}