/* * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"). * You may not use this file except in compliance with the License. * A copy of the License is located at * * http://aws.amazon.com/apache2.0 * * or in the "license" file accompanying this file. This file is distributed * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either * express or implied. See the License for the specific language governing * permissions and limitations under the License. */ using Amazon.Runtime; using Amazon.Runtime.Internal.Auth; using Amazon.Runtime.Internal.Util; using Microsoft.VisualStudio.TestTools.UnitTesting; using System; using System.Collections.Generic; using System.IO; using System.Text; namespace AWSSDK.UnitTests { /// /// Tests for the SigV4 chunked stream wrapper /// [TestClass] public class ChunkedUploadWrapperStreamTests { private static DateTime _fixedSigningTimestamp = new DateTime(2015, 8, 30, 12, 36, 0, DateTimeKind.Utc); private static string _accessKey = "accesskey"; private static byte[] _signingKey = new byte[32]; private static byte[] _headerSignature = new byte[64]; private const string expectedSHA1Content = "B;chunk-signature=6a4d50a3307c001ad83900a73442136a0a0f203520fd8c0e966f655cc830bbe8\r\n" + "Hello world\r\n" + "0;chunk-signature=9384094dc67fd7c29a4c7e0aa3866233b3774e41d1470b8f51a96becbd91f60c\r\n" + "x-amz-checksum-sha1:e1AsOh9IyGCa4hLN+2Od7jlnP14=\r\n" + "x-amz-trailer-signature:5e9fae6e80d8cb558e2c43d228a8c36d6b36b5f6f8b86fb8f6596111f3f229a1\r\n" + "\r\n"; private const string expectedSHA256Content = "B;chunk-signature=6a4d50a3307c001ad83900a73442136a0a0f203520fd8c0e966f655cc830bbe8\r\n" + "Hello world\r\n" + "0;chunk-signature=9384094dc67fd7c29a4c7e0aa3866233b3774e41d1470b8f51a96becbd91f60c\r\n" + "x-amz-checksum-sha256:ZOyIygCyaOW6GjVnihtTFtIS9PNmskdyMlNKiuyjfzw=\r\n" + "x-amz-trailer-signature:e80653c66f820ac440e6a520b0953d44605b2c9a81d9e8d98f50012b00bad6c6\r\n" + "\r\n"; private const string expectedCRC32Content = "B;chunk-signature=6a4d50a3307c001ad83900a73442136a0a0f203520fd8c0e966f655cc830bbe8\r\n" + "Hello world\r\n" + "0;chunk-signature=9384094dc67fd7c29a4c7e0aa3866233b3774e41d1470b8f51a96becbd91f60c\r\n" + "x-amz-checksum-crc32:i9aeUg==\r\n" + "x-amz-trailer-signature:c236bc8c064531085d756c476de022427a9604260ea6f3687bdaab9d6b5f3b9b\r\n" + "\r\n"; private const string expectedCRC32CContent = "B;chunk-signature=6a4d50a3307c001ad83900a73442136a0a0f203520fd8c0e966f655cc830bbe8\r\n" + "Hello world\r\n" + "0;chunk-signature=9384094dc67fd7c29a4c7e0aa3866233b3774e41d1470b8f51a96becbd91f60c\r\n" + "x-amz-checksum-crc32c:crUfeA==\r\n" + "x-amz-trailer-signature:ad2c42bee2f802836062a35974f2145e8fa97ae75ac6170c70ac367c8bcaff87\r\n" + "\r\n"; /// /// Tests a given trailing checksum for a signed, chunked stream /// [DataTestMethod] [DataRow("x-amz-checksum-sha1", CoreChecksumAlgorithm.SHA1, expectedSHA1Content)] [DataRow("x-amz-checksum-sha256", CoreChecksumAlgorithm.SHA256, expectedSHA256Content)] [DataRow("x-amz-checksum-crc32", CoreChecksumAlgorithm.CRC32, expectedCRC32Content)] [DataRow("x-amz-checksum-crc32c", CoreChecksumAlgorithm.CRC32C, expectedCRC32CContent)] public void TestTrailingChecksum(string checksumKey, CoreChecksumAlgorithm algorithm, string expectedContent) { var contentStream = new MemoryStream(Encoding.Default.GetBytes("Hello world")); var trailingHeaders = new Dictionary { {checksumKey, "" } // checksum will be calculated as the stream is read then replaced at the end }; var headerSigningResult = new AWS4SigningResult(_accessKey, _fixedSigningTimestamp, "", "", _signingKey, _headerSignature); var wrappedStream = new ChunkedUploadWrapperStream(contentStream, 8192 , headerSigningResult, algorithm, trailingHeaders); var actualContent = new StreamReader(wrappedStream).ReadToEnd(); Assert.AreEqual(expectedContent.Length, wrappedStream.Length); Assert.AreEqual(expectedContent, actualContent); } /// /// Read the stream with a small buffer, to test the index state between reads /// [TestMethod] public void SmallBuffer() { var contentStream = new MemoryStream(Encoding.Default.GetBytes("Hello world")); var trailingHeaders = new Dictionary { {"x-amz-checksum-sha256", "" } // checksum will be calculated as the stream is read then replaced at the end }; var headerSigningResult = new AWS4SigningResult(_accessKey, _fixedSigningTimestamp, "", "", _signingKey, _headerSignature); var wrappedStream = new ChunkedUploadWrapperStream(contentStream, 1, headerSigningResult, CoreChecksumAlgorithm.SHA256, trailingHeaders); var bytesRead = -1; var bufferSize = 1; var buffer = new byte[bufferSize]; var outputAsString = ""; while (bytesRead != 0) { bytesRead = wrappedStream.Read(buffer, 0, bufferSize); outputAsString += Encoding.Default.GetString(buffer, 0, bytesRead); } Assert.AreEqual(expectedSHA256Content.Length, wrappedStream.Length); Assert.AreEqual(expectedSHA256Content, outputAsString); } /// /// Test reading the stream with a larger underlying stream /// (which requires multiple chunks) /// [TestMethod] public void LargeData() { var data = new string('a', 100000); var contentStream = new MemoryStream(Encoding.Default.GetBytes(data)); var trailingHeaders = new Dictionary { {"x-amz-checksum-sha256", "" } // checksum will be calculated as the stream is read then replaced at the end }; var headerSigningResult = new AWS4SigningResult(_accessKey, _fixedSigningTimestamp, "", "", _signingKey, _headerSignature); var wrappedStream = new ChunkedUploadWrapperStream(contentStream, 8192, headerSigningResult, CoreChecksumAlgorithm.SHA256, trailingHeaders); var actualContent = new StreamReader(wrappedStream).ReadToEnd(); var expectedContent = "14000;chunk-signature=dd6818ebe851d9f6006431fac25c71960881bf8d86501344f19a43c1a2c2a9a7\r\n" + $"{new string('a', 81920)}\r\n" + "46A0;chunk-signature=88f059571f2bc312c8fd7ebd2082f587561ca83a6d5bb863e6e3d4ef78819256\r\n" + $"{new string('a', 18080)}\r\n" + "0;chunk-signature=07857eed4f1a53ae7d042e0c410053d610ed947827ca1c5572ed401666732805\r\n" + "x-amz-checksum-sha256:bRzyLXzAmwhd/CXuGh864CZYBMYHvCB0rSU7zIL9ge4=\r\n" + "x-amz-trailer-signature:cd8a0ba8bc4abaaa5f6e9921c30ca6e018110bcbaa3ea876e7b777b924bb4009\r\n" + "\r\n"; Assert.AreEqual(expectedContent.Length, wrappedStream.Length); Assert.AreEqual(expectedContent, actualContent); } /// /// Tests wrapping a stream with trailing headers that are not a checksum /// [TestMethod] public void NonChecksumTrailingHeaders() { var contentStream = new MemoryStream(Encoding.Default.GetBytes("Hello world")); var trailingHeaders = new Dictionary { {"header-a", "value-a" }, {"header-b", "value-b" } }; var headerSigningResult = new AWS4SigningResult(_accessKey, _fixedSigningTimestamp, "", "", _signingKey, _headerSignature); var wrappedStream = new ChunkedUploadWrapperStream(contentStream, 8192, headerSigningResult, CoreChecksumAlgorithm.NONE, trailingHeaders); var actualContent = new StreamReader(wrappedStream).ReadToEnd(); var expectedContent = "B;chunk-signature=6a4d50a3307c001ad83900a73442136a0a0f203520fd8c0e966f655cc830bbe8\r\n" + "Hello world\r\n" + "0;chunk-signature=9384094dc67fd7c29a4c7e0aa3866233b3774e41d1470b8f51a96becbd91f60c\r\n" + "header-a:value-a\r\n" + "header-b:value-b\r\n" + "x-amz-trailer-signature:ff2899b910cb941057f921d11738b5d875f2e117ea9504cfea4f9c7a788a0852\r\n" + "\r\n"; Assert.AreEqual(expectedContent.Length, wrappedStream.Length); Assert.AreEqual(expectedContent, actualContent); } /// /// Tests wrapping a stream with multiple trailing headers, /// one set up front and one checksum that is calculated while /// reading the stream. /// [TestMethod] public void ChecksumAndOtherTrailingHeaders() { var contentStream = new MemoryStream(Encoding.Default.GetBytes("Hello world")); var trailingHeaders = new Dictionary { {"header-a", "value-a" }, {"header-b", "value-b" }, {"x-amz-checksum-sha256", "" } // checksum will be calculated as the stream is read then replaced at the end }; var headerSigningResult = new AWS4SigningResult(_accessKey, _fixedSigningTimestamp, "", "", _signingKey, _headerSignature); var wrappedStream = new ChunkedUploadWrapperStream(contentStream, 8192, headerSigningResult, CoreChecksumAlgorithm.SHA256, trailingHeaders); var actualContent = new StreamReader(wrappedStream).ReadToEnd(); var expectedContent = "B;chunk-signature=6a4d50a3307c001ad83900a73442136a0a0f203520fd8c0e966f655cc830bbe8\r\n" + "Hello world\r\n" + "0;chunk-signature=9384094dc67fd7c29a4c7e0aa3866233b3774e41d1470b8f51a96becbd91f60c\r\n" + "header-a:value-a\r\n" + "header-b:value-b\r\n" + "x-amz-checksum-sha256:ZOyIygCyaOW6GjVnihtTFtIS9PNmskdyMlNKiuyjfzw=\r\n" + "x-amz-trailer-signature:0e357651fe17d33ea0d4173b2fd745d596354a66347ee8b5e4de44036c62becb\r\n" + "\r\n"; Assert.AreEqual(expectedContent.Length, wrappedStream.Length); Assert.AreEqual(expectedContent, actualContent); } } }