Redirect Failing on CORS Request - javascript

I'm trying to download a file in client-side Javascript using the Box API, which redirects the request to a temporary download link once the file has been found. The browser is blocking the redirect, though, throwing the following error:
XMLHttpRequest cannot load https://api.box.com/2.0/files/file-id/content. The request was redirected to 'https://dl.boxcloud.com/d/1/some-big-hash/download', which is disallowed for cross-origin requests that require preflight.
In the Network console I see three requests, the first is an OPTIONS (which must be the pre-flight because the actual code sends a GET) with a 200 response, and the second two are identical GET requests which both get 302'd (the expected response for that API call). Here's the code that makes the request:
var xhr = new XMLHttpRequest();
xhr.open('GET', url);
xhr.setRequestHeader('Authorization', 'Bearer '+MyToken);
xhr.onload = function()
{
//some stuff
}
xhr.onerror = function()
{
//some other stuff
}
xhr.send();
My question is (a): Why are two GETs being sent after the preflight comes back?
And (b): Is there any way I can format the request to allow following the redirect? And (c) if not, can I at least retrieve the redirect URL from the response and follow it with another explicit request? Every response in the console has the 'Access-Control-Allow-Origin' header set with the correct origin.
Thanks

I don't understand why you get three rather than two requests, but the way CORS has worked thus far is that a request with a preflight cannot be redirected. This has changed in the Fetch Standard, but user agents have not yet picked up the change.

Related

XMLHttpRequest causes two network events

I'm noticing when I have use a XMLHttpRequest in my script, that for each time it gets called two events appear in Chrome's network waterfall.
The first event has a type xhr and a size of around ~27bytes and the second event has a type of text/html and a size of 0bytes.
I've noticed it in the past and have looked over it, but now I'm noticing its causing the page it connects to for it to run twice.
Is this normal? Did I implement something incorrectly?
function example(){
console.log('ran'); // this shows the function only ran once
var form = new FormData(), xml = new XMLHttpRequest();
form.append('test', '...');
xml.upload.onprogress = function(e){something.style.width = (e.loaded*100/e.total) + "%";}
xml.onload = function(){alert('done');}
xml.open('POST', 'https://externaldomainexample.net', true);
xml.send(form);
}
The two requests are being made because you are making a request to a different domain from which your page is hosted (cross origin). If you enable the "method" column in Chrome's network tab you'll see that the first request is an OPTIONS request, whereas the second is your POST request.
The first request is what's known as a Preflight request and asks the remote server what remote hosts are allowed to connect and what methods they are allowed to call. If this step fails, then you'll see an error in the browser saying the request has been "blocked by CORS policy".
If the preflight request is successful, then the second (POST) request is made.
Depending on how the server is configured, you may need to have it handle OPTIONS requests differently, so that it doesn't perform the same action twice.

Is it possible to add a request header to a CORS preflight request?

I have a website that accesses an API from an external server (not the server
that serves the website) via a plain XmlHttpRequest (see below). That API
requires an API key for accessing the service to be added as request header.
However, as these are CORS
requests the browser first does a preflight request to check if that server
supports CORS. Now, it seems that the server also wants to see the API key in
these preflight requests that are done by the browser. Is it possible to pass
the API key also to the preflight request?
const req = new XMLHttpRequest();
req.open("GET", "https://some/api/endpoint");
req.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
req.setRequestHeader("x-api-key", _apiKey);
req.onload = () => {
// ...
};
req.send();
The CORS preflight OPTIONS request is totally controlled by the browser; so it’s not possible to add request headers to it. See https://fetch.spec.whatwg.org/#cors-preflight-fetch. That’s why any endpoint you send requests to must be set up to allow unauthenticated OPTIONS requests, and respond to them with a 200 OK (at least as long as a request triggers a preflight, which it always will if you add custom request headers, such as the x-api-key header in the question).

Curl rest API to a second site in Javascript

I am trying to display a result from a rest API GET request, for example, "http://ifconfig.co/ip/" on my page. However, I am running into many different errors, and just cannot seem to get it down.
Her is what I have so far:
var req = new XMLHttpRequest();
req.open('GET', 'https://ifconfig.co/ip', true);
req.withCredentials = false;
req.setRequestHeader( 'Access-Control-Allow-Origin', '*' );
req.send();
document.write(req);
document.write(req.responseText);
document.write(req.responseXML);
In the javascript console it says "XMLHttpRequest cannot load https://ifconfig.co/ip. Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource."
I am very new to javascript, can anyone point me in the right direction?
The No Access-Control-Allow-Origin message means that the server is configured not to accept requests from the client's domain. Here's a great article on MDN https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS

CORS to fetch .js content - Javascript

I'm trying to get the content of various .js files from a code that runs on the browser (through plugin).
I have no problem getting .js files that reside on the same server, using XMLHttpRequest but when I need to fetch the content of .js files that are on other domains I'm trying to use CORS but I can't seem to get it to work
This is my code
// Create the XHR object.
function createCORSRequest(method, url) {
var xhr = new XMLHttpRequest();
if ("withCredentials" in xhr) {
// XHR for Chrome/Firefox/Opera/Safari.
xhr.open(method, url, true);
} else if (typeof XDomainRequest != "undefined") {
// XDomainRequest for IE.
xhr = new XDomainRequest();
xhr.open(method, url);
} else {
// CORS not supported.
xhr = null;
}
return xhr;
}
// Make the actual CORS request.
function makeCorsRequest(url) {
var xhr = createCORSRequest('GET', url);
if (!xhr) {
alert('CORS not supported');
return;
}
// Response handlers.
xhr.onload = function() {
return xhr.responseText;
};
xhr.onerror = function() {
alert('There was an error making the request.');
};
xhr.send();
}
When I run:
url = `https://......./javascript.js'
res = makeCORSTRequest(url)
I get the 'There was an error making the request.' error alert, and the console logs
XMLHttpRequest cannot load https://......./javascript.js. No
'Access-Control-Allow-Origin' header is present on the requested
resource. Origin 'https://.....com' is therefore not allowed access.
Your browser will only let your frontend JavaScript code access responses from cross-origin requests when the servers you’re making the requests to explicitly indicate they’re opting in to receiving cross-origin requests, which they do by sending the Access-Control-Allow-Origin response header in their responses.
https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS has more details.
In cases where a site never sends the Access-Control-Allow-Origin response header, the only way you will be able to get content that site cross-origin is by using a CORS proxy. See the answer at "No 'Access-Control-Allow-Origin' header is present on the requested resource" for details.
Browsers are the only clients that enforce restrictions on cross-origin requests, and they only enforce them on web applications.
That’s why even when you see a No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin … is therefore not allowed access message in your devtools console, you’ll still be able to go to the Network tab in devtools and view the response there.
That’s because the server has sent the response and the browser has received it, but the browser is just refusing to allow your frontend JavaScript code to access the response due to the fact the server sending the response hasn‘t opted into to cross-origin requests by sending the Access-Control-Allow-Origin response header.
The reason you can get the response just fine when you make the request from Python, etc., is that no client other than browsers will refuse to allow your code to access the response if it lacks the Access-Control-Allow-Origin response header. But browsers always will.
And note that in none of this is the server doing any blocking or refusing to respond to any requests. The server always continues to just receive requests and send responses. The only difference is in whether the server sends the Access-Control-Allow-Origin header in the response, or not.

CORS AJAX Call not Successful

I have an AJAX call trying to execute the following CORS request to a Web Server (I am currently testing using only the latest version of Chrome):
var xhr = new XMLHttpRequest();
xhr.open("get", "http://www.web_server_url.com/query", true);
xhr.onload = function(){
};
xhr.send(null);
Meanwhile, I am still getting the following message:
XMLHttpRequest cannot load http://www.web_server_url.com/query. Origin http://localhost is not allowed by Access-Control-Allow-Origin.
Would someone know what I am missing?
The reason is exactly what it says in the error: The server at www.web_server_url.com is not allowing the localhost origin. It's up to the server to decide whether to allow the origin of the call. In this case, apparently it's not allowing it.
The way CORS works, the server replies to the request (or a "preflight" request) with headers either allowing or disallowing the origin on the basis of the information the browser sends it.

Categories

Resources