1616package  com .google .cloud .storage ;
1717
1818import  static  com .google .cloud .storage .MultipartUploadUtility .getRfc1123Date ;
19- import  static  com .google .cloud .storage .MultipartUploadUtility .readStream ;
2019import  static  com .google .cloud .storage .MultipartUploadUtility .signRequest ;
2120
2221import  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 ;
2326import  com .google .api .client .http .HttpRequestFactory ;
27+ import  com .google .api .client .http .HttpResponse ;
2428import  com .google .cloud .storage .Retrying .Retrier ;
2529import  com .google .cloud .storage .multipartupload .model .AbortMultipartUploadRequest ;
2630import  com .google .cloud .storage .multipartupload .model .AbortMultipartUploadResponse ;
3337import  com .google .common .hash .HashCode ;
3438import  com .google .common .hash .Hashing ;
3539import  java .io .IOException ;
36- import  java .io .InputStream ;
37- import  java .io .OutputStream ;
3840import  java .io .UnsupportedEncodingException ;
39- import  java .net .HttpURLConnection ;
4041import  java .net .URI ;
41- import  java .net .URL ;
4242import  java .net .URLEncoder ;
4343import  java .nio .ByteBuffer ;
4444import  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