@@ -304,7 +304,7 @@ private void addPreSignInformationToRequest(SdkHttpFullRequest.Builder mutableRe
304
304
mutableRequest .putRawQueryParameter (SignerConstant .X_AMZ_CREDENTIAL , signingCredentials );
305
305
}
306
306
307
- private Map <String , List <String >> canonicalizeSigningHeaders (Map <String , List <String >> headers ) {
307
+ static Map <String , List <String >> canonicalizeSigningHeaders (Map <String , List <String >> headers ) {
308
308
Map <String , List <String >> result = new TreeMap <>();
309
309
310
310
for (Map .Entry <String , List <String >> header : headers .entrySet ()) {
@@ -319,48 +319,73 @@ private Map<String, List<String>> canonicalizeSigningHeaders(Map<String, List<St
319
319
return result ;
320
320
}
321
321
322
- private String getCanonicalizedHeaderString (Map <String , List <String >> canonicalizedHeaders ) {
322
+ /**
323
+ * Step 4 of the AWS Signature version 4 calculation.
324
+ * Refer to
325
+ * https://docs.aws.amazon.com/general/latest/gr/sigv4-create-canonical-request.html
326
+ */
327
+ static String getCanonicalizedHeaderString (Map <String , List <String >> canonicalizedHeaders ) {
323
328
StringBuilder buffer = new StringBuilder ();
324
329
325
330
canonicalizedHeaders .forEach ((headerName , headerValues ) -> {
326
- for ( String headerValue : headerValues ) {
331
+ if ( headerValues . size () > 0 ) {
327
332
appendCompactedString (buffer , headerName );
328
- buffer .append (":" );
329
- if (headerValue != null ) {
330
- appendCompactedString (buffer , headerValue );
333
+ buffer .append (':' );
334
+ boolean headerValueAppended = false ;
335
+ // Append a comma-separated list of values for that header.
336
+ // Do not sort the values in headers that have multiple values.
337
+ for (int i = 0 ; i < headerValues .size (); i ++) {
338
+ String headerValue = headerValues .get (i );
339
+ if (headerValue != null ) {
340
+ if (headerValueAppended ) {
341
+ buffer .append (',' );
342
+ }
343
+ appendCompactedString (buffer , headerValue );
344
+ headerValueAppended = true ;
345
+ }
331
346
}
332
- buffer .append ("\n " );
347
+
348
+ buffer .append ('\n' );
333
349
}
334
350
});
335
351
336
352
return buffer .toString ();
337
353
}
338
354
339
355
/**
340
- * This method appends a string to a string builder and collapses contiguous
341
- * white space is a single space.
356
+ * This method appends a modified version of the source string to the destination string builder.
357
+ * The source string's leading and trailing whitespace is removed and
358
+ * and all contiguous white space not at the beginning or end is collapsed into a single space.
359
+ *
360
+ * e.g.,
361
+ * Given a source String of " a b c ",
362
+ * "a b c" is appended to the destination StringBuilder.
342
363
*
343
364
* This is equivalent to:
344
- * destination.append(source.replaceAll("\\s+", " "))
365
+ * <code>
366
+ * destination.append(source.replaceAll("(^\\s*|\\s*$)", "").replaceAll("\\s+", " "))
367
+ * </code>
345
368
* but does not create a Pattern object that needs to compile the match
346
369
* string; it also prevents us from having to make a Matcher object as well.
347
- *
348
370
*/
349
- private void appendCompactedString (final StringBuilder destination , final String source ) {
371
+ static void appendCompactedString (final StringBuilder destination , final String source ) {
372
+ boolean appendedNonWhitespaceChar = false ;
350
373
boolean previousIsWhiteSpace = false ;
351
374
int length = source .length ();
352
375
353
376
for (int i = 0 ; i < length ; i ++) {
354
377
char ch = source .charAt (i );
355
378
if (isWhiteSpace (ch )) {
356
- if (previousIsWhiteSpace ) {
357
- continue ;
379
+ if (appendedNonWhitespaceChar ) {
380
+ previousIsWhiteSpace = true ;
358
381
}
359
- destination .append (' ' );
360
- previousIsWhiteSpace = true ;
361
382
} else {
383
+ if (previousIsWhiteSpace ) {
384
+ destination .append (' ' );
385
+ previousIsWhiteSpace = false ;
386
+ }
362
387
destination .append (ch );
363
- previousIsWhiteSpace = false ;
388
+ appendedNonWhitespaceChar = true ;
364
389
}
365
390
}
366
391
}
@@ -373,7 +398,7 @@ private void appendCompactedString(final StringBuilder destination, final String
373
398
* @param ch the character to be tested
374
399
* @return true if the character is white space, false otherwise.
375
400
*/
376
- private boolean isWhiteSpace (final char ch ) {
401
+ private static boolean isWhiteSpace (final char ch ) {
377
402
return ch == ' ' || ch == '\t' || ch == '\n' || ch == '\u000b' || ch == '\r' || ch == '\f' ;
378
403
}
379
404
0 commit comments