Reputation: 342
First of all I'm sorry for pasting so much code here, but as there's a lot of things that could go wrong in each step of this process, I'm trying to make sure that every error that I faced and was able to fix is recorded here so there's no back and forth in comunication.
Im trying to create a signed upload url to send some files from the browser to a gcp bucket.
I have a backend in go creating the signed upload url like this
func generateV4PutObjectSignedURL(bucket, object string) (string, error) {
ctx := context.Background()
client, err := storage.NewClient(ctx)
if err != nil {
return "", fmt.Errorf("storage.NewClient: %v", err)
}
defer client.Close()
pkey, err := ioutil.ReadFile("key.pem")
check(err)
opts := &storage.SignedURLOptions{
PrivateKey: pkey,
Scheme: storage.SigningSchemeV4,
Method: "PUT",
ContentType: "video/wav",
Expires: time.Now().Add(20 * time.Hour),
}
u, err := client.Bucket(bucket).SignedURL(object, opts)
if err != nil {
return "", fmt.Errorf("Bucket(%q).SignedURL: %v", bucket, err)
}
return u, nil
}
key.pem has every permission possible.
I'm sending the file like this
const reader = new FileReader();
console.log(file);
reader.onabort = () => console.log("file reading was aborted");
reader.onerror = () => console.log("file reading has failed");
reader.onload = () => {
const binaryFile = reader.result;
const blob = new Blob([binaryFile], { type: file.type });
var request = new XMLHttpRequest();
request.open("PUT", uploadUrl, true);
request.setRequestHeader("Content-Type", file.type);
request.onload = (e) => {
if (request.status === 200) {
poll();
}
};
request.send(blob);
};
reader.readAsArrayBuffer(file);
And I'm receiving this error
Access to XMLHttpRequest at {THE_SIGNED_URL} from origin 'http://localhost:3000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
CORS configuration in the bucket is like this
[{"maxAgeSeconds": 86400, "method": ["*"], "origin": ["*"], "responseHeader": ["*"]}]
And the XML error I'm getting is this
<Error>
<Code>MalformedSecurityHeader</Code>
<Message>Your request has a malformed header.</Message>
<ParameterName>content-type</ParameterName>
<Details>Header was included in signedheaders, but not in the request.</Details>
</Error>
But chrome developers network tab says that the Content-Type header is present in the request and is exactly what I said it would be in the backend.
What am I doing wrong?
Upvotes: 0
Views: 1101
Reputation: 342
GCP makes you receive CORS error even if you have configured CORS correctly!
I ended up solving the problem by removing the content type header from the request.
After I did this the CORS problem returned and I ended up finding out it actually wasn't a CORS problem but a GCS problem.
I don't know what happens exactly but I suppose google does something with your OPTIONS preflight request before adding the CORS headers that says you're good to go (Access-Control-Allow-Origin). If something in this process breaks, it returns your answer without this header so your browser understands you've failed CORS validation.
Using some tool that automatically adds this header to every request you receive allows you to view the body of the request and the real problem with your request. There are some chrome extensions that do this.
In my case the problem was that I needed to use a service account email when signing the upload signed request but yours may be different.
Upvotes: 2