/// <inheritdoc />
 public Task <IWebDavResult> PropPatchAsync(string path, propertyupdate request, CancellationToken cancellationToken)
 {
     if (_propPatchHandler == null)
     {
         throw new NotSupportedException();
     }
     return(_propPatchHandler.PropPatchAsync(path, request, cancellationToken));
 }
예제 #2
0
        internal Task <IActionResult> QuearyManualControllerCall(HttpContext context, string filePath, IServiceProvider serviceProvider, CancellationToken ct = default(CancellationToken))
        {
            switch (context.Request.Method.ToUpperInvariant())
            {
            case "OPTIONS":
                return(QueryOptionsAsync(filePath, ct));

            case "MKCOL":
                return(MkColAsync(filePath, ct));

            case "GET":
                return(GetAsync(filePath, ct));

            case "PUT":
                return(PutAsync(filePath, ct));

            case "DELETE":
                return(DeleteAsync(filePath, ct));

            case "PROPFIND":
                propfind request = null;
                return(PropFindAsync(filePath, request, ct));

            case "PROPPATCH":
                propertyupdate propUp = null;
                return(PropPatchAsync(filePath, propUp, ct));

            case "HEAD":
                return(HeadAsync(filePath, ct));

            case "COPY":
                string copyDestination = context.Request.Headers["Destination"];
                return(CopyAsync(filePath, copyDestination, ct));

            case "MOVE":
                string moveDestination = context.Request.Headers["Destination"];
                return(MoveAsync(filePath, moveDestination, ct));

            case "LOCK":
                Stream       body = context.Request.Body;
                MemoryStream mem  = new MemoryStream();
                body.CopyTo(mem);
                body.Dispose();
                byte[] raw  = mem.ToArray();
                string json = Encoding.UTF8.GetString(raw);    //?
                return(LockAsync(filePath, null, ct));

            case "UNLOCK":
                string lockToken = context.Request.Headers["Lock-Token"];
                return(this.UnlockAsync(filePath, lockToken));

            default:
                return(null);
            }
        }
예제 #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
        private async Task <IReadOnlyCollection <ChangeItem> > ApplyChangesAsync([NotNull] IEntry entry, [NotNull] Dictionary <XName, IUntypedReadableProperty> properties, [NotNull] propertyupdate request, CancellationToken cancellationToken)
        {
            var result = new List <ChangeItem>();

            if (request.Items == null)
            {
                return(result);
            }

            var failed = false;

            foreach (var item in request.Items)
            {
                IReadOnlyCollection <ChangeItem> changeItems;
                var set = item as propset;
                if (set != null)
                {
                    changeItems = await ApplySetAsync(entry, properties, set, failed, cancellationToken).ConfigureAwait(false);
                }
                else if (item is propremove remove)
                {
                    changeItems = await ApplyRemoveAsync(entry, properties, remove, failed, cancellationToken).ConfigureAwait(false);
                }
                else
                {
                    changeItems = new ChangeItem[0];
                }

                result.AddRange(changeItems);

                failed = failed || changeItems.Any(x => !x.IsSuccess);
            }

            return(result);
        }
예제 #5
0
        public async Task <IActionResult> PropPatchAsync(string path, [FromBody] propertyupdate request, CancellationToken cancellationToken)
        {
            var result = await _dispatcher.Class1.PropPatchAsync(path ?? string.Empty, request, cancellationToken).ConfigureAwait(false);

            return(new WebDavIndirectResult(_dispatcher, result, _responseLogger));
        }
        private async Task <IReadOnlyCollection <XName> > SetPropertiesAsync([NotNull] Uri targetUrl, [NotNull][ItemNotNull] IEnumerable <IUntypedWriteableProperty> properties, CancellationToken cancellationToken)
        {
            var elements = new List <XElement>();

            foreach (var property in properties)
            {
                var element = await property.GetXmlValueAsync(cancellationToken).ConfigureAwait(false);

                var deadProp = property as IDeadProperty;
                if (deadProp == null || !deadProp.IsDefaultValue(element))
                {
                    elements.Add(element);
                }
            }

            var requestData = new propertyupdate()
            {
                Items = new object[]
                {
                    new propset()
                    {
                        prop = new prop()
                        {
                            Any = elements.ToArray(),
                        },
                    },
                },
            };

            multistatus result;

            using (var httpRequest = new HttpRequestMessage(_propPatchHttpMethod, targetUrl)
            {
                Content = CreateContent(_propertyUpdateSerializer, requestData),
            })
            {
                using (var httpResponse = await Client.SendAsync(httpRequest, cancellationToken).ConfigureAwait(false))
                {
                    if (httpResponse.IsSuccessStatusCode)
                    {
                        return(new XName[0]);
                    }

                    var resultDoc = await ReadResponseAsync(httpResponse).ConfigureAwait(false);

                    if (resultDoc == null)
                    {
                        throw new RemoteTargetException("The destination server didn't return a response", targetUrl);
                    }

                    result = Parse(targetUrl, httpResponse, resultDoc);
                }
            }

            if (result.response == null || result.response.Length == 0)
            {
                throw new RemoteTargetException("The destination server didn't return a response", targetUrl);
            }
            if (result.response.Length != 1)
            {
                throw new RemoteTargetException("Received more than one multi-status response", targetUrl);
            }

            var response = result.response[0];

            var hrefs = response.GetHrefs().Select(x => new Uri(x, UriKind.RelativeOrAbsolute)).ToList();

            if (hrefs.Count == 0)
            {
                hrefs.Add(targetUrl);
            }

            var statusIndex = Array.IndexOf(response.ItemsElementName, ItemsChoiceType2.status);
            var isFailure   = response.error != null;

            if (statusIndex != -1 && !isFailure)
            {
                var responseStatus = Status.Parse((string)response.Items[statusIndex]);
                isFailure = !responseStatus.IsSuccessStatusCode;
            }

            var hasFailedPropStats = false;
            var failedProperties   = new List <XName>();

            foreach (var propstat in response.Items.OfType <propstat>())
            {
                var propStatIsFailure =
                    isFailure ||
                    propstat.error != null ||
                    (!string.IsNullOrEmpty(propstat.status) && !Status.Parse(propstat.status).IsSuccessStatusCode);
                hasFailedPropStats |= propStatIsFailure;
                if (propStatIsFailure && propstat.prop?.Any != null)
                {
                    foreach (var element in propstat.prop.Any)
                    {
                        failedProperties.Add(element.Name);
                    }
                }
            }

            if (failedProperties.Count == 0 && (isFailure || hasFailedPropStats))
            {
                throw new RemoteTargetException("Failed properties were not returned by the server.");
            }

            return(failedProperties);
        }