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(); } }
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>(); } }
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))); }
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>(); } }
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(); } }
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()); } }
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(); } }