Skip to content
Open
Show file tree
Hide file tree
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
14 changes: 8 additions & 6 deletions src/Dav.AspNetCore.Server.Extensions.Ado/SqlLockManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -67,12 +67,13 @@ public async ValueTask<LockResult> LockAsync(
timeout,
DateTime.UtcNow);

var depth = uri.LocalPath.Count(x => x == '/') - 1;
var pathForDepth = uri.GetPath();
var depth = pathForDepth.Count(x => x == '/') - 1;

await using var command = GetInsertCommand(
connection.Value,
newLock.Id.AbsoluteUri,
newLock.Uri.LocalPath,
newLock.Uri.GetPath(),
newLock.LockType,
newLock.Owner,
newLock.Recursive,
Expand Down Expand Up @@ -111,7 +112,7 @@ public async ValueTask<LockResult> RefreshLockAsync(
await using var command = GetActiveLockByIdCommand(
connection.Value,
token.AbsoluteUri,
uri.LocalPath,
uri.GetPath(),
(long)(DateTime.UtcNow - DateTime.UnixEpoch).TotalSeconds);

await using var reader = await command.ExecuteReaderAsync(cancellationToken);
Expand Down Expand Up @@ -153,7 +154,7 @@ public async ValueTask<DavStatusCode> UnlockAsync(
await using var command = GetActiveLockByIdCommand(
connection.Value,
token.AbsoluteUri,
uri.LocalPath,
uri.GetPath(),
(long)(DateTime.UtcNow - DateTime.UnixEpoch).TotalSeconds);

await using var reader = await command.ExecuteReaderAsync(cancellationToken);
Expand Down Expand Up @@ -186,11 +187,12 @@ public async ValueTask<IReadOnlyCollection<ResourceLock>> GetLocksAsync(
await connection.Value.OpenAsync(cancellationToken);

var allActiveLocks = new List<ResourceLock>();
var depth = uri.LocalPath.Count(x => x == '/') - 1;
var pathForDepth = uri.GetPath();
var depth = pathForDepth.Count(x => x == '/') - 1;

await using var command = GetActiveLocksCommand(
connection.Value,
uri.LocalPath,
uri.GetPath(),
depth,
(long)(DateTime.UtcNow - DateTime.UnixEpoch).TotalSeconds);

Expand Down
12 changes: 6 additions & 6 deletions src/Dav.AspNetCore.Server.Extensions.Ado/SqlPropertyStore.cs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ public async ValueTask SaveChangesAsync(CancellationToken cancellationToken = de
if (!writeLookup.ContainsKey(entry.Key))
continue;

await using var deleteCommand = GetDeleteCommand(connection.Value, entry.Key.Uri.LocalPath);
await using var deleteCommand = GetDeleteCommand(connection.Value, entry.Key.Uri.GetPath());
await deleteCommand.ExecuteNonQueryAsync(cancellationToken);

foreach (var propertyData in entry.Value)
Expand All @@ -65,7 +65,7 @@ public async ValueTask SaveChangesAsync(CancellationToken cancellationToken = de

await using var insertCommand = GetInsertCommand(
connection.Value,
entry.Key.Uri.LocalPath,
entry.Key.Uri.GetPath(),
propertyData.Key.LocalName,
propertyData.Key.NamespaceName,
propertyValue);
Expand All @@ -90,7 +90,7 @@ public async ValueTask DeletePropertiesAsync(IStoreItem item, CancellationToken

await using var deleteCommand = GetDeleteCommand(
connection.Value,
item.Uri.LocalPath);
item.Uri.GetPath());

await deleteCommand.ExecuteNonQueryAsync(cancellationToken);

Expand All @@ -117,8 +117,8 @@ public async ValueTask CopyPropertiesAsync(

await using var copyCommand = GetCopyCommand(
connection.Value,
source.Uri.LocalPath,
destination.Uri.LocalPath);
source.Uri.GetPath(),
destination.Uri.GetPath());

await copyCommand.ExecuteNonQueryAsync(cancellationToken);

Expand Down Expand Up @@ -184,7 +184,7 @@ public async ValueTask<IReadOnlyCollection<PropertyData>> GetPropertiesAsync(
if (connection.Value.State != ConnectionState.Open)
await connection.Value.OpenAsync(cancellationToken);

await using var command = GetSelectCommand(connection.Value, item.Uri.LocalPath);
await using var command = GetSelectCommand(connection.Value, item.Uri.GetPath());

var propertyDataList = new List<PropertyData>();

Expand Down
14 changes: 10 additions & 4 deletions src/Dav.AspNetCore.Server/Handlers/CopyHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,11 @@ protected override async Task HandleRequestAsync(CancellationToken cancellationT
if (!string.IsNullOrWhiteSpace(Context.Request.PathBase))
{
if (Context.Request.PathBase.HasValue)
destination = new Uri(destination.LocalPath.Substring(Context.Request.PathBase.Value.Length));
{
var destPath = destination.IsAbsoluteUri ? destination.LocalPath : destination.OriginalString;
var trimmed = destPath.Substring(Context.Request.PathBase.Value.Length);
destination = new Uri(trimmed, UriKind.Relative);
}
}

var overwrite = WebDavHeaders.Overwrite ?? false;
Expand All @@ -54,7 +58,8 @@ protected override async Task HandleRequestAsync(CancellationToken cancellationT
return;
}

var destinationItemName = destination.GetRelativeUri(destinationParentUri).LocalPath.Trim('/');
var destRel = destination.GetRelativeUri(destinationParentUri);
var destinationItemName = (destRel.IsAbsoluteUri ? destRel.LocalPath : destRel.OriginalString).Trim('/');
var destinationItem = await Store.GetItemAsync(destination, cancellationToken);
if (destinationItem != null && !overwrite)
{
Expand Down Expand Up @@ -84,7 +89,7 @@ protected override async Task HandleRequestAsync(CancellationToken cancellationT
var responses = new List<XElement>();
foreach (var davError in errors)
{
var href = new XElement(XmlNames.Href, $"{Context.Request.PathBase}{davError.Uri.AbsolutePath}");
var href = new XElement(XmlNames.Href, $"{Context.Request.PathBase}{davError.Uri.GetPath()}");
var status = new XElement(XmlNames.Status, $"HTTP/1.1 {(int)davError.StatusCode} {davError.StatusCode.GetDisplayName()}");
var response = new XElement(XmlNames.Response, href, status);

Expand Down Expand Up @@ -154,7 +159,8 @@ private async Task<bool> CopyItemRecursiveAsync(
if (destinationCopy == null)
throw new InvalidOperationException("If the copied item is a collection, the copy result must also be a collection.");

var itemName = subItem.Uri.GetRelativeUri(collection.Uri).LocalPath.TrimStart('/');
var subRel = subItem.Uri.GetRelativeUri(collection.Uri);
var itemName = (subRel.IsAbsoluteUri ? subRel.LocalPath : subRel.OriginalString).TrimStart('/');
var error = await CopyItemRecursiveAsync(subItem, destinationCopy, itemName, recursive, errors, cancellationToken);
if (!error)
subItemError = true;
Expand Down
2 changes: 1 addition & 1 deletion src/Dav.AspNetCore.Server/Handlers/DeleteHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ protected override async Task HandleRequestAsync(CancellationToken cancellationT
var responses = new List<XElement>();
foreach (var davError in errors)
{
var href = new XElement(XmlNames.Href, $"{Context.Request.PathBase}{davError.Uri.AbsolutePath}");
var href = new XElement(XmlNames.Href, $"{Context.Request.PathBase}{davError.Uri.GetPath()}");
var status = new XElement(XmlNames.Status, $"HTTP/1.1 {(int)davError.StatusCode} {davError.StatusCode.GetDisplayName()}");
var response = new XElement(XmlNames.Response, href, status);

Expand Down
14 changes: 13 additions & 1 deletion src/Dav.AspNetCore.Server/Handlers/GetHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,18 @@ protected override async Task HandleRequestAsync(CancellationToken cancellationT
return;
}

if (Item is IRedirectableStoreItem redirectableItem)
{
var redirectUri = await redirectableItem.GetRedirectUriAsync(Context, cancellationToken);
if (redirectUri != null)
{
Context.Response.Headers["Location"] = redirectUri.ToString();
Context.Response.Headers["Cache-Control"] = "no-store";
Context.Response.StatusCode = StatusCodes.Status302Found;
return;
}
}

var contentType = await GetNonExpensivePropertyAsync(Item, XmlNames.GetContentType, cancellationToken);
if (!string.IsNullOrWhiteSpace(contentType))
Context.Response.Headers["Content-Type"] = contentType;
Expand Down Expand Up @@ -148,4 +160,4 @@ private static async Task SendDataAsync(
context.SetResult(DavStatusCode.Ok);
await stream.CopyToAsync(context.Response.Body, cancellationToken);
}
}
}
2 changes: 1 addition & 1 deletion src/Dav.AspNetCore.Server/Handlers/LockHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ private XDocument BuildDocument(ResourceLock resourceLock)
: $"Second-{resourceLock.Timeout.TotalSeconds:F0}");

var lockToken = new XElement(XmlNames.LockToken, new XElement(XmlNames.Href, resourceLock.Id.AbsoluteUri));
var lockRoot = new XElement(XmlNames.LockRoot, new XElement(XmlNames.Href, $"{Context.Request.PathBase}{resourceLock.Uri.AbsolutePath}"));
var lockRoot = new XElement(XmlNames.LockRoot, new XElement(XmlNames.Href, $"{Context.Request.PathBase}{resourceLock.Uri.GetPath()}"));
var activeLock = new XElement(XmlNames.ActiveLock, lockType, lockScope, depth, owner, timeout, lockToken, lockRoot);
var lockDiscovery = new XElement(XmlNames.LockDiscovery, activeLock);
var prop = new XElement(XmlNames.Property, lockDiscovery);
Expand Down
3 changes: 2 additions & 1 deletion src/Dav.AspNetCore.Server/Handlers/MkColHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ protected override async Task HandleRequestAsync(CancellationToken cancellationT
var requestUri = Context.Request.Path.ToUri();
var parentUri = requestUri.GetParent();

var collectionName = requestUri.GetRelativeUri(parentUri).LocalPath.Trim('/');
var rel = requestUri.GetRelativeUri(parentUri);
var collectionName = (rel.IsAbsoluteUri ? rel.LocalPath : rel.OriginalString).Trim('/');
var result = await Collection.CreateCollectionAsync(collectionName, cancellationToken);
Context.SetResult(result.StatusCode);
}
Expand Down
17 changes: 12 additions & 5 deletions src/Dav.AspNetCore.Server/Handlers/MoveHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,11 @@ protected override async Task HandleRequestAsync(CancellationToken cancellationT
if (!string.IsNullOrWhiteSpace(Context.Request.PathBase))
{
if (Context.Request.PathBase.HasValue)
destination = new Uri(destination.LocalPath.Substring(Context.Request.PathBase.Value.Length));
{
var destPath = destination.IsAbsoluteUri ? destination.LocalPath : destination.OriginalString;
var trimmed = destPath.Substring(Context.Request.PathBase.Value.Length);
destination = new Uri(trimmed, UriKind.Relative);
}
}

var overwrite = WebDavHeaders.Overwrite ?? false;
Expand All @@ -45,7 +49,8 @@ protected override async Task HandleRequestAsync(CancellationToken cancellationT
return;
}

var destinationItemName = destination.GetRelativeUri(destinationParentUri).LocalPath.Trim('/');
var destRel = destination.GetRelativeUri(destinationParentUri);
var destinationItemName = (destRel.IsAbsoluteUri ? destRel.LocalPath : destRel.OriginalString).Trim('/');
var destinationItem = await Store.GetItemAsync(destination, cancellationToken);
if (destinationItem != null && !overwrite)
{
Expand Down Expand Up @@ -75,7 +80,7 @@ protected override async Task HandleRequestAsync(CancellationToken cancellationT
var responses = new List<XElement>();
foreach (var davError in errors)
{
var href = new XElement(XmlNames.Href, $"{Context.Request.PathBase}{davError.Uri.AbsolutePath}");
var href = new XElement(XmlNames.Href, $"{Context.Request.PathBase}{davError.Uri.GetPath()}");
var status = new XElement(XmlNames.Status, $"HTTP/1.1 {(int)davError.StatusCode} {davError.StatusCode.GetDisplayName()}");
var response = new XElement(XmlNames.Response, href, status);

Expand Down Expand Up @@ -145,7 +150,8 @@ private async Task<bool> MoveItemRecursiveAsync(
if (destinationMove == null)
throw new InvalidOperationException("If the copied item is a collection, the copy result must also be a collection.");

var subItemName = subItem.Uri.GetRelativeUri(collectionToMove.Uri).LocalPath.Trim('/');
var subRel = subItem.Uri.GetRelativeUri(collectionToMove.Uri);
var subItemName = (subRel.IsAbsoluteUri ? subRel.LocalPath : subRel.OriginalString).Trim('/');
var error = await MoveItemRecursiveAsync(collectionToMove, subItem, destinationMove, subItemName, errors, cancellationToken);
if (!error)
subItemError = true;
Expand All @@ -155,7 +161,8 @@ private async Task<bool> MoveItemRecursiveAsync(
return false;
}

var itemName = item.Uri.GetRelativeUri(collection.Uri).LocalPath.Trim('/');
var itemRel = item.Uri.GetRelativeUri(collection.Uri);
var itemName = (itemRel.IsAbsoluteUri ? itemRel.LocalPath : itemRel.OriginalString).Trim('/');
var status = await collection.DeleteItemAsync(itemName, cancellationToken);
if (status != DavStatusCode.NoContent)
{
Expand Down
2 changes: 1 addition & 1 deletion src/Dav.AspNetCore.Server/Handlers/PropFindHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ protected override async Task HandleRequestAsync(CancellationToken cancellationT
foreach (var item in items)
{
var response = new XElement(XmlNames.Response);
response.Add(new XElement(XmlNames.Href, $"{Context.Request.PathBase}{item.Uri.AbsolutePath}"));
response.Add(new XElement(XmlNames.Href, $"{Context.Request.PathBase}{item.Uri.GetPath()}"));

var propertyValues = await GetPropertiesAsync(
item,
Expand Down
2 changes: 1 addition & 1 deletion src/Dav.AspNetCore.Server/Handlers/PropPatchHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ protected override async Task HandleRequestAsync(CancellationToken cancellationT
}
}

var href = new XElement(XmlNames.Href, $"{Context.Request.PathBase}{Item.Uri.AbsolutePath}");
var href = new XElement(XmlNames.Href, $"{Context.Request.PathBase}{Item.Uri.GetPath()}");
var response = new XElement(XmlNames.Response, href);
var multiStatus = new XElement(XmlNames.MultiStatus, response);
var document = new XDocument(
Expand Down
3 changes: 2 additions & 1 deletion src/Dav.AspNetCore.Server/Handlers/PutHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ internal class PutHandler : RequestHandler
protected override async Task HandleRequestAsync(CancellationToken cancellationToken = default)
{
var requestUri = Context.Request.Path.ToUri();
var itemName = requestUri.GetRelativeUri(Collection.Uri).LocalPath.Trim('/');
var rel = requestUri.GetRelativeUri(Collection.Uri);
var itemName = (rel.IsAbsoluteUri ? rel.LocalPath : rel.OriginalString).Trim('/');
var result = await Collection.CreateItemAsync(itemName, cancellationToken);
if (result.Item == null)
{
Expand Down
11 changes: 7 additions & 4 deletions src/Dav.AspNetCore.Server/Handlers/RequestHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,8 @@ public async Task HandleRequestAsync(
}
else
{
var itemName = requestUri.GetRelativeUri(Collection.Uri).LocalPath.Trim('/');
var relativeUri = requestUri.GetRelativeUri(Collection.Uri);
var itemName = (relativeUri.IsAbsoluteUri ? relativeUri.LocalPath : relativeUri.OriginalString).Trim('/');
Item = await collection.GetItemAsync(itemName, cancellationToken);
}

Expand Down Expand Up @@ -216,7 +217,8 @@ protected async Task<bool> DeleteItemRecursiveAsync(
if (error)
return false;

var itemName = item.Uri.GetRelativeUri(collection.Uri).LocalPath.TrimStart('/');
var itemUri = item.Uri.GetRelativeUri(collection.Uri);
var itemName = (itemUri.IsAbsoluteUri ? itemUri.LocalPath : itemUri.OriginalString).TrimStart('/');
var status = await collection.DeleteItemAsync(itemName, cancellationToken);
if (status != DavStatusCode.NoContent)
{
Expand Down Expand Up @@ -249,8 +251,9 @@ async ValueTask<bool> ValidateConditionAsync(IfHeaderValueCondition condition)
var collection = await Store.GetCollectionAsync(parentUri, cancellationToken);
if (collection != null)
{
var itemName = resourceUri.GetRelativeUri(collection.Uri).LocalPath.Trim('/');
if (string.IsNullOrWhiteSpace(itemName))
var itemUri = resourceUri.GetRelativeUri(collection.Uri);
var itemName = (itemUri.IsAbsoluteUri ? itemUri.LocalPath : itemUri.OriginalString).Trim('/');
if (string.IsNullOrEmpty(itemName))
{
items[resourceUri] = collection;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,14 +49,14 @@ public static bool TryParse(string? input, [NotNullWhen(true)] out DestinationHe

if (Uri.TryCreate(input, UriKind.Absolute, out var uri))
{
var pathString = new PathString(uri.LocalPath);
var pathString = new PathString(uri.GetPath());
parsedValue = new DestinationHeaderValue(pathString.ToUri());
return true;
}

if(!input.StartsWith("/") && Uri.TryCreate($"/{input}", UriKind.Absolute, out var uri2))
{
var pathString = new PathString(uri2.LocalPath);
var pathString = new PathString(uri2.GetPath());
parsedValue = new DestinationHeaderValue(pathString.ToUri());
return true;
}
Expand Down
15 changes: 7 additions & 8 deletions src/Dav.AspNetCore.Server/Locks/InMemoryLockManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -146,19 +146,18 @@ public ValueTask<IReadOnlyCollection<ResourceLock>> GetLocksAsync(
ArgumentNullException.ThrowIfNull(uri, nameof(uri));

var allActiveLocks = new List<ResourceLock>();
var pathParts = uri.LocalPath.Split('/');
if (uri.AbsoluteUri.Equals("/"))
pathParts = new[] { "" };

var path = uri.GetPath().Trim('/');
string[] pathParts = string.IsNullOrEmpty(path) ? new[] { "" } : path.Split('/');

var currentPath = string.Empty;

for (var i = 0; i < pathParts.Length; i++)
{
currentPath += currentPath.Equals("/") ? pathParts[i] : $"/{pathParts[i]}";
currentPath += string.IsNullOrEmpty(currentPath) || currentPath == "/" ? $"/{pathParts[i]}" : $"/{pathParts[i]}";
var activeLocks = locks.Values
.Where(x => x.Uri.LocalPath == currentPath && x.IsActive && (x.Recursive || i == pathParts.Length - 1))
.Where(x => x.Uri.GetPath() == currentPath && x.IsActive && (x.Recursive || i == pathParts.Length - 1))
.ToList();

allActiveLocks.AddRange(activeLocks);
}

Expand Down
23 changes: 19 additions & 4 deletions src/Dav.AspNetCore.Server/PathStringExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,27 @@ internal static class PathStringExtensions
public static Uri ToUri(this PathString path)
{
if (string.IsNullOrWhiteSpace(path))
return new Uri("/");
return new Uri("/", UriKind.Relative);

var uri = Uri.UnescapeDataString(path.ToUriComponent().TrimEnd('/'));
// Normalizza il percorso: sostituisci backslash con forward slash (per Windows)
var normalized = path.ToUriComponent().Replace("\\", "/").TrimEnd('/');
var uri = Uri.UnescapeDataString(normalized);

if (string.IsNullOrWhiteSpace(uri))
return new Uri("/");
return new Uri("/", UriKind.Relative);

return new Uri(uri);
// Assicurati che inizi con /
if (!uri.StartsWith("/"))
uri = "/" + uri;

try
{
return new Uri(uri, UriKind.Relative);
}
catch (UriFormatException)
{
// Se l'URI è ancora invalido, ritorna il percorso root
return new Uri("/", UriKind.Relative);
}
}
}
2 changes: 1 addition & 1 deletion src/Dav.AspNetCore.Server/Store/Files/File.cs
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ public async Task<ItemResult> CopyAsync(
private static string GetMimeTypeForFileExtension(Uri uri)
{
var provider = new FileExtensionContentTypeProvider();
if (!provider.TryGetContentType(uri.AbsolutePath, out var contentType))
if (!provider.TryGetContentType(uri.GetPath(), out var contentType))
{
contentType = "application/octet-stream";
}
Expand Down
Loading