Example #1
0
        public async Task Handles_Abrupt_Disconnects_Gracefully(string pipeline)
        {
            // This test differs in structure from the others as this test needs to test that tusdotnet handles pipeline specifics correctly.
            // We can only emulate the pipelines so this test might not be 100% accurate.
            // Also we must bypass the TestServer and go directly for the TusProtcolHandler as we would otherwise introduce yet another pipeline.

            var pipelineDetails = PipelineDisconnectEmulationDataAttribute.GetInfo(pipeline);

            var cts   = new CancellationTokenSource();
            var store = Substitute.For <ITusStore>().WithExistingFile("testfile", uploadLength: 10, uploadOffset: 5);

            var requestStream = Substitute.For <Stream>();

            requestStream.ReadAsync(Arg.Any <byte[]>(), Arg.Any <int>(), Arg.Any <int>(), Arg.Any <CancellationToken>())
            .ThrowsForAnyArgs(_ =>
            {
                if (pipelineDetails.FlagsCancellationTokenAsCancelled)
                {
                    cts.Cancel();
                }
                throw pipelineDetails.ExceptionThatIsThrown;
            });

            store.AppendDataAsync("testfile", Arg.Any <Stream>(), Arg.Any <CancellationToken>())
            .ReturnsForAnyArgs <Task <long> >(async callInfo => await callInfo.Arg <Stream>().ReadAsync(null, 0, 0, callInfo.Arg <CancellationToken>()));

            var responseHeaders = new Dictionary <string, string>(StringComparer.OrdinalIgnoreCase);
            var responseStatus  = HttpStatusCode.OK;
            var response        = new ResponseAdapter
            {
                Body      = new MemoryStream(),
                SetHeader = (key, value) => responseHeaders[key] = value,
                SetStatus = status => responseStatus = status
            };

            var context = new ContextAdapter
            {
                CancellationToken = cts.Token,
                Configuration     = new DefaultTusConfiguration
                {
                    UrlPath = "/files",
                    Store   = store
                },
                Request = new RequestAdapter("/files")
                {
                    Headers = new Dictionary <string, List <string> >(StringComparer.OrdinalIgnoreCase)
                    {
                        { "Content-Type", new List <string>(1)
                          {
                              "application/offset+octet-stream"
                          } },
                        { "Tus-Resumable", new List <string>(1)
                          {
                              "1.0.0"
                          } },
                        { "Upload-Offset", new List <string>(1)
                          {
                              "5"
                          } }
                    },
                    Method     = "PATCH",
                    Body       = requestStream,
                    RequestUri = new Uri("https://localhost:8080/files/testfile")
                },
                Response = response
            };

            var handled = await TusProtocolHandlerIntentBased.Invoke(context);

            handled.ShouldBe(ResultType.StopExecution);
            responseStatus.ShouldBe(HttpStatusCode.OK);
            responseHeaders.Count.ShouldBe(0);
            response.Body.Length.ShouldBe(0);
        }
Example #2
0
        public async Task Checksum_Is_Verified_If_Client_Disconnects()
        {
            var cts = new CancellationTokenSource();

            var store = Substitute.For <ITusStore, ITusChecksumStore>();

            store.FileExistAsync("checksum", CancellationToken.None).ReturnsForAnyArgs(true);
            store.GetUploadOffsetAsync("checksum", Arg.Any <CancellationToken>()).Returns(5);
            store.GetUploadLengthAsync("checksum", Arg.Any <CancellationToken>()).Returns(10);

            // Cancel token source to emulate a client disconnect
            store.AppendDataAsync("checksum", Arg.Any <Stream>(), Arg.Any <CancellationToken>()).Returns(5).AndDoes(_ => cts.Cancel());

            var cstore = (ITusChecksumStore)store;

            cstore.GetSupportedAlgorithmsAsync(CancellationToken.None).ReturnsForAnyArgs(new[] { "sha1" });
            cstore.VerifyChecksumAsync(null, null, null, CancellationToken.None).ReturnsForAnyArgs(false);

            var responseStatusCode = HttpStatusCode.OK;
            var responseStream     = new MemoryStream();

            await TusProtocolHandlerIntentBased.Invoke(new ContextAdapter
            {
                CancellationToken = cts.Token,
                Configuration     = new DefaultTusConfiguration
                {
                    Store   = store,
                    UrlPath = "/files",
                },
                Request = new RequestAdapter("/files")
                {
                    Body       = new MemoryStream(),
                    RequestUri = new System.Uri("https://localhost/files/checksum"),
                    Headers    = new Dictionary <string, List <string> >
                    {
                        { Constants.HeaderConstants.TusResumable, new List <string> {
                              Constants.HeaderConstants.TusResumableValue
                          } },
                        // Just random gibberish as checksum
                        { Constants.HeaderConstants.UploadChecksum, new List <string> {
                              "sha1 Kq5sNclPz7QV2+lfQIuc6R7oRu0="
                          } },
                        { Constants.HeaderConstants.UploadOffset, new List <string> {
                              "5"
                          } },
                        { Constants.HeaderConstants.ContentType, new List <string> {
                              "application/offset+octet-stream"
                          } },
                    },
                    Method = "PATCH"
                },
                Response = new ResponseAdapter
                {
                    Body      = responseStream,
                    SetHeader = (key, value) => { },
                    SetStatus = status => responseStatusCode = status
                }
            });

            await cstore.ReceivedWithAnyArgs().VerifyChecksumAsync(null, null, null, CancellationToken.None);

            responseStatusCode.ShouldBe((HttpStatusCode)460);

            responseStream.Seek(0, SeekOrigin.Begin);
            using (var sr = new StreamReader(responseStream))
            {
                sr.ReadToEnd().ShouldBe("Header Upload-Checksum does not match the checksum of the file");
            }
        }