Get hands-on experience with 20+ free Google Cloud products and $300 in free credit for new customers.

Signed Url to write to bucket returns message about missing header, which isn't missing.

I am using the javascript API.

 I am trying to use a signed url to upload a file to my Google Cloud Storage. The code to create the signed url is this:

 

 

    // args have name of file and type
    // config has information about the bucket, etc
    const uploadOptions = {
        destination: args.name,
    };
    console.log(`Content-Type: ${args.fileType}`)
    const signingOptions = {
        version: "v4",
        action: "write",
        expires: Date.now() + 15*60*1000,
        contentType: args.fileType,
    };

    const response = Promise.await(myStorage.bucket(config.bucketName).file(args.name, uploadOptions).getSignedUrl(signingOptions));
    return response;

 

 

I then use this url to try to upload the file with fetch thus:

 

 

                // writeUrl is the url created by the above code
                fetch(writeUrl, 
                    {method: "PUT", 
                    origin: "https:localhost:3000",
                    headers: {"content-type": fileElement.files[0].type},
                    body: fileElement.files[0]})
                .then((response) => {
                    // Do something 
                })
                .catch((error) => {
                    console.log(error);
                })

 

 

This fails. The url returns an error message from the server that looks like this:

<Error>
  <Code>MalformedSecurityHeader</Code>
  <Message>Invalid argument.</Message>
  <Details>Your request has a malformed header. Header was included in signedheaders, 
    but not in the request.</Details>
  <ParameterName>content-type</ParameterName>
</Error>

This appears to be telling me I did not include a header "content-type".  However, I think I did.  I looked at Chrome's network tab to verify, and it says this:

 

 

Content-Type: image/png
Referer: http://localhost:3000/
Sec-Ch-Ua: "Not_A Brand";v="8", "Chromium";v="120", "Google Chrome";v="120"
Sec-Ch-Ua-Mobile: ?0
Sec-Ch-Ua-Platform: "macOS"
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36

 

 

However, Chrome also says that this is "provisional", as it might have come from the cache or from a failed request.  It certainly came from a failed request, but the caching off box is checked in the Chrome network tab.

I am at a loss.  It appears as though some comparison was case-sensitive and returned a mismatch erroneously.  But that doesn't seem very plausible, since headers are supposed to be case insensitive, and this kind of functionality gets used every day successfully.

Help?  Thoughts?

1 1 2,063
1 REPLY 1

I have figured out what's going on here. It was my mistake. I misinterpreted some things that the browser was telling me, and I thought I would share my error because it might help someone else at some point.

What I was seeing was a failure of a CORS preflight request. This was due to a misconfiguration of the CORS response on my server.

However, when I looked in Chrome's Network tab, it does not show me the preflight request at all. So I wasn't aware that it was happening let alone looking at it to see what was wrong.

And then, not knowing this, I clicked on the link in the Chrome console that corresponded to the (signed) URL I was trying to PUT to. This got a response that didn't depend on CORS, it seems. It also didn't add the "content-type" header, because I just clicked on a link. So that's why that error showed up.

So, in the end, I was doing two different things and thinking they were the same thing. Confusion abouts.

With that insight, I fixed the CORS misconfiguration and it works now.