예제 #1
0
        public async Task OnAuthorized_Is_Called_For_Final_Files()
        {
            var        onAuthorizeWasCalled            = false;
            IntentType?intentProvidedToOnAuthorize     = null;
            FileConcat fileConcatProvidedToOnAuthorize = null;

            using (var server = TestServerFactory.Create(CreateStoreForFinalFileConcatenation(), new Events
            {
                OnAuthorizeAsync = ctx =>
                {
                    onAuthorizeWasCalled = true;
                    intentProvidedToOnAuthorize = ctx.Intent;
                    fileConcatProvidedToOnAuthorize = ctx.FileConcatenation;
                    return(Task.FromResult(0));
                }
            }))
            {
                var response = await server.CreateRequest("/files").AddTusResumableHeader().AddHeader("Upload-Concat", "final;/files/partial1 /files/partial2").SendAsync("POST");

                response.ShouldContainTusResumableHeader();
                response.ShouldContainHeader("location", "/files/finalId");

                onAuthorizeWasCalled.ShouldBeTrue();
                intentProvidedToOnAuthorize.ShouldBe(IntentType.ConcatenateFiles);
                var fileConcatFinal = fileConcatProvidedToOnAuthorize.ShouldBeOfType <FileConcatFinal>();
                fileConcatFinal.Files.Length.ShouldBe(2);
                fileConcatFinal.Files.All(f => f == "partial1" || f == "partial2").ShouldBeTrue();
            }
        }
예제 #2
0
        public async Task OnBeforeCreateAsync_Receives_FileConcatPartial_For_Partial_Files(string methodToUse)
        {
            FileConcat fileConcat = null;

            using (var server = TestServerFactory.Create(CreateStoreForPartialFileConcatenation(), new Events
            {
                OnBeforeCreateAsync = ctx =>
                {
                    fileConcat = ctx.FileConcatenation;
                    return(Task.FromResult(0));
                }
            }))
            {
                var response = await server
                               .CreateRequest("/files")
                               .AddTusResumableHeader()
                               .AddHeader("Upload-Length", "1")
                               .AddHeader("Upload-Concat", "partial")
                               .OverrideHttpMethodIfNeeded("POST", methodToUse)
                               .SendAsync(methodToUse);

                response.StatusCode.ShouldBe(HttpStatusCode.Created);
                fileConcat.ShouldBeOfType <FileConcatPartial>();
            }
        }
예제 #3
0
        public async Task OnCreateCompleteAsync_Receives_FileConcatFinal_For_Final_Files(string methodToUse)
        {
            FileConcat fileConcat = null;

            using (var server = TestServerFactory.Create(CreateStoreForFinalFileConcatenation(), (Events) new Events
            {
                OnCreateCompleteAsync = ctx =>
                {
                    fileConcat = ctx.FileConcatenation;
                    return((Task)Task.FromResult((int)0));
                }
            }))
            {
                var response = await server
                               .CreateRequest("/files")
                               .AddTusResumableHeader()
                               .AddHeader("Upload-Concat", "final;/files/partial1 /files/partial2")
                               .OverrideHttpMethodIfNeeded("POST", methodToUse)
                               .SendAsync(methodToUse);

                response.StatusCode.ShouldBe(HttpStatusCode.Created);
                var fileConcatFinal = fileConcat.ShouldBeOfType <FileConcatFinal>();
                fileConcatFinal.Files.Length.ShouldBe(2);
                fileConcatFinal.Files.All(f => f == "partial1" || f == "partial2").ShouldBeTrue();
            }
        }
        /// <summary>
        /// Creates an internal WriteFile request and runs it. Returns the Upload-Offset for the file or 0 if something failed.
        /// The <code>UploadExpires</code> property is also updated if sliding expiration is used.
        /// </summary>
        /// <param name="fileConcat">Null for regular files or FileConcatPartial if the file is a partial file</param>
        /// <returns>The Upload-Offset for the file or 0 if something failed.</returns>
        internal async Task <long> SaveFileContent(FileConcat fileConcat = null)
        {
            var authResponse = await EventHelper.Validate <AuthorizeContext>(_context, ctx =>
            {
                ctx.Intent            = IntentType.WriteFile;
                ctx.FileConcatenation = fileConcat;
            });

            if (authResponse == ResultType.StopExecution)
            {
                return(0);
            }

            var writeFileHandler = new WriteFileHandler(_context, initiatedFromCreationWithUpload: true);

            if (!await writeFileHandler.Validate())
            {
                return(0);
            }

            try
            {
                await writeFileHandler.Invoke();
            }
            catch
            {
                // Left blank
            }

            return(GetUploadOffset() ?? (await _context.Configuration.Store.GetUploadOffsetAsync(_fileId, _context.CancellationToken)));
        }
예제 #5
0
        public async Task OnCreateCompleteAsync_Receives_FileConcatPartial_For_Partial_Files(string methodToUse)
        {
            var store       = Substitute.For <ITusStore, ITusCreationStore, ITusConcatenationStore>();
            var concatStore = (ITusConcatenationStore)store;

            concatStore.CreatePartialFileAsync(-1, null, CancellationToken.None)
            .ReturnsForAnyArgs(Guid.NewGuid().ToString());

            FileConcat fileConcat = null;
            var        events     = new Events
            {
                OnCreateCompleteAsync = ctx =>
                {
                    fileConcat = ctx.FileConcatenation;
                    return(Task.FromResult(0));
                }
            };

            using (var server = TestServerFactory.Create(store, events))
            {
                var response = await server
                               .CreateRequest("/files")
                               .AddTusResumableHeader()
                               .AddHeader("Upload-Length", "1")
                               .AddHeader("Upload-Concat", "partial")
                               .OverrideHttpMethodIfNeeded("POST", methodToUse)
                               .SendAsync(methodToUse);

                response.StatusCode.ShouldBe(HttpStatusCode.Created);
                fileConcat.ShouldBeOfType <FileConcatPartial>();
            }
        }
예제 #6
0
        public async Task Runs_OnCreateCompleteAsync_After_Creating_The_File(string method)
        {
            var store  = Substitute.For <ITusCreationStore, ITusStore>();
            var fileId = Guid.NewGuid().ToString();

            store.CreateFileAsync(Arg.Any <long>(), Arg.Any <string>(), Arg.Any <CancellationToken>()).Returns(fileId);

            long?      uploadLength                = null;
            bool?      uploadLengthIsDeferred      = null;
            FileConcat fileConcat                  = null;
            Dictionary <string, Metadata> metadata = null;
            string callbackFileId                  = null;
            var    events = new Events
            {
                OnCreateCompleteAsync = ctx =>
                {
                    store.ReceivedWithAnyArgs().CreateFileAsync(-1, null, CancellationToken.None);

                    callbackFileId         = ctx.FileId;
                    uploadLength           = ctx.UploadLength;
                    uploadLengthIsDeferred = ctx.UploadLengthIsDeferred;
                    fileConcat             = ctx.FileConcatenation;
                    metadata = ctx.Metadata;

                    return(Task.FromResult(0));
                }
            };

            using (var server = TestServerFactory.Create((ITusStore)store, events))
            {
                var response = await server.CreateRequest("/files")
                               .AddTusResumableHeader()
                               .AddHeader("Upload-Length", "1")
                               .AddHeader("Upload-Metadata", "filename d29ybGRfZG9taW5hdGlvbl9wbGFuLnBkZg==,othermeta c29tZSBvdGhlciBkYXRh")
                               .OverrideHttpMethodIfNeeded("POST", method)
                               .SendAsync(method);

                response.StatusCode.ShouldBe(HttpStatusCode.Created);

                callbackFileId.ShouldBe(fileId);
                uploadLength.ShouldBe(1);
                uploadLengthIsDeferred.ShouldBe(false);
                fileConcat.ShouldBeNull();
                metadata.ShouldNotBeNull();
                metadata.ContainsKey("filename").ShouldBeTrue();
                metadata.ContainsKey("othermeta").ShouldBeTrue();
            }
        }
예제 #7
0
        internal override async Task <bool> Handle(ContextAdapter context)
        {
            var response          = context.Response;
            var cancellationToken = context.CancellationToken;
            var store             = context.Configuration.Store;

            var fileId = context.GetFileId();

            response.SetHeader(HeaderConstants.TusResumable, HeaderConstants.TusResumableValue);
            response.SetHeader(HeaderConstants.CacheControl, HeaderConstants.NoStore);

            await AddUploadMetadata(context, fileId, cancellationToken);

            var uploadLength = await store.GetUploadLengthAsync(fileId, cancellationToken);

            AddUploadLength(context, uploadLength);

            var uploadOffset = await store.GetUploadOffsetAsync(fileId, cancellationToken);

            FileConcat uploadConcat    = null;
            var        addUploadOffset = true;

            if (context.Configuration.Store is ITusConcatenationStore tusConcatStore)
            {
                uploadConcat = await tusConcatStore.GetUploadConcatAsync(fileId, cancellationToken);

                // Only add Upload-Offset to final files if they are complete.
                if (uploadConcat is FileConcatFinal && uploadLength != uploadOffset)
                {
                    addUploadOffset = false;
                }
            }

            if (addUploadOffset)
            {
                response.SetHeader(HeaderConstants.UploadOffset, uploadOffset.ToString());
            }

            if (uploadConcat != null)
            {
                (uploadConcat as FileConcatFinal)?.AddUrlPathToFiles(context.Configuration.UrlPath);
                response.SetHeader(HeaderConstants.UploadConcat, uploadConcat.GetHeader());
            }

            return(true);
        }
        internal override async Task Invoke()
        {
            Response.SetHeader(HeaderConstants.TusResumable, HeaderConstants.TusResumableValue);
            Response.SetHeader(HeaderConstants.CacheControl, HeaderConstants.NoStore);

            var uploadMetadata = await GetMetadata(Context);

            if (!string.IsNullOrEmpty(uploadMetadata))
            {
                Response.SetHeader(HeaderConstants.UploadMetadata, uploadMetadata);
            }

            var uploadLength = await Store.GetUploadLengthAsync(Request.FileId, CancellationToken);

            SetUploadLengthHeader(Context, uploadLength);

            var uploadOffset = await Store.GetUploadOffsetAsync(Request.FileId, CancellationToken);

            FileConcat uploadConcat    = null;
            var        addUploadOffset = true;

            if (Context.Configuration.Store is ITusConcatenationStore tusConcatStore)
            {
                uploadConcat = await tusConcatStore.GetUploadConcatAsync(Request.FileId, CancellationToken);

                // Only add Upload-Offset to final files if they are complete.
                if (uploadConcat is FileConcatFinal && uploadLength != uploadOffset)
                {
                    addUploadOffset = false;
                }
            }

            if (addUploadOffset)
            {
                Response.SetHeader(HeaderConstants.UploadOffset, uploadOffset.ToString());
            }

            if (uploadConcat != null)
            {
                (uploadConcat as FileConcatFinal)?.AddUrlPathToFiles(Context.Configuration.UrlPath);
                Response.SetHeader(HeaderConstants.UploadConcat, uploadConcat.GetHeader());
            }
        }
예제 #9
0
        public async Task OnCreateCompleteAsync_Receives_FileConcatFinal_For_Final_Files(string methodToUse)
        {
            var store       = Substitute.For <ITusStore, ITusCreationStore, ITusConcatenationStore>();
            var concatStore = (ITusConcatenationStore)store;

            store.FileExistAsync("partial1", Arg.Any <CancellationToken>()).Returns(true);
            store.FileExistAsync("partial2", Arg.Any <CancellationToken>()).Returns(true);
            store.GetUploadLengthAsync("partial1", Arg.Any <CancellationToken>()).Returns(10);
            store.GetUploadLengthAsync("partial2", Arg.Any <CancellationToken>()).Returns(20);
            store.GetUploadOffsetAsync("partial1", Arg.Any <CancellationToken>()).Returns(10);
            store.GetUploadOffsetAsync("partial2", Arg.Any <CancellationToken>()).Returns(20);
            concatStore.GetUploadConcatAsync("partial1", Arg.Any <CancellationToken>()).Returns(new FileConcatPartial());
            concatStore.GetUploadConcatAsync("partial2", Arg.Any <CancellationToken>()).Returns(new FileConcatPartial());
            concatStore.CreateFinalFileAsync(null, null, Arg.Any <CancellationToken>())
            .ReturnsForAnyArgs("finalId");

            FileConcat fileConcat = null;
            var        events     = new Events
            {
                OnCreateCompleteAsync = ctx =>
                {
                    fileConcat = ctx.FileConcatenation;
                    return(Task.FromResult(0));
                }
            };

            using (var server = TestServerFactory.Create(store, events))
            {
                var response = await server
                               .CreateRequest("/files")
                               .AddTusResumableHeader()
                               .AddHeader("Upload-Concat", "final;/files/partial1 /files/partial2")
                               .OverrideHttpMethodIfNeeded("POST", methodToUse)
                               .SendAsync(methodToUse);

                response.StatusCode.ShouldBe(HttpStatusCode.Created);
                fileConcat.ShouldBeOfType <FileConcatFinal>();
                var fileConcatFinal = (FileConcatFinal)fileConcat;
                fileConcatFinal.Files.Length.ShouldBe(2);
                fileConcatFinal.Files.All(f => f == "partial1" || f == "partial2").ShouldBeTrue();
            }
        }