Skip to content

Commit f255243

Browse files
committed
feat(header-plz)!: added http/2 InfoLine and made MessageHead generic
1 parent 1e9385b commit f255243

File tree

23 files changed

+295
-214
lines changed

23 files changed

+295
-214
lines changed

header-plz/src/body_headers/from_header_map.rs

Lines changed: 31 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -2,22 +2,22 @@ use mime_plz::ContentType;
22

33
use super::{BodyHeader, transfer_types::TransferType};
44
use crate::{
5-
Header, HeaderMap, body_headers::encoding_info::EncodingInfo,
6-
const_headers::*,
5+
OneHeaderMap, body_headers::encoding_info::EncodingInfo, const_headers::*,
6+
message_head::header_map::one::OneHeader,
77
};
88

9-
impl From<&HeaderMap> for Option<BodyHeader> {
10-
fn from(header_map: &HeaderMap) -> Self {
9+
impl From<&OneHeaderMap> for Option<BodyHeader> {
10+
fn from(header_map: &OneHeaderMap) -> Self {
1111
let bh = BodyHeader::from(header_map);
1212
bh.sanitize()
1313
}
1414
}
1515

16-
impl From<&HeaderMap> for BodyHeader {
16+
impl From<&OneHeaderMap> for BodyHeader {
1717
#[inline(always)]
18-
fn from(header_map: &HeaderMap) -> BodyHeader {
18+
fn from(header_map: &OneHeaderMap) -> BodyHeader {
1919
let mut bh = BodyHeader::default();
20-
header_map.headers().iter().enumerate().for_each(|(index, header)| {
20+
header_map.into_iter().enumerate().for_each(|(index, header)| {
2121
parse_body_headers(&mut bh, index, header)
2222
});
2323

@@ -34,22 +34,29 @@ impl From<&HeaderMap> for BodyHeader {
3434
}
3535
}
3636

37-
pub fn parse_body_headers(bh: &mut BodyHeader, index: usize, header: &Header) {
38-
let key = header.key_as_str();
39-
if key.eq_ignore_ascii_case(CONTENT_LENGTH) {
40-
let transfer_type = TransferType::from_cl(header.value_as_str());
41-
bh.update_transfer_type(transfer_type);
42-
} else if key.eq_ignore_ascii_case(TRANSFER_ENCODING) {
43-
let einfo = EncodingInfo::from((index, header.value_as_str()));
44-
bh.transfer_encoding.get_or_insert_with(Vec::new).push(einfo);
45-
if bh.chunked_te_position().is_some() {
46-
bh.transfer_type = Some(TransferType::Chunked)
47-
}
48-
} else if key.eq_ignore_ascii_case(CONTENT_ENCODING) {
49-
let einfo = EncodingInfo::from((index, header.value_as_str()));
50-
bh.content_encoding.get_or_insert_with(Vec::new).push(einfo);
51-
} else if key.eq_ignore_ascii_case(CONTENT_TYPE) {
52-
if let Some((main_type, _)) = header.value_as_str().split_once('/') {
37+
pub fn parse_body_headers(
38+
bh: &mut BodyHeader,
39+
index: usize,
40+
header: &OneHeader,
41+
) {
42+
if let Some(key) = header.key_as_str()
43+
&& let Some(value) = header.value_as_str()
44+
{
45+
if key.eq_ignore_ascii_case(CONTENT_LENGTH) {
46+
let transfer_type = TransferType::from_cl(value);
47+
bh.update_transfer_type(transfer_type);
48+
} else if key.eq_ignore_ascii_case(TRANSFER_ENCODING) {
49+
let einfo = EncodingInfo::from((index, value));
50+
bh.transfer_encoding.get_or_insert_with(Vec::new).push(einfo);
51+
if bh.chunked_te_position().is_some() {
52+
bh.transfer_type = Some(TransferType::Chunked)
53+
}
54+
} else if key.eq_ignore_ascii_case(CONTENT_ENCODING) {
55+
let einfo = EncodingInfo::from((index, value));
56+
bh.content_encoding.get_or_insert_with(Vec::new).push(einfo);
57+
} else if key.eq_ignore_ascii_case(CONTENT_TYPE)
58+
&& let Some((main_type, _)) = value.split_once('/')
59+
{
5360
bh.content_type = Some(ContentType::from(main_type));
5461
}
5562
}
@@ -62,7 +69,7 @@ mod tests {
6269
use bytes::BytesMut;
6370

6471
fn build_body_header(input: &str) -> BodyHeader {
65-
let header_map = HeaderMap::from(BytesMut::from(input));
72+
let header_map = OneHeaderMap::from(BytesMut::from(input));
6673
BodyHeader::from(&header_map)
6774
}
6875

header-plz/src/body_headers/parse.rs

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
use tracing::error;
22

33
use crate::{
4-
Request, Response,
5-
message_head::MessageHead,
4+
OneMessageHead, OneRequestLine, OneResponseLine,
65
methods::{METHODS_WITH_BODY, Method},
76
};
87

@@ -13,7 +12,7 @@ pub trait ParseBodyHeaders {
1312
}
1413

1514
// If request method is in METHODS_WITH_BODY , build BodyHeader from HeaderMap
16-
impl ParseBodyHeaders for MessageHead<Request> {
15+
impl ParseBodyHeaders for OneMessageHead<OneRequestLine> {
1716
fn parse_body_headers(&self) -> Option<BodyHeader> {
1817
let method: Method = self.infoline().method().into();
1918
if METHODS_WITH_BODY.contains(&method) {
@@ -25,7 +24,7 @@ impl ParseBodyHeaders for MessageHead<Request> {
2524

2625
// If status code is in 100-199, 204, 304, then return None else build
2726
// BodyHeader from HeaderMap
28-
impl ParseBodyHeaders for MessageHead<Response> {
27+
impl ParseBodyHeaders for OneMessageHead<OneResponseLine> {
2928
fn parse_body_headers(&self) -> Option<BodyHeader> {
3029
match self.infoline().status_as_u8() {
3130
Ok(scode) => match scode {
@@ -61,7 +60,7 @@ mod tests {
6160
User-Agent: curl/7.29.0\r\n\
6261
Connection: keep-alive\r\n\r\n";
6362
let buf = BytesMut::from(request);
64-
let result = MessageHead::<Request>::try_from(buf).unwrap();
63+
let result = OneMessageHead::<OneRequestLine>::try_from(buf).unwrap();
6564
let body_headers = result.parse_body_headers();
6665
assert!(body_headers.is_none());
6766
}
@@ -75,7 +74,7 @@ mod tests {
7574
User-Agent: curl/7.29.0\r\n\
7675
Connection: keep-alive\r\n\r\n";
7776
let buf = BytesMut::from(request);
78-
let result = MessageHead::<Request>::try_from(buf).unwrap();
77+
let result = OneMessageHead::<OneRequestLine>::try_from(buf).unwrap();
7978
let body_headers = result.parse_body_headers();
8079
assert!(body_headers.is_none());
8180
}
@@ -87,7 +86,7 @@ mod tests {
8786
Content-Type: application/json\r\n\
8887
\r\n";
8988
let buf = BytesMut::from(request);
90-
let result = MessageHead::<Request>::try_from(buf).unwrap();
89+
let result = OneMessageHead::<OneRequestLine>::try_from(buf).unwrap();
9190
let body_headers = result.parse_body_headers().unwrap();
9291
assert!(body_headers.content_type.is_some());
9392
assert!(body_headers.content_encoding.is_none());
@@ -103,7 +102,7 @@ mod tests {
103102
Content-Encoding: gzip\r\n\
104103
Transfer-Encoding: chunked\r\n\r\n";
105104
let buf = BytesMut::from(request);
106-
let result = MessageHead::<Request>::try_from(buf).unwrap();
105+
let result = OneMessageHead::<OneRequestLine>::try_from(buf).unwrap();
107106
let body_headers = result.parse_body_headers().unwrap();
108107
assert_eq!(
109108
body_headers.content_type.unwrap(),
@@ -128,7 +127,7 @@ mod tests {
128127
Content-Type: text/plain\r\n\
129128
Content-Length: 12\r\n\r\n";
130129
let buf = BytesMut::from(response);
131-
let result = MessageHead::<Response>::try_from(buf).unwrap();
130+
let result = OneMessageHead::<OneResponseLine>::try_from(buf).unwrap();
132131
let body_headers = result.parse_body_headers().unwrap();
133132
assert!(body_headers.content_encoding.is_none());
134133
assert_eq!(body_headers.content_type.unwrap(), ContentType::Text);
@@ -145,7 +144,7 @@ mod tests {
145144
Host: localhost\r\n\
146145
Content-Type: text/plain\r\n\r\n";
147146
let buf = BytesMut::from(response);
148-
let result = MessageHead::<Response>::try_from(buf).unwrap();
147+
let result = OneMessageHead::<OneResponseLine>::try_from(buf).unwrap();
149148
let body_headers = result.parse_body_headers().unwrap();
150149
assert!(body_headers.content_encoding.is_none());
151150
assert_eq!(body_headers.content_type.unwrap(), ContentType::Text);
@@ -160,7 +159,7 @@ mod tests {
160159
Content-Length: 0\r\n\
161160
Content-Type: text/plain\r\n\r\n";
162161
let buf = BytesMut::from(response);
163-
let result = MessageHead::<Response>::try_from(buf).unwrap();
162+
let result = OneMessageHead::<OneResponseLine>::try_from(buf).unwrap();
164163
let body_headers = result.parse_body_headers();
165164
assert!(body_headers.is_none());
166165
}
@@ -172,7 +171,7 @@ mod tests {
172171
Content-Length: 0\r\n\
173172
Content-Type: text/plain\r\n\r\n";
174173
let buf = BytesMut::from(response);
175-
let result = MessageHead::<Response>::try_from(buf).unwrap();
174+
let result = OneMessageHead::<OneResponseLine>::try_from(buf).unwrap();
176175
let body_headers = result.parse_body_headers();
177176
assert!(body_headers.is_none());
178177
}

header-plz/src/bytes_str.rs

Lines changed: 43 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
11
use bytes::Bytes;
22

3-
use std::{fmt, ops, str};
3+
use std::str;
44

55
#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
66
pub struct BytesStr(Bytes);
77

88
impl BytesStr {
9+
pub(crate) fn new() -> Self {
10+
Self(Bytes::new())
11+
}
12+
913
pub const fn from_static(value: &'static str) -> Self {
1014
BytesStr(Bytes::from_static(value.as_bytes()))
1115
}
@@ -14,11 +18,6 @@ impl BytesStr {
1418
BytesStr(Bytes::copy_from_slice(value))
1519
}
1620

17-
pub fn try_from(bytes: Bytes) -> Result<Self, std::str::Utf8Error> {
18-
std::str::from_utf8(bytes.as_ref())?;
19-
Ok(BytesStr(bytes))
20-
}
21-
2221
pub(crate) fn as_str(&self) -> &str {
2322
// Safety: check valid utf-8 in constructor
2423
unsafe { std::str::from_utf8_unchecked(self.0.as_ref()) }
@@ -27,6 +26,35 @@ impl BytesStr {
2726
pub(crate) fn into_inner(self) -> Bytes {
2827
self.0
2928
}
29+
30+
pub(crate) fn from_utf8(
31+
bytes: Bytes,
32+
) -> Result<Self, std::str::Utf8Error> {
33+
str::from_utf8(&bytes)?;
34+
// Invariant: just checked is utf8
35+
Ok(BytesStr(bytes))
36+
}
37+
38+
#[inline]
39+
/// ## Panics
40+
/// In a debug build this will panic if `bytes` is not valid UTF-8.
41+
///
42+
/// ## Safety
43+
/// `bytes` must contain valid UTF-8. In a release build it is undefined
44+
/// behavior to call this with `bytes` that is not valid UTF-8.
45+
pub unsafe fn from_utf8_unchecked(bytes: Bytes) -> BytesStr {
46+
if cfg!(debug_assertions) {
47+
match str::from_utf8(&bytes) {
48+
Ok(_) => (),
49+
Err(err) => panic!(
50+
"ByteStr::from_utf8_unchecked() with invalid bytes| error = {}, bytes = {:?}",
51+
err, bytes
52+
),
53+
}
54+
}
55+
// Invariant: assumed by the safety requirements of this function.
56+
BytesStr(bytes)
57+
}
3058
}
3159

3260
impl From<&str> for BytesStr {
@@ -37,6 +65,7 @@ impl From<&str> for BytesStr {
3765

3866
impl std::ops::Deref for BytesStr {
3967
type Target = str;
68+
4069
fn deref(&self) -> &str {
4170
self.as_str()
4271
}
@@ -47,3 +76,11 @@ impl AsRef<[u8]> for BytesStr {
4776
self.0.as_ref()
4877
}
4978
}
79+
80+
impl TryFrom<&[u8]> for BytesStr {
81+
type Error = str::Utf8Error;
82+
83+
fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
84+
Ok(BytesStr::from(str::from_utf8(value)?))
85+
}
86+
}

header-plz/src/error.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use std::fmt::Debug;
22
use thiserror::Error;
33

4-
use crate::message_head::info_line::error::InfoLineError;
4+
use crate::message_head::info_line::one::error::InfoLineError;
55

66
#[cfg_attr(any(test, debug_assertions), derive(PartialEq))]
77
#[derive(Debug, Error)]

header-plz/src/lib.rs

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,32 @@
11
#![allow(clippy::len_without_is_empty)]
2-
//#![allow(warnings, unused)]
2+
#![allow(unused)]
33
pub mod abnf;
44
pub mod body_headers;
5+
pub mod bytes_str;
56
pub mod const_headers;
67
pub mod error;
78
pub mod message_head;
89
pub mod methods;
10+
pub mod uri;
911

12+
// control lines
13+
use message_head::info_line;
14+
// http1
15+
pub use info_line::one::request::RequestLine as OneRequestLine;
16+
pub use info_line::one::response::ResponseLine as OneResponseLine;
17+
18+
// http2
19+
pub use info_line::two::request::RequestLine;
20+
pub use info_line::two::response::ResponseLine;
21+
22+
// headers
23+
pub use message_head::header_map::one::OneHeader;
24+
pub use message_head::header_map::two::Header;
25+
26+
// headermap
1027
pub use message_head::header_map::HeaderMap;
11-
pub use message_head::header_map::header::Header;
12-
pub use message_head::info_line::{
13-
InfoLine, request::Request, response::Response,
14-
};
28+
pub use message_head::header_map::OneHeaderMap;
29+
30+
// MessageHead
31+
pub use message_head::MessageHead;
32+
pub use message_head::OneMessageHead;

0 commit comments

Comments
 (0)