firebase storage cors strange Behaviour - javascript

I'm building an app in witch the user see a set of downsized images and than press " ok" for the app to download all of the original files, put them into a zip file and send the zip file.
the app is using polymer, polymerfire, firebase (including the storage).
during the upload of the images i save in the database both the download url and the storage reference for both the original file and the downsized one.
when i put the download url in the iron-image element to show the images in the browser everything works perfectly, the downsized images are shown on the screen.
When i try to download the fullsize images via XMLHttpRequest() i get the Cors error.
I can't understand why, both request are coming from the same app, why two different cors response?
here is the code for the XMLHttpRequest() (mostly copied from the firebase documentation):
for (var z = 0; z < visita.immagini.length; z++) {
var immagine =visita.immagini[z]
var storage = firebase.storage();
var pathReference = storage.ref('immagini/'+ immagine.original.ref);
pathReference.getDownloadURL().then(function(url) {
var xhr = new XMLHttpRequest();
xhr.responseType = 'blob';
xhr.onload = function(event) {
var blob = xhr.response;
console.log(blob);
};
xhr.open('GET', url);
xhr.send();
}).catch(function(error) {
console.log(error);
});
}
and here is the error response:
XMLHttpRequest cannot load ***** [image link]******. No
'Access-Control-Allow-Origin' header is present on the requested
resource. Origin 'http://localhost:3000' is therefore not allowed
access.
note that if i copy the ***** [image link]****** and put in another tab of the browser i can see without problems.

I finally found some information on CORS + storage as asked. Check out the firebase docs on storage here: https://firebase.google.com/docs/storage/web/download-files#cors_configuration.
Firstly, you will need gsutil (https://cloud.google.com/storage/docs/gsutil_install).
Then make a file named cors.json somewhere in your project with the following content:
[
{
"origin": ["*"],
"method": ["GET"],
"maxAgeSeconds": 3600
}
]
Finally run:
gsutil cors set cors.json gs://<your-cloud-storage-bucket>
These steps worked for me!
This is also answered here: Firebase Storage and Access-Control-Allow-Origin, which I found after answering.

The section on headers in the Firebase “Deployment Configuration” docs says that to enable cross-origin requests for images, you must add to your firebase.json something like this:
"headers": [ {
"source" : "**/*.#(jpg|jpeg|gif|png)",
"headers" : [ {
"key" : "Access-Control-Allow-Origin",
"value" : "*"
} ]
} ]
when i put the download url in the iron-image element to show the
images in the browser everything works perfectly, … When i try to
download the fullsize images via XMLHttpRequest() i get the Cors
error. I can't understand why, both request are coming from the same
app, why two different cors response?
Because browsers block cross-origin XHR requests unless the server receiving the requests uses CORS to allow them, by responding with an Access-Control-Allow-Origin: * header.
note that if i copy the ***** [image link]****** and put in another
tab of the browser i can see without problems.
That’s expected. When you put a URL into your browser’s address bar, it’s not a cross-origin request—instead it’s just you navigating directly to a URL.
But when you put that URL into the JavaScript for a Web application running at some origin on the Web, then when that request is sent, it’s not you navigating directly to the URL but instead it’s some Web application making a cross-origin request to another Web site.
So browsers by default block such cross-origin requests from frontend JavaScript code. But to opt-in to receiving such requests, a site can include the Access-Control-Allow-Origin header in its response to the browser. If the browser sees that header, it won’t block the request.
For more details, see the HTTP access control (CORS) article at MDN.

Related

What headers are necessary to complete an XMLHttpRequest?

I am trying to access images from a Google Photos album and populate a webpage with those images. This goal has been completed before, but implemented with Axios (which I'm not very familiar with). My issue is that my origin (currently a local port) is not allowed by Access-Control-Allow-Origin. From the tutorials and examples I've followed, including this one from MDN, I thought my implementation allows the port I'm running on, but I still run into the same issue.
// This is not the actual album url; for privacy I have changed it
const ALBUM_URL = "https://my-google-photos-album-url";
$(document).ready(function()
{
GetAlbum();
});
function GetAlbum()
{
const xhr = new XHRHttpRequest();
xhr.open("GET", ALBUM_URL);
// Set the origin to the port we will be using
xhr.setRequestHeader("Access-Control-Allow-Origin", "http://localhost:8000");
xhr.onreadystatechange = function(data)
{
console.log(data);
}
xhr.send();
}
Expected Behavior: Print a string of HTML and JS as was shown in the linked example.
Actual Behavior: Gives an error indicating that "http://localhost:8000" is not allowed. Exact details are given below.
Error log:
Origin http://localhost:8000 is not allowed by Access-Control-Allow-Origin.
XMLHttpRequest cannot load https://my-google-photos-album-url due to access control checks.
Failed to load resource: Origin http://localhost:8000 is not allowed by Access-Control-Allow-Origin.
What am I missing here? I have also tried setting "Access-Control-Allow-Origin" to "*", but without any luck. Any and all help is useful, thanks!
The CORS error that you get is returned by the server that you are trying to access - the server behind the https://my-google-photos-album-url.
If you have access to this server, you should set there the CORS policy that will allow the client (http://localhost:8000 in your case) to access its resources. Otherwise, I'm not sure you can access it.

XMLHttpRequest in ChromeCast Custom Receiver does not send Cookie header to Same Domain

Using XMLHttpRequest I would like to send the Cookie to the same domain via ChromeCast custom receiver. I'm using the following code, but when I look at the headers in the Request, the Cookie header does not appear.
Is there a way to send a request using cookies with XMLHttpRequest via ChromeCast?
$.cookie("a", "test",{expires: 7, path: "/"});
var r = new XMLHttpRequest();
r.open('GET', '/api/checksession', true);
r.withCredentials = true;
r.send();
Thanks.
You may refer with this thread which suggested to make sure that the manifest.json permissions are setup properly.
From this documentation, you have to properly set the cross site domain request permission in the manifest.json of your chrome extension. When done properly, the cookies who are already set for the targeted domain will be sent along with the request you are making to that domain.
You have to be especially careful when playing with localhost:port_number. You will need to specify that domain in full in the manifest.json for it to work. I ended up with awkward behaviors when my localhost domain was NOT specify in full.

How to set the Access-Control-Allow-Origin to "*" using XMLHttpRequest object?

I am trying to send a request to my api deployed in Heroku. I used an XMLHttpRequest object to fire a request to the api. I am trying out a simple
GET and no tricks. However, I receive this error:
XMLHttpRequest cannot load https://xxx-xxxx-xx.herokuapp.com/api/foods/. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost' is therefore not allowed access.
Which is normal for Chrome. However, I wanted to do this the way Postman handles it. How should I make the request to the api so that it allows everything?
I used this Chrome extension and it worked.
https://github.com/vitvad/Access-Control-Allow-Origin/
What I was able to figure out that it is basically setting this rule:
rule = {
"name": "Access-Control-Allow-Origin",
"value": "*"
};
However, when I try to set it using xhr.setRequestHeader() method, it doesn't work.
<script>
var xhr = new XMLHttpRequest();
xhr.open('GET', 'https://xxx-xxxx-xx.herokuapp.com/api/foods/', true);
xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
xhr.onload = function(){
console.log(xhr)
}
xhr.send(null);
</script>
It is your API in Heroku that needs to set the header, not the web client calling it.
Your browser is following the same origin policy by not allowing your page to request a resource in another domain. Your server can use CORS to let the browser know it is ok to make a request from another domain to this particular resource, but this information needs to come from your server.
The extension and Postman are not following the same origin policy like the browser is doing. The browser needs to follow this policy for your security.
How you set those headers really depends on how you implemented your endpoint in Heroku.

CORs does not get enabled when using XMLHttpRequest?

I have spent hours trying to access a resource from a different domain.
http://www.nczonline.net/blog/2010/05/25/cross-domain-ajax-with-cross-origin-resource-sharing/ which is referenced in other SO posts states that by simply using XMLHttpRequest in a browser that supports CORS, CORS policy should be enabled. However I am still getting
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at https://www.nczonline.net/. This can be fixed by moving the resource to the same domain or enabling CORS.
When using it in Firefox 34 which according to http://caniuse.com/#feat=cors should be sufficient.
I am trying a simple example from http://www.nczonline.net/blog/2010/05/25/cross-domain-ajax-with-cross-origin-resource-sharing/
<script type="text/javascript">
function log(msg){
var output = $('#output');
output.text(output.text() + " | " + msg);
console.log(msg);
}
function createCORSRequest(method, url){
var xhr = new XMLHttpRequest();
if ("withCredentials" in xhr){
xhr.open(method, url, true);
log("'withCredentials' exist in xhr");
} else if (typeof XDomainRequest != "undefined"){
xhr = new XDomainRequest();
xhr.open(method, url);
log("XDomainRequest is being used");
} else {
xhr = null;
log("xhr is null");
}
return xhr;
}
function main(){
log("Attempting to make CORS request");
var request = createCORSRequest("get", "https://www.nczonline.net/");
if (request){
request.onload = function(){
log("LOADED!");
};
request.send();
}
}
$(window).load(function(){
main();
});
</script>
And I am getting the following output:
Attempting to make CORS request
'withCredentials' exist in xhr
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at https://www.nczonline.net/. This can be fixed by moving the resource to the same domain or enabling CORS.
Trying it on fiddle https://jsfiddle.net/zf8ydb9v/ gives same results. Is there another lever somewhere that needs to switched on to be able to use CORS bBesides using XMLHttpRequest?
The same origin policy (which prevents making of CORS requests) is there for your security, not the security of the server: it prevents malicious scripts to access your data on other servers using your cookies.
So, if you want you can still disable it at your own risk, on your browser.
In Chrome/Chromium, if you want to disable the same origin policy you can start it with the --disable-web-security option:
chromium-browser --disable-web-security
Anyway, if you want it to work for your users, they will not able to make CORS requests if they have not disabled this security check in their browsers (which is discouraged if not for testing).
As noted in other answers, some servers can purposely allow this kind of requests if they believe this can be useful and not harmful for their users, and they can do this with the Access-control headers.
Moreover, if you still want to find a way to provide this kind of functionality to the users, you might make a Chrome extension, which is not bound to the same origin policy.
A common solution to this is to make the cross origin request server side, returning the result to your application. You should be careful coding this: passing the url to fetch to the server will easily cause security concerns for your server side software. But if you have to fetch the same url every time, you could hard code it server side, in PHP would look like something like this:
<?php
echo file_get_contents("http://your_cross_request/");
?>
then making an ajax request to this page (which will be from the same origin) will return the content of the remote url.
CORS headers are found in the response sent by the server to your request. If the requested page isn't sending the header, it doesn't matter what you did with the request in a stock browser, you'll get a security error
The relevant CORS headers look like this, the last being the most important one
Access-Control-Allow-Credentials: false
Access-Control-Allow-Methods: GET
Access-Control-Allow-Origin: *
I tried opening "nczonline.net" and when I looked at the response headers I did not see any of these, so the server is not configured to permit being loaded in this way
If you are an administrator of that website, you may want to consider adding the required headers to your responses, perhaps being specific about permitted origins rather than using the wildcard
If you're simply trying to demo your code and want to try it with a third party, load a page which does send these headers e.g. developer.mozilla.org

My AJAX request object doesn't properly resolve the protocol portion of the URL

I'm trying to send an AJAX request from a secure page, but the XMLHttpRequest object doesn't properly resolve the protocol portion of the URL. This behavior is identical in Safari, Chrome, and Canary.
Here's my JavaScript:
function sendGETRequest(url, params, callback) {
"use strict";
var req = new XMLHttpRequest();
req.onreadystatechange = function () {
if (req.readyState === 4) {
if (req.status !== 200) {
callback({ajaxError: true, status: req.status});
} else {
callback(req);
}
}
};
req.open("GET", url + "?" + params, true);
req.setRequestHeader("X-Requested-With", "XMLHttpRequest");
req.send();
}
Here are some different URLs passed to sendGETRequest(), along with their results:
url = "ajax/";
GET https://mydomain/mypage/ajax/?params 404 (NOT FOUND)
The above is the expected behavior: the relative url is correctly resolved with protocol intact.
url = "/ajax/";
The page at https://mydomain/mypage/ displayed insecure content from http://mydomain/ajax/?params.
Here, the realtive url is correctly appended to the domain root, but with the wrong protocol.
url = "https://mydomain/ajax/";
The page at https://mydomain/mypage/ displayed insecure content from http://mydomain/ajax/?params.
Here, the protocol is just ignored.
To be clear, I'm not trying to work around the same origin policy; I want to send an AJAX request from a secure page to a resource with the same (secure) origin. How can I accomplish this simple task?
There is a conversation here about this topic: http://bytes.com/topic/javascript/answers/459071-ajax-https
One of the last posts states "Just to be absolutely unambiguous; XML HTTP requests work over https
exactly as they do over http. If they did not our QA department would
have said something by now as they test over https almost exclusively"
Perhaps the server is not using Https (ssl) at the point where the request is being made: mydomain/ajax/.
This has nothing to do with HTTP and HTTPS. As you mentioned in a comment, the request is never being sent due to same-origin policy. How can the request be using the wrong policy if the request is never sent? What is confusing you is that whatever program/add-on/tool/etc that is generating the error message is showing "HTTP" instead of "HTTPS". The request IS and ALWAYS respects HTTPS when HTTPS is set.
Your real issue is quite simply that you are violating cross-origin policy. See this:
https://developer.mozilla.org/en-US/docs/Same-origin_policy_for_file:_URIs
You cannot go UP the directory tree, only down. In the first example, you are requesting a subfolder. That's fine. In the second and third examples, you are requesting a page from a parent directory (ie, instead of https://mydomain/mypage/ajax/ you are asking for https://mydomain/ajax/. You cannot make a request up a directory tree like that.
Either move your index page up to the root of the domain, or change the same-origin policy header being sent on the files, or make a sub directory on the server handle the request (you can use something like PHP's include to just include the parent file).
This is a bug in WebKit. It's been fixed in Safari 5 for Lion but not Snow Leopard, and it's been fixed in Chrome but not Canary,... helluva a bug.

Categories

Resources