From 31a254103c7e80a58e0fef688c3899ec7d682aa8 Mon Sep 17 00:00:00 2001 From: Igor Katson Date: Tue, 27 Aug 2024 18:10:52 +0100 Subject: [PATCH] Remove custom XML parsing --- Cargo.lock | 2 + crates/librqbit/Cargo.toml | 2 +- crates/upnp-serve/Cargo.toml | 8 +++- crates/upnp-serve/src/upnp_types.rs | 57 ++++++++++++++++++----------- 4 files changed, 46 insertions(+), 23 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6f6e9fa..02f9ba9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2264,6 +2264,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "96a05e2e8efddfa51a84ca47cec303fac86c8541b686d37cac5efc0e094417bc" dependencies = [ "memchr", + "serde", ] [[package]] @@ -3599,6 +3600,7 @@ dependencies = [ "parking_lot", "quick-xml", "reqwest", + "serde", "socket2", "tokio", "tokio-util", diff --git a/crates/librqbit/Cargo.toml b/crates/librqbit/Cargo.toml index f112817..f4d7a44 100644 --- a/crates/librqbit/Cargo.toml +++ b/crates/librqbit/Cargo.toml @@ -40,7 +40,7 @@ peer_binary_protocol = { path = "../peer_binary_protocol", default-features = fa sha1w = { path = "../sha1w", default-features = false, package = "librqbit-sha1-wrapper", version = "4" } dht = { path = "../dht", package = "librqbit-dht", version = "5.1.0" } librqbit-upnp = { path = "../upnp", version = "0.1.1" } -upnp-serve = { path = "../upnp-serve", version = "0.1.0", optional = true } +upnp-serve = { path = "../upnp-serve", default-features = false, version = "0.1.0", optional = true } tokio = { version = "1", features = [ "macros", diff --git a/crates/upnp-serve/Cargo.toml b/crates/upnp-serve/Cargo.toml index f9c0efb..77ab1aa 100644 --- a/crates/upnp-serve/Cargo.toml +++ b/crates/upnp-serve/Cargo.toml @@ -3,13 +3,18 @@ name = "upnp-serve" version = "0.1.0" edition = "2021" +[features] +default = ["sha1-crypto-hash"] +sha1-crypto-hash = ["librqbit-sha1-wrapper/sha1-crypto-hash"] +sha1-ring = ["librqbit-sha1-wrapper/sha1-ring"] + [dependencies] anyhow = "1.0.86" axum = { version = "0.7.5", features = ["tokio"] } tokio = { version = "1.39.3", features = ["full"] } tracing = "0.1.40" bstr = "1.10.0" -quick-xml = "0.36.1" +serde = { version = "1", features = ["derive"] } http = "1.1.0" httparse = "1.9.4" uuid = { version = "1.10.0", features = ["v4"] } @@ -23,6 +28,7 @@ parking_lot = "0.12.3" tokio-util = "0.7.11" reqwest = { version = "0.12.7", default-features = false } socket2 = "0.5.7" +quick-xml = { version = "0.36.1", features = ["serialize"] } [dev-dependencies] tracing-subscriber = "0.3.18" diff --git a/crates/upnp-serve/src/upnp_types.rs b/crates/upnp-serve/src/upnp_types.rs index db6cf1a..28489f0 100644 --- a/crates/upnp-serve/src/upnp_types.rs +++ b/crates/upnp-serve/src/upnp_types.rs @@ -2,32 +2,44 @@ pub mod content_directory { use response::ItemOrContainer; pub mod request { + use anyhow::Context; + use serde::Deserialize; + + #[derive(Deserialize)] + struct Envelope { + #[serde(rename = "Body")] + body: Body, + } + + #[derive(Deserialize)] + struct Body { + #[serde(rename = "Browse")] + browse: ContentDirectoryControlRequest, + } + + #[derive(Deserialize, PartialEq, Eq, Debug)] + pub enum BrowseFlag { + BrowseDirectChildren, + BrowseMetadata, + } + + #[derive(Deserialize, Debug)] pub struct ContentDirectoryControlRequest { + #[serde(rename = "ObjectID")] pub object_id: usize, + #[serde(rename = "BrowseFlag")] + pub browse_flag: BrowseFlag, + #[serde(rename = "StartingIndex", default)] + pub starting_index: usize, + #[serde(rename = "RequestedCount", default)] + pub requested_count: usize, } impl ContentDirectoryControlRequest { pub fn parse(s: &str) -> anyhow::Result { - let mut reader = quick_xml::Reader::from_str(s); - - use quick_xml::events::Event::{Eof, Start}; - - let mut object_id: Option = None; - - loop { - match reader.read_event()? { - Eof => break, - Start(e) if e.name().as_ref() == b"ObjectID" => { - let t = reader.read_text(e.to_end().name())?; - object_id = t.trim().parse().ok(); - } - _ => continue, - } - } - - Ok(ContentDirectoryControlRequest { - object_id: object_id.unwrap_or(0), - }) + let envelope: Envelope = + quick_xml::de::from_str(s).context("error deserializing")?; + Ok(envelope.body.browse) } } } @@ -70,12 +82,15 @@ pub mod content_directory { #[cfg(test)] mod tests { - use crate::upnp_types::content_directory::request::ContentDirectoryControlRequest; + use crate::upnp_types::content_directory::request::{ + BrowseFlag, ContentDirectoryControlRequest, + }; #[test] fn test_parse_content_directory_request() { let s = include_str!("resources/test/ContentDirectoryControlExampleRequest.xml"); let req = ContentDirectoryControlRequest::parse(s).unwrap(); assert_eq!(req.object_id, 5); + assert_eq!(req.browse_flag, BrowseFlag::BrowseDirectChildren) } }