chore(users/edef): move to contrib
Change-Id: I1a6972fab8ada26917f29607fc401e376d634070
This commit is contained in:
parent
a7916624dc
commit
403d8fc897
55 changed files with 15 additions and 17 deletions
103
contrib/turbofetch/src/lib.rs
Normal file
103
contrib/turbofetch/src/lib.rs
Normal file
|
|
@ -0,0 +1,103 @@
|
|||
use std::{mem::MaybeUninit, str};
|
||||
use tokio::io::{self, AsyncRead, AsyncReadExt};
|
||||
|
||||
pub use buffer::Buffer;
|
||||
mod buffer;
|
||||
|
||||
/// Read as much data into `buffer` as possible.
|
||||
/// Returns [io::ErrorKind::OutOfMemory] if the buffer is already full.
|
||||
async fn slurp(buffer: &mut Buffer, sock: &mut (impl AsyncRead + Unpin)) -> io::Result<()> {
|
||||
match buffer.space() {
|
||||
[] => Err(io::Error::new(io::ErrorKind::OutOfMemory, "buffer filled")),
|
||||
buf => {
|
||||
let n = sock.read(buf).await?;
|
||||
if n == 0 {
|
||||
return Err(io::ErrorKind::UnexpectedEof.into());
|
||||
}
|
||||
buffer.commit(n);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn get_content_length(headers: &[httparse::Header]) -> io::Result<u64> {
|
||||
for header in headers {
|
||||
if header.name == "Transfer-Encoding" {
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::InvalidData,
|
||||
"Transfer-Encoding is unsupported",
|
||||
));
|
||||
}
|
||||
|
||||
if header.name == "Content-Length" {
|
||||
return str::from_utf8(header.value)
|
||||
.ok()
|
||||
.and_then(|v| v.parse().ok())
|
||||
.ok_or_else(|| {
|
||||
io::Error::new(io::ErrorKind::InvalidData, "invalid Content-Length")
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Err(io::Error::new(
|
||||
io::ErrorKind::InvalidData,
|
||||
"Content-Length missing",
|
||||
))
|
||||
}
|
||||
|
||||
/// Read an HTTP response from `sock` using `buffer`, returning the response body.
|
||||
/// Returns an error if anything but 200 OK is received.
|
||||
///
|
||||
/// The buffer must have enough space to contain the entire response body.
|
||||
/// If there is not enough space, [io::ErrorKind::OutOfMemory] is returned.
|
||||
///
|
||||
/// The HTTP response must use `Content-Length`, without `Transfer-Encoding`.
|
||||
pub async fn parse_response<'a>(
|
||||
sock: &mut (impl AsyncRead + Unpin),
|
||||
buffer: &'a mut Buffer,
|
||||
) -> io::Result<&'a [u8]> {
|
||||
let body_len = loop {
|
||||
let mut headers = [MaybeUninit::uninit(); 16];
|
||||
let mut response = httparse::Response::new(&mut []);
|
||||
let status = httparse::ParserConfig::default()
|
||||
.parse_response_with_uninit_headers(&mut response, buffer.data(), &mut headers)
|
||||
.map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
|
||||
|
||||
if let httparse::Status::Complete(n) = status {
|
||||
buffer.consume(n);
|
||||
|
||||
let code = response.code.unwrap();
|
||||
if code != 200 {
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::Other,
|
||||
format!("HTTP response {code}"),
|
||||
));
|
||||
}
|
||||
|
||||
break get_content_length(response.headers)?;
|
||||
}
|
||||
|
||||
slurp(buffer, sock).await?;
|
||||
};
|
||||
|
||||
let buf_len = buffer.space().len() + buffer.data().len();
|
||||
|
||||
if body_len > buf_len as u64 {
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::OutOfMemory,
|
||||
"HTTP response body does not fit in buffer",
|
||||
));
|
||||
}
|
||||
|
||||
let body_len = body_len as usize;
|
||||
|
||||
while buffer.data().len() < body_len {
|
||||
slurp(buffer, sock).await?;
|
||||
}
|
||||
|
||||
let data = buffer.data();
|
||||
buffer.consume(body_len);
|
||||
|
||||
Ok(&data[..body_len])
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue