diff --git a/packages/router-macro/src/lib.rs b/packages/router-macro/src/lib.rs index 836cb6bfd7..72e0b7d623 100644 --- a/packages/router-macro/src/lib.rs +++ b/packages/router-macro/src/lib.rs @@ -532,9 +532,14 @@ impl RouteEnum { // Remove any trailing slashes. We parse /route/ and /route in the same way // Note: we don't use trim because it includes more code let route = route.strip_suffix('/').unwrap_or(route); - let query = dioxus_router::exports::percent_encoding::percent_decode_str(query) + // Replace '+' with space in query strings before percent-decoding. + // Per the application/x-www-form-urlencoded spec, '+' is an + // alternative encoding for space in query strings. Some services + // (e.g. Facebook) rewrite '%20' to '+' when processing URLs. + let query_replaced = query.replace('+', " "); + let query = dioxus_router::exports::percent_encoding::percent_decode_str(&query_replaced) .decode_utf8() - .unwrap_or(query.into()); + .unwrap_or(query_replaced.into()); let hash = dioxus_router::exports::percent_encoding::percent_decode_str(hash) .decode_utf8() .unwrap_or(hash.into()); diff --git a/packages/router/tests/parsing.rs b/packages/router/tests/parsing.rs index 7825d8fcd3..ea13348201 100644 --- a/packages/router/tests/parsing.rs +++ b/packages/router/tests/parsing.rs @@ -162,3 +162,47 @@ fn optional_query_segments_parse() { route_without_query_and_other ); } + +// Regression test for https://github.com/DioxusLabs/dioxus/issues/5280 +// '+' in query strings should be decoded as space per the +// application/x-www-form-urlencoded spec. +#[test] +fn query_plus_decoded_as_space() { + #[derive(Routable, Clone, PartialEq, Debug)] + enum Route { + #[route("/?:query")] + Home { query: String }, + } + + #[component] + fn Home(query: String) -> Element { + unimplemented!() + } + + // '+' in query value should be parsed as space + let parsed = "/?query=Shis+Kebap".parse::().unwrap(); + assert_eq!( + parsed, + Route::Home { + query: "Shis Kebap".to_string() + } + ); + + // '%20' should still work as space + let parsed_pct = "/?query=Shis%20Kebap".parse::().unwrap(); + assert_eq!( + parsed_pct, + Route::Home { + query: "Shis Kebap".to_string() + } + ); + + // Multiple '+' signs + let parsed_multi = "/?query=hello+world+test".parse::().unwrap(); + assert_eq!( + parsed_multi, + Route::Home { + query: "hello world test".to_string() + } + ); +}