@@ -1301,6 +1301,39 @@ public void testSignUrlWithOptions() throws NoSuchAlgorithmException, InvalidKey
13011301 URLDecoder .decode (signature , UTF_8 .name ()))));
13021302 }
13031303
1304+ @ Test
1305+ public void testSignUrlForBlobWithSpecialChars () throws NoSuchAlgorithmException , InvalidKeyException ,
1306+ SignatureException , UnsupportedEncodingException {
1307+ // List of chars under test were taken from https://en.wikipedia.org/wiki/Percent-encoding#Percent-encoding_reserved_characters
1308+ char [] specialChars = new char []{'!' ,'#' ,'$' ,'&' ,'\'' ,'(' ,')' ,'*' ,'+' ,',' ,':' ,';' ,'=' ,'?' ,'@' ,'[' ,']' };
1309+ EasyMock .replay (storageRpcMock );
1310+ ServiceAccountAuthCredentials authCredentials =
1311+ ServiceAccountAuthCredentials .createFor (ACCOUNT , privateKey );
1312+ storage = options .toBuilder ().authCredentials (authCredentials ).build ().service ();
1313+
1314+ for (char specialChar : specialChars ) {
1315+ String blobName = "/a" + specialChar + "b" ;
1316+ URL url = storage .signUrl (BlobInfo .builder (BUCKET_NAME1 , blobName ).build (), 14 , TimeUnit .DAYS );
1317+ String escapedBlobName = UrlEscapers .urlPathSegmentEscaper ().escape (blobName );
1318+ String stringUrl = url .toString ();
1319+ String expectedUrl = new StringBuilder ("https://storage.googleapis.com/" ).append (BUCKET_NAME1 )
1320+ .append (escapedBlobName ).append ("?GoogleAccessId=" ).append (ACCOUNT ).append ("&Expires=" )
1321+ .append (42L + 1209600 ).append ("&Signature=" ).toString ();
1322+ assertTrue (stringUrl .startsWith (expectedUrl ));
1323+ String signature = stringUrl .substring (expectedUrl .length ());
1324+
1325+ StringBuilder signedMessageBuilder = new StringBuilder ();
1326+ signedMessageBuilder .append (HttpMethod .GET ).append ("\n \n \n " ).append (42L + 1209600 ).append ("\n /" )
1327+ .append (BUCKET_NAME1 ).append (escapedBlobName );
1328+
1329+ Signature signer = Signature .getInstance ("SHA256withRSA" );
1330+ signer .initVerify (publicKey );
1331+ signer .update (signedMessageBuilder .toString ().getBytes (UTF_8 ));
1332+ assertTrue (signer .verify (BaseEncoding .base64 ().decode (
1333+ URLDecoder .decode (signature , UTF_8 .name ()))));
1334+ }
1335+ }
1336+
13041337 @ Test
13051338 public void testGetAllArray () {
13061339 BlobId blobId1 = BlobId .of (BUCKET_NAME1 , BLOB_NAME1 );
0 commit comments