Skip to content

Commit 7dbb869

Browse files
committed
added fix for crc32 checksuming
1 parent d686ce5 commit 7dbb869

File tree

1 file changed

+97
-68
lines changed

1 file changed

+97
-68
lines changed

google-cloud-storage/src/main/java/com/google/cloud/storage/MultipartUploadClientImpl.java

Lines changed: 97 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,15 @@
1616
package com.google.cloud.storage;
1717

1818
import static com.google.cloud.storage.MultipartUploadUtility.getRfc1123Date;
19-
import static com.google.cloud.storage.MultipartUploadUtility.readStream;
2019
import static com.google.cloud.storage.MultipartUploadUtility.signRequest;
2120

2221
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
22+
import com.google.api.client.http.ByteArrayContent;
23+
import com.google.api.client.http.GenericUrl;
24+
import com.google.api.client.http.HttpHeaders;
25+
import com.google.api.client.http.HttpRequest;
2326
import com.google.api.client.http.HttpRequestFactory;
27+
import com.google.api.client.http.HttpResponse;
2428
import com.google.cloud.storage.Retrying.Retrier;
2529
import com.google.cloud.storage.multipartupload.model.AbortMultipartUploadRequest;
2630
import com.google.cloud.storage.multipartupload.model.AbortMultipartUploadResponse;
@@ -33,12 +37,8 @@
3337
import com.google.common.hash.HashCode;
3438
import com.google.common.hash.Hashing;
3539
import java.io.IOException;
36-
import java.io.InputStream;
37-
import java.io.OutputStream;
3840
import java.io.UnsupportedEncodingException;
39-
import java.net.HttpURLConnection;
4041
import java.net.URI;
41-
import java.net.URL;
4242
import java.net.URLEncoder;
4343
import java.nio.ByteBuffer;
4444
import java.nio.charset.StandardCharsets;
@@ -52,8 +52,10 @@ public class MultipartUploadClientImpl extends MultipartUploadClient {
5252

5353
// --- End Configuration ---
5454
private static final String GCS_ENDPOINT = "https://storage.googleapis.com";
55+
private final HttpRequestFactory requestFactory;
5556

5657
public MultipartUploadClientImpl(URI uri, HttpRequestFactory requestFactory, Retrier retrier) {
58+
this.requestFactory = requestFactory;
5759
}
5860

5961
public CreateMultipartUploadResponse createMultipartUpload(CreateMultipartUploadRequest request)
@@ -64,68 +66,82 @@ public CreateMultipartUploadResponse createMultipartUpload(CreateMultipartUpload
6466
String uri = GCS_ENDPOINT + resourcePath + "?uploads";
6567
String date = getRfc1123Date();
6668
String contentType = "application/x-www-form-urlencoded";
69+
String canonicalizedHeaders =
70+
"x-goog-api-client:gl-java/11.0.27__OpenLogic-OpenJDK__OpenLogic-OpenJDK gccl/2.56.1-SNAPSHOT--protobuf-3.25.8 gax/2.70.0 protobuf/3.25.8\n"
71+
+ "x-goog-user-project:aipp-internal-testing\n";
72+
6773
// GCS Signature Rule #1: The '?uploads' query string IS included for the initiate request.
68-
String signature = signRequest("POST", "", contentType, date, resourcePath + "?uploads", GOOGLE_SECRET_KEY);
74+
String signature =
75+
signRequest(
76+
"POST", "", contentType, date, canonicalizedHeaders, resourcePath + "?uploads", GOOGLE_SECRET_KEY);
6977
String authHeader = "GOOG1 " + GOOGLE_ACCESS_KEY + ":" + signature;
7078

71-
HttpURLConnection connection = (HttpURLConnection) new URL(uri).openConnection();
72-
connection.setRequestMethod("POST");
73-
connection.setRequestProperty("Date", date);
74-
connection.setRequestProperty("Authorization", authHeader);
75-
connection.setRequestProperty("Content-Type", contentType);
76-
connection.setFixedLengthStreamingMode(0);
77-
connection.setDoOutput(true);
78-
79-
if (connection.getResponseCode() != 200) {
80-
String error = readStream(connection.getErrorStream());
81-
throw new RuntimeException("Failed to initiate upload: " + connection.getResponseCode() + " " + error);
79+
HttpRequest httpRequest =
80+
requestFactory.buildPostRequest(
81+
new GenericUrl(uri), new ByteArrayContent(contentType, new byte[0]));
82+
HttpHeaders headers = httpRequest.getHeaders();
83+
headers.setDate(date);
84+
headers.setAuthorization(authHeader);
85+
headers.setContentType(contentType);
86+
headers.set("x-goog-api-client", "gl-java/11.0.27__OpenLogic-OpenJDK__OpenLogic-OpenJDK gccl/2.56.1-SNAPSHOT--protobuf-3.25.8 gax/2.70.0 protobuf/3.25.8");
87+
headers.set("x-goog-user-project", "aipp-internal-testing");
88+
HttpResponse response = httpRequest.execute();
89+
90+
if (!response.isSuccessStatusCode()) {
91+
throw new RuntimeException(
92+
"Failed to initiate upload: "
93+
+ response.getStatusCode()
94+
+ " "
95+
+ response.getStatusMessage());
8296
}
8397

8498
XmlMapper xmlMapper = new XmlMapper();
85-
return xmlMapper.readValue(
86-
connection.getInputStream(), CreateMultipartUploadResponse.class);
99+
return xmlMapper.readValue(response.getContent(), CreateMultipartUploadResponse.class);
87100
}
88101

89102
public UploadPartResponse uploadPart(UploadPartRequest request, RequestBody requestBody)
90103
throws IOException, NoSuchAlgorithmException {
91104
String encodedBucket = encode(request.bucket());
92105
String encodedKey = encode(request.key());
93106
String resourcePath = "/" + encodedBucket + "/" + encodedKey;
94-
String queryString = "?partNumber=" + request.partNumber() + "&uploadId=" + encode(request.uploadId());
107+
String queryString =
108+
"?partNumber=" + request.partNumber() + "&uploadId=" + encode(request.uploadId());
95109
String uri = GCS_ENDPOINT + resourcePath + queryString;
96110
String date = getRfc1123Date();
97111
String contentType = "application/octet-stream";
98112
// GCS Signature Rule #2: The query string IS NOT included for the PUT part request.
99113
MessageDigest md = MessageDigest.getInstance("MD5");
100114
byte[] partData = requestBody.getPartData();
101115
String contentMd5 = Base64.getEncoder().encodeToString(md.digest(partData));
102-
String signature = signRequest("PUT", contentMd5, contentType, date, resourcePath, GOOGLE_SECRET_KEY);
116+
String signature =
117+
signRequest("PUT", contentMd5, contentType, date, resourcePath, GOOGLE_SECRET_KEY);
103118

104119
String authHeader = "GOOG1 " + GOOGLE_ACCESS_KEY + ":" + signature;
105120

106-
HttpURLConnection connection = (HttpURLConnection) new URL(uri).openConnection();
107-
connection.setRequestMethod("PUT");
108-
connection.setRequestProperty("Date", date);
109-
connection.setRequestProperty("Authorization", authHeader);
110-
connection.setRequestProperty("Content-Type", contentType);
111-
connection.setRequestProperty("Content-MD5", contentMd5);
112-
connection.setFixedLengthStreamingMode(partData.length);
113-
connection.setDoOutput(true);
114-
115-
try (OutputStream os = connection.getOutputStream()) {
116-
os.write(partData);
117-
}
118-
119-
if (connection.getResponseCode() != 200) {
120-
String error = readStream(connection.getErrorStream());
121-
throw new RuntimeException("Failed to upload part " + request.partNumber() + ": " + connection.getResponseCode() + " " + error);
121+
HttpRequest httpRequest =
122+
requestFactory.buildPutRequest(new GenericUrl(uri), new ByteArrayContent(contentType, partData));
123+
HttpHeaders headers = httpRequest.getHeaders();
124+
headers.setDate(date);
125+
headers.setAuthorization(authHeader);
126+
headers.setContentType(contentType);
127+
headers.setContentMD5(contentMd5);
128+
HttpResponse response = httpRequest.execute();
129+
130+
if (!response.isSuccessStatusCode()) {
131+
throw new RuntimeException(
132+
"Failed to upload part "
133+
+ request.partNumber()
134+
+ ": "
135+
+ response.getStatusCode()
136+
+ " "
137+
+ response.getStatusMessage());
122138
}
123-
String eTag = connection.getHeaderField("ETag");
139+
String eTag = response.getHeaders().getETag();
124140
return UploadPartResponse.builder().eTag(eTag).build();
125141
}
126142

127-
public CompleteMultipartUploadResponse completeMultipartUpload(CompleteMultipartUploadRequest request)
128-
throws NoSuchAlgorithmException, IOException {
143+
public CompleteMultipartUploadResponse completeMultipartUpload(
144+
CompleteMultipartUploadRequest request) throws NoSuchAlgorithmException, IOException {
129145
String encodedBucket = encode(request.bucket());
130146
String encodedKey = encode(request.key());
131147
String resourcePath = "/" + encodedBucket + "/" + encodedKey;
@@ -147,32 +163,41 @@ public CompleteMultipartUploadResponse completeMultipartUpload(CompleteMultipart
147163
String canonicalizedHeaders = "x-goog-hash:crc32c=" + crc32cBase64 + "\n";
148164

149165
// GCS Signature Rule #3: The query string IS NOT included for the POST complete request.
150-
String signature = signRequest("POST", contentMd5, contentType, date, canonicalizedHeaders, resourcePath, GOOGLE_SECRET_KEY);
166+
String signature =
167+
signRequest(
168+
"POST",
169+
contentMd5,
170+
contentType,
171+
date,
172+
canonicalizedHeaders,
173+
resourcePath,
174+
GOOGLE_SECRET_KEY);
151175
String authHeader = "GOOG1 " + GOOGLE_ACCESS_KEY + ":" + signature;
152176

153-
HttpURLConnection connection = (HttpURLConnection) new URL(uri).openConnection();
154-
connection.setRequestMethod("POST");
155-
connection.setRequestProperty("Date", date);
156-
connection.setRequestProperty("Authorization", authHeader);
157-
connection.setRequestProperty("Content-Type", contentType);
158-
connection.setRequestProperty("Content-MD5", contentMd5);
159-
connection.setRequestProperty("x-goog-hash", "crc32c=" + crc32cBase64);
160-
connection.setFixedLengthStreamingMode(xmlBodyBytes.length);
161-
connection.setDoOutput(true);
162-
163-
try (OutputStream os = connection.getOutputStream()) {
164-
os.write(xmlBodyBytes);
177+
HttpRequest httpRequest =
178+
requestFactory.buildPostRequest(
179+
new GenericUrl(uri), new ByteArrayContent(contentType, xmlBodyBytes));
180+
HttpHeaders headers = httpRequest.getHeaders();
181+
headers.setDate(date);
182+
headers.setAuthorization(authHeader);
183+
headers.setContentType(contentType);
184+
headers.setContentMD5(contentMd5);
185+
headers.set("x-goog-hash", "crc32c=" + crc32cBase64);
186+
HttpResponse response = httpRequest.execute();
187+
188+
if (!response.isSuccessStatusCode()) {
189+
throw new RuntimeException(
190+
"Failed to complete upload: "
191+
+ response.getStatusCode()
192+
+ " "
193+
+ response.getStatusMessage());
165194
}
166-
167-
if (connection.getResponseCode() != 200) {
168-
String error = readStream(connection.getErrorStream());
169-
throw new RuntimeException("Failed to complete upload: " + connection.getResponseCode() + " " + error);
170-
}
171-
return xmlMapper.readValue(connection.getInputStream(), CompleteMultipartUploadResponse.class);
195+
return xmlMapper.readValue(response.getContent(), CompleteMultipartUploadResponse.class);
172196
}
173197

174198
@Override
175-
public AbortMultipartUploadResponse abortMultipartUpload(AbortMultipartUploadRequest request) throws IOException{
199+
public AbortMultipartUploadResponse abortMultipartUpload(AbortMultipartUploadRequest request)
200+
throws IOException {
176201
String encodedBucket = encode(request.bucket());
177202
String encodedKey = encode(request.key());
178203
String resourcePath = "/" + encodedBucket + "/" + encodedKey;
@@ -185,14 +210,18 @@ public AbortMultipartUploadResponse abortMultipartUpload(AbortMultipartUploadReq
185210

186211
String authHeader = "GOOG1 " + GOOGLE_ACCESS_KEY + ":" + signature;
187212

188-
HttpURLConnection connection = (HttpURLConnection) new URL(uri).openConnection();
189-
connection.setRequestMethod("DELETE");
190-
connection.setRequestProperty("Date", date);
191-
connection.setRequestProperty("Authorization", authHeader);
192-
193-
if (connection.getResponseCode() != 204) {
194-
String error = readStream(connection.getErrorStream());
195-
throw new RuntimeException("Failed to abort upload: " + connection.getResponseCode() + " " + error);
213+
HttpRequest httpRequest = requestFactory.buildDeleteRequest(new GenericUrl(uri));
214+
HttpHeaders headers = httpRequest.getHeaders();
215+
headers.setDate(date);
216+
headers.setAuthorization(authHeader);
217+
HttpResponse response = httpRequest.execute();
218+
219+
if (response.getStatusCode() != 204) {
220+
throw new RuntimeException(
221+
"Failed to abort upload: "
222+
+ response.getStatusCode()
223+
+ " "
224+
+ response.getStatusMessage());
196225
}
197226
return new AbortMultipartUploadResponse();
198227
}

0 commit comments

Comments
 (0)