From b9847b8b6b59e010d5fef56ff33cae7219f112f7 Mon Sep 17 00:00:00 2001 From: perf3ct Date: Mon, 23 Jun 2025 19:03:24 +0000 Subject: [PATCH] feat(server): normalize etags from webdav to properly check for file changes --- src/webdav_xml_parser.rs | 8 +++++++- tests/webdav_sync_tests.rs | 20 ++++++++++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/src/webdav_xml_parser.rs b/src/webdav_xml_parser.rs index 45ed279..6fcc17d 100644 --- a/src/webdav_xml_parser.rs +++ b/src/webdav_xml_parser.rs @@ -83,7 +83,13 @@ pub fn parse_propfind_response(xml_text: &str) -> Result> { resp.content_type = Some(text.trim().to_string()); } "getetag" => { - resp.etag = Some(text.trim().to_string()); + // Normalize ETag by removing quotes and weak ETag prefix + let etag = text.trim(); + let normalized = etag + .trim_start_matches("W/") + .trim_matches('"') + .to_string(); + resp.etag = Some(normalized); } "status" if in_propstat => { // Check if status is 200 OK diff --git a/tests/webdav_sync_tests.rs b/tests/webdav_sync_tests.rs index 24fae0c..71e1954 100644 --- a/tests/webdav_sync_tests.rs +++ b/tests/webdav_sync_tests.rs @@ -182,6 +182,26 @@ fn test_etag_change_detection() { assert_eq!(normalized_etag, old_etag); } +#[test] +fn test_etag_normalization() { + // Test various ETag formats that WebDAV servers might return + let test_cases = vec![ + ("abc123", "abc123"), // Plain ETag + ("\"abc123\"", "abc123"), // Quoted ETag + ("W/\"abc123\"", "abc123"), // Weak ETag + ("\"abc-123-def\"", "abc-123-def"), // Quoted with dashes + ("W/\"abc-123-def\"", "abc-123-def"), // Weak ETag with dashes + ]; + + for (input, expected) in test_cases { + let normalized = input + .trim_start_matches("W/") + .trim_matches('"'); + assert_eq!(normalized, expected, + "Failed to normalize ETag: {} -> expected {}", input, expected); + } +} + #[test] fn test_path_normalization() { let test_paths = vec![