Exemple #1
0
        public async Task VerifyChecksumAsync_Data_Is_Truncated_If_Client_Disconnects()
        {
            // Checksum is valid for "Hello " <-- note the last space
            const string checksum   = "lka6E6To6r7KT1JZv9faQdNooaY=";
            var          dataBuffer = new UTF8Encoding(false).GetBytes("Hello ");

            var fileId = await _fixture.Store.CreateFileAsync(6, null, CancellationToken.None);

            var cts           = new CancellationTokenSource();
            var requestStream = new RequestStreamFake(
                (stream, bufferToFill, offset, count, cancellationToken) =>
            {
                // Emulate client disconnect before entire stream has been read
                if (stream.Position == 2)
                {
                    cts.Cancel();
                    cts.Token.ThrowIfCancellationRequested();
                }

                return(stream.ReadBackingStreamAsync(bufferToFill, offset, 2, cancellationToken));
            },
                dataBuffer);

            var guardedStream = new ClientDisconnectGuardedReadOnlyStream(requestStream, cts);

            await _fixture.Store.AppendDataAsync(fileId, guardedStream, guardedStream.CancellationToken);

            var checksumOk = await _fixture.Store.VerifyChecksumAsync(fileId, "sha1", Convert.FromBase64String(checksum), cts.Token);

            checksumOk.ShouldBeFalse();

            new FileInfo(Path.Combine(_fixture.Path, fileId)).Length.ShouldBe(0);
        }
Exemple #2
0
        internal override async Task Invoke()
        {
            await WriteUploadLengthIfDefered();

            var guardedStream = new ClientDisconnectGuardedReadOnlyStream(Request.Body, CancellationTokenSource.CreateLinkedTokenSource(CancellationToken));
            var bytesWritten  = await Store.AppendDataAsync(Request.FileId, guardedStream, guardedStream.CancellationToken);

            if (guardedStream.CancellationToken.IsCancellationRequested)
            {
                return;
            }

            var expires = _expirationHelper.IsSlidingExpiration
                ? await _expirationHelper.SetExpirationIfSupported(Request.FileId, CancellationToken)
                : await _expirationHelper.GetExpirationIfSupported(Request.FileId, CancellationToken);

            if (!await MatchChecksum())
            {
                await Response.Error((HttpStatusCode)460, "Header Upload-Checksum does not match the checksum of the file");

                return;
            }

            var fileOffset = long.Parse(Request.GetHeader(HeaderConstants.UploadOffset));

            Response.SetHeader(HeaderConstants.TusResumable, HeaderConstants.TusResumableValue);
            Response.SetHeader(HeaderConstants.UploadOffset, (fileOffset + bytesWritten).ToString());

            if (expires.HasValue)
            {
                Response.SetHeader(HeaderConstants.UploadExpires, _expirationHelper.FormatHeader(expires));
            }

            Response.SetStatus(HttpStatusCode.NoContent);

            if (await FileIsComplete(Request.FileId, fileOffset, bytesWritten))
            {
                if (!await IsPartialUpload())
                {
                    await EventHelper.NotifyFileComplete(Context);
                }
            }
        }
Exemple #3
0
        public async Task VerifyChecksumAsync_Data_Is_Truncated_If_Verification_Fails_Using_Single_Chunk()
        {
            // Checksum is for "hello world"
            const string incorrectChecksum = "Kq5sNclPz7QV2+lfQIuc6R7oRu0=";
            const string message           = "Hello World 12345!!@@åäö";

            var buffer = new UTF8Encoding(false).GetBytes(message);

            var cts = new CancellationTokenSource();

            var fileId = await _fixture.Store.CreateFileAsync(buffer.Length, null, cts.Token);

            var guardedStream = new ClientDisconnectGuardedReadOnlyStream(new MemoryStream(buffer), cts);
            await _fixture.Store.AppendDataAsync(fileId, guardedStream, guardedStream.CancellationToken);

            var checksumOk = await _fixture.Store.VerifyChecksumAsync(fileId, "sha1", Convert.FromBase64String(incorrectChecksum), cts.Token);

            // File should not have been saved.
            checksumOk.ShouldBeFalse();
            new FileInfo(Path.Combine(_fixture.Path, fileId)).Length.ShouldBe(0);
        }
Exemple #4
0
        public async Task VerifyChecksumAsync_Data_Is_Kept_If_Client_Disconnects_After_Complete_Chunk_Has_Been_Written_And_Checksum_Matches()
        {
            // Checksum is valid for "Hello " <-- note the last space
            const string checksum   = "lka6E6To6r7KT1JZv9faQdNooaY=";
            var          dataBuffer = new UTF8Encoding(false).GetBytes("Hello ");

            var fileId = await _fixture.Store.CreateFileAsync(6, null, CancellationToken.None);

            var cts = new CancellationTokenSource();

            var guardedStream = new ClientDisconnectGuardedReadOnlyStream(new MemoryStream(dataBuffer), cts);
            await _fixture.Store.AppendDataAsync(fileId, guardedStream, guardedStream.CancellationToken);

            // Emulate client disconnect after entire stream has been read
            cts.Cancel();

            var checksumOk = await _fixture.Store.VerifyChecksumAsync(fileId, "sha1", Convert.FromBase64String(checksum), cts.Token);

            checksumOk.ShouldBeTrue();

            new FileInfo(Path.Combine(_fixture.Path, fileId)).Length.ShouldBe(6);
        }
Exemple #5
0
        public async Task VerifyChecksumAsync_Data_Is_Truncated_If_Verification_Fails_Using_Multiple_Chunks()
        {
            var chunks = new[]
            {
                new Tuple <string, string, bool>("Hello ", "lka6E6To6r7KT1JZv9faQdNooaY=", true),
                new Tuple <string, string, bool> ("World ", "eh6F0TXbUPbEiz7TtUFJ7WzNb9Q=", true),
                new Tuple <string, string, bool> ("12345!!@@åäö", "eh6F0TXbUPbEiz7TtUFJ7WzNb9Q=", false)
            };

            var encoding  = new UTF8Encoding(false);
            var totalSize = 0;

            var fileId = await _fixture.Store.CreateFileAsync(chunks.Sum(f => encoding.GetBytes(f.Item1).Length), null, CancellationToken.None);

            var filePath = Path.Combine(_fixture.Path, fileId);

            foreach (var chunk in chunks)
            {
                var data            = chunk.Item1;
                var checksum        = chunk.Item2;
                var isValidChecksum = chunk.Item3;
                var dataBuffer      = encoding.GetBytes(data);

                // Create a new store and cancellation token source on each request as one would do in a real scenario.
                _fixture.CreateNewStore();
                var cts = new CancellationTokenSource();

                var guardedStream = new ClientDisconnectGuardedReadOnlyStream(new MemoryStream(dataBuffer), cts);
                await _fixture.Store.AppendDataAsync(fileId, guardedStream, guardedStream.CancellationToken);

                var checksumOk = await _fixture.Store.VerifyChecksumAsync(fileId, "sha1", Convert.FromBase64String(checksum), cts.Token);

                checksumOk.ShouldBe(isValidChecksum);

                totalSize += isValidChecksum ? dataBuffer.Length : 0;

                new FileInfo(filePath).Length.ShouldBe(totalSize);
            }
        }
Exemple #6
0
        public async Task VerifyChecksumAsync_Data_Is_Truncated_If_Verification_Fails_Using_Multiple_Chunks()
        {
            var chunks = new[]
            {
                new Tuple <string, string, bool>("Hello ", "lka6E6To6r7KT1JZv9faQdNooaY=", true),
                new Tuple <string, string, bool> ("World ", "eh6F0TXbUPbEiz7TtUFJ7WzNb9Q=", true),
                new Tuple <string, string, bool> ("12345!!@@åäö", "eh6F0TXbUPbEiz7TtUFJ7WzNb9Q=", false)
            };

            var encoding  = new UTF8Encoding(false);
            var totalSize = 0;

            var fileId = await _fixture.Store.CreateFileAsync(chunks.Sum(f => encoding.GetBytes(f.Item1).Length), null, CancellationToken.None);

            foreach (var chunk in chunks)
            {
                var data            = chunk.Item1;
                var checksum        = chunk.Item2;
                var isValidChecksum = chunk.Item3;
                var dataBuffer      = encoding.GetBytes(data);

                var bytesWritten = 0L;

                // Emulate several requests
                do
                {
                    // Create a new store and cancellation token source on each request as one would do in a real scenario.
                    _fixture.CreateNewStore();
                    var cts = new CancellationTokenSource();

                    var buffer = new RequestStreamFake(
                        (stream, bufferToFill, offset, count, ct) =>
                    {
                        // Emulate that the request completed
                        if (bytesWritten == dataBuffer.Length)
                        {
                            return(Task.FromResult(0));
                        }

                        // Emulate client disconnect after two bytes read.
                        if (stream.Position == 2)
                        {
                            cts.Cancel();
                            cts.Token.ThrowIfCancellationRequested();
                        }

                        bytesWritten += 2;
                        return(stream.ReadBackingStreamAsync(bufferToFill, offset, 2, ct));
                    },
                        dataBuffer.Skip((int)bytesWritten).ToArray());

                    var guardedStream = new ClientDisconnectGuardedReadOnlyStream(buffer, cts);
                    await _fixture.Store.AppendDataAsync(fileId, guardedStream, guardedStream.CancellationToken);
                } while (bytesWritten < dataBuffer.Length);

                var checksumOk = await _fixture.Store.VerifyChecksumAsync(fileId, "sha1",
                                                                          Convert.FromBase64String(checksum), CancellationToken.None);

                checksumOk.ShouldBe(isValidChecksum);

                totalSize += isValidChecksum ? dataBuffer.Length : 0;
            }

            var filePath = Path.Combine(_fixture.Path, fileId);

            new FileInfo(filePath).Length.ShouldBe(totalSize);
        }