Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Reintroduce separate lifetimes for buffer and stream #53

Merged
merged 1 commit into from
Oct 24, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 13 additions & 14 deletions src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -230,11 +230,11 @@ where
/// The response headers are stored in the provided rx_buf, which should be sized to contain at least the response headers.
///
/// The response is returned.
pub async fn send<'buf, B: RequestBody>(
&'buf mut self,
pub async fn send<'req, 'buf, B: RequestBody>(
&'req mut self,
request: Request<'conn, B>,
rx_buf: &'buf mut [u8],
) -> Result<Response<'buf, HttpConnection<'conn, T>>, Error> {
) -> Result<Response<'req, 'buf, HttpConnection<'conn, T>>, Error> {
request.write(self).await?;
Response::read(self, request.method, rx_buf).await
}
Expand Down Expand Up @@ -326,10 +326,10 @@ where
/// The response headers are stored in the provided rx_buf, which should be sized to contain at least the response headers.
///
/// The response is returned.
pub async fn send<'buf>(
&'buf mut self,
pub async fn send<'req, 'buf>(
&'req mut self,
rx_buf: &'buf mut [u8],
) -> Result<Response<'buf, HttpConnection<'conn, C>>, Error> {
) -> Result<Response<'req, 'buf, HttpConnection<'conn, C>>, Error> {
let request = self.request.take().ok_or(Error::AlreadySent)?.build();
request.write(&mut self.conn).await?;
Response::read(&mut self.conn, request.method, rx_buf).await
Expand Down Expand Up @@ -454,11 +454,11 @@ where
/// The response headers are stored in the provided rx_buf, which should be sized to contain at least the response headers.
///
/// The response is returned.
pub async fn send<'req, B: RequestBody>(
pub async fn send<'req, 'buf, B: RequestBody>(
&'req mut self,
mut request: Request<'req, B>,
rx_buf: &'req mut [u8],
) -> Result<Response<'req, HttpConnection<'res, C>>, Error> {
rx_buf: &'buf mut [u8],
) -> Result<Response<'req, 'buf, HttpConnection<'res, C>>, Error> {
request.base_path = Some(self.base_path);
request.write(&mut self.conn).await?;
Response::read(&mut self.conn, request.method, rx_buf).await
Expand Down Expand Up @@ -486,11 +486,10 @@ where
/// The response headers are stored in the provided rx_buf, which should be sized to contain at least the response headers.
///
/// The response is returned.
pub async fn send<'buf>(self, rx_buf: &'buf mut [u8]) -> Result<Response<'buf, HttpConnection<'conn, C>>, Error>
where
'conn: 'req + 'buf,
'req: 'buf,
{
pub async fn send<'buf>(
self,
rx_buf: &'buf mut [u8],
) -> Result<Response<'req, 'buf, HttpConnection<'conn, C>>, Error> {
let conn = self.conn;
let mut request = self.request.build();
request.base_path = Some(self.base_path);
Expand Down
14 changes: 7 additions & 7 deletions src/reader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,34 +42,34 @@ impl ReadBuffer<'_> {
}
}

pub struct BufferingReader<'buf, B>
pub struct BufferingReader<'resp, 'buf, B>
where
B: Read,
{
buffer: ReadBuffer<'buf>,
stream: &'buf mut B,
stream: &'resp mut B,
}

impl<'buf, 'conn, B> BufferingReader<'buf, B>
impl<'resp, 'buf, B> BufferingReader<'resp, 'buf, B>
where
B: Read,
{
pub fn new(buffer: &'buf mut [u8], loaded: usize, stream: &'buf mut B) -> Self {
pub fn new(buffer: &'buf mut [u8], loaded: usize, stream: &'resp mut B) -> Self {
Self {
buffer: ReadBuffer::new(buffer, loaded),
stream,
}
}
}

impl<C> ErrorType for BufferingReader<'_, C>
impl<C> ErrorType for BufferingReader<'_, '_, C>
where
C: Read,
{
type Error = ErrorKind;
}

impl<C> Read for BufferingReader<'_, C>
impl<C> Read for BufferingReader<'_, '_, C>
where
C: Read,
{
Expand All @@ -83,7 +83,7 @@ where
}
}

impl<C> BufRead for BufferingReader<'_, HttpConnection<'_, C>>
impl<C> BufRead for BufferingReader<'_, '_, HttpConnection<'_, C>>
where
C: Read + Write,
{
Expand Down
22 changes: 11 additions & 11 deletions src/response.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use crate::Error;
/// Type representing a parsed HTTP response.
#[derive(Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct Response<'resp, C>
pub struct Response<'resp, 'buf, C>
where
C: Read,
{
Expand All @@ -27,17 +27,17 @@ where
pub transfer_encoding: heapless::Vec<TransferEncoding, 4>,
/// The keep-alive parameters.
pub keep_alive: Option<KeepAlive>,
header_buf: &'resp mut [u8],
header_buf: &'buf mut [u8],
header_len: usize,
raw_body_read: usize,
}

impl<'resp, C> Response<'resp, C>
impl<'resp, 'buf, C> Response<'resp, 'buf, C>
where
C: Read,
{
// Read at least the headers from the connection.
pub async fn read(conn: &'resp mut C, method: Method, header_buf: &'resp mut [u8]) -> Result<Self, Error> {
pub async fn read(conn: &'resp mut C, method: Method, header_buf: &'buf mut [u8]) -> Result<Self, Error> {
let mut header_len = 0;
let mut pos = 0;
while pos < header_buf.len() {
Expand Down Expand Up @@ -135,7 +135,7 @@ where
}

/// Get the response body
pub fn body(self) -> ResponseBody<'resp, C> {
pub fn body(self) -> ResponseBody<'resp, 'buf, C> {
let reader_hint = if self.method == Method::HEAD {
// Head requests does not have a body so we return an empty reader
ReaderHint::Empty
Expand Down Expand Up @@ -179,7 +179,7 @@ impl<'a> Iterator for HeaderIterator<'a> {
/// This type contains the original header buffer provided to `read_headers`,
/// now renamed to `body_buf`, the number of read body bytes that are available
/// in `body_buf`, and a reader to be used for reading the remaining body.
pub struct ResponseBody<'resp, C>
pub struct ResponseBody<'resp, 'buf, C>
where
C: Read,
{
Expand All @@ -188,7 +188,7 @@ where
/// The number of raw bytes read from the body and available in the beginning of `body_buf`.
raw_body_read: usize,
/// The buffer initially provided to read the header.
pub body_buf: &'resp mut [u8],
pub body_buf: &'buf mut [u8],
}

enum ReaderHint {
Expand All @@ -198,11 +198,11 @@ enum ReaderHint {
ToEnd, // https://www.rfc-editor.org/rfc/rfc7230#section-3.3.3 pt. 7: Until end of connection
}

impl<'resp, C> ResponseBody<'resp, C>
impl<'resp, 'buf, C> ResponseBody<'resp, 'buf, C>
where
C: Read,
{
pub fn reader(self) -> BodyReader<BufferingReader<'resp, C>> {
pub fn reader(self) -> BodyReader<BufferingReader<'resp, 'buf, C>> {
let raw_body = BufferingReader::new(self.body_buf, self.raw_body_read, self.conn);

match self.reader_hint {
Expand All @@ -220,7 +220,7 @@ where
}
}

impl<'resp, C> ResponseBody<'resp, C>
impl<'resp, 'buf, C> ResponseBody<'resp, 'buf, C>
where
C: Read,
{
Expand All @@ -231,7 +231,7 @@ where
/// while parsing the http response header would be available for the body reader.
/// For this case, or if the original buffer is not large enough, use
/// [`BodyReader::read_to_end()`] instead from the reader returned by [`ResponseBody::reader()`].
pub async fn read_to_end(self) -> Result<&'resp mut [u8], Error> {
pub async fn read_to_end(self) -> Result<&'buf mut [u8], Error> {
// We can only read responses with Content-Length header to end using the body_buf buffer,
// as any other response would require the body reader to know the entire body.
match self.reader_hint {
Expand Down
12 changes: 12 additions & 0 deletions tests/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -395,3 +395,15 @@ async fn echo(req: hyper::Request<Body>) -> Result<hyper::Response<Body>, hyper:
_ => Ok(hyper::Response::new(req.into_body())),
}
}

#[test]
fn compile_tests() {
#[allow(dead_code)]
async fn rx_buffer_lifetime_is_propagated_to_output<'buf>(port: u16, rx_buf: &'buf mut [u8]) -> &'buf mut [u8] {
let mut http = HttpClient::new(&TCP, &LOOPBACK_DNS);
let url = format!("http://127.0.0.1:{}", port);
let mut request = http.request(Method::GET, &url).await.unwrap();
let response = request.send(rx_buf).await.unwrap();
response.body().read_to_end().await.unwrap()
}
}