PDA

View Full Version : (CORS) Cross-Origin Resource Sharing requests



luismerino
16 Dec 2011, 9:00 AM
Hi all:

With a growing number of services allowing the use of XMLHttpRequest2 and its advantages, I found if anything annoying that ST2 didn't provide a convenient way of making use of Ext.Ajax and proxy.Ajax to requests data cross domain.

At first I started using the Ext.Ajax singleton's property Ext.Ajax.useDefaultXhrHeader = false/true, but I hated having to switch its value between calls and besides, using it like this can cause some headaches.

For this reason, I'm sharing now the cleanest solution I've come up with (not the shortest) to make things a bit easier on this subject.


Ext.define('Ext.data.Cors', {

extend: 'Ext.data.Connection',

alternateClassName: ['Ext.Cors'],

singleton: true,

useDefaultXhrHeader: false,

autoAbort: false

});




Ext.define('Ext.data.proxy.Cors', {

extend: 'Ext.data.proxy.Ajax',

uses: ['Ext.data.Cors'],

alias: 'proxy.cors',

alternateClassName: ['Ext.data.CorsProxy'],

doRequest: function(operation, callback, scope) {
var writer = this.getWriter(),
request = this.buildRequest(operation, callback, scope);

if (operation.allowWrite()) {
request = writer.write(request);
}

Ext.apply(request, {
headers : this.headers,
timeout : this.timeout,
scope : this,
callback : this.createRequestCallback(request, operation, callback, scope),
method : this.getMethod(request),
disableCaching: false // explicitly set it to false, ServerProxy handles caching
});

Ext.Cors.request(request);

return request;
}


});


Note that for the proxy to work, you must override Ext.data.Model like this:



Ext.define('YourNamespace.data.Model', {
override: 'Ext.data.Model',
requires: ['Ext.data.proxy.Cors']
});


Since I don't advice you to mess around with ST2 source's at all (updates will break your code if replaced).

I'm not sure if somebody proposed some other solution for CORS requests about the forum, but anyhoo.

Enjoy :)

mitchellsimoens
16 Dec 2011, 9:15 AM
This is excellant. Haven't tested it myself but it looks like it is good.

jlyman
30 Jan 2012, 10:06 PM
Great job Luis, works like a charm.

ST PR4 rewrote the doRequest method a little bit, so I had to grab the new version from the sencha-*.js file and modify to make it go again. Code below.



doRequest: function(operation, callback, scope) {
var writer = this.getWriter(),
request = this.buildRequest(operation);

request.setConfig({
headers : this.getHeaders(),
timeout : this.getTimeout(),
method : this.getMethod(request),
callback : this.createRequestCallback(request, operation, callback, scope),
scope : this,
disableCaching: false // explicitly set it to false, ServerProxy handles caching
});

// We now always have the writer prepare the request
request = writer.write(request);
Ext.Cors.request(request.getCurrentConfig());

return request;
}

marceloverdijk
28 Mar 2012, 6:35 AM
In ST 2.0 I had to put the settings inside the config block to get it to work:



Ext.define('App.data.CrossOriginConnection', {
extend: 'Ext.data.Connection',
singleton: true,
config: {
autoAbort : false,
useDefaultXhrHeader: false
}
});


Would be nice if ST would provide CORS aware proxies in the future.

bnerd
1 Apr 2012, 6:56 AM
I'm still new to Sencha Touch.

Where exactly do I place this code? In what folder? and under what file name?

clifficious
14 May 2012, 1:36 AM
Hi,

I'm too relatively new to this topic and am totally confused how to implement CORS in ST2. Is there by now a convenient way to enable it?

Also, just like bnerd I'm not sure on how to use this example with ST2.0.1.

mitchellsimoens noted here (http://www.sencha.com/forum/showthread.php?197685-Post-request-in-jsonp&highlight=Cors) that ST supports CORS now. But I do not really now how.

Anyone willing to enlighten me? ;)

Thanks a tousand times!

luismerino
14 May 2012, 1:53 AM
Hi, I've been quite a while away from ST2, but the basic paradigm is (or it was) that the Ajax proxy won't use the CORS config unless X-Requested-With is not included in the headers, and for that you need to prevent it explicitly.

When dealing with cross domain requests, most server-side solutions or frameworks would filter requests with such header as "ajax" and you wouldn't want that filter to be applied.

Hope it helps.

btek
26 Jun 2012, 8:51 PM
Hi,

I am also confused by this.

Can someone please post a working example app that uses CORS to get data from a web service, and plug it into a data store.

Thanks,
Adam.

mitchellsimoens
27 Jun 2012, 4:31 AM
Simple to do:

Store:


new Ext.data.Store({
autoLoad : true,
fields : ['test'],
proxy : {
type : 'ajax',
url : 'http://test/data/php.php'
},
listeners : {
load : function(store, recs) {
console.log(recs);
}
}
});

php.php:


<?php

//CORS
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Headers: X-Requested-With');

//JSON
header('Content-Type: application/json');

$array = array(
array(
'test' => 'one'
),
array(
'test' => 'two'
)
);

echo json_encode($array);

?>

And now it will work!

btek
27 Jun 2012, 5:57 PM
We had these changes made to the server and finally it worked!

# add these lines after the htdocs directory section
<Directory "/usr/local/apache2/htdocs/ws">
Header set Access-Control-Allow-Origin "*"
Header set Access-Control-Allow-Methods "GET,POST"
Header set Access-Control-Allow-Headers "x-prototype-version,x-requested-with"
</Directory>

rgporter
28 Jun 2012, 6:07 PM
We had these changes made to the server and finally it worked!

# add these lines after the htdocs directory section
<Directory "/usr/local/apache2/htdocs/ws">
Header set Access-Control-Allow-Origin "*"
Header set Access-Control-Allow-Methods "GET,POST"
Header set Access-Control-Allow-Headers "x-prototype-version,x-requested-with"
</Directory>



I would be careful with using a wildcard (*) with CORS, this makes you vulnerable to XSS attacks. You should specify a site there, or if you need to have multiple sites, use HTTP_ORIGIN (webkit only) and compare it with a list of approved sites then insert that site into the Allow-Origin header.

clifficious
28 Jun 2012, 11:40 PM
But what if you have to allow access from mobile devices? They do not have a fixed IP address.

rgporter
29 Jun 2012, 7:22 AM
Hi Cliff,

CORS actually doesn't have anything to do with the IP of the end-user. It's used to allow (non-JSONP) ajax requests between two different web domains.

Normally an ajax request is between your site's javascript and your server on the same domain. But if, for some reason, you need ajax to between a site on a different domain (say, my-sencha-touch-app.com) and your site (say, my-website.com) you need to use CORS to give your app domain permission to make AJAX requests to your website domain. Otherwise errors come up in your Javascript console about XSS.

In this example, if my-website.com was using PHP, you'd want something like:


header("Access-Control-Allow-Origin: http://my-sencha-touch-app.com");

header("Access-Control-Allow-Credentials: true"); // if you're using a cookie from this website
header("Access-Control-Allow-Headers: x-requested-with");
header("Access-Control-Request-Method: GET,POST");



If you have multiple apps or have multiple domain names for your app, there isn't yet a way to specify multiple domains, though what you can do is use some PHP to check where the HTTP_ORIGIN of the request is and compare it to an approved list.

The vulnerability in specifying a wildcard is most pronounced when login is being done via CORS. Any third-party website could then act on behalf of the logged in user, for examples, see here - https://www.owasp.org/index.php/Cross-Site_Request_Forgery_(CSRF)

clifficious
2 Jul 2012, 12:29 AM
Hi rgporter,

thanks a lot for your post. I got confused with the IP-address and the domain name.
Now just to get it right. If I have a ST2 app with the domain com.test.myapp and pack it with PhoneGap for example. Then on the server side, I would only need to allow that domain to perform CORS request, right?

Once again thanks a lot. You really helped me understanding the principles.