예제 #1
0
        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));
        }
예제 #3
0
        /// <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);
            }
        }
예제 #4
0
        /// <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;
            }
        }
예제 #5
0
        /// <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);
            }
        }