Ejemplo n.º 1
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);
        }
        public async Task HandleAsync_FormsWOPICompliantResponseUsingFileMetadataAndUserContextAndFeatures(string title, string description, string groupName, string version, string owner, string fileName, string extension, ulong sizeInBytes, string contentHash)
        {
            var cancellationToken = new CancellationToken();

            var services = new ServiceCollection();

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

            var fileRepositoryInvoked = false;

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

            var httpContext = new DefaultHttpContext {
                RequestServices = services.BuildServiceProvider()
            };

            using var responseBodyStream = new MemoryStream();

            httpContext.Response.Body = responseBodyStream;

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

            var fileMetadata = new FileMetadata(
                title: title,
                description: description,
                groupName: groupName,
                version: version,
                owner: owner,
                name: fileName,
                extension: extension,
                blobName: fileName,
                sizeInBytes: sizeInBytes,
                lastWriteTime: DateTimeOffset.UtcNow,
                contentHash: contentHash,
                fileStatus: FileStatus.Verified
                );

            fileRepository.
            Setup(x => x.GetMetadataAsync(Moq.It.IsAny <FutureNHS.WOPIHost.File>(), Moq.It.IsAny <CancellationToken>())).
            Callback((FutureNHS.WOPIHost.File givenFile, CancellationToken givenCancellationToken) => {
                Assert.IsFalse(givenFile.IsEmpty);

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

                Assert.AreSame(fileName, givenFile.Name, "Expected the SUT to request the file from the repository whose name it was provided with");
                Assert.AreSame(fileVersion, givenFile.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");

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

            var ephemeralDownloadLink = new Uri("https://www.file-storage.com/files/file_id", UriKind.Absolute);

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

            var features = new Features();

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

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

            var checkFileInfoWopiRequest = CheckFileInfoWopiRequest.With(file, accessToken, features);

            await checkFileInfoWopiRequest.HandleAsync(httpContext, cancellationToken);

            Assert.IsTrue(fileRepositoryInvoked);

            Assert.AreEqual("application/json", httpContext.Response.ContentType);

            Assert.AreSame(responseBodyStream, httpContext.Response.Body);

            responseBodyStream.Position = 0;

            dynamic responseBody = await JsonSerializer.DeserializeAsync <ExpandoObject>(responseBodyStream, cancellationToken : cancellationToken);

            Assert.IsNotNull(responseBody);

            Assert.AreEqual(fileMetadata.Title, ((JsonElement)(responseBody.BaseFileName)).GetString());
            Assert.AreEqual(fileMetadata.Version, ((JsonElement)(responseBody.Version)).GetString());
            Assert.AreEqual(fileMetadata.Owner, ((JsonElement)(responseBody.OwnerId)).GetString());
            Assert.AreEqual(fileMetadata.Extension, ((JsonElement)(responseBody.FileExtension)).GetString());
            Assert.AreEqual(fileMetadata.SizeInBytes, ((JsonElement)(responseBody.Size)).GetUInt64());
            Assert.AreEqual(ephemeralDownloadLink.AbsoluteUri, ((JsonElement)(responseBody.FileUrl)).GetString());
            Assert.AreEqual(fileMetadata.LastWriteTime.ToIso8601(), ((JsonElement)(responseBody.LastModifiedTime)).GetString());

            Assert.AreEqual(FutureNHS.WOPIHost.File.FILENAME_MAXIMUM_LENGTH, ((JsonElement)(responseBody.FileNameMaxLength)).GetInt32());
        }