From b09cb04a9812381c082879f48bb25ac73e6694aa Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 14 Jan 2026 12:19:24 +0000 Subject: [PATCH 1/3] Initial plan From ab456c3215784580f940050b98e68ead4e71778a Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 14 Jan 2026 12:27:54 +0000 Subject: [PATCH 2/3] Fix WebDavStorage GetRelativePath to correctly strip root path from WebDAV resource URLs Co-authored-by: Menelion <595597+Menelion@users.noreply.github.com> --- src/SharpSync/Storage/WebDavStorage.cs | 32 +++++++++++++++---- .../Storage/WebDavStorageTests.cs | 5 --- 2 files changed, 25 insertions(+), 12 deletions(-) diff --git a/src/SharpSync/Storage/WebDavStorage.cs b/src/SharpSync/Storage/WebDavStorage.cs index 40b9dff..ff71cb8 100644 --- a/src/SharpSync/Storage/WebDavStorage.cs +++ b/src/SharpSync/Storage/WebDavStorage.cs @@ -930,14 +930,32 @@ private string GetFullPath(string relativePath) { } private string GetRelativePath(string fullUrl) { - var prefix = string.IsNullOrEmpty(RootPath) ? _baseUrl : $"{_baseUrl}/{RootPath}"; - - if (fullUrl.StartsWith(prefix)) { - var relativePath = fullUrl.Substring(prefix.Length).Trim('/'); - return string.IsNullOrEmpty(relativePath) ? "/" : relativePath; + // The fullUrl is typically a path, not a full URL. It may or may not start with a slash. + // We need to strip the RootPath prefix to get the relative path. + + // If there's no root path, return the path as-is (trimming leading/trailing slashes) + if (string.IsNullOrEmpty(RootPath)) { + return fullUrl.Trim('/'); } - - return fullUrl; + + // Normalize the root path (no leading/trailing slashes) + var normalizedRoot = RootPath.Trim('/'); + + // The fullUrl should start with /RootPath/ or RootPath/ + // Try both with and without leading slash + var pathToStrip1 = $"/{normalizedRoot}/"; + var pathToStrip2 = $"{normalizedRoot}/"; + + if (fullUrl.StartsWith(pathToStrip1)) { + return fullUrl.Substring(pathToStrip1.Length).TrimEnd('/'); + } + if (fullUrl.StartsWith(pathToStrip2)) { + return fullUrl.Substring(pathToStrip2.Length).TrimEnd('/'); + } + + // If it doesn't start with the root path, it might be the root itself + // or just return as-is (trim leading/trailing slashes) + return fullUrl.Trim('/'); } private bool _rootPathCreated; diff --git a/tests/SharpSync.Tests/Storage/WebDavStorageTests.cs b/tests/SharpSync.Tests/Storage/WebDavStorageTests.cs index 9a10642..95d2ef7 100644 --- a/tests/SharpSync.Tests/Storage/WebDavStorageTests.cs +++ b/tests/SharpSync.Tests/Storage/WebDavStorageTests.cs @@ -606,11 +606,6 @@ public async Task ListItemsAsync_WithFiles_ReturnsAllItems() { await Task.Delay(100); } - // Debug output - foreach (var item in items!) { - System.Diagnostics.Debug.WriteLine($"Found item: {item.Path}, IsDirectory: {item.IsDirectory}"); - } - // Assert Assert.Equal(3, items.Count); Assert.Contains(items, i => i.Path.EndsWith("file1.txt") && !i.IsDirectory); From 481eff664ff1bad1a472e13a6fcd2fd44873c1e8 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 14 Jan 2026 12:35:29 +0000 Subject: [PATCH 3/3] Fix WebDavStorage GetRelativePath to handle full URLs from WebDAV server Co-authored-by: Menelion <595597+Menelion@users.noreply.github.com> --- src/SharpSync/Storage/WebDavStorage.cs | 42 ++++++++++++++++---------- 1 file changed, 26 insertions(+), 16 deletions(-) diff --git a/src/SharpSync/Storage/WebDavStorage.cs b/src/SharpSync/Storage/WebDavStorage.cs index ff71cb8..7b5e3c3 100644 --- a/src/SharpSync/Storage/WebDavStorage.cs +++ b/src/SharpSync/Storage/WebDavStorage.cs @@ -930,32 +930,42 @@ private string GetFullPath(string relativePath) { } private string GetRelativePath(string fullUrl) { - // The fullUrl is typically a path, not a full URL. It may or may not start with a slash. - // We need to strip the RootPath prefix to get the relative path. + // The fullUrl can be either a full URL (http://server/path) or just a path (/path) + // We need to strip the base URL and RootPath to get the relative path - // If there's no root path, return the path as-is (trimming leading/trailing slashes) + // Extract the path portion if it's a full URL + string path; + if (Uri.TryCreate(fullUrl, UriKind.Absolute, out var uri)) { + // It's a full URL - get the path component and decode it + path = Uri.UnescapeDataString(uri.AbsolutePath); + } else { + // It's already a path + path = fullUrl; + } + + // Remove leading slash for consistency + path = path.TrimStart('/'); + + // If there's no root path, return the path as-is (trimming trailing slashes) if (string.IsNullOrEmpty(RootPath)) { - return fullUrl.Trim('/'); + return path.TrimEnd('/'); } // Normalize the root path (no leading/trailing slashes) var normalizedRoot = RootPath.Trim('/'); - // The fullUrl should start with /RootPath/ or RootPath/ - // Try both with and without leading slash - var pathToStrip1 = $"/{normalizedRoot}/"; - var pathToStrip2 = $"{normalizedRoot}/"; - - if (fullUrl.StartsWith(pathToStrip1)) { - return fullUrl.Substring(pathToStrip1.Length).TrimEnd('/'); + // The path should start with RootPath/ + if (path.StartsWith($"{normalizedRoot}/")) { + return path.Substring(normalizedRoot.Length + 1).TrimEnd('/'); } - if (fullUrl.StartsWith(pathToStrip2)) { - return fullUrl.Substring(pathToStrip2.Length).TrimEnd('/'); + + // If it's exactly the root path itself (directory listing) + if (path == normalizedRoot || path == $"{normalizedRoot}/") { + return ""; } - // If it doesn't start with the root path, it might be the root itself - // or just return as-is (trim leading/trailing slashes) - return fullUrl.Trim('/'); + // Otherwise return as-is (trim trailing slashes) + return path.TrimEnd('/'); } private bool _rootPathCreated;