Skip to content
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 35 additions & 4 deletions crates/google-workspace/src/validate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -273,10 +273,35 @@ fn normalize_non_existing(path: &Path) -> Result<PathBuf, GwsError> {
// ── URL encoding ──────────────────────────────────────────────────────

/// Percent-encode a value for use as a single URL path segment (e.g., file ID,
/// calendar ID, message ID). All non-alphanumeric characters are encoded.
/// calendar ID, message ID). RFC 3986 unreserved characters (`A-Z`, `a-z`,
/// `0-9`, `-`, `.`, `_`, `~`) are left intact; everything else that can alter
/// URL structure is encoded.
pub fn encode_path_segment(s: &str) -> String {
use percent_encoding::{utf8_percent_encode, NON_ALPHANUMERIC};
utf8_percent_encode(s, NON_ALPHANUMERIC).to_string()
use percent_encoding::{utf8_percent_encode, AsciiSet, CONTROLS};

const PATH_SEGMENT_ENCODE_SET: &AsciiSet = &CONTROLS
.add(b' ')
.add(b'"')
.add(b'#')
.add(b'%')
.add(b'<')
.add(b'>')
.add(b'?')
.add(b'`')
.add(b'{')
.add(b'}')
.add(b'/')
.add(b':')
.add(b';')
.add(b'=')
.add(b'@')
.add(b'[')
.add(b'\\')
.add(b']')
.add(b'^')
.add(b'|');

utf8_percent_encode(s, PATH_SEGMENT_ENCODE_SET).to_string()
Comment on lines +280 to +304

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

By manually constructing PATH_SEGMENT_ENCODE_SET starting from CONTROLS and adding specific characters, several characters that were previously encoded by NON_ALPHANUMERIC (such as !, $, &, ', (, ), *, +, ,) are now left unencoded. This could lead to unexpected behavior or bugs if a path segment contains these characters (for example, + might be decoded to a space by some servers, or & could be misinterpreted as a query parameter separator).

Instead, we can define PATH_SEGMENT_ENCODE_SET by starting from NON_ALPHANUMERIC and removing the RFC 3986 unreserved characters (-, ., _, ~). This is much cleaner, less error-prone, and ensures all other non-alphanumeric characters remain safely encoded.

Suggested change
use percent_encoding::{utf8_percent_encode, AsciiSet, CONTROLS};
const PATH_SEGMENT_ENCODE_SET: &AsciiSet = &CONTROLS
.add(b' ')
.add(b'"')
.add(b'#')
.add(b'%')
.add(b'<')
.add(b'>')
.add(b'?')
.add(b'`')
.add(b'{')
.add(b'}')
.add(b'/')
.add(b':')
.add(b';')
.add(b'=')
.add(b'@')
.add(b'[')
.add(b'\\')
.add(b']')
.add(b'^')
.add(b'|');
utf8_percent_encode(s, PATH_SEGMENT_ENCODE_SET).to_string()
use percent_encoding::{utf8_percent_encode, AsciiSet, NON_ALPHANUMERIC};
const PATH_SEGMENT_ENCODE_SET: &AsciiSet = &NON_ALPHANUMERIC
.remove(b'-')
.remove(b'.')
.remove(b'_')
.remove(b'~');
utf8_percent_encode(s, PATH_SEGMENT_ENCODE_SET).to_string()

}

/// Percent-encode a value for use in URI path templates where `/` should stay
Expand Down Expand Up @@ -509,7 +534,13 @@ mod tests {
fn test_encode_path_segment_email() {
let encoded = encode_path_segment("user@gmail.com");
assert!(!encoded.contains('@'));
assert!(!encoded.contains('.'));
assert!(encoded.contains('.'));
}

#[test]
fn test_encode_path_segment_preserves_unreserved_script_id() {
let script_id = "1-ukYIb8XjT9KQlsj6_NbryM5UJXBwAMeY5GKtSBA05csXty3iY7DhO-P";
assert_eq!(encode_path_segment(script_id), script_id);
}

#[test]
Expand Down
Loading