Skip to content

Commit 9b58046

Browse files
committed
Improved the way Body is read
1 parent f95975a commit 9b58046

File tree

10 files changed

+152
-136
lines changed

10 files changed

+152
-136
lines changed

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
**/target
22
**/Cargo.lock
33
.vscode
4-
.idea
4+
.idea
5+
.DS_Store

my-http-server-core/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,4 +34,5 @@ hyper-util = { version = "*", features = ["tokio"] }
3434
flate2 = "*"
3535
brotli = "*"
3636
http = "*"
37+
bytes = "*"
3738
my-hyper-utils = { tag = "0.1.0", git = "https://github.com/MyJetTools/my-hyper-utils.git" }

my-http-server-core/src/http_request/http_request.rs

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use std::{collections::HashMap, net::SocketAddr, sync::Arc};
22

33
use crate::{
44
http_headers::*, CookiesReader, HttpFailResult, HttpPath, HttpPathReader, HttpRequestBody,
5-
HttpRequestHeaders, RequestData, RequestIp, UrlEncodedData,
5+
HttpRequestHeaders, MyHyperHttpRequest, RequestData, RequestIp, UrlEncodedData,
66
};
77

88
use hyper::{Method, Uri};
@@ -46,7 +46,7 @@ impl HttpRequest {
4646
let http_path = HttpPath::from_str(req.uri().path());
4747

4848
Self {
49-
data: RequestData::Incoming(Some(req)),
49+
data: RequestData::new(req),
5050
addr,
5151
key_values: None,
5252
content_type_header: None,
@@ -79,16 +79,15 @@ impl HttpRequest {
7979
}
8080

8181
pub async fn get_body(&mut self) -> Result<&HttpRequestBody, HttpFailResult> {
82-
let result = self.data.convert_to_body_if_requires().await?;
83-
Ok(result.unwrap())
82+
self.data.get_body().await
8483
}
8584

8685
pub async fn receive_body(&mut self) -> Result<HttpRequestBody, HttpFailResult> {
8786
self.data.receive_body().await
8887
}
8988

90-
pub fn take_incoming_body(&mut self) -> hyper::Request<hyper::body::Incoming> {
91-
self.data.take_incoming_body()
89+
pub fn take_my_hyper_http_request(&mut self) -> MyHyperHttpRequest {
90+
self.data.take_my_hyper_http_request()
9291
}
9392

9493
pub fn get_path<'s>(&'s self) -> HttpPathReader<'s> {
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
use crate::{ContentEncoding, HttpFailResult, HttpRequestBody};
2+
3+
pub enum HttpRequestBodyMode {
4+
Incoming(Option<hyper::body::Incoming>),
5+
Full(HttpRequestBody),
6+
}
7+
8+
impl HttpRequestBodyMode {
9+
pub async fn get_http_request_body(&mut self) -> Result<&HttpRequestBody, HttpFailResult> {
10+
match self {
11+
HttpRequestBodyMode::Incoming(incoming) => {
12+
let take = incoming.take().unwrap();
13+
let bytes = read_bytes(ContentEncoding::None, take).await?;
14+
let body = HttpRequestBody::new(bytes, None)?;
15+
*self = HttpRequestBodyMode::Full(body);
16+
}
17+
HttpRequestBodyMode::Full(http_request_body) => return Ok(http_request_body),
18+
}
19+
20+
match self {
21+
HttpRequestBodyMode::Incoming(_) => {
22+
panic!("We should never be here")
23+
}
24+
HttpRequestBodyMode::Full(http_request_body) => Ok(http_request_body),
25+
}
26+
}
27+
28+
pub async fn into_http_request_body(self) -> Result<HttpRequestBody, HttpFailResult> {
29+
match self {
30+
HttpRequestBodyMode::Incoming(mut incoming) => {
31+
let take = incoming.take().unwrap();
32+
let bytes = read_bytes(ContentEncoding::None, take).await?;
33+
let body = HttpRequestBody::new(bytes, None)?;
34+
return Ok(body);
35+
}
36+
HttpRequestBodyMode::Full(http_request_body) => return Ok(http_request_body),
37+
}
38+
}
39+
}
40+
41+
async fn read_bytes(
42+
body_compression: ContentEncoding,
43+
incoming: impl hyper::body::Body<Data = hyper::body::Bytes, Error = hyper::Error>,
44+
) -> Result<Vec<u8>, HttpFailResult> {
45+
use http_body_util::BodyExt;
46+
47+
let collected = incoming.collect().await?;
48+
let bytes = collected.to_bytes();
49+
50+
body_compression.decompress_if_needed(bytes)
51+
}

my-http-server-core/src/http_request/mod.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,7 @@ mod http_path_reader;
1414
pub use http_path_reader::*;
1515
mod content_encoding;
1616
pub use content_encoding::*;
17+
mod http_request_body_mode;
18+
pub use http_request_body_mode::*;
19+
mod my_hyper_http_request;
20+
pub use my_hyper_http_request::*;
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
use http::Uri;
2+
3+
pub enum MyHyperHttpRequest {
4+
Incoming(hyper::Request<hyper::body::Incoming>),
5+
Full(hyper::Request<http_body_util::Full<bytes::Bytes>>),
6+
}
7+
8+
impl MyHyperHttpRequest {
9+
pub fn uri(&self) -> &Uri {
10+
match self {
11+
MyHyperHttpRequest::Incoming(req) => &req.uri(),
12+
MyHyperHttpRequest::Full(req) => &req.uri(),
13+
}
14+
}
15+
pub fn headers(&self) -> &http::HeaderMap<http::header::HeaderValue> {
16+
match self {
17+
MyHyperHttpRequest::Incoming(req) => req.headers(),
18+
MyHyperHttpRequest::Full(req) => req.headers(),
19+
}
20+
}
21+
22+
pub fn version(&self) -> http::Version {
23+
match self {
24+
MyHyperHttpRequest::Incoming(req) => req.version(),
25+
MyHyperHttpRequest::Full(req) => req.version(),
26+
}
27+
}
28+
29+
pub fn extensions(&self) -> &http::Extensions {
30+
match self {
31+
MyHyperHttpRequest::Incoming(req) => req.extensions(),
32+
MyHyperHttpRequest::Full(req) => req.extensions(),
33+
}
34+
}
35+
}
Lines changed: 45 additions & 123 deletions
Original file line numberDiff line numberDiff line change
@@ -1,149 +1,71 @@
1-
use hyper::{HeaderMap, Uri};
1+
use http::{HeaderMap, HeaderValue};
22

3-
use crate::{HttpFailResult, HttpRequestBody, HttpRequestHeaders};
3+
use hyper::Uri;
44

5-
use super::ContentEncoding;
5+
use crate::{HttpFailResult, HttpRequestBody, HttpRequestBodyMode, MyHyperHttpRequest};
66

7-
pub enum RequestData {
8-
Incoming(Option<hyper::Request<hyper::body::Incoming>>),
9-
AsBody {
10-
uri: Uri,
11-
headers: HeaderMap,
12-
body: Option<HttpRequestBody>,
13-
},
14-
Taken,
7+
pub struct RequestData {
8+
parts: hyper::http::request::Parts,
9+
body: Option<HttpRequestBodyMode>,
1510
}
1611

1712
impl RequestData {
18-
pub async fn convert_to_body_if_requires(
19-
&mut self,
20-
) -> Result<Option<&HttpRequestBody>, HttpFailResult> {
21-
let (uri, headers, bytes) = match self {
22-
Self::Incoming(incoming) => {
23-
let incoming = incoming.take().unwrap();
24-
let (parts, incoming) = incoming.into_parts();
25-
26-
let headers = parts.headers;
27-
28-
let content_encoding = headers.get_content_encoding()?;
29-
30-
let body = read_bytes(content_encoding, incoming).await?;
31-
32-
(parts.uri, headers, body)
33-
}
34-
Self::AsBody { body, .. } => match body.as_ref() {
35-
Some(itm) => {
36-
return Ok(Some(itm));
37-
}
38-
None => {
39-
panic!("You are trying to access body content after receiving ownership of it")
40-
}
41-
},
42-
Self::Taken => {
43-
panic!("Body is taken by some middleware before")
44-
}
45-
};
46-
47-
let content_type = headers.try_get_case_insensitive("content-type");
48-
49-
let content_type = match content_type {
50-
Some(content_type) => Some(content_type.as_str()?.to_string()),
51-
None => None,
52-
};
53-
54-
let body = HttpRequestBody::new(bytes, content_type)?;
55-
*self = Self::AsBody {
56-
body: Some(body),
57-
uri,
58-
headers,
59-
};
60-
Ok(self.try_unwrap_as_body())
13+
pub fn new(req: hyper::Request<hyper::body::Incoming>) -> Self {
14+
let parts = req.into_parts();
15+
Self {
16+
parts: parts.0,
17+
body: Some(HttpRequestBodyMode::Incoming(Some(parts.1))),
18+
}
6119
}
6220

63-
pub async fn receive_body(&mut self) -> Result<HttpRequestBody, HttpFailResult> {
64-
match self {
65-
Self::Incoming(incoming) => {
66-
let incoming = incoming.take().unwrap();
67-
68-
let content_encoding = incoming.headers().get_content_encoding()?;
69-
70-
let bytes = read_bytes(content_encoding, incoming).await?;
71-
72-
let body = HttpRequestBody::new(bytes, None)?;
73-
return Ok(body);
74-
}
75-
Self::AsBody { body, .. } => match body.take() {
76-
Some(itm) => {
77-
return Ok(itm);
78-
}
79-
None => {
80-
panic!("You are trying to receive body for a second time")
81-
}
82-
},
83-
Self::Taken => {
84-
panic!("Body is taken by some middleware before")
21+
pub async fn get_body(&mut self) -> Result<&HttpRequestBody, HttpFailResult> {
22+
match self.body.as_mut() {
23+
Some(body) => body.get_http_request_body().await,
24+
None => {
25+
panic!("Body is removed and can not be accessed")
8526
}
86-
};
27+
}
8728
}
8829

89-
fn try_unwrap_as_body(&self) -> Option<&HttpRequestBody> {
90-
match self {
91-
Self::Incoming(_) => None,
92-
Self::AsBody { body, .. } => {
93-
let body = body.as_ref()?;
94-
return Some(body);
95-
}
96-
Self::Taken => {
30+
pub async fn receive_body(&mut self) -> Result<HttpRequestBody, HttpFailResult> {
31+
match self.body.take() {
32+
Some(body) => return body.into_http_request_body().await,
33+
None => {
9734
panic!("Body is taken by some middleware before")
9835
}
9936
}
10037
}
10138

10239
pub fn uri(&self) -> &Uri {
103-
match self {
104-
Self::Incoming(incoming) => incoming.as_ref().unwrap().uri(),
105-
Self::AsBody { uri, .. } => uri,
106-
Self::Taken => {
107-
panic!("Body is taken by some middleware before")
108-
}
109-
}
40+
&self.parts.uri
11041
}
11142

112-
pub fn headers(&self) -> &impl HttpRequestHeaders {
113-
match self {
114-
Self::Incoming(incoming) => incoming.as_ref().unwrap().headers(),
115-
Self::AsBody { headers, .. } => headers,
116-
Self::Taken => {
117-
panic!("Body is taken by some middleware before")
118-
}
119-
}
43+
pub fn headers(&self) -> &HeaderMap<HeaderValue> {
44+
&self.parts.headers
12045
}
12146

122-
pub fn take_incoming_body(&mut self) -> hyper::Request<hyper::body::Incoming> {
123-
match self {
124-
Self::Incoming(incoming) => {
125-
let result = incoming.take().unwrap();
126-
*self = Self::Taken;
127-
result
128-
}
129-
Self::AsBody { .. } => {
130-
panic!("Body is taken by some middleware before")
131-
}
132-
Self::Taken => {
47+
pub fn take_my_hyper_http_request(&mut self) -> MyHyperHttpRequest {
48+
match self.body.take() {
49+
Some(body) => match body {
50+
HttpRequestBodyMode::Incoming(mut incoming) => {
51+
let result =
52+
hyper::Request::from_parts(self.parts.clone(), incoming.take().unwrap());
53+
54+
return MyHyperHttpRequest::Incoming(result);
55+
}
56+
HttpRequestBodyMode::Full(body) => {
57+
let body = body.as_slice().to_vec();
58+
59+
let body = http_body_util::Full::new(bytes::Bytes::from(body));
60+
61+
let req = hyper::Request::from_parts(self.parts.clone(), body);
62+
63+
MyHyperHttpRequest::Full(req)
64+
}
65+
},
66+
None => {
13367
panic!("Body is taken by some middleware before")
13468
}
13569
}
13670
}
13771
}
138-
139-
async fn read_bytes(
140-
body_compression: ContentEncoding,
141-
incoming: impl hyper::body::Body<Data = hyper::body::Bytes, Error = hyper::Error>,
142-
) -> Result<Vec<u8>, HttpFailResult> {
143-
use http_body_util::BodyExt;
144-
145-
let collected = incoming.collect().await?;
146-
let bytes = collected.to_bytes();
147-
148-
body_compression.decompress_if_needed(bytes)
149-
}

my-http-server-web-sockets/src/helpers.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ pub async fn handle_web_socket_upgrade<
2323

2424
let addr = req.addr.clone();
2525

26-
let req = req.take_incoming_body();
26+
let req = req.take_my_hyper_http_request();
2727

2828
let upgrade_result = crate::web_sockets_upgrade::upgrade(
2929
id,

my-http-server-web-sockets/src/my_web_socket_http_request.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use hyper::{header::*, *};
22
use hyper_tungstenite::tungstenite::http::Extensions;
3+
use my_http_server_core::MyHyperHttpRequest;
34

45
pub struct MyWebSocketHttpRequest {
56
uri: Uri,
@@ -9,7 +10,7 @@ pub struct MyWebSocketHttpRequest {
910
}
1011

1112
impl<'s> MyWebSocketHttpRequest {
12-
pub fn new(req: &Request<hyper::body::Incoming>) -> Self {
13+
pub fn new(req: &MyHyperHttpRequest) -> Self {
1314
Self {
1415
uri: req.uri().clone(),
1516
headers: req.headers().clone(),

0 commit comments

Comments
 (0)