diff --git a/crates/ruma-client-api/src/state/send_state_event.rs b/crates/ruma-client-api/src/state/send_state_event.rs index 77d3b453..0bd79f6e 100644 --- a/crates/ruma-client-api/src/state/send_state_event.rs +++ b/crates/ruma-client-api/src/state/send_state_event.rs @@ -229,7 +229,7 @@ pub mod v3 { assert_eq!( req.uri(), - "https://server.tld/_matrix/client/v3/rooms/%21room%3Aserver%2Etld/state/m%2Eroom%2Ename/" + "https://server.tld/_matrix/client/v3/rooms/!room:server.tld/state/m.room.name/" ); } } diff --git a/crates/ruma-common/CHANGELOG.md b/crates/ruma-common/CHANGELOG.md index 1f1a021e..90266a10 100644 --- a/crates/ruma-common/CHANGELOG.md +++ b/crates/ruma-common/CHANGELOG.md @@ -11,6 +11,7 @@ Bug fixes: * Fix deserialization of `StateUnsigned` when the `prev_content` is redacted * Allow to deserialize `PushCondition` with unknown kind * Allow to deserialize `push::Action` with unknown value +* Only percent-encode reserved characters in endpoint URL path Breaking changes: diff --git a/crates/ruma-common/src/api/metadata.rs b/crates/ruma-common/src/api/metadata.rs index 4b122e65..22810ce3 100644 --- a/crates/ruma-common/src/api/metadata.rs +++ b/crates/ruma-common/src/api/metadata.rs @@ -9,7 +9,7 @@ use http::{ header::{self, HeaderName, HeaderValue}, Method, }; -use percent_encoding::utf8_percent_encode; +use percent_encoding::{utf8_percent_encode, AsciiSet, CONTROLS}; use tracing::warn; use super::{ @@ -18,6 +18,19 @@ use super::{ }; use crate::{serde::slice_to_buf, RoomVersionId}; +// The path percent-encode set as defined in the WHATWG URL standard +// +const PATH_PERCENT_ENCODE_SET: &AsciiSet = &CONTROLS + .add(b' ') + .add(b'"') + .add(b'#') + .add(b'<') + .add(b'>') + .add(b'?') + .add(b'`') + .add(b'{') + .add(b'}'); + /// Metadata about an API endpoint. #[derive(Clone, Debug)] #[allow(clippy::exhaustive_structs)] @@ -101,7 +114,7 @@ impl Metadata { .next() .expect("number of placeholders must match number of arguments") .to_string(); - let arg = utf8_percent_encode(&arg, percent_encoding::NON_ALPHANUMERIC); + let arg = utf8_percent_encode(&arg, PATH_PERCENT_ENCODE_SET); write!(res, "/{arg}").expect("writing to a String using fmt::Write can't fail"); } else { @@ -708,6 +721,21 @@ mod tests { assert_eq!(url, "https://example.org/s/123"); } + #[test] + fn make_endpoint_url_with_path_args_with_dash() { + let meta = stable_only_metadata(&[(V1_0, "/s/:x")]); + let url = + meta.make_endpoint_url(&[V1_0], "https://example.org", &[&"my-path"], "").unwrap(); + assert_eq!(url, "https://example.org/s/my-path"); + } + + #[test] + fn make_endpoint_url_with_path_args_with_reserved_char() { + let meta = stable_only_metadata(&[(V1_0, "/s/:x")]); + let url = meta.make_endpoint_url(&[V1_0], "https://example.org", &[&"#path"], "").unwrap(); + assert_eq!(url, "https://example.org/s/%23path"); + } + #[test] fn make_endpoint_url_with_query() { let meta = stable_only_metadata(&[(V1_0, "/s/")]);