diff --git a/casper-server/src/http/mod.rs b/casper-server/src/http/mod.rs index 9702896..58acef8 100644 --- a/casper-server/src/http/mod.rs +++ b/casper-server/src/http/mod.rs @@ -16,3 +16,4 @@ pub async fn buffer_body(mut body: impl MessageBody) -> Result(&'a HeaderMap, &'a HeaderName); + + impl<'a> Serialize for ToSeq<'a> { + fn serialize(&self, ser: S) -> Result { + let name = self.1; + let count = self.0.get_all(name).count(); + if ser.is_human_readable() { + if count == 1 { + let v = self.0.get(name).expect("header is present"); + if let Ok(s) = v.to_str() { + return ser.serialize_str(s); + } + } + ser.collect_seq(self.0.get_all(name).filter_map(|v| v.to_str().ok())) + } else { + let mut seq = ser.serialize_seq(Some(count))?; + for v in self.0.get_all(name) { + seq.serialize_element(v.as_bytes())?; + } + seq.end() + } + } + } + + /// Implementation detail. Use derive annotations instead. + pub fn serialize(headers: &HeaderMap, ser: S) -> Result { + ser.collect_map(headers.keys().map(|k| (k.as_str(), ToSeq(headers, k)))) + } + + #[derive(serde::Deserialize)] + #[serde(untagged)] + enum OneOrMore<'a> { + One(Cow<'a, str>), + Strings(Vec>), + Bytes(Vec>), + } + + struct HeaderMapVisitor { + is_human_readable: bool, + } + + impl<'de> Visitor<'de> for HeaderMapVisitor { + type Value = HeaderMap; + + // Format a message stating what data this Visitor expects to receive. + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("lots of things can go wrong with HeaderMap") + } + + fn visit_map(self, mut access: M) -> Result + where + M: MapAccess<'de>, + { + let mut map = HeaderMap::with_capacity(access.size_hint().unwrap_or(0)); + + if !self.is_human_readable { + while let Some((key, arr)) = access.next_entry::, Vec>>()? { + let key = HeaderName::from_bytes(key.as_bytes()) + .map_err(|_| de::Error::invalid_value(Unexpected::Str(&key), &self))?; + for val in arr { + let val = HeaderValue::from_bytes(&val).map_err(|_| { + de::Error::invalid_value(Unexpected::Bytes(&val), &self) + })?; + map.append(key.clone(), val); + } + } + } else { + while let Some((key, val)) = access.next_entry::, OneOrMore>()? { + let key = HeaderName::from_bytes(key.as_bytes()) + .map_err(|_| de::Error::invalid_value(Unexpected::Str(&key), &self))?; + match val { + OneOrMore::One(val) => { + let val = val.parse().map_err(|_| { + de::Error::invalid_value(Unexpected::Str(&val), &self) + })?; + map.insert(key, val); + } + OneOrMore::Strings(arr) => { + for val in arr { + let val = val.parse().map_err(|_| { + de::Error::invalid_value(Unexpected::Str(&val), &self) + })?; + map.append(key.clone(), val); + } + } + OneOrMore::Bytes(arr) => { + for val in arr { + let val = HeaderValue::from_bytes(&val).map_err(|_| { + de::Error::invalid_value(Unexpected::Bytes(&val), &self) + })?; + map.append(key.clone(), val); + } + } + }; + } + } + Ok(map) + } + } + + /// Implementation detail. + pub fn deserialize<'de, D>(de: D) -> Result + where + D: Deserializer<'de>, + { + let is_human_readable = de.is_human_readable(); + de.deserialize_map(HeaderMapVisitor { is_human_readable }) + } +} diff --git a/casper-server/src/storage/common.rs b/casper-server/src/storage/common.rs index ffd316e..bb83db0 100644 --- a/casper-server/src/storage/common.rs +++ b/casper-server/src/storage/common.rs @@ -1,13 +1,20 @@ use ntex::http::header::HeaderMap; -use serde::{Deserialize, Serialize}; +use serde::{Deserialize /*Serialize*/}; + +use crate::http::serde as http_serde; pub fn encode_headers(headers: &HeaderMap) -> Result, flexbuffers::SerializationError> { let mut serializer = flexbuffers::FlexbufferSerializer::new(); - headers.serialize(&mut serializer)?; + // headers.serialize(&mut serializer)?; + http_serde::header_map::serialize(headers, &mut serializer)?; Ok(serializer.take_buffer()) } pub fn decode_headers(data: &[u8]) -> Result { let deserializer = flexbuffers::Reader::get_root(data)?; - HeaderMap::deserialize(deserializer) + if let Ok(headers) = HeaderMap::deserialize(deserializer) { + Ok(headers) + } else { + http_serde::header_map::deserialize(flexbuffers::Reader::get_root(data)?) + } }