I've been asked to create a feedback page that can be requested from another site.
I'm using progressive enhancement to display the page.
The ajax request for when I am able to use a jquery dialog is as follows
jQuery.support.cors = true;
$.ajax({
type: 'get',
crossDomain: true,
url: this.href
}).done(function (data) {
$dialogFeedback.html(data);
}).error(function (jqXHR, textStatus, errorThrown) {
$dialogFeedback.html(jqXHR.responseText || textStatus);
});
During testing I have noticed Internet explorer seems to be allowing a cross domain call even when the response Access-Control-Allow-Origin HttpHeader is not set to be the client domain. I've noticed the Http origin header is always null.
Chrome and Firefox respect it. The Http origin header is not null.
The client site making the call is on a different port to the feedback site but both are localhost. I have read that a different port number is considered cross domain.
At the moment I find myself having to retrieve the caller/client domain from the Referrer Http header and returning a 404 if the domain is not known by us.
Really I was hoping to rely on the Access-Control-Allow-Origin HttpHeader!
. . . so my question is why is this happening? Is it actually expected/probable? What is the best solution?
Thanks
If the origin header is missing, then the request is not cross-domain according to IE. IE violates the same-origin policy RFC in several ways. First, it ignores port numbers. Second, IE will allow domains that are in the trusted zone to interact without applying the same origin policy
Related
I want to login to a website and follow redirection whit ajax or XMLHttpRequest or any thing else exept php.
Actually whene i try to do it, i have error "302 Moved Temporarily" but the webpage is the right page so i don't know why i get this error.
The website is an external website (not on my server).
This is my code :
$.ajax({
type: "POST",
contentType: "application/x-www-form-urlencoded",
url: "http://website/index.php",
data: { username: "myuser", password: "123456" },
success: function(data) {
console.log("success ", data.response);
},
error: function(data) {
console.log("error ", data.error);
},
dataType: "html"
});
If you try use ajax outside your domain, you will probably get this error message:
XMLHttpRequest cannot load http://www.example.com/path/filename. Origin
null is not allowed by Access-Control-Allow-Origin.
The reason you get this error message is because of the Same-origin policy. The policy permits scripts running on pages originating from the same site to access each other's data with no specific restrictions, but prevents scripts access to data that is stored on a different domain.
This could be a problem if you are trying to access publicly hosted data, but there are ways around it.
Here is the list of methods:
Implement CORS (Cross-Origin Resource Sharing)
Use JSONP (JSON Padding)
Use postMessage method
Setting up a local proxy
CORS (Cross-Origin Resource Sharing)
CORS is a mechanism that allows resources on a web page to be requested from another domain outside the domain the resource originated from. In particular, JavaScript's AJAX calls can use the XMLHttpRequest mechanism. Such "cross-domain" requests would otherwise be forbidden by web browsers, per the same origin security policy. CORS defines a way in which the browser and the server can interact to determine whether or not to allow the cross-origin request. It is more useful than only allowing same-origin requests, but it is more secure than simply allowing all such cross-origin requests.
JSONP (JSON Padding)
JSONP or "JSON with padding" is a communication technique used in JavaScript programs running in web browsers to request data from a server in a different domain, something prohibited by typical web browsers because of the same-origin policy. JSONP takes advantage of the fact that browsers do not enforce the same-origin policy on <script> tags.
Because of the same origin policy, we can not make cross domain AJAX requests, but we can have <script> tags that load javascript files from other domains. JSONP uses this exception in order to make cross domain requests by dynamically creating a <script> tag with necessary URL.
postMessage method
window.postMessage method is part of HTML5 introductions. It allows communication between window frames without being subject to same origin policy. Using postMessage() one can trigger a message event with attached data on another window, even if the window has different domain, port or a protocol. The frame where the event is triggered must add an event listener in order to be able to respond.
Let's see an example. Assume, we are on http://example.com (1) website and would like to make a request to http://example2.net (2) domain. We first must obtain a reference to (2) window. This can be either iframe.contentWindow, window.open, or window.frames[]. For our case it's best to create a hidden iframe element and send messages to it.
Setup local proxy
This method overcomes same origin policy by proxying content on another domain through itself. Thus making cross-domain issue irrelevant. To use this method you will either a) setup your server as a reverse proxy to fetch content from another server or b) write a script that would do that.
This cross domain querying solution works because you actually loading content from your own domain. You request the URL and the proxy script on your server loads the content and passes it over to you.
http://www.ajax-cross-origin.com/how.html You can visit this link if you want to learn about these methods in details. There is also a jquery plugin named ajax cross origin to tackle similar issues.
So I've been having issues sending cookies with a cross-domain request to a service. I've gotten to make it work in our CI environment, but not locally. Basically, I have an API at api.service.com, and it's accessed via AJAX calls run from clients at webapp.service.com. The API sets a cookie for .service.com via set-cookie. Then all subsequent calls to the API should include this cookie. This works as intended, when running from webapp.service.com. This will work in prod just fine. However, for obvious reasons, I'd like be able to develop the webapp locally, and run API calls against api.service.com from either local files or localhost service.
I understand that Chrome is a little iffy regarding saving cookies for local files, but I've addressed that, and it is not the issue. The cookie is, in fact, saving. It's just not sending that cookie with subsequent API calls. Here's the workflow I've got going on (with some genericized/censored product names):
An AJAX call POSTS to our API:
$.ajax({
method: "POST",
crossDomain: true,
xhrFields: {
withCredentials: true,
},
url: 'https://api.service.com/login',
data: data,
contentType:"text/plain",
dataType: "json",
success: function(data){
...
}
});
The CORS stuff is set up to allow credentials and this origin (the allowed origin updates dynamically, doesn't use *. So we get this cookie back: cookie:service-token=7f7d251ebeec37f7c0815....; SameSite=lax;Max-Age=2629744; domain=.service.com; path=/;
It shows up in Chrome like this:
Request cookie
I know for a fact that this actually works to save the cookie. However, perhaps not how I want. I go into Chrome's cookies, and it updates properly as seen:
Chrome saved cookie
The problem I'm seeing there is that its "send for" value is "same-site connections only". I have no idea how to originally set that for Chrome to treat it as "any kind of connection." I think this is the reason that, when I send another AJAX call, that cookie is not included in the request.
I've seen other posts like this that were resolved by adding crossDomain and/or withCredentials to the AJAX call. This did not resolve it for me. This is a subsequent call to the API:
$.ajax({
url: 'https://api.service.com/getTheThing',
crossDomain: true,
xhrFields: {
withCredentials: true
},
success: function(data){...}
});
The cookie is not included in this request, and thus fails.
It turns out, setting SameSite=lax was doing the opposite of what I thought it would. Removing that solved this issue.
Question Overview:
I am accessing a list of files stored in my AWS S3 bucket through a CORS request of presigned files. This basically works fine. However, the objects have some custom METADATA attached to them, which I can't access. I understood, that I can access this metadata only when I add the header key (e.g. "x-amz-meta-1234", where 1234 is the key of my metadata) to the Expose-Headers of the target-bucket's CORS config. While this works so far for me, I can't set the expose-header with a wildcard (e.g. "x-amz-meta-*"), which would solve my problem, but AWS doesn't support wildcards for the expose-header entries.
However, when I look in the NETWORK tab of my Chrome Dev Tools, all desired metadata is showing up in the headers during the GET/HEAD request (note the entries on the lower part, x-amz-meta-4021 and -template_id):
This is my HEAD call:
$.ajax({
url: url,
dataType: 'json',
crossDomain: true,
type: 'HEAD',
success: function(data, status, jqXHR) {
console.log('got some response ..?');
console.log(data);
console.log(jqXHR);
console.log('responseHeader template_id: ' + jqXHR.getResponseHeader('x-amz-meta-template_id'));
console.log('responseHeader meta-4021: ' + jqXHR.getResponseHeader('x-amz-meta-4021'));
console.log(jqXHR.getAllResponseHeaders());
},
error: function(error, xhr, data) {
console.log('in error..');
console.log(error);
console.log(xhr);
console.log(data);
}
});
});
And this is the console output:
Object {readyState: 4, getResponseHeader: function, getAllResponseHeaders:
function, setRequestHeader: function, overrideMimeType: function…}
responseHeader template_id: 813
responseHeader meta-4021: null
x-amz-meta-template_id: 813
Last-Modified: Fri, 09 Jun 2017 13:05:33 GMT
Content-Type: video/mp4
I set expose-header for the metadata-entry 'template_id' explicitly and therefore the header-data is returned correctly for this entry. However, for the entry '4021' I didn't set the expose-header. The problem is, that this metadata (and the keys) are produced by our (android/ios) apps, and I can't really control the keys of that metadata that easily.
Whats puzzling me: why am I able to see the whole response in the chrome network tab, but can't access this data from a client-side script? There are many possible workarounds and solutions, but I basically want to understand, why my browser can display me data, which can't be accessed by jQuery.
PS: in case you want to see the CORS config or the full script, please let me know. I tried to be as precise as possible. Thanks in advance!
I basically want to understand, why my browser can display me data, which can't be accessed by jQuery.
To understand this, you need to understand the purpose of CORS.
CORS isn't really about access control, and CORS isn't really working on your site's behalf. CORS is working on behalf of the user and the browser, to prevent the browser from becoming a confused deputy and doing something the user would not have wanted. This usually coincides with something the site would also not have wanted, but that's secondary.
The browser's default behavior is to assume that programmatic access to cross-origin requests is bad, which is why they are denied when no Access-Control-Allow-Origin header is present. Your bank would not want internetbadguys.com to make ajax requests to the bank web site, and if that site tried, the browser would block it unless the bank's web server foolishly allowed it with a CORS response.
CORS is a mechanism for your site to tell the brower, "yes, the cross-origin request you are making is not unexpected, it's allowed... and from this response, the browser is allowed to engage in certain behaviors, such as exposing the following response headers to the code making the request."
In that light, the behavior you observe is correct. Exposing headers (or not) doesn't mean include them in the HTTP response (or not) -- exposing headers gives the browser permission to expose what it knows to the ajax caller. If the cross-origin origin wants them exposed, it has to be explicit.
I have a login setup for one of my sites where the user types their information into a login popup on the home page, which then submits the information back to a servlet and then receives a response back via JSON. The home page then proceeds to send the user to their profile page or alternatively displays an error (e.g., if username and password do not match).
$.ajax({
dataType: 'jsonp',
async: false,
url: loginLocation,
type: 'GET',
crossDomain: true,
cache: false,
xhrFields: crossDomain ? {
withCredentials: true
} : {},
data: ({'key1': value1, 'key2': value2, ..., 'keyN':'valueN'}),
success: function(data){
if (data && data.status && data.status == "success") {
window.location = profileLocation;
} else {
errorHandler();
}
},
error: errorHandler
});
I am looking to change this from a GET request to a POST in order to prevent arbitrary query strings being sent into the servlet. However, it appears that there are several considerations at play here with regards to how the solution ought to be laid out. It must:
use POST instead of GET
be a cross-domain request (the login page and the servlet are on different domains over both of which I have access/control)
use the withCredentials parameter (the login functionality relies on the JSESSIONID cookie so this parameter is required)
be compatible with IE8 and above
I have tried looking into cross-domain ajax requests that fit the above criteria, but the major sticking point seems to be the IE8/IE9 compatibility. Approaches such as easyXDM appear to be ambiguous as to support for these browsers (I have seen conflicting reports online as to how it works in IE8) and I don't want to run into the danger of realizing it won't work halfway through implementation.
So in short, is there a way to do cross-domain ajax requests using POST and with the withCredentials parameter, that is also compatible with IE8+? Is easyXDM an appropriate solution to this?
I was able to determine the solution to the above question by using the xdomain library (found at https://github.com/jpillora/xdomain) which overrides the request behavior to allow cross-domain ajax in IE8 and IE9. This involved setting up the proxy.html as shown in the example on the xdomain site as well as adding Access-Control-Allow-Origin and other related headers to the server response. This allows cross-domain ajax JSON POST requests using withCredentials in IE8+ per the criteria listed in the original post. It also allows cross-domain requests between HTTP and HTTPS.
We are trying to create a RESTful API that will be hosted on server x.foo.com. Client html applications (built in jquery) will be hosted on y.foo.com.
I am dealing with cross-domain issues by setting the Access-Control-Allow-Origin header as described here http://www.w3.org/TR/cors/.
So far so good, and I can now successfully make AJAX calls from host y to host x.
However, I ran into a gotcha with POST requests. The typical response to a post request is a redirect. However, the XMLHttpRequest object will not follow cross domain redirects, thus resulting in a failed call.
// Hosted on y.foo.com
$.ajax({
type: "POST",
url : http://x.foo.com/myapp/",
success: function(data) {
alert("success!");
}
});
// Return status: 302
// (Which errors out in firebug)
Anyone know of any techniques to handle the redirect (to a resource on server x) that I get from this post for a client hosted on y?
How about the client sends a special header for AJAX requests, and depending on whether it's an AJAX request or not, you can change the response instead of doing a redirect.