public async Task <string> PropfindAsync(PropfindRequest r)
        {
            bool withDirectoryContent = r.Depth == DepthType.One;

            var propertiesList = _fileStorageService.GetProperties(r.Drive, r.Path, withDirectoryContent);

            XNamespace ns = "DAV:";

            var dictNamespaces = new Dictionary <string, XNamespace>();

            dictNamespaces.Add("D", ns);

            var xMultiStatus = XmlHelper.GetRoot(ns, "multistatus", dictNamespaces);

            var xResponse = GetPropfindXmlResponse(ns, new List <string>(), propertiesList.First(), r.Url);

            xMultiStatus.Add(xResponse);

            foreach (var properties in propertiesList.Skip(1))
            {
                var url = r.Url + properties.Name;

                if (properties.Type == ItemType.Directory)
                {
                    url += "/";
                }

                xResponse = GetPropfindXmlResponse(ns, new List <string>(), properties, url);

                xMultiStatus.Add(xResponse);
            }

            return(xMultiStatus.ToString());
        }
        public void PROPFIND_should_handle_empty_url_when_rewriting_response_href()
        {
            context.Setup(c => c.Request).Returns(request.Object);
            request.Setup(r => r.Url).Returns(new Uri("http://localhost/web/files/litmus"));

            var propFind = new PropfindRequest { PathInfo = "/" };
            provider.Setup(p => p.CheckExists(It.IsAny<string>())).Returns(true);

            var multiStatusResult = new MultiStatusResult();
            multiStatusResult.Responses.AddRange(new[] { new Response { Href = "/" }, new Response { Href = "/newFile" }});
            provider.Setup(p => p.Process(propFind)).Returns(multiStatusResult);

            var result = controller.Propfind(propFind) as MultiStatusResult;

            Assert.That(result, Is.SameAs(multiStatusResult));
            Assert.That(result.Responses.Count, Is.EqualTo(2));

            Assert.That(result.Responses[0].Href, Is.EqualTo("/web/files/litmus"));
            Assert.That(result.Responses[1].Href, Is.EqualTo("/web/files/litmus/newFile"));
        }
        public virtual MultiStatusResult Propfind(PropfindRequest request)
        {
            if (!storageProvider.CheckExists(request.PathInfo))
                throw new HttpException(404, "path doesn't exist");

            var result = storageProvider.Process(request);
            foreach (var response in result.Responses)
                if (response.Href == "/")
                    response.Href = Request.Url.LocalPath;
                else if (request.PathInfo == "/")
                    response.Href = Request.Url.LocalPath.TrimEnd('/') + EnsureStartSlash(response.Href);
                else
                    response.Href = Request.Url.LocalPath.Replace(request.PathInfo, EnsureStartSlash(response.Href));

            return result;
        }
        public void should_use_depth_as_directory_recursion_level_recurse_two_levels()
        {
            var startDirName = Path.GetRandomFileName();
            var startDir = CreateDirectory(Path.Combine(Path.GetTempPath(), startDirName));
            fileSystem.basePath = startDir;

            var startDirTempFileName = Path.GetRandomFileName();
            var startDirTempFile = AddPath(Path.Combine(startDir, startDirTempFileName));
            File.WriteAllText(startDirTempFile, "start dir temp file");

            var subDirName = Path.GetRandomFileName();
            var subDir = CreateDirectory(Path.Combine(startDir, subDirName));
            Directory.CreateDirectory(subDir);
            var subDirTempFileName = Path.GetRandomFileName();
            var subDirTempFile = AddPath(Path.Combine(subDir, subDirTempFileName));
            File.WriteAllText(subDirTempFile, "sub dir temp file");

            var newDir = AddPath(Path.Combine(Path.GetTempPath(), Path.GetRandomFileName()));

            var request = new PropfindRequest("/", "2");
            var result = fileSystem.Process(request);

            Assert.That(result.Responses.Count, Is.EqualTo(4));
            Assert.That(result.Responses[0].Href, Is.EqualTo("/"));
            Assert.That(result.Responses[0].Found.Status, Is.EqualTo("HTTP/1.1 200 OK"));
            Assert.That(result.Responses[0].Found.IsCollection, Is.True);

            Assert.That(result.Responses[1].Href, Is.EqualTo("/" + startDirTempFileName));
            Assert.That(result.Responses[1].Found.Status, Is.EqualTo("HTTP/1.1 200 OK"));
            Assert.That(result.Responses[1].Found.IsCollection, Is.False);
            Assert.That(result.Responses[1].Found.ContentLength, Is.EqualTo(19));

            Assert.That(result.Responses[2].Href, Is.EqualTo("/" + subDirName + "/"));
            Assert.That(result.Responses[2].Found.Status, Is.EqualTo("HTTP/1.1 200 OK"));
            Assert.That(result.Responses[2].Found.IsCollection, Is.True);

            Assert.That(result.Responses[3].Href, Is.EqualTo("/" + subDirName + "/" + subDirTempFileName));
            Assert.That(result.Responses[3].Found.Status, Is.EqualTo("HTTP/1.1 200 OK"));
            Assert.That(result.Responses[3].Found.IsCollection, Is.False);
            Assert.That(result.Responses[3].Found.ContentLength, Is.EqualTo(17));
        }
        public void should_use_depth_as_directory_recursion_level_and_only_return_information_about_the_current_level()
        {
            var startDirName = Path.GetRandomFileName();
            var startDir = CreateDirectory(Path.Combine(Path.GetTempPath(), startDirName));
            fileSystem.basePath = startDir;

            var startDirTempFileName = Path.GetRandomFileName();
            var startDirTempFile = AddPath(Path.Combine(startDir, startDirTempFileName));
            File.WriteAllText(startDirTempFile, "start dir temp file");

            var subDirName = Path.GetRandomFileName();
            var subDir = CreateDirectory(Path.Combine(startDir, subDirName));
            Directory.CreateDirectory(subDir);
            var subDirTempFileName = Path.GetRandomFileName();
            var subDirTempFile = AddPath(Path.Combine(subDir, subDirTempFileName));
            File.WriteAllText(subDirTempFile, "sub dir temp file");

            var newDir = AddPath(Path.Combine(Path.GetTempPath(), Path.GetRandomFileName()));

            var request = new PropfindRequest("/", "0");
            var result = fileSystem.Process(request);

            Assert.That(result.Responses.Count, Is.EqualTo(1));
            Assert.That(result.Responses[0].Href, Is.EqualTo("/"));
            Assert.That(result.Responses[0].Found.Status, Is.EqualTo("HTTP/1.1 200 OK"));
            Assert.That(result.Responses[0].Found.IsCollection, Is.True);
        }
        public void should_return_unhandled_properties_as_not_found()
        {
            var tempPath = AddPath(Path.GetTempFileName());
            var fileName = Path.GetFileName(tempPath);

            XNamespace nameSpace = "http://example.com/neon/litmus/";
            var element = new XElement(nameSpace + "foo", null);
            var request = new PropfindRequest { PathInfo = fileName, NonDavProperties = new List<XElement> { element } };
            var result = fileSystem.Process(request);

            Assert.That(result.Responses.Count, Is.EqualTo(1));
            var response = result.Responses[0];
            Assert.That(response.Href, Is.EqualTo("/" + fileName));
            Assert.That(response.Found.Properties, Is.Empty);
            Assert.That(response.NotFound.Status, Is.EqualTo("HTTP/1.1 404 Not Found"));
            Assert.That(response.NotFound.Properties.Count, Is.EqualTo(1));

            var displayNameProperty = response.NotFound.Properties[0];
            Assert.That(displayNameProperty.Name.LocalName, Is.EqualTo("foo"));
            Assert.That(displayNameProperty.Name.Namespace, Is.EqualTo(nameSpace));
        }
        public void should_return_unhandled_dav_properties_as_not_found()
        {
            var tempPath = AddPath(Path.GetTempFileName());
            var fileName = Path.GetFileName(tempPath);

            var request = new PropfindRequest { PathInfo = fileName, DavProperties = new List<string> { "displayname" } };
            var result = fileSystem.Process(request);

            Assert.That(result.Responses.Count, Is.EqualTo(1));
            var response = result.Responses[0];
            Assert.That(response.Href, Is.EqualTo("/" + fileName));
            Assert.That(response.Found.Properties, Is.Empty);
            Assert.That(response.NotFound.Status, Is.EqualTo("HTTP/1.1 404 Not Found"));
            Assert.That(response.NotFound.Properties.Count, Is.EqualTo(1));

            var displayNameProperty = response.NotFound.Properties[0];
            Assert.That(displayNameProperty.Name.LocalName, Is.EqualTo("displayname"));
            Assert.That(displayNameProperty.Name.Namespace, Is.EqualTo(Util.DavNamespace));
        }
        public void should_return_last_modified_of_file()
        {
            var tempPath = AddPath(Path.GetTempFileName());
            var fileName = Path.GetFileName(tempPath);
            var lastModified = File.GetLastWriteTimeUtc(tempPath);

            var request = new PropfindRequest { HasGetLastModified = true, PathInfo = fileName };
            var result = fileSystem.Process(request);

            Assert.That(result.Responses.Count, Is.EqualTo(1));
            var response = result.Responses[0];
            Assert.That(response.Href, Is.EqualTo("/" + fileName));
            Assert.That(response.Found.LastModified, Is.EqualTo(lastModified));
            Assert.That(response.Found.Status, Is.EqualTo("HTTP/1.1 200 OK"));
        }
        public void should_return_is_collection_property()
        {
            var tempPath = Path.GetTempPath();
            var newDir = Path.GetRandomFileName();
            var tempDir = CreateDirectory(Path.Combine(tempPath, newDir));

            var request = new PropfindRequest { HasResourceType = true, PathInfo = newDir };
            var result = fileSystem.Process(request);

            Assert.That(result.Responses.Count, Is.EqualTo(1));
            var response = result.Responses[0];
            Assert.That(response.Href, Is.EqualTo("/" + newDir));
            Assert.That(response.Found.IsCollection, Is.True);
            Assert.That(response.Found.Status, Is.EqualTo("HTTP/1.1 200 OK"));
        }
        public void should_return_empty_resourcetype_when_not_dir()
        {
            var tempPath = AddPath(Path.GetTempFileName());
            var fileName = Path.GetFileName(tempPath);

            var request = new PropfindRequest { HasResourceType = true, PathInfo = fileName};
            var result = fileSystem.Process(request);

            Assert.That(result.Responses.Count, Is.EqualTo(1));
            var response = result.Responses[0];
            Assert.That(response.Href, Is.EqualTo("/" + fileName));
            Assert.That(response.Found.IsCollection, Is.False);
            Assert.That(response.Found.Status, Is.EqualTo("HTTP/1.1 200 OK"));
        }
        public void should_return_content_length_of_file()
        {
            var tempPath = AddPath(Path.GetTempFileName());
            var fileName = Path.GetFileName(tempPath);
            File.WriteAllBytes(tempPath, new byte[] { 23, 45, 45 });

            var request = new PropfindRequest { HasGetContentLength = true, PathInfo = fileName };
            var result = fileSystem.Process(request);

            Assert.That(result.Responses.Count, Is.EqualTo(1));
            var response = result.Responses[0];
            Assert.That(response.Href, Is.EqualTo("/" + fileName));
            Assert.That(response.Found.ContentLength, Is.EqualTo(3));
            Assert.That(response.Found.Status, Is.EqualTo("HTTP/1.1 200 OK"));
        }
        public void should_not_return_content_length_of_directory()
        {
            var tempDir = Path.GetTempPath();
            var newDir = Path.GetRandomFileName();
            var tempPath = CreateDirectory(Path.Combine(tempDir, newDir));

            var request = new PropfindRequest { HasGetContentLength = true, PathInfo = newDir};
            var result = fileSystem.Process(request);

            Assert.That(result.Responses.Count, Is.EqualTo(1));
            var response = result.Responses[0];
            Assert.That(response.Href, Is.EqualTo("/" + newDir));
            Assert.That(response.NotFound.Status, Is.EqualTo("HTTP/1.1 404 Not Found"));
            Assert.That(response.NotFound.Properties.Count, Is.EqualTo(1));

            var displayNameProperty = response.NotFound.Properties[0];
            Assert.That(displayNameProperty.Name.LocalName, Is.EqualTo("getcontentlength"));
            Assert.That(displayNameProperty.Name.Namespace, Is.EqualTo(Util.DavNamespace));
        }
        public void PROPFIND_should_rewrite_urls_relative_to_web_host()
        {
            context.Setup(c => c.Request).Returns(request.Object);
            request.Setup(r => r.Url).Returns(new Uri("http://localhost/web/files/litmus/"));

            var propFind = new PropfindRequest("/litmus/", null);
            provider.Setup(p => p.CheckExists("/litmus/")).Returns(true);

            var multiStatusResult = new MultiStatusResult();
            multiStatusResult.Responses.AddRange(new [] { new Response { Href = "litmus/test" }, new Response { Href = "litmus/test2" }});
            provider.Setup(p => p.Process(propFind)).Returns(multiStatusResult);

            var result = controller.Propfind(propFind) as MultiStatusResult;

            Assert.That(result, Is.SameAs(multiStatusResult));
            Assert.That(result.Responses.Count, Is.EqualTo(2));

            Assert.That(result.Responses[0].Href, Is.EqualTo("/web/files/litmus/test"));
            Assert.That(result.Responses[1].Href, Is.EqualTo("/web/files/litmus/test2"));
        }
        public void PROPFIND_should_return_status_for_directory()
        {
            var request = new PropfindRequest { PathInfo = "/litmus/" };
            request.DavProperties.AddRange(new[] { "getcontentlength" });
            XNamespace ns = "urn:someNamespace";
            request.NonDavProperties.Add(new XElement(ns + "test"));

            provider.Setup(p => p.CheckExists("/litmus/")).Returns(true);
            var multiStatusResult = new MultiStatusResult();
            provider.Setup(p => p.Process(request)).Returns(multiStatusResult);

            var result = controller.Propfind(request) as MultiStatusResult;

            Assert.That(result, Is.Not.Null);
            Assert.That(result, Is.SameAs(multiStatusResult));
        }
        void Process(PropfindRequest request, string relativePath, int currentDepth, MultiStatusResult multiStatus)
        {
            var fullPath = GetFullPath(relativePath);

            var response = new Response { Href = relativePath };
            multiStatus.Responses.Add(response);
            var isACollection = IsACollection(fullPath);

            if (request.HasGetContentLength)
            {
                if (isACollection)
                    response.NotFound.AddProperty("getcontentlength", null);
                else
                    response.Found.AddContentLength(new FileInfo(fullPath).Length);
            }

            if (request.HasGetLastModified) {
                if (isACollection)
                    response.Found.AddLastModified(Directory.GetLastWriteTimeUtc(fullPath));
                else
                    response.Found.AddLastModified(File.GetLastWriteTimeUtc(fullPath));
            }

            if (request.HasResourceType)
                response.Found.AddResourceType(isACollection);

            if (response.Found.Properties.Any())
                response.Found.Status = "HTTP/1.1 200 OK";

            var supportedProperties = new[] { "getcontentlength", "getlastmodified", "resourcetype" };
            foreach (var prop in request.DavProperties.Where(p => !supportedProperties.Contains(p)))
                response.NotFound.AddProperty(prop, null);

            response.NotFound.Properties.AddRange(request.NonDavProperties);

            if (response.NotFound.Properties.Any())
                response.NotFound.Status = "HTTP/1.1 404 Not Found";

            if (currentDepth == 0)
                return;

            if (isACollection)
            {
                //process files
                var files = Directory.GetFiles(fullPath);
                foreach (var file in files)
                    Process(request, JoinRelativePath(relativePath, Path.GetFileName(file)), 0, multiStatus);

                //process directories
                var dirs = Directory.GetDirectories(fullPath);
                foreach (var dir in dirs)
                    Process(request, JoinRelativePath(relativePath, Path.GetFileName(dir)) + "/", currentDepth - 1, multiStatus);
            }
        }
        public MultiStatusResult Process(PropfindRequest request)
        {
            var multiStatus = new MultiStatusResult();

            var relativePath = request.PathInfo.StartsWith("/") ? request.PathInfo : "/" + request.PathInfo;

            Process(request, relativePath, request.Depth, multiStatus);

            return multiStatus;
        }