Skip to content

Commit 5d5d330

Browse files
fix(bigquerystorage): pick the base64 alphabet up front instead of by fallback
Falling back through a caught IllegalArgumentException put an exception on the happy path for every record when a producer uses the URL-safe alphabet. A value containing - or _ is never valid standard base64, so the alphabet can be chosen before decoding. The original exception is now kept as the cause.
1 parent c4c78b9 commit 5d5d330

2 files changed

Lines changed: 13 additions & 19 deletions

File tree

‎java-bigquerystorage/google-cloud-bigquerystorage/src/main/java/com/google/cloud/bigquery/storage/v1/JsonToProtoMessage.java‎

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1120,25 +1120,23 @@ private static void throwWrongFieldType(
11201120
}
11211121

11221122
/**
1123-
* Decodes a base64 string into bytes, the encoding protobuf's canonical JSON mapping defines for
1124-
* the {@code bytes} type. Standard and URL-safe alphabets are both accepted, with or without
1125-
* padding, as that mapping requires; the two alphabets are mutually exclusive on {@code +/}
1126-
* versus {@code -_}, so the fallback is what makes both work.
1123+
* Decodes a base64 string, the encoding protobuf's canonical JSON mapping defines for {@code
1124+
* bytes}. Both the standard and URL-safe alphabets are accepted, with or without padding.
11271125
*
1128-
* @throws IllegalArgumentException if the value decodes under neither alphabet
1126+
* @throws IllegalArgumentException if the value is not valid base64
11291127
*/
11301128
private static byte[] parseBase64(String currentScope, String value) {
11311129
try {
1132-
return Base64.getDecoder().decode(value);
1133-
} catch (IllegalArgumentException standardAlphabetFailed) {
1134-
try {
1130+
if (value.indexOf('-') >= 0 || value.indexOf('_') >= 0) {
11351131
return Base64.getUrlDecoder().decode(value);
1136-
} catch (IllegalArgumentException urlSafeAlphabetFailed) {
1137-
throw new IllegalArgumentException(
1138-
"Error: "
1139-
+ currentScope
1140-
+ " could not be converted to byte[]: not a valid base64 string.");
11411132
}
1133+
return Base64.getDecoder().decode(value);
1134+
} catch (IllegalArgumentException e) {
1135+
throw new IllegalArgumentException(
1136+
"Error: "
1137+
+ currentScope
1138+
+ " could not be converted to byte[]: not a valid base64 string.",
1139+
e);
11421140
}
11431141
}
11441142

‎java-bigquerystorage/google-cloud-bigquerystorage/src/test/java/com/google/cloud/bigquery/storage/v1/JsonToProtoMessageTest.java‎

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1123,8 +1123,6 @@ void testBytesFromBase64() throws Exception {
11231123
TableSchema tableSchema = bytesTableSchema("test_field_type", TableFieldSchema.Mode.NULLABLE);
11241124
BytesType expectedProto =
11251125
BytesType.newBuilder().setTestFieldType(ByteString.copyFromUtf8("hi")).build();
1126-
// Base64 for "hi". Padding is optional in protobuf's canonical JSON mapping, and "hi" encodes
1127-
// to characters the standard and URL-safe alphabets share.
11281126
for (String encoded : ImmutableList.of("aGk=", "aGk")) {
11291127
JSONObject json = new JSONObject();
11301128
json.put("test_field_type", encoded);
@@ -1140,8 +1138,7 @@ void testBytesFromBase64EitherAlphabet() throws Exception {
11401138
TableSchema tableSchema = bytesTableSchema("test_field_type", TableFieldSchema.Mode.NULLABLE);
11411139
BytesType expectedProto =
11421140
BytesType.newBuilder().setTestFieldType(ByteString.copyFrom(new byte[] {-5, -1})).build();
1143-
// 0xFB 0xFF is "+/8" in the standard alphabet and "-_8" in the URL-safe one — the only place
1144-
// the two differ. Protobuf's mapping accepts both, with or without padding.
1141+
// 0xFB 0xFF is "+/8" in the standard alphabet and "-_8" in the URL-safe one.
11451142
for (String encoded : ImmutableList.of("+/8=", "-_8=", "+/8", "-_8")) {
11461143
JSONObject json = new JSONObject();
11471144
json.put("test_field_type", encoded);
@@ -1185,8 +1182,7 @@ void testBytesFromInvalidBase64() throws Exception {
11851182

11861183
@Test
11871184
void testBytesFromBase64NeedsTableSchema() throws Exception {
1188-
// Without a TableSchema the converter cannot tell BYTES from NUMERIC and BIGNUMERIC, which
1189-
// share the same proto type, so a string stays an error rather than being decoded.
1185+
// Without a TableSchema, BYTES is indistinguishable from NUMERIC and BIGNUMERIC.
11901186
JSONObject json = new JSONObject();
11911187
json.put("test_field_type", "aGk=");
11921188
IllegalArgumentException e =

0 commit comments

Comments
 (0)