Skip to content

Commit 616e113

Browse files
committed
Added MpuObjectSize and ChecksumValue parameters to Write-S3Object to support precalculated checkums for multipart uploads
1 parent f625b07 commit 616e113

File tree

2 files changed

+84
-1
lines changed

2 files changed

+84
-1
lines changed

modules/AWSPowerShell/Cmdlets/S3/Advanced/Write-S3Object-Cmdlet.cs

Lines changed: 70 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ namespace Amazon.PowerShell.Cmdlets.S3
4848
public class WriteS3ObjectCmdlet : AmazonS3ClientCmdlet, IExecutor
4949
{
5050
const string ParamSet_FromLocalFile = "UploadSingleFile";
51+
const string ParamSet_FromLocalFileChecksum = "UploadSingleFileChecksum";
5152
const string ParamSet_FromContent = "UploadFromContent";
5253
const string ParamSet_FromLocalFolder = "UploadFolder";
5354
const string ParamSet_FromStream = "UploadFromStream";
@@ -117,6 +118,7 @@ public class WriteS3ObjectCmdlet : AmazonS3ClientCmdlet, IExecutor
117118
/// and the object key can be inferred from the filename value supplied to the -File parameter.
118119
/// </summary>
119120
[Parameter(Position = 1, ParameterSetName = ParamSet_FromLocalFile, ValueFromPipelineByPropertyName = true)]
121+
[Parameter(Position = 1, ParameterSetName = ParamSet_FromLocalFileChecksum, ValueFromPipelineByPropertyName = true)]
120122
[Parameter(Position = 1, ParameterSetName = ParamSet_FromContent, Mandatory = true, ValueFromPipelineByPropertyName = true)]
121123
[Parameter(Position = 1, ParameterSetName = ParamSet_FromStream, Mandatory = true, ValueFromPipelineByPropertyName = true)]
122124
[Amazon.PowerShell.Common.AWSRequiredParameter(ParameterSets = new[] { ParamSet_FromContent, ParamSet_FromStream })]
@@ -128,6 +130,7 @@ public class WriteS3ObjectCmdlet : AmazonS3ClientCmdlet, IExecutor
128130
/// The full path to the local file to be uploaded.
129131
/// </summary>
130132
[Parameter(Position = 2, ParameterSetName = ParamSet_FromLocalFile, Mandatory = true, ValueFromPipelineByPropertyName = true)]
133+
[Parameter(Position = 2, ParameterSetName = ParamSet_FromLocalFileChecksum, Mandatory = true, ValueFromPipelineByPropertyName = true)]
131134
[Amazon.PowerShell.Common.AWSRequiredParameter]
132135
public System.String File { get; set; }
133136
#endregion
@@ -401,10 +404,36 @@ public class WriteS3ObjectCmdlet : AmazonS3ClientCmdlet, IExecutor
401404
[Parameter(ValueFromPipelineByPropertyName = true, ParameterSetName = ParamSet_FromLocalFile)]
402405
[Parameter(ValueFromPipelineByPropertyName = true, ParameterSetName = ParamSet_FromContent)]
403406
[Parameter(ValueFromPipelineByPropertyName = true, ParameterSetName = ParamSet_FromStream)]
407+
[Parameter(ValueFromPipelineByPropertyName = true, ParameterSetName = ParamSet_FromLocalFileChecksum, Mandatory = true)]
408+
[Amazon.PowerShell.Common.AWSRequiredParameter(ParameterSets = new[] { ParamSet_FromLocalFileChecksum })]
404409
[AWSConstantClassSource("Amazon.S3.ChecksumAlgorithm")]
405410
public ChecksumAlgorithm ChecksumAlgorithm { get; set; }
406411
#endregion
407412

413+
#region Parameter ChecksumValue
414+
/// <summary>
415+
/// The checksum of the object base64 encoded with the alorithm specified in the <code>ChecksumAlgorithm</code> parameter. This checksum is only present if the checksum was uploaded
416+
/// with the object. When you use an API operation on an object that was uploaded using multipart uploads, this value may not be a direct checksum value of the full object.
417+
/// Instead, it's a calculation based on the checksum values of each individual part. For more information about how checksums are calculated
418+
/// with multipart uploads, see <a href=\"https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity.html#large-object-checksums\">
419+
/// Checking object integrity</a> in the <i>Amazon S3 User Guide</i>."
420+
/// </summary>
421+
[Parameter(ValueFromPipelineByPropertyName = true, ParameterSetName = ParamSet_FromLocalFileChecksum)]
422+
public String ChecksumValue { get; set; }
423+
#endregion
424+
425+
#region Parameter MpuObjectSize
426+
/// <summary>
427+
/// The expected total object size of the multipart upload request. If there's a mismatch
428+
/// between the specified object size value and the actual object size value, it results in an
429+
/// <code>HTTP 400 InvalidRequest</code> error. This value is ignored if the operation is not a
430+
/// multipart upload.
431+
/// </summary>
432+
[Parameter(ValueFromPipelineByPropertyName = true, ParameterSetName = ParamSet_FromLocalFile)]
433+
[Parameter(ValueFromPipelineByPropertyName = true, ParameterSetName = ParamSet_FromLocalFileChecksum)]
434+
public long? MpuObjectSize { get; set; }
435+
#endregion
436+
408437
#region Parameter RequestPayer
409438
/// <summary>
410439
/// <para>
@@ -498,7 +527,7 @@ protected override void ProcessRecord()
498527
base.UserAgentAddition = AmazonS3Helper.GetCleanKeyUserAgentAdditionString(this.Key, context.Key);
499528
}
500529

501-
if (this.ParameterSetName == ParamSet_FromLocalFile)
530+
if (this.ParameterSetName == ParamSet_FromLocalFile || this.ParameterSetName == ParamSet_FromLocalFileChecksum)
502531
{
503532
context.File = PSHelpers.PSPathToAbsolute(this.SessionState.Path, this.File.Trim());
504533
if (string.IsNullOrEmpty(context.Key))
@@ -576,6 +605,15 @@ protected override void ProcessRecord()
576605
context.ChecksumAlgorithm = this.ChecksumAlgorithm;
577606
}
578607

608+
if (!string.IsNullOrEmpty(this.ChecksumValue))
609+
context.ChecksumValue = this.ChecksumValue;
610+
611+
if (this.MpuObjectSize != null)
612+
{
613+
long mpuObjectSize = this.MpuObjectSize.Value;
614+
context.MpuObjectSize = mpuObjectSize;
615+
}
616+
579617
if (this.PartSize != null)
580618
{
581619
if (this.PartSize.FileSizeInBytes < MinPartSize || this.PartSize.FileSizeInBytes > MaxPartSize)
@@ -725,6 +763,35 @@ private CmdletOutput UploadFileToS3(ExecutorContext context)
725763
request.TagSet = new List<Tag>(cmdletContext.TagSet);
726764
if (cmdletContext.ChecksumAlgorithm != null)
727765
request.ChecksumAlgorithm = cmdletContext.ChecksumAlgorithm;
766+
767+
if (!string.IsNullOrEmpty(cmdletContext.ChecksumValue))
768+
{
769+
switch (cmdletContext.ChecksumAlgorithm.Value)
770+
{
771+
case "CRC32":
772+
request.ChecksumCRC32 = cmdletContext.ChecksumValue;
773+
break;
774+
case "CRC32C":
775+
request.ChecksumCRC32C = cmdletContext.ChecksumValue;
776+
break;
777+
case "CRC64NVME":
778+
request.ChecksumCRC64NVME = cmdletContext.ChecksumValue;
779+
break;
780+
case "SHA1":
781+
request.ChecksumSHA1 = cmdletContext.ChecksumValue;
782+
break;
783+
case "SHA256":
784+
request.ChecksumSHA256 = cmdletContext.ChecksumValue;
785+
break;
786+
}
787+
}
788+
789+
if (cmdletContext.MpuObjectSize != null)
790+
{
791+
long mpuObjectSize = cmdletContext.MpuObjectSize.Value;
792+
request.MpuObjectSize = mpuObjectSize;
793+
}
794+
728795
if (!string.IsNullOrEmpty(cmdletContext.IfNoneMatch))
729796
request.IfNoneMatch = cmdletContext.IfNoneMatch;
730797

@@ -878,6 +945,8 @@ internal class CmdletContext : ExecutorContext
878945
public string ServerSideEncryptionCustomerProvidedKeyMD5 { get; set; }
879946

880947
public ChecksumAlgorithm ChecksumAlgorithm { get; set; }
948+
public String ChecksumValue { get; set; }
949+
public long? MpuObjectSize { get; set; }
881950

882951
public Hashtable Metadata { get; set; }
883952
public Hashtable Headers { get; set; }

tests/S3/S3.Tests.ps1

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,10 +184,12 @@ Describe -Tag "Smoke" "S3" {
184184
BeforeAll {
185185
$script:bucketName = "pstest-" + [DateTime]::Now.ToFileTime()
186186
New-S3Bucket -BucketName $script:bucketName
187+
$testFilePath = Join-Path -Path (Split-Path -Path (Get-Location)) -ChildPath 'foo.txt'
187188
}
188189

189190
AfterAll {
190191
$script:bucketName | Remove-S3Bucket -Force -DeleteBucketContent
192+
Remove-Item $testFilePath -ErrorAction 'SilentlyContinue'
191193
}
192194

193195
It "Put and get an object with a SHA1 checksum" {
@@ -222,5 +224,17 @@ Describe -Tag "Smoke" "S3" {
222224
{ Read-S3Object -BucketName $script:bucketName -Key "key1" -File "temp\key1.txt" } | Should -Throw
223225
{ Read-S3Object -BucketName $script:bucketName -Key "key2" -File "temp\key2.txt" } | Should -Throw
224226
}
227+
228+
It "Can write objects with a precalcuated checksum value" {
229+
Set-Content -Path $testFilePath -Value "Hello world!"
230+
$checksumValue = 'vjV9Yg=='
231+
Write-S3Object -BucketName $script:bucketName -Key foo.txt -File $testFilePath -ChecksumAlgorithm CRC32C -ChecksumValue $checksumValue
232+
}
233+
234+
It "Throws when writing objects with an invalid checksum value" {
235+
Set-Content -Path $testFilePath -Value "Hello world!"
236+
$checksumValue = 'abc123'
237+
{Write-S3Object -BucketName $script:bucketName -Key foo.txt -File $testFilePath -ChecksumAlgorithm CRC32C -ChecksumValue $checksumValue} | Should -Throw '* is invalid.'
238+
}
225239
}
226240
}

0 commit comments

Comments
 (0)