Skip to content

Commit 0428018

Browse files
committed
Fix http header accept parsing problem (#3185)
## Issue Addressed Which issue # does this PR address? #3114 ## Proposed Changes 1. introduce `mime` package 2. Parse `Accept` field in the header with `mime` ## Additional Info Please provide any additional information. For example, future considerations or information useful for reviewers.
1 parent def9bc6 commit 0428018

File tree

3 files changed

+51
-6
lines changed

3 files changed

+51
-6
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

common/eth2/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ futures-util = "0.3.8"
2626
futures = "0.3.8"
2727
store = { path = "../../beacon_node/store", optional = true }
2828
slashing_protection = { path = "../../validator_client/slashing_protection", optional = true }
29+
mime = "0.3.16"
2930

3031
[target.'cfg(target_os = "linux")'.dependencies]
3132
psutil = { version = "3.2.2", optional = true }

common/eth2/src/types.rs

Lines changed: 49 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@
33
44
use crate::Error as ServerError;
55
use lighthouse_network::{ConnectionDirection, Enr, Multiaddr, PeerConnectionStatus};
6+
use mime::{Mime, APPLICATION, JSON, OCTET_STREAM, STAR};
67
use serde::{Deserialize, Serialize};
8+
use std::cmp::Reverse;
79
use std::convert::TryFrom;
810
use std::fmt;
911
use std::str::{from_utf8, FromStr};
@@ -1008,15 +1010,37 @@ impl FromStr for Accept {
10081010
type Err = String;
10091011

10101012
fn from_str(s: &str) -> Result<Self, Self::Err> {
1011-
match s {
1012-
"application/octet-stream" => Ok(Accept::Ssz),
1013-
"application/json" => Ok(Accept::Json),
1014-
"*/*" => Ok(Accept::Any),
1015-
_ => Err("accept header cannot be parsed.".to_string()),
1016-
}
1013+
let mut mimes = parse_accept(s)?;
1014+
1015+
// [q-factor weighting]: https://datatracker.ietf.org/doc/html/rfc7231#section-5.3.2
1016+
// find the highest q-factor supported accept type
1017+
mimes.sort_by_key(|m| {
1018+
Reverse(m.get_param("q").map_or(1000_u16, |n| {
1019+
(n.as_ref().parse::<f32>().unwrap_or(0_f32) * 1000_f32) as u16
1020+
}))
1021+
});
1022+
mimes
1023+
.into_iter()
1024+
.find_map(|m| match (m.type_(), m.subtype()) {
1025+
(APPLICATION, OCTET_STREAM) => Some(Accept::Ssz),
1026+
(APPLICATION, JSON) => Some(Accept::Json),
1027+
(STAR, STAR) => Some(Accept::Any),
1028+
_ => None,
1029+
})
1030+
.ok_or_else(|| "accept header is not supported".to_string())
10171031
}
10181032
}
10191033

1034+
fn parse_accept(accept: &str) -> Result<Vec<Mime>, String> {
1035+
accept
1036+
.split(',')
1037+
.map(|part| {
1038+
part.parse()
1039+
.map_err(|e| format!("error parsing Accept header: {}", e))
1040+
})
1041+
.collect()
1042+
}
1043+
10201044
#[derive(Debug, Serialize, Deserialize)]
10211045
pub struct LivenessRequestData {
10221046
pub epoch: Epoch,
@@ -1045,4 +1069,23 @@ mod tests {
10451069
}
10461070
);
10471071
}
1072+
1073+
#[test]
1074+
fn parse_accept_header_content() {
1075+
assert_eq!(
1076+
Accept::from_str("application/json; charset=utf-8").unwrap(),
1077+
Accept::Json
1078+
);
1079+
1080+
assert_eq!(
1081+
Accept::from_str("text/plain,application/octet-stream;q=0.3,application/json;q=0.9")
1082+
.unwrap(),
1083+
Accept::Json
1084+
);
1085+
1086+
assert_eq!(
1087+
Accept::from_str("text/plain"),
1088+
Err("accept header is not supported".to_string())
1089+
)
1090+
}
10481091
}

0 commit comments

Comments
 (0)