I have been debugging this for a few days, and I am hopeful that one of you fine people have run into something similar before, and have some ideas for us.
MacOS Big Sur, Client and API are both JavaScript, React/Node.js, Hapi/Joi,
The problem is as follows: Some PDFs/images will fail to upload to our REST APIs. Never in Safari, sometimes in Firefox, always in Chrome and Edge.
The APIs are deployed to AWS and when running our local instances we cannot reproduce this issue(the uploads never fail locally of course, no CORS invoked. Local environment is identical to what is deployed).
The upload request will fail consistently when using some files, and will work consistently when using other files, as if the files themselves are corrupt. For example, PDF-A will always fail (unless being sent locally, then it will work. We get no failures or errors in the API code locally), PDF-B will never fail.
We receive this classic error(consistent in Edge and Chrome, intermittent in Firefox, not present in Safari):
Access to fetch at 'https://apiUrl/relevant-endpoint' from origin 'http://localhost:3000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
We handle CORS in our APIs, by dynamically returning the preflight request info:
if (request.method === 'options') {
response.statusCode = 200;
response.headers['access-control-expose-headers'] = 'content-type, content-length, etag';
response.headers['access-control-max-age'] = 60 * 10; // 10 minutes
// dynamically set allowed headers & method
if (request.headers['access-control-request-headers']) {
response.headers['access-control-allow-headers'] = request.headers['access-control-request-headers'];
}
if (request.headers['access-control-request-method']) {
response.headers['access-control-allow-methods'] = request.headers['access-control-request-method'];
}
return h.continue;
}
It has been in production for 2 years, and already had handled a few thousand successful file uploads, 10s of thousands of requests.
Our client side request is as follows:
function request(req) {
return new Promise((resolve, reject) => {
const endpoint = `${ apiUrl }${ req.endpoint }`;
const options = {
method: req.method.toUpperCase()
};
fetch(endpoint, options)
.then((res) => res.json())
.then((res) => {
if (res.status === 'Fail') {
reject(res);
} else {
resolve(res.data);
}
})
.catch((err) => {
reject(err);
});
});
function submit(body) {
const options = {
endpoint: '/relevant-endpoint',
method: 'POST',
body
};
// Body : FormData { ... }
return new Promise((resolve, reject) => {
request(options)
.then(resolve)
.catch(reject);
});
}
const form = new FormData();
form.append('string A', this.state.stringA);
form.append('string B', this.state.stringB);
form.append('string C', this.state.stringC);
form.append('int A', this.state.intA);
form.append('file A', this.state.fileA); // the culprit
form.append('date A', this.state.dateA));
submit(form);
If the files that cause errors are optimized, in the case of a jpeg/png, or edited (i.e., fonts removed in Adobe) in the case of PDFs, they will upload successfully. I have not been able to discover exactly what characteristic is causing the files to fail. We are able to successfully submit larger and smaller files, and as mentioned before, some with identical content.
I can add some additional server side logic if necessary, I am not sure that the problem is related to that however.