Skip to content

Commit ed61e17

Browse files
authored
Fix bug in V4 where copy object wasn't working for some special characters (#3710)
Fix copy object to work for all special characters
1 parent 7373cac commit ed61e17

File tree

7 files changed

+47
-24
lines changed

7 files changed

+47
-24
lines changed
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"services": [
3+
{
4+
"serviceName": "S3",
5+
"type": "patch",
6+
"changeLogMessages": [
7+
"Fix: Fix a bug where copy object wasn't working with some special characters."
8+
]
9+
}
10+
]
11+
}

sdk/src/Services/S3/Custom/AmazonS3Client.Extensions.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -389,7 +389,7 @@ private static SigningResult ReturnSigningResult(SignatureVersion signatureVersi
389389
Amazon.S3.Internal.S3Signer.SignRequest(iRequest, metrics, immutableCredentials.AccessKey, immutableCredentials.SecretKey);
390390
signingResult.Authorization = iRequest.Headers[HeaderKeys.AuthorizationHeader];
391391
signingResult.Authorization = signingResult.Authorization.Substring(signingResult.Authorization.IndexOf(":", StringComparison.Ordinal) + 1);
392-
signingResult.Authorization = "&Signature=" + AmazonS3Util.UrlEncode(signingResult.Authorization, false);
392+
signingResult.Authorization = "&Signature=" + AWSSDKUtils.UrlEncode(signingResult.Authorization, false);
393393
signingResult.Result = ComposeUrl(iRequest).AbsoluteUri + signingResult.Authorization;
394394
break;
395395
}

sdk/src/Services/S3/Custom/Model/Internal/MarshallTransformations/CopyObjectRequestMarshaller.cs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -164,15 +164,16 @@ static string ConstructCopySourceHeaderValue(string bucket, string key, string v
164164
{
165165
var isAccessPoint = S3ArnUtils.IsS3AccessPointsArn(bucket) || S3ArnUtils.IsS3OutpostsArn(bucket);
166166
// 'object/' needed appended to key for copy header with access points
167-
source = AmazonS3Util.UrlEncode(String.Concat(bucket, isAccessPoint ? "/object/" : "/", key), !isAccessPoint);
167+
168+
source = AWSSDKUtils.UrlEncode(String.Concat(bucket, isAccessPoint ? "/object/" : "/", key), false);
168169
if (!String.IsNullOrEmpty(version))
169170
{
170-
source = string.Format(CultureInfo.InvariantCulture, "{0}?versionId={1}", source, AmazonS3Util.UrlEncode(version, true));
171+
source = string.Format(CultureInfo.InvariantCulture, "{0}?versionId={1}", source, AWSSDKUtils.UrlEncode(version, true));
171172
}
172173
}
173174
else
174175
{
175-
source = AmazonS3Util.UrlEncode(bucket, true);
176+
source = AWSSDKUtils.UrlEncode(bucket, true);
176177
}
177178

178179
return source;

sdk/src/Services/S3/Custom/Model/Internal/MarshallTransformations/CopyPartRequestMarshaller.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -120,15 +120,15 @@ static string ConstructCopySourceHeaderValue(string bucket, string key, string v
120120
{
121121
var isAccessPoint = S3ArnUtils.IsS3AccessPointsArn(bucket) || S3ArnUtils.IsS3OutpostsArn(bucket);
122122
// 'object/' needed appended to key for copy header with access points
123-
source = AmazonS3Util.UrlEncode(String.Concat(bucket, isAccessPoint ? "/object/" : "/", key), !isAccessPoint);
123+
source = AWSSDKUtils.UrlEncode(String.Concat(bucket, isAccessPoint ? "/object/" : "/", key), false);
124124
if (!String.IsNullOrEmpty(version))
125125
{
126-
source = string.Format(CultureInfo.InvariantCulture, "{0}?versionId={1}", source, AmazonS3Util.UrlEncode(version, true));
126+
source = string.Format(CultureInfo.InvariantCulture, "{0}?versionId={1}", source, AWSSDKUtils.UrlEncode(version, true));
127127
}
128128
}
129129
else
130130
{
131-
source = AmazonS3Util.UrlEncode(bucket, true);
131+
source = AWSSDKUtils.UrlEncode(bucket, true);
132132
}
133133

134134
return source;

sdk/src/Services/S3/Custom/Model/Internal/MarshallTransformations/S3Transforms.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ internal static string ToURLEncodedValue(string value, bool path)
3535
if (value == null)
3636
return string.Empty;
3737

38-
return AmazonS3Util.UrlEncode(value, path);
38+
return AWSSDKUtils.UrlEncode(value, path);
3939
}
4040

4141
internal static string ToURLEncodedValue(int value, bool path)

sdk/src/Services/S3/Custom/Util/AmazonS3Util.cs

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -241,17 +241,6 @@ public static string MimeTypeFromExtension(string ext)
241241
}
242242
}
243243

244-
/// <summary>
245-
/// URL encodes a string. If the path property is specified,
246-
/// the accepted path characters {/+:} are not encoded.
247-
/// </summary>
248-
/// <param name="data">The string to encode</param>
249-
/// <param name="path">Whether the string is a URL path or not</param>
250-
/// <returns></returns>
251-
public static string UrlEncode(string data, bool path)
252-
{
253-
return AWSSDKUtils.UrlEncode(data, path);
254-
}
255244

256245
/// <summary>
257246
/// Converts a non-seekable stream into a System.IO.MemoryStream.

sdk/test/Services/S3/IntegrationTests/CopyObjectTests.cs

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -72,18 +72,40 @@ public void TestCleanup()
7272

7373
BaseClean();
7474
}
75-
76-
[TestMethod]
75+
[DataTestMethod]
76+
[DataRow(testKey, testKey)]
77+
[DataRow("ObjectWithAllSpecialCharacters/'()!*$+,;=&", "DestinationObjectWithAllSpecialCharacters/'()!*$+,;=&")]
7778
[TestCategory("S3")]
78-
public void TestCopyObject()
79+
public void TestCopyObject(string sourceKey, string destinationKey)
7980
{
81+
var putObjectResponse = usEastClient.PutObject(new PutObjectRequest
82+
{
83+
BucketName = eastBucketName,
84+
Key = sourceKey,
85+
ContentBody = testContent
86+
});
8087
var response = usEastClient.CopyObject(new CopyObjectRequest
8188
{
8289
SourceBucket = eastBucketName,
83-
SourceKey = testKey,
90+
SourceKey = sourceKey,
8491
DestinationBucket = westBucketName,
85-
DestinationKey = testKey
92+
DestinationKey = destinationKey
8693
});
94+
95+
Assert.AreEqual(HttpStatusCode.OK, response.HttpStatusCode);
96+
97+
var getObjectResponse = usWestClient.GetObject(new GetObjectRequest
98+
{
99+
BucketName = westBucketName,
100+
Key = destinationKey
101+
});
102+
103+
using (getObjectResponse.ResponseStream)
104+
using (var reader = new StreamReader(getObjectResponse.ResponseStream))
105+
{
106+
var actualText = reader.ReadToEnd();
107+
Assert.AreEqual(testContent, actualText);
108+
}
87109
}
88110

89111
[TestMethod]

0 commit comments

Comments
 (0)