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 <sebastien.boeuf@intel.com>
This commit is contained in:
committed by
georgepisaltu
parent
3c4cc3aa91
commit
9517a30037
@@ -1 +1 @@
|
||||
{"coverage_score": 93.1, "exclude_path": "", "crate_features": ""}
|
||||
{"coverage_score": 92.8, "exclude_path": "", "crate_features": ""}
|
||||
|
||||
@@ -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<T> {
|
||||
/// A buffer containing the bytes of a response that is currently
|
||||
/// being sent.
|
||||
response_buffer: Option<Vec<u8>>,
|
||||
/// The latest file that has been received and which must be associated
|
||||
/// with the pending request.
|
||||
file: Option<File>,
|
||||
}
|
||||
|
||||
impl<T: Read + Write + ScmSocket> HttpConnection<T> {
|
||||
@@ -66,6 +70,7 @@ impl<T: Read + Write + ScmSocket> HttpConnection<T> {
|
||||
parsed_requests: VecDeque::new(),
|
||||
response_queue: VecDeque::new(),
|
||||
response_buffer: None,
|
||||
file: None,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -107,8 +112,9 @@ impl<T: Read + Write + ScmSocket> HttpConnection<T> {
|
||||
// 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<T: Read + Write + ScmSocket> HttpConnection<T> {
|
||||
}
|
||||
// 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<T: Read + Write + ScmSocket> HttpConnection<T> {
|
||||
.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!(
|
||||
|
||||
@@ -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<Body>,
|
||||
/// The optional file associated with the request.
|
||||
pub file: Option<File>,
|
||||
}
|
||||
|
||||
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\
|
||||
|
||||
Reference in New Issue
Block a user