|
3 | 3 |
|
4 | 4 | use crate::Error as ServerError;
|
5 | 5 | use lighthouse_network::{ConnectionDirection, Enr, Multiaddr, PeerConnectionStatus};
|
| 6 | +use mime::{Mime, APPLICATION, JSON, OCTET_STREAM, STAR}; |
6 | 7 | use serde::{Deserialize, Serialize};
|
| 8 | +use std::cmp::Reverse; |
7 | 9 | use std::convert::TryFrom;
|
8 | 10 | use std::fmt;
|
9 | 11 | use std::str::{from_utf8, FromStr};
|
@@ -1008,15 +1010,37 @@ impl FromStr for Accept {
|
1008 | 1010 | type Err = String;
|
1009 | 1011 |
|
1010 | 1012 | 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()) |
1017 | 1031 | }
|
1018 | 1032 | }
|
1019 | 1033 |
|
| 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 | + |
1020 | 1044 | #[derive(Debug, Serialize, Deserialize)]
|
1021 | 1045 | pub struct LivenessRequestData {
|
1022 | 1046 | pub epoch: Epoch,
|
@@ -1045,4 +1069,23 @@ mod tests {
|
1045 | 1069 | }
|
1046 | 1070 | );
|
1047 | 1071 | }
|
| 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 | + } |
1048 | 1091 | }
|
0 commit comments