From 9517a300370a158a7af0996b7eebf040d171e1a4 Mon Sep 17 00:00:00 2001 From: Sebastien Boeuf Date: Tue, 13 Jul 2021 10:56:18 +0200 Subject: [PATCH] Retrieve the optional file associated with a Request The sever is now able to get any optional file descriptor that might have been sent over with the bytes related to a request. This patch leverages this ability by extending the Request structure with an optional File, which might have been received from the byte stream. With the Request containing an optional File, we give the consumers of this crate the possibility to receive a file descriptor associated with the HTTP request. Signed-off-by: Sebastien Boeuf --- coverage_config.json | 2 +- src/connection.rs | 30 +++++++++++++++++++++++++++--- src/request.rs | 6 ++++++ 3 files changed, 34 insertions(+), 4 deletions(-) diff --git a/coverage_config.json b/coverage_config.json index ade818e..258501e 100644 --- a/coverage_config.json +++ b/coverage_config.json @@ -1 +1 @@ -{"coverage_score": 93.1, "exclude_path": "", "crate_features": ""} +{"coverage_score": 92.8, "exclude_path": "", "crate_features": ""} diff --git a/src/connection.rs b/src/connection.rs index b1d0963..2bf53b4 100644 --- a/src/connection.rs +++ b/src/connection.rs @@ -2,6 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 use std::collections::VecDeque; +use std::fs::File; use std::io::{Read, Write}; use crate::common::ascii::{CR, CRLF_LEN, LF}; @@ -50,6 +51,9 @@ pub struct HttpConnection { /// A buffer containing the bytes of a response that is currently /// being sent. response_buffer: Option>, + /// The latest file that has been received and which must be associated + /// with the pending request. + file: Option, } impl HttpConnection { @@ -66,6 +70,7 @@ impl HttpConnection { parsed_requests: VecDeque::new(), response_queue: VecDeque::new(), response_buffer: None, + file: None, } } @@ -107,8 +112,9 @@ impl HttpConnection { // the `parsed_requests` queue. self.state = ConnectionState::WaitingForRequestLine; self.body_bytes_to_be_read = 0; - self.parsed_requests - .push_back(self.pending_request.take().unwrap()); + let mut pending_request = self.pending_request.take().unwrap(); + pending_request.file = self.file.take(); + self.parsed_requests.push_back(pending_request); } }; } @@ -127,11 +133,16 @@ impl HttpConnection { } // Append new bytes to what we already have in the buffer. // The slice access is safe, the index is checked above. - let (bytes_read, _) = self + let (bytes_read, file) = self .stream .recv_with_fd(&mut self.buffer[self.read_cursor..]) .map_err(ConnectionError::StreamReadError)?; + // Update the internal file that must be associated with the request. + if file.is_some() { + self.file = file; + } + // If the read returned 0 then the client has closed the connection. if bytes_read == 0 { return Err(ConnectionError::ConnectionClosed); @@ -176,6 +187,7 @@ impl HttpConnection { .map_err(ConnectionError::ParseError)?, headers: Headers::default(), body: None, + file: None, }); self.state = ConnectionState::WaitingForHeaders; Ok(true) @@ -517,6 +529,7 @@ mod tests { request_line: RequestLine::new(Method::Patch, "http://localhost/home", Version::Http11), headers: Headers::new(26, true, true), body: Some(Body::new(b"this is not\n\r\na json \nbody".to_vec())), + file: None, }; assert_eq!(request, expected_request); @@ -553,6 +566,7 @@ mod tests { request_line: RequestLine::new(Method::Patch, "http://localhost/home", Version::Http11), headers: Headers::new(26, true, true), body: Some(Body::new(b"this is not\n\r\na json \nbody".to_vec())), + file: None, }; assert_eq!(request, expected_request); } @@ -586,6 +600,7 @@ mod tests { request_line: RequestLine::new(Method::Patch, "http://localhost/home", Version::Http11), headers: Headers::new(26, true, true), body: Some(Body::new(b"this is not\n\r\na json \nbody".to_vec())), + file: None, }; assert_eq!(request, expected_request); } @@ -650,6 +665,7 @@ mod tests { request_line: RequestLine::new(Method::Patch, "http://localhost/home", Version::Http11), headers: Headers::new(1400, true, true), body: Some(Body::new(request_body)), + file: None, }; assert_eq!(request, expected_request); @@ -720,6 +736,7 @@ mod tests { request_line: RequestLine::new(Method::Patch, "http://localhost/home", Version::Http11), headers: Headers::new(0, true, true), body: None, + file: None, }; assert_eq!(request, expected_request); } @@ -741,6 +758,7 @@ mod tests { request_line: RequestLine::new(Method::Patch, "http://localhost/home", Version::Http11), headers: Headers::new(0, false, false), body: None, + file: None, }; assert_eq!(request, expected_request); } @@ -769,6 +787,7 @@ mod tests { request_line: RequestLine::new(Method::Patch, "http://localhost/home", Version::Http11), headers: Headers::new(0, false, false), body: None, + file: None, }; assert_eq!(request, expected_request); @@ -787,6 +806,7 @@ mod tests { ), headers: Headers::new(0, false, false), body: None, + file: None, }; assert_eq!(request, expected_request); } @@ -814,6 +834,7 @@ mod tests { request_line: RequestLine::new(Method::Patch, "http://localhost/home", Version::Http11), headers: Headers::new(26, false, true), body: Some(Body::new(b"this is not\n\r\na json \nbody".to_vec())), + file: None, }; conn.try_read().unwrap(); @@ -824,6 +845,7 @@ mod tests { request_line: RequestLine::new(Method::Put, "http://farhost/away", Version::Http11), headers: Headers::new(23, false, false), body: Some(Body::new(b"this is another request".to_vec())), + file: None, }; assert_eq!(request_first, expected_request_first); assert_eq!(request_second, expected_request_second); @@ -1036,6 +1058,7 @@ mod tests { request_line: RequestLine::new(Method::Get, "http://foo/bar", Version::Http11), headers: Headers::new(0, true, true), body: None, + file: None, }); assert_eq!( conn.parse_headers(&mut 0, BUFFER_SIZE).unwrap_err(), @@ -1093,6 +1116,7 @@ mod tests { request_line: RequestLine::new(Method::Get, "http://foo/bar", Version::Http11), headers: Headers::new(0, true, true), body: None, + file: None, }); conn.body_vec = vec![0xde, 0xad, 0xbe, 0xef]; assert_eq!( diff --git a/src/request.rs b/src/request.rs index 419331c..dbf10fa 100644 --- a/src/request.rs +++ b/src/request.rs @@ -1,6 +1,7 @@ // Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 +use std::fs::File; use std::str::from_utf8; use crate::common::ascii::{CR, CRLF_LEN, LF, SP}; @@ -158,6 +159,8 @@ pub struct Request { pub headers: Headers, /// The body of the request. pub body: Option, + /// The optional file associated with the request. + pub file: Option, } impl Request { @@ -217,6 +220,7 @@ impl Request { request_line, headers: Headers::default(), body: None, + file: None, }), Some(headers_end) => { // Parse the request headers. @@ -276,6 +280,7 @@ impl Request { request_line, headers, body, + file: None, }) } // If we can't find a CR LF CR LF even though the request should have headers @@ -444,6 +449,7 @@ mod tests { uri: Uri::new("http://localhost/home"), }, body: None, + file: None, headers: Headers::default(), }; let request_bytes = b"GET http://localhost/home HTTP/1.0\r\n\