Skip to content

Commit

Permalink
Temporary support writing/decoding headers in old format
Browse files Browse the repository at this point in the history
  • Loading branch information
khvzak committed Mar 19, 2024
1 parent 16c075c commit 19ba94d
Show file tree
Hide file tree
Showing 3 changed files with 134 additions and 3 deletions.
1 change: 1 addition & 0 deletions casper-server/src/http/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,4 @@ pub async fn buffer_body(mut body: impl MessageBody) -> Result<Bytes, Box<dyn St
pub(crate) mod proxy;
pub(crate) mod trace;
pub(crate) mod websocket;
pub(crate) mod serde;
123 changes: 123 additions & 0 deletions casper-server/src/http/serde.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
//! Based on `http-serde` crate

/// For `HeaderMap`
///
/// `#[serde(with = "casper_server::http::serde::header_map")]`
pub mod header_map {
use std::borrow::Cow;
use std::fmt;

use ntex::http::header::{HeaderMap, HeaderName, HeaderValue};
use serde::de::{self, Deserializer, MapAccess, Unexpected, Visitor};
use serde::ser::SerializeSeq;
use serde::{Serialize, Serializer};

struct ToSeq<'a>(&'a HeaderMap, &'a HeaderName);

impl<'a> Serialize for ToSeq<'a> {
fn serialize<S: Serializer>(&self, ser: S) -> Result<S::Ok, S::Error> {
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<S: Serializer>(headers: &HeaderMap, ser: S) -> Result<S::Ok, S::Error> {
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<Cow<'a, str>>),
Bytes(Vec<Cow<'a, [u8]>>),
}

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<M>(self, mut access: M) -> Result<Self::Value, M::Error>
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::<Cow<str>, Vec<Cow<[u8]>>>()? {
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::<Cow<str>, 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<HeaderMap, D::Error>
where
D: Deserializer<'de>,
{
let is_human_readable = de.is_human_readable();
de.deserialize_map(HeaderMapVisitor { is_human_readable })
}
}
13 changes: 10 additions & 3 deletions casper-server/src/storage/common.rs
Original file line number Diff line number Diff line change
@@ -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<Vec<u8>, 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<HeaderMap, flexbuffers::DeserializationError> {
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)?)
}
}

0 comments on commit 19ba94d

Please sign in to comment.