Skip to content

Commit b81ba7d

Browse files
Encode non UTF-8 characters only once
1 parent cf6f413 commit b81ba7d

File tree

2 files changed

+55
-11
lines changed

2 files changed

+55
-11
lines changed

common/src/main/java/com/genexus/CommonUtil.java

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import java.math.BigDecimal;
1010
import java.io.*;
1111
import java.net.URLEncoder;
12+
import java.nio.charset.StandardCharsets;
1213
import java.text.*;
1314
import java.util.*;
1415

@@ -3490,4 +3491,34 @@ public static String Sanitize(String input, HashMap<Character, Character> whiteL
34903491
}
34913492
return sanitizedInput.toString();
34923493
}
3494+
3495+
public static String encodeUtf8Once(String input) {
3496+
StringBuilder sb = new StringBuilder();
3497+
for (int i = 0; i < input.length(); i++) {
3498+
char c = input.charAt(i);
3499+
if (c == '%' && i + 2 < input.length() &&
3500+
(((input.charAt(i+1) >= '0' && input.charAt(i+1) <= '9') ||
3501+
(input.charAt(i+1) >= 'A' && input.charAt(i+1) <= 'F') ||
3502+
(input.charAt(i+1) >= 'a' && input.charAt(i+1) <= 'f')) &&
3503+
((input.charAt(i+2) >= '0' && input.charAt(i+2) <= '9') ||
3504+
(input.charAt(i+2) >= 'A' && input.charAt(i+2) <= 'F') ||
3505+
(input.charAt(i+2) >= 'a' && input.charAt(i+2) <= 'f')))) {
3506+
sb.append('%').append(input.charAt(i+1)).append(input.charAt(i+2));
3507+
i += 2;
3508+
}
3509+
else if ((c >= 'A' && c <= 'Z') ||
3510+
(c >= 'a' && c <= 'z') ||
3511+
(c >= '0' && c <= '9') ||
3512+
c == '-' || c == '_' || c == '.' || c == '~') {
3513+
sb.append(c);
3514+
}
3515+
else {
3516+
byte[] bytes = String.valueOf(c).getBytes(StandardCharsets.UTF_8);
3517+
for (byte b : bytes) {
3518+
sb.append(String.format("%%%02X", b));
3519+
}
3520+
}
3521+
}
3522+
return sb.toString();
3523+
}
34933524
}

gxcloudstorage-awss3-v2/src/main/java/com/genexus/db/driver/ExternalProviderS3V2.java

Lines changed: 24 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.genexus.db.driver;
22

3+
import com.genexus.CommonUtil;
34
import software.amazon.awssdk.auth.credentials.*;
45
import software.amazon.awssdk.core.ResponseBytes;
56
import software.amazon.awssdk.core.ResponseInputStream;
@@ -25,7 +26,6 @@
2526

2627
import java.io.*;
2728
import java.net.URI;
28-
import java.net.URL;
2929
import java.net.URLEncoder;
3030
import java.nio.ByteBuffer;
3131
import java.nio.charset.StandardCharsets;
@@ -251,13 +251,26 @@ public String upload(String externalFileName, InputStream input, ResourceAccessC
251251
public String get(String externalFileName, ResourceAccessControlList acl, int expirationMinutes) {
252252
// Send a request to AWS S3 to retrieve the metadata for the specified object to see if
253253
// the object exists and is accessible under the provided credentials and permissions.
254-
HeadObjectRequest headObjectRequest = HeadObjectRequest.builder()
255-
.bucket(bucket)
256-
.key(externalFileName)
257-
.build();
258-
client.headObject(headObjectRequest);
259-
260-
return getResourceUrl(externalFileName, acl, expirationMinutes);
254+
try {
255+
HeadObjectRequest headObjectRequest = HeadObjectRequest.builder()
256+
.bucket(bucket)
257+
.key(externalFileName)
258+
.build();
259+
client.headObject(headObjectRequest);
260+
return getResourceUrl(externalFileName, acl, expirationMinutes);
261+
} catch (Exception e) {
262+
int lastIndex = Math.max(externalFileName.lastIndexOf('/'), externalFileName.lastIndexOf('\\'));
263+
String path = lastIndex >= 0 ? externalFileName.substring(0, lastIndex + 1) : "";
264+
String fileName = lastIndex >= 0 ? externalFileName.substring(lastIndex + 1) : externalFileName;
265+
String encodedFileName = CommonUtil.encodeUtf8Once(fileName);
266+
String encodedExternalFileName = path + encodedFileName;
267+
HeadObjectRequest headObjectRequest = HeadObjectRequest.builder()
268+
.bucket(bucket)
269+
.key(encodedExternalFileName)
270+
.build();
271+
client.headObject(headObjectRequest);
272+
return getResourceUrl(encodedExternalFileName, acl, expirationMinutes);
273+
}
261274
}
262275

263276
private String getResourceUrl(String externalFileName, ResourceAccessControlList acl, int expirationMinutes) {
@@ -645,7 +658,7 @@ private String getResourceUrlWithACL(String externalFileName, ResourceAccessCont
645658
int lastIndex = Math.max(externalFileName.lastIndexOf('/'), externalFileName.lastIndexOf('\\'));
646659
String path = externalFileName.substring(0, lastIndex + 1);
647660
String fileName = externalFileName.substring(lastIndex + 1);
648-
String encodedFileName = URLEncoder.encode(fileName, StandardCharsets.UTF_8.toString());
661+
String encodedFileName = CommonUtil.encodeUtf8Once(fileName);
649662

650663
String url = String.format(
651664
"https://%s.s3.%s.amazonaws.com/%s%s",
@@ -656,8 +669,8 @@ private String getResourceUrlWithACL(String externalFileName, ResourceAccessCont
656669
);
657670

658671
return url;
659-
} catch (UnsupportedEncodingException uee) {
660-
logger.error("Failed to encode resource URL for " + externalFileName, uee);
672+
} catch (Exception e) {
673+
logger.error("Failed to encode resource URL for " + externalFileName, e);
661674
return "";
662675
}
663676
}

0 commit comments

Comments
 (0)