Beispiel #1
0
        public async Task HandleAsync_ResolvesAndWritesFileCorrectlyToGivenStream(string fileName)
        {
            var cancellationToken = new CancellationToken();

            var httpContext = new DefaultHttpContext();

            var contentRootPath = Environment.CurrentDirectory;

            var filePath = Path.Combine(contentRootPath, "Files", fileName);

            Assert.IsTrue(System.IO.File.Exists(filePath), $"Expected the {fileName} file to be accessible in the test environment");

            var fileInfo = new FileInfo(filePath);

            var fileBuffer = await System.IO.File.ReadAllBytesAsync(filePath, cancellationToken);

            using var responseBodyStream = new MemoryStream(fileBuffer.Length);

            httpContext.Response.Body = responseBodyStream;

            var fileRepository = new Moq.Mock <IFileRepository>();

            var fileRepositoryInvoked = false;

            var services = new ServiceCollection();

            services.AddScoped(sp => fileRepository.Object);

            httpContext.RequestServices = services.BuildServiceProvider();

            var fileVersion = Guid.NewGuid().ToString();

            using var algo = MD5.Create();

            var contentHash = algo.ComputeHash(fileBuffer);

            var fileMetadata = new FileMetadata("title", "description", "group-name", fileVersion, "owner", fileName, fileInfo.Extension, (ulong)fileInfo.Length, "blobName", DateTimeOffset.UtcNow, Convert.ToBase64String(contentHash), FileStatus.Verified);

            var fileWriteDetails = new FileWriteDetails(fileVersion, "content-type", contentHash, (ulong)fileBuffer.Length, "content-encoding", "content-language", DateTimeOffset.UtcNow, DateTimeOffset.UtcNow, fileMetadata);

            fileRepository.
            Setup(x => x.WriteToStreamAsync(Moq.It.IsAny <FileMetadata>(), Moq.It.IsAny <Stream>(), Moq.It.IsAny <CancellationToken>())).
            Callback(async(FileMetadata givenFileMetadata, Stream givenStream, CancellationToken givenCancellationToken) => {
                Assert.IsFalse(givenFileMetadata.IsEmpty);
                Assert.IsNotNull(givenStream);

                Assert.IsFalse(givenCancellationToken.IsCancellationRequested, "Expected the cancellation token to not be cancelled");

                Assert.AreSame(responseBodyStream, givenStream, "Expected the SUT to as the repository to write the file to the stream it was asked to");
                Assert.AreSame(fileName, givenFileMetadata.Name, "Expected the SUT to request the file from the repository whose name it was provided with");
                Assert.AreSame(fileVersion, givenFileMetadata.Version, "Expected the SUT to request the file version from the repository that it was provided with");
                Assert.AreEqual(cancellationToken, givenCancellationToken, "Expected the same cancellation token to propagate between service interfaces");

                await givenStream.WriteAsync(fileBuffer, cancellationToken);
                await givenStream.FlushAsync(cancellationToken);

                fileRepositoryInvoked = true;
            }).
            Returns(Task.FromResult(fileWriteDetails));

            fileRepository.Setup(x => x.GetMetadataAsync(Moq.It.IsAny <File>(), Moq.It.IsAny <CancellationToken>())).Returns(Task.FromResult(fileMetadata));

            var accessToken = Guid.NewGuid().ToString();

            var file = File.With(fileName, fileVersion);

            var getFileWopiRequest = GetFileWopiRequest.With(file, accessToken);

            await getFileWopiRequest.HandleAsync(httpContext, cancellationToken);

            Assert.IsTrue(fileRepositoryInvoked, "Expected the SUT to defer to the file repository with the correct parameters");

            Assert.AreEqual(fileBuffer.Length, responseBodyStream.Length, "All bytes in the file should be written to the target stream");

            Assert.IsTrue(httpContext.Response.Headers.ContainsKey("X-WOPI-ItemVersion"), "Expected the X-WOPI-ItemVersion header to have been written to the response");

            Assert.IsNotNull(httpContext.Response.Headers["X-WOPI-ItemVersion"], "Expected the X-WOPI-ItemVersion header in the response to not be null");
        }
Beispiel #2
0
        private WopiRequest IdentifyFileRequest(HttpRequest httpRequest, PathString path, string accessToken, Features features)
        {
            var fileSegment = path.Value.Substring("/wopi/files/".Length)?.Trim();

            var method = httpRequest.Method;

            _logger?.LogTrace($"Extracted file segment from request path: '{fileSegment ?? "null"}' for method {method ?? "null"}");

            if (string.IsNullOrWhiteSpace(fileSegment))
            {
                return(WopiRequest.EMPTY);
            }

            // NB - Collabora have not implemented support for the X-WOPI-ItemVersion header and so the Version field set in the
            //      CheckFileInfo response does not flow through to those endpoints where it is optional - eg GetFile.
            //      This unfortunately means we have to do some crazy workaround using the fileId, and thus use that to derive
            //      the relevant metadata needed for us to operate correctly.  Hopefully this will prove to be just a temporary
            //      workaround

            if (fileSegment.EndsWith("/contents"))
            {
                var fileId = fileSegment.Substring(0, fileSegment.Length - "/contents".Length)?.Trim() ?? "null";

                _logger?.LogTrace($"Identified 'contents' request.  File Id extracted from url is: '{fileId}'");

                if (string.IsNullOrWhiteSpace(fileId))
                {
                    return(WopiRequest.EMPTY);
                }

                var fileVersion = httpRequest.Headers["X-WOPI-ItemVersion"].FirstOrDefault();

                var file = File.FromId(fileId, fileVersion);

                if (0 == string.Compare("GET", method, StringComparison.OrdinalIgnoreCase))
                {
                    _logger?.LogTrace($"Identified this to be a Get File request");

                    var isEphemeralRedirect = bool.Parse(httpRequest.Query["ephemeral_redirect"].FirstOrDefault() ?? bool.FalseString);

                    if (isEphemeralRedirect)
                    {
                        return(RedirectToFileStoreRequest.With(file, accessToken));
                    }

                    return(GetFileWopiRequest.With(file, accessToken));
                }
                else if (0 == string.Compare("POST", method, StringComparison.OrdinalIgnoreCase))
                {
                    _logger?.LogTrace($"Identified this to be a Save File request");

                    return(PostFileWopiRequest.With(file.Name, accessToken));
                }
                else
                {
                    _logger?.LogTrace($"The request method '{method}' is not supported for path '{path.Value ?? "null"}'");
                }
            }
            else
            {
                var fileId = fileSegment;

                _logger?.LogTrace($"File Id extracted from url is: '{fileId}'.  Attempting to identity request type");

                if (0 == string.Compare("GET", method, StringComparison.OrdinalIgnoreCase))
                {
                    _logger?.LogTrace($"Identified this is a Check File Info request");

                    var file = (File)fileId;

                    return(CheckFileInfoWopiRequest.With(file, accessToken, features));
                }
                else
                {
                    _logger?.LogTrace($"The request method '{method}' is not supported for path '{path.Value ?? "null"}");
                }
            }

            return(WopiRequest.EMPTY);
        }
Beispiel #3
0
        public void With_DoesNotThrowIfAccessTokenIsNeitherNullNorWhitespace()
        {
            var file = File.With("file-name", "file-version");

            GetFileWopiRequest.With(file, accessToken: "access-token");
        }
Beispiel #4
0
        public void With_ThrowsIfAccessTokenIsWhitespace()
        {
            var file = File.With("file-name", "file-version");

            GetFileWopiRequest.With(file, accessToken: " ");
        }
Beispiel #5
0
        public void With_ThrowsIfAccessTokenIsEmpty()
        {
            var file = File.With("file-name", "file-version");

            GetFileWopiRequest.With(file, accessToken: string.Empty);
        }
Beispiel #6
0
        public void With_ThrowsIfAccessTokenIsNull()
        {
            var file = File.With("file-name", "file-version");

            GetFileWopiRequest.With(file, accessToken: default);
        }
Beispiel #7
0
 public void With_ThrowsIfFileIsEmpty()
 {
     GetFileWopiRequest.With(File.EMPTY, accessToken: "access-token");
 }