diff --git a/aquatic_http/src/lib/network/mod.rs b/aquatic_http/src/lib/network/mod.rs index 0c54503..99bf662 100644 --- a/aquatic_http/src/lib/network/mod.rs +++ b/aquatic_http/src/lib/network/mod.rs @@ -184,6 +184,13 @@ pub fn run_handshake_and_read_requests<'a>( debug!("read request, sending to handler"); + if let Request::Announce(ref request) = request { + for (i, c) in request.info_hash.0.chars().enumerate() { + debug!("{}: {}", i, c.escape_unicode()); + } + debug!("request info hash char count: {}", request.info_hash.0.chars().count()); + } + if let Err(err) = request_channel_sender .send((meta, request)) { diff --git a/aquatic_http/src/lib/protocol/mod.rs b/aquatic_http/src/lib/protocol/mod.rs index d56e21c..d8a26ae 100644 --- a/aquatic_http/src/lib/protocol/mod.rs +++ b/aquatic_http/src/lib/protocol/mod.rs @@ -4,9 +4,9 @@ use serde::{Serialize, Deserialize, Serializer}; use crate::common::Peer; -// mod serde_helpers; +mod serde_helpers; -// use serde_helpers::*; +use serde_helpers::*; pub fn serialize_response_peers_compact( @@ -36,10 +36,9 @@ pub fn serialize_response_peers_compact( #[derive(Debug, Clone, Hash, PartialEq, Eq, Serialize, Deserialize)] #[serde(transparent)] pub struct PeerId( - // #[serde( - // deserialize_with = "deserialize_20_bytes", - // serialize_with = "serialize_20_bytes" - // )] + #[serde( + deserialize_with = "deserialize_20_char_string", + )] pub String ); @@ -47,10 +46,9 @@ pub struct PeerId( #[derive(Debug, Clone, Hash, PartialEq, Eq, Serialize, Deserialize)] #[serde(transparent)] pub struct InfoHash( - // #[serde( - // deserialize_with = "deserialize_20_bytes", - // serialize_with = "serialize_20_bytes" - // )] + #[serde( + deserialize_with = "deserialize_20_char_string", + )] pub String ); @@ -129,7 +127,10 @@ pub struct AnnounceResponseFailure { #[derive(Debug, Clone, Deserialize)] pub struct ScrapeRequest { - #[serde(rename = "info_hash")] + #[serde( + rename = "info_hash", + deserialize_with = "deserialize_info_hashes" // FIXME: does this work? + )] pub info_hashes: Vec, } diff --git a/aquatic_http/src/lib/protocol/serde_helpers.rs b/aquatic_http/src/lib/protocol/serde_helpers.rs index a59b525..00ba4a8 100644 --- a/aquatic_http/src/lib/protocol/serde_helpers.rs +++ b/aquatic_http/src/lib/protocol/serde_helpers.rs @@ -3,71 +3,35 @@ use serde::{Serializer, Deserializer, de::{Visitor, SeqAccess}}; use super::InfoHash; -pub fn serialize_20_bytes( - data: &[u8; 20], - serializer: S -) -> Result where S: Serializer { - let text: String = data.iter().map(|byte| *byte as char).collect(); +struct TwentyCharStringVisitor; - serializer.serialize_str(&text) -} - - -struct TwentyByteVisitor; - -impl<'de> Visitor<'de> for TwentyByteVisitor { - type Value = [u8; 20]; +impl<'de> Visitor<'de> for TwentyCharStringVisitor { + type Value = String; fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { - formatter.write_str("string consisting of 20 bytes") + formatter.write_str("string consisting of 20 chars") } #[inline] fn visit_str(self, value: &str) -> Result where E: ::serde::de::Error, { - // Value is encoded in nodejs reference client something as follows: - // ``` - // var infoHash = 'abcd..'; // 40 hexadecimals - // Buffer.from(infoHash, 'hex').toString('binary'); - // ``` - // As I understand it: - // - the code above produces a UTF16 string of 20 chars, each having - // only the "low byte" set (e.g., numeric value ranges from 0-255) - // - serde_json decodes this to string of 20 chars (tested), each in - // the aforementioned range (tested), so the bytes can be extracted - // by casting each char to u8. - - let mut arr = [0u8; 20]; - let mut char_iter = value.chars(); - - for a in arr.iter_mut(){ - if let Some(c) = char_iter.next(){ - if c as u32 > 255 { - return Err(E::custom(format!( - "character not in single byte range: {:#?}", - c - ))); - } - - *a = c as u8; - } else { - return Err(E::custom(format!("not 20 bytes: {:#?}", value))); - } + if value.chars().count() == 20 { + Ok(value.to_string()) + } else { + Err(E::custom(format!("not 20 chars: {:#?}", value))) } - - Ok(arr) } } #[inline] -pub fn deserialize_20_bytes<'de, D>( +pub fn deserialize_20_char_string<'de, D>( deserializer: D -) -> Result<[u8; 20], D::Error> +) -> Result where D: Deserializer<'de> { - deserializer.deserialize_any(TwentyByteVisitor) + deserializer.deserialize_any(TwentyCharStringVisitor) } @@ -85,7 +49,7 @@ impl<'de> Visitor<'de> for InfoHashVecVisitor { fn visit_str(self, value: &str) -> Result where E: ::serde::de::Error, { - match TwentyByteVisitor::visit_str::(TwentyByteVisitor, value){ + match TwentyCharStringVisitor::visit_str::(TwentyCharStringVisitor, value){ Ok(arr) => Ok(vec![InfoHash(arr)]), Err(err) => Err(E::custom(format!("got string, but {}", err))) } @@ -98,8 +62,8 @@ impl<'de> Visitor<'de> for InfoHashVecVisitor { let mut info_hashes: Self::Value = Vec::new(); while let Ok(Some(value)) = seq.next_element::<&str>(){ - let arr = TwentyByteVisitor::visit_str( - TwentyByteVisitor, value + let arr = TwentyCharStringVisitor::visit_str( + TwentyCharStringVisitor, value )?; info_hashes.push(InfoHash(arr));