google-cloud-storageaws-sdk-java

Uploading to GCS using S3 Java SDK: `The MD5 you specified in Content-MD5 or x-goog-hash did not match what we computed`


I am trying to upload to Google Cloud Storage using the AWS SDK For Java 1.x. I have enabled interoperability mode and put AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY in the environment. I can list objects, but uploading is not working for me.

The code I am using is

    AmazonS3 client =
        AmazonS3ClientBuilder.standard()
            .withEndpointConfiguration(
                new AwsClientBuilder.EndpointConfiguration(
                    "http://storage.googleapis.com", "auto"))
            .build();

    TransferManager tm = TransferManagerBuilder.standard()
        .withS3Client(client)
        .build();
    Upload upload = tm.upload(bucketName, key, new File(filename));
    upload.waitForCompletion();

But the result I get is:

com.amazonaws.services.s3.model.AmazonS3Exception: The MD5 you specified in Content-MD5 or x-goog-hash did not match what we computed. (Service: Amazon S3; Status Code: 400; Error Code: BadDigest; Request ID: null; S3 Extended Request ID: null; Proxy: null), S3 Extended Request ID: null
        at com.amazonaws.http.AmazonHttpClient$RequestExecutor.handleErrorResponse(AmazonHttpClient.java:1819)
        at com.amazonaws.http.AmazonHttpClient$RequestExecutor.handleServiceErrorResponse(AmazonHttpClient.java:1403)
        at com.amazonaws.http.AmazonHttpClient$RequestExecutor.executeOneRequest(AmazonHttpClient.java:1372)
        at com.amazonaws.http.AmazonHttpClient$RequestExecutor.executeHelper(AmazonHttpClient.java:1145)
        at com.amazonaws.http.AmazonHttpClient$RequestExecutor.doExecute(AmazonHttpClient.java:802)
        at com.amazonaws.http.AmazonHttpClient$RequestExecutor.executeWithTimer(AmazonHttpClient.java:770)
        at com.amazonaws.http.AmazonHttpClient$RequestExecutor.execute(AmazonHttpClient.java:744)
        at com.amazonaws.http.AmazonHttpClient$RequestExecutor.access$500(AmazonHttpClient.java:704)
        at com.amazonaws.http.AmazonHttpClient$RequestExecutionBuilderImpl.execute(AmazonHttpClient.java:686)
        at com.amazonaws.http.AmazonHttpClient.execute(AmazonHttpClient.java:550)
        at com.amazonaws.http.AmazonHttpClient.execute(AmazonHttpClient.java:530)
        at com.amazonaws.services.s3.AmazonS3Client.invoke(AmazonS3Client.java:5437)
        at com.amazonaws.services.s3.AmazonS3Client.invoke(AmazonS3Client.java:5384)

The same code works OK with S3 (minus the EndpointConfiguration)


Solution

  • The GCS docs say:

    In the Cloud Storage XML API, chunked transfer encoding and V4 signatures cannot currently be used simultaneously. Some Amazon S3 tools use chunked transfer encoding along with signatures by default; you should disable chunked transfer encoding in such cases.

    I found two ways to resolve this error

    1. You can .withChunkedEncodingDisabled(true) when building the client:

       AmazonS3 client =
           AmazonS3ClientBuilder.standard()
               .withChunkedEncodingDisabled(true)  // <<<<<<<
               .withEndpointConfiguration(
                   new AwsClientBuilder.EndpointConfiguration(
                       "http://storage.googleapis.com", "auto"))
               .build();
      
    2. You can switch to the https endpoint:

       AmazonS3 client =
           AmazonS3ClientBuilder.standard()
               .withEndpointConfiguration(
                   new AwsClientBuilder.EndpointConfiguration(
                       "https://storage.googleapis.com", "auto"))
               .build();