private async Task <IWebDavResult> HandlePropNameAsync([NotNull][ItemNotNull] IEnumerable <IEntry> entries, CancellationToken cancellationToken) { var responses = new List <response>(); foreach (var entry in entries) { var entryPath = entry.Path.OriginalString; var href = _context.PublicControllerUrl.Append(entryPath, true); if (!_options.UseAbsoluteHref) { href = new Uri("/" + _context.PublicRootUrl.MakeRelativeUri(href).OriginalString, UriKind.Relative); } var collector = new PropertyCollector(this, _context, new ReadableFilter(), new CostFilter(0)); var propStats = await collector.GetPropertyNamesAsync(entry, cancellationToken).ConfigureAwait(false); var response = new response() { href = href.OriginalString, ItemsElementName = propStats.Select(x => ItemsChoiceType2.propstat).ToArray(), Items = propStats.Cast <object>().ToArray(), }; responses.Add(response); } var result = new multistatus() { response = responses.ToArray(), }; return(new WebDavResult <multistatus>(WebDavStatusCode.MultiStatus, result)); }
/// <summary> /// Evaluate the result of a <see cref="CollectionActionResult"/> and return a <see cref="IWebDavResult"/> implementation object. /// </summary> /// <param name="collectionResult">The <see cref="CollectionActionResult"/> to evaluate</param> /// <param name="context">The <see cref="IWebDavContext"/> to create the response for</param> /// <returns>The created response</returns> public static IWebDavResult Evaluate(this CollectionActionResult collectionResult, IWebDavContext context) { if (collectionResult.Status == ActionStatus.Ignored) { return(new WebDavResult(GetWebDavStatusCode(collectionResult.DocumentActionResults.Select(x => x.Status).Single()))); } var resultsByStatus = collectionResult .Flatten() .Where(x => x.Status != ActionStatus.ParentFailed) .GroupBy(x => x.Status) .ToDictionary(x => x.Key, x => x.ToList()); if (resultsByStatus.Count == 1) { var resultItem = resultsByStatus.Single(); var statusCode = GetWebDavStatusCode(resultItem.Key); if (resultItem.Value.Count == 1) { var response = CreateResponse(resultItem.Key, resultItem.Value, context); if (response.error != null) { return(new WebDavResult <error>(statusCode, response.error)); } } return(new WebDavResult(statusCode)); } var result = new multistatus() { response = resultsByStatus.Select(x => CreateResponse(x.Key, x.Value, context)).ToArray(), }; return(new WebDavResult <multistatus>(WebDavStatusCode.MultiStatus, result)); }
/// <inheritdoc /> public async Task <IWebDavResult> PropPatchAsync( string path, propertyupdate request, CancellationToken cancellationToken) { var selectionResult = await _fileSystem.SelectAsync(path, cancellationToken).ConfigureAwait(false); if (selectionResult.IsMissing) { if (_context.RequestHeaders.IfNoneMatch != null) { throw new WebDavException(WebDavStatusCode.PreconditionFailed); } throw new WebDavException(WebDavStatusCode.NotFound); } var targetEntry = selectionResult.TargetEntry; Debug.Assert(targetEntry != null, "targetEntry != null"); await _context.RequestHeaders .ValidateAsync(selectionResult.TargetEntry, cancellationToken).ConfigureAwait(false); var lockRequirements = new Lock( new Uri(path, UriKind.Relative), _context.PublicRelativeRequestUrl, false, new XElement(WebDavXml.Dav + "owner", _context.User.Identity.Name), LockAccessType.Write, LockShareMode.Shared, TimeoutHeader.Infinite); var lockManager = _fileSystem.LockManager; var tempLock = lockManager == null ? new ImplicitLock(true) : await lockManager.LockImplicitAsync( _fileSystem, _context.RequestHeaders.If?.Lists, lockRequirements, cancellationToken) .ConfigureAwait(false); if (!tempLock.IsSuccessful) { return(tempLock.CreateErrorResponse()); } try { var propertiesList = new List <IUntypedReadableProperty>(); using (var propEnum = targetEntry.GetProperties(_context.Dispatcher, returnInvalidProperties: true).GetEnumerator()) { while (await propEnum.MoveNext(cancellationToken).ConfigureAwait(false)) { propertiesList.Add(propEnum.Current); } } var properties = propertiesList.ToDictionary(x => x.Name); var changes = await ApplyChangesAsync(targetEntry, properties, request, cancellationToken).ConfigureAwait(false); var hasError = changes.Any(x => !x.IsSuccess); if (hasError) { changes = await RevertChangesAsync( targetEntry, changes, properties, cancellationToken) .ConfigureAwait(false); } else { var targetPropStore = targetEntry.FileSystem.PropertyStore; if (targetPropStore != null) { await targetPropStore.UpdateETagAsync(targetEntry, cancellationToken).ConfigureAwait(false); } var parent = targetEntry.Parent; while (parent != null) { var parentPropStore = parent.FileSystem.PropertyStore; if (parentPropStore != null) { await parentPropStore.UpdateETagAsync(parent, cancellationToken) .ConfigureAwait(false); } parent = parent.Parent; } } var statusCode = hasError ? WebDavStatusCode.Forbidden : WebDavStatusCode.MultiStatus; var propStats = new List <propstat>(); var readOnlyProperties = changes.Where(x => x.Status == ChangeStatus.ReadOnlyProperty).ToList(); if (readOnlyProperties.Count != 0) { propStats.AddRange( CreatePropStats( readOnlyProperties, new error() { ItemsElementName = new[] { ItemsChoiceType.cannotmodifyprotectedproperty, }, Items = new[] { new object(), }, })); changes = changes.Except(readOnlyProperties).ToList(); } propStats.AddRange(CreatePropStats(changes, null)); var status = new multistatus() { response = new[] { new response() { href = _context.PublicControllerUrl.Append(path, true).OriginalString, ItemsElementName = propStats.Select(x => ItemsChoiceType2.propstat).ToArray(), Items = propStats.Cast <object>().ToArray(), }, }, }; return(new WebDavResult <multistatus>(statusCode, status)); } finally { await tempLock.DisposeAsync(cancellationToken).ConfigureAwait(false); } }
/// <inheritdoc /> public async Task <IWebDavResult> LockAsync(string path, lockinfo info, CancellationToken cancellationToken) { if (_lockManager == null) { throw new NotSupportedException(); } var owner = info.owner; var recursive = (_context.RequestHeaders.Depth ?? DepthHeader.Infinity) == DepthHeader.Infinity; var accessType = LockAccessType.Write; var shareType = info.lockscope.ItemElementName == ItemChoiceType.exclusive ? LockShareMode.Exclusive : LockShareMode.Shared; var timeout = _timeoutPolicy?.SelectTimeout( _context.RequestHeaders.Timeout?.Values ?? new[] { TimeoutHeader.Infinite }) ?? TimeoutHeader.Infinite; var href = GetHref(path); var l = new Lock( path, href, recursive, owner, accessType, shareType, timeout); Debug.Assert(_lockManager != null, "_lockManager != null"); var lockResult = await _lockManager.LockAsync(l, cancellationToken); if (lockResult.ConflictingLocks != null) { // Lock cannot be acquired if (lockResult.ConflictingLocks.ChildLocks.Count == 0) { return(new WebDavResult <error>(WebDavStatusCode.Locked, CreateError(lockResult.ConflictingLocks.GetLocks()))); } var errorResponses = new List <response>(); if (lockResult.ConflictingLocks.ChildLocks.Count != 0 || lockResult.ConflictingLocks.ReferenceLocks.Count != 0) { errorResponses.Add(CreateErrorResponse( WebDavStatusCode.Forbidden, lockResult.ConflictingLocks.ChildLocks.Concat(lockResult.ConflictingLocks.ReferenceLocks))); } if (lockResult.ConflictingLocks.ParentLocks.Count != 0) { var errorResponse = CreateErrorResponse( WebDavStatusCode.Forbidden, lockResult.ConflictingLocks.ChildLocks); errorResponse.error = CreateError(new IActiveLock[0]); errorResponses.Add(errorResponse); } errorResponses.Add(new response() { href = GetHref(l.Path), ItemsElementName = new[] { ItemsChoiceType2.status, }, Items = new object[] { new Status(_context.RequestProtocol, WebDavStatusCode.FailedDependency).ToString(), }, }); var multistatus = new multistatus() { response = errorResponses.ToArray(), }; return(new WebDavResult <multistatus>(WebDavStatusCode.MultiStatus, multistatus)); } var activeLock = lockResult.Lock; Debug.Assert(activeLock != null, "activeLock != null"); try { var selectionResult = await _rootFileSystem.SelectAsync(path, cancellationToken); WebDavStatusCode statusCode; if (selectionResult.IsMissing) { if (_context.RequestHeaders.IfNoneMatch != null) { throw new WebDavException(WebDavStatusCode.PreconditionFailed); } if (selectionResult.MissingNames.Count > 1) { return(new WebDavResult(WebDavStatusCode.Conflict)); } var current = selectionResult.Collection; var docName = selectionResult.MissingNames.Single(); await current.CreateDocumentAsync(docName, cancellationToken); statusCode = WebDavStatusCode.Created; } else { await _context .RequestHeaders.ValidateAsync(selectionResult.TargetEntry, cancellationToken) ; statusCode = WebDavStatusCode.OK; } var activeLockXml = activeLock.ToXElement(); var result = new prop() { Any = new[] { new XElement(WebDavXml.Dav + "lockdiscovery", activeLockXml) }, }; var webDavResult = new WebDavResult <prop>(statusCode, result); webDavResult.Headers["Lock-Token"] = new[] { new LockTokenHeader(new Uri(activeLock.StateToken)).ToString() }; return(webDavResult); } catch { await _lockManager .ReleaseAsync(activeLock.Path, new Uri(activeLock.StateToken, UriKind.RelativeOrAbsolute), cancellationToken) ; throw; } }
/// <inheritdoc /> public async Task <IWebDavResult> DeleteAsync(string path, CancellationToken cancellationToken) { var selectionResult = await _rootFileSystem.SelectAsync(path, cancellationToken); if (selectionResult.IsMissing) { if (_context.RequestHeaders.IfNoneMatch != null) { throw new WebDavException(WebDavStatusCode.PreconditionFailed); } throw new WebDavException(WebDavStatusCode.NotFound); } var targetEntry = selectionResult.TargetEntry; Debug.Assert(targetEntry != null, "targetEntry != null"); await _context.RequestHeaders .ValidateAsync(selectionResult.TargetEntry, cancellationToken); var lockRequirements = new Lock( new Uri(path, UriKind.Relative), _context.PublicRelativeRequestUrl, selectionResult.ResultType == SelectionResultType.FoundCollection, new XElement(WebDavXml.Dav + "owner", _context.User.Identity.Name), LockAccessType.Write, LockShareMode.Exclusive, TimeoutHeader.Infinite); var lockManager = _rootFileSystem.LockManager; var tempLock = lockManager == null ? new ImplicitLock(true) : await lockManager.LockImplicitAsync(_rootFileSystem, _context.RequestHeaders.If?.Lists, lockRequirements, cancellationToken) ; if (!tempLock.IsSuccessful) { return(tempLock.CreateErrorResponse()); } try { DeleteResult deleteResult; try { deleteResult = await targetEntry.DeleteAsync(cancellationToken); if (targetEntry.FileSystem.PropertyStore != null) { // Remove dead properties (if there are any) await targetEntry .FileSystem.PropertyStore.RemoveAsync(targetEntry, cancellationToken) ; } } catch { deleteResult = new DeleteResult(WebDavStatusCode.Forbidden, targetEntry); } var result = new multistatus() { response = new[] { new response() { href = _context.PublicControllerUrl .Append((deleteResult.FailedEntry ?? targetEntry).Path).OriginalString, ItemsElementName = new[] { ItemsChoiceType2.status, }, Items = new object[] { new Status(_context.RequestProtocol, deleteResult.StatusCode).ToString(), }, }, }, }; if (lockManager != null) { var locksToRemove = await lockManager .GetAffectedLocksAsync(path, true, false, cancellationToken) ; foreach (var activeLock in locksToRemove) { await lockManager.ReleaseAsync( activeLock.Path, new Uri(activeLock.StateToken), cancellationToken) ; } } return(new WebDavResult <multistatus>(WebDavStatusCode.MultiStatus, result)); } finally { await tempLock.DisposeAsync(cancellationToken); } }