• .NET Developer Tools DevTools

    UI controls for ASP.NET AJAX, MVC, WPF,
    Silverlight, Windows 8 and Windows Phone

  • Hybrid Mobile Development Icenium

    Cross-platform Mobile Development Tool
    with cloud-based architecture

  • HTML5 / JavaScript Development Kendo UI

    Everything you need to build sites and
    mobile apps with JavaScript and HTML5

  • Testing Tools TestStudio

    One easy tool for Functional, Performance,
    Load and Mobile software testing

  • Web Presence Platform Sitefinity CMS

    Everything for your online business - content
    management, ecommerce, emarketing

  • Agile Project Management TeamPulse

    Simple and intuitive project management
    and collaboration software

Contact us

We are here for you.
  • usa+1‒888‒365‒2779
  • uk+44‒20‒7291‒0580
  • bg+359‒2‒8099850
  • de+49‒89‒2441642‒70
  • au+61‒2‒8090‒1465
  • emailsales@telerik.com
Your account Access to your products, updates and support
Telerik Product Families
  • Your Account
    Your Account
    Log in
  • ABOUT US

    About Telerik

    • Company
    • Press Center
    • Customers
    • Community
    • Careers
    • Contacts
Kendo UI - The way of HTML5
Products ▼
Kendo UI Web Kendo UI Mobile Kendo UI DataViz Server Side Wrappers
Demos Purchase Download
Blogs Documentation
Support ▼
Premium Forums StackOverflow Forums
Resources ▼

Featured Resource

Kendo UI Dojo


Blogs Code Library Demos Documentation FAQ Testing
Premium Forums Roadmap User Voice Videos Webinars More Resources
Contact Us Search
 

Blogs

Using CORS with All (Modern) Browsers

Sunday, October 02, 2011 by Kendo UI Team Blog | Comments 24

CORS is cool. Cross-Origin Resource Sharing is a (slowly) emerging technology for the web that finally gives async web operations a way to directly grab resources from different domains. In fact, I've already talked about it a couple of times on the Kendo UI blogs here and here.

By default, the "same origin" security sandbox built-in to all browsers does not allow XHR (Ajax) calls across different domains. You can try, sure, but you'll get an error that looks something like this:

XMLHttpRequest cannot load [URL]. Origin [YOUR WEBSITE] is not allowed by Access-Control-Allow-Origin.

This is basically a message that says you can't use Ajax to load resources from a different domain. But what's that last part of the error?

Access-Control-Allow-Origin

CORS works by adding a special header to responses from a server to the client. If a response contains the Access-Control-Allow-Origin header, and if the browser supports CORS, then there is a chance you can load the resource directly with Ajax - no need for a proxy or JSONP hacks.

Why just a chance?

The header is capable of specifying which remote sites are allowed to load the cross-origin resources. For example, consider the following CORS header in a response from kendoui.com:

Access-Control-Allow-Origin: http://htmlui.com

With this configuration, only scripts that originate from http://htmlui.com are allowed to load resources from kendoui.com. Any other domain trying to use Ajax to load resources from kendoui.com will be given the standard security error message. In this way, site owners can limit which domains are allowed to load their resources with CORS.

Alternatively, site owners can grant wide-open access with the always ready to party asterisk:

Access-Control-Allow-Origin: *

Now, any site that wants to load a resource directly using Ajax can do so without getting the browser security error. It's really a thing of beauty, and hopefully more modern web APIs will start to support CORS. You can already find CORS in action with the GeoNames.org and Last.fm APIs (but not on Twitter or Facebook…boo…).

Server-side Setting

Clearly, CORS is powerful. It opens-up the tightly controlled browser security sandbox that is essential to the trusted fabric of the web. As you might expect, then, it's a decision that must be made by site owners (you can't use CORS with sites that don't allow it), and it's controlled by web server configuration.

Anyone can "CORS-enable" their site by simply having the web server add the necessary Access-Control-Allow-Origin header. In fact, there is an entire website dedicated to showing you how to add this header for a host of different web servers.

Dealing with Browsers

Ah, browsers. It's never simple with browsers.

As confirmed by the super-useful CanIUse.com, support for CORS is a bit of a mixed-bag. CORS is 100% ready to roll in:

  • Webkit browsers (Chrome, Safari, iOS, Android)
  • Gecko browsers (Firefox)
  • Trident browsers (Internet Explorer 8+)**

That's not bad. In fact, the only major browser completely missing in this list is Opera, which is unusual. Usually Opera is a good early adopter of popular web standards. Go figure. Fortunately, Opera claims it is "actively working" on adding CORS support, so soon Opera will "complete" the browser support story.

We'll talk about Opera more in a minute, but let's first address IE.

Internet Explorer and XDomainRequest

It's always something IE, and with CORS it's the XDomainRequest object. Rather than go the route of Webkit and Gecko, IE does not reuse the XMLHttpRequest object for CORS requests. Instead, it introduces a brand new object for cross-origin resource sharing called XDomainRequest.

So while your Ajax code for cross-domain calls looks 100% identical to "same-domain" calls in Chrome and Firefox, it will have to "fork" in Internet Explorer to use the new XDR object with CORS requests. A pain, but a solvable problem. (There are some other limits with XDR, but I'll leave that to you to research.)

With this small snippet, we can write code that works with CORS XHR, XDR, and when that doesn't work, some kind of fallback approach:

//Detect browser support for CORS
if ('withCredentials' in new XMLHttpRequest()) {
    /* supports cross-domain requests */
    document.write("CORS supported (XHR)");
}
else{
  if(typeof XDomainRequest !== "undefined"){
     //Use IE-specific "CORS" code with XDR
     document.write("CORS supported (XDR)");
  }else{
     //Time to retreat with a fallback or polyfill
     document.write("No CORS Support!");
  }
}

(You can try this code snippet live in different browsers to confirm it works.)

The XMLHttpRequest2 object, which includes required support for CORS, can be used to feature detect browser support for CORS. If the browser's XHR object has the XHR2 "withCredentials" property, we're in business. If not, step 2.

In step 2, we take one more attempt to use CORS by looking for IE's proprietary XDomainRequest object (which works with the same Access-Control-Allow-Origin headers, by the way). If the XDR object exists, we're in IE and we can write the necessary code to do XDR CORS.

Finally, if all else fails (Opera), we have to either provide an alternate experience or find a hack for CORS.

Handling Opera (or non-CORS browsers)

Assuming we reach the point where XHR2/CORS and XDR are not available, what's the next step? Abandon CORS? Yell at the user? As it turns out, you have a few choices. You can:

  1. Use a CORS polyfill
    There are a couple of rather "hacky" polyfills for CORS that rely on either A) Flash under the covers, or B) some voodoo HTML5. Either way, they work around the browser limits and try to give you some semblance of CORS support.
  2. Use JSONP
    Of course, if you can use JSONP, the argument can be made that you should just use JSONP instead of CORS for all browsers since it is still more universally supported. But let's say you're trying to "evolve" past JSONP except when you absolutely need. In that case, you can fallback to XHR and JSONP callbacks with Opera.
  3. Display an error message
    The most draconian of your choices, but given most browsers do support CORS, you could simply elect to tell the less than 2% (on average) users of Opera to use a different browser. Just depends how important Opera traffic is to your site.

The choice is yours, but clearly, you have some choice. Fortunately, we're talking about Opera and not IE, so the share of the browser market in question affected by this scenario is comparatively small.

Putting It All Together

In my Kendo UI Feed Reader demo, I use YQL to feed RSS XML directly to the browser. YQL supports CORS, so I elected to send XML to the browser instead of JSONP to highlight Kendo UI's data source support for XML.

Unfortunately, I overlooked IE and Opera in v1. To add support for these browsers, I modified the code to use XDR with IE and YQL JSONP with Opera.

Fixing IE with jQuery $.ajax transports

Fixing IE was actually very easy thanks to some code written by Derek Kastner. With jQuery 1.5+, you can create custom "transport" implementations to control the inner-workings of jQuery $.ajax. Derek has done just that with XDR.

His "iecors" project simply creates a jQuery transport that uses XDR in jQuery $.ajax requests when it's needed. All I have to do is add the small JS file to my page and everything starts working. The Kendo UI Data Source, which uses jQuery $.ajax under the covers, will now use XDR in IE.

So, I just add this to the bottom of my page, after jQuery but before any Kendo script references:

<!--[if lt IE 10]>
<!--iecors provides a jQuery ajax custom transport for IE8/9 XDR-->
<script src="scripts/jquery.iecors.js"></script>
<![endif]-->

Fixing Opera with More Code and JSONP

Unfortunately, fixing Opera is not as easy. And, ultimately, there is no clean way to do CORS in Opera. My choices were to either display a "browser not supported" message for Opera users OR bite the bullet and "fallback" to YQL JSONP when CORS is just not going to work.

I elected to use the later approach.

//**HACK for OPERA (and non-XHR2/XDR browsers)
//For lack of a reasonable Opera workaround to support CORS, fallback to use
//YQL support for JSONP when dealing with a browser than doesn't support 
//CORS XHR or XDR
if (!('withCredentials' in new XMLHttpRequest()) && !(typeof XDomainRequest !== "undefined")){
    _feedItemDS = new kendo.data.DataSource({
        transport:{
            read:{
                url: "#",
                dataType: "jsonp"
            },
            dialect: function (options) {
                var result = ["callback=?","format=json"],
                    data = options || {};
             
                return result.join("&");
            }
        },
        schema:{
            type:"json",
            data:"query.results.rss.channel.item",
        }
    });
//**END OPERA/Non-CORS HACK
}

Now, Opera (any other non-CORS browser) will use an alternate configuration of the Kendo UI data source pointed at a JSONP endpoint and expecting a JSON response. Pretty? No. Functional? Yes. Sometimes, that's what it takes to build software that runs in every major browser and platform.

Of course, you can see everything in action by visiting the updated Feed Reader demo. Full source and context are a right-click, view source away.

Bottom Line on CORS

Going forward, do you think the Kendo UI Data Source should help with some of these scenarios by automatically handling CORS in browsers like IE? Should something like "iecors" be built-in to Kendo UI if jQuery core continues to omit it? Would it be useful to see this as a core feature in the Kendo UI Data Source? Let us know what you think.

Ultimately, if you really need to support Opera, CORS is probably more work than it's worth right now. Just stick with JSONP. Meanwhile, supporting CORS in IE isn't hard as long as your use of CORS stays inside of XDR's limits, so IE, Firefox, Chrome, and Safari are safe bets.

Hopefully this post helps highlight the value of CORS and how it can be used with most modern browsers. As more app code moves to the client, the need for CORS will only grow. Start playing with it today and help push web standards to the next level.

About the Author
Todd Anglin is an avid HTML5, CSS3, and JavaScript advocate, and geek about all things web development. He is an active speaker and author, helping developers around the world learn and adopt HTML5. Todd works for Telerik as Chief Evangelist where his current technical focus is on Kendo UI. Todd is @toddanglin on Twitter.

24 Comments

  1. 1 Josh Peters 04 Oct 2011
    It's worth noting that if you blindly follow "Access-Control-Allow-Origin: *" you will open your users up to some very bad cross-domain hacks. The reason the same domain policy exists in the first place is to prevent accidental worms and/or user-generated content stealing credentials or other valuable data.

    Open this hole with extreme caution and only specify domains you absolutely trust.
  2. 2 Todd 04 Oct 2011
    @Josh- I think the user risk exposure is minimal.

    Can CORS be abused by malicious scripts and domains? Probably. I'm not sure it's any more threatening than JSONP or other vectors for communicating remotely from JS (like hidden IFRAMES), but a malicious script could use CORS.

    But I'm not sure I see how ACAO exposes new XSS security threats. Maybe you can link to a deeper explanation?

    Here is one article talking about some of the security considerations with CORS:
    http://code.google.com/p/html5security/wiki/CrossOriginRequestSecurity
  3. 3 Allan Hanson 07 Oct 2011
    In HTML5 why son't you use the embed tag like this to embed content across domain? Any html doc published in one domain can be embed in another. this is the simplicity and beauty of HTML5. HTML Objects can be embed in other HTML Objects. 
    <article class="column" id="two">
     
       <embed src="http://en.wikipedia.org/wiki/Asperger_syndrome"
                         width="990" height="732" />
     
               </article>


  4. 4 @pdeschen 07 Oct 2011
    @todd  It really depends on what your service is exposing in terms of data and methods. If your service accept DELETE, PUT, and POST with headers, which is also subject to the CORS, then returning "Access-Control-Allow-Origin: *"  as part of the preflight request opens up for malicious scripts and security breach.

    The mozilla developer site has a nice article about CORS

    http://hacks.mozilla.org/2009/07/cross-site-xmlhttprequest-with-cors/

  5. 5 Julian Aubourg 07 Oct 2011
    There is an XDR transport in ajaxHooks too: https://github.com/jaubourg/ajaxHooks/blob/master/src/ajax/xdr.js I just wish I has more time to work on this lib right now.

    You could also use an ajax transport for your jsonp through yql fallback (I experimented a bit with ajax "emulation" in yajax back in the days (https://github.com/jaubourg/yajax) still need more time to work on this too though ;)
  6. 6 Todd 07 Oct 2011
    @pdeschen- True. The security issues are for the server/site-owner, *not* the user.

    That said, even in your example of PUT/POST/DELETE, with CORS were only talking about allowing async JS to make these requests. If you expose those endpoints, nothing prevents server-side code from making those calls. I expect the security you'd apply to public methods like this would "flow through" to CORS.

    @Julian- Thanks for sharing the additional libraries! I think we all wish we had more time explore more code. :) 
  7. 7 Benjamin Lewis 07 Oct 2011
    That's all great but safari doesn't support cookies and IE doesn't and might never support them. Apparently safari has a bug that stops it from working. No cookie hacks for safari worked. I was so excited when I got CORS working... and so disappointed when I discovered safari and IE didn't support cookies. Well about safari anyway.
  8. 8 Niko 10 Oct 2011
    I was trying to get the response header out of the IE XDR object... to no avail. Anybody had success with that?
  9. 9 Todd 10 Oct 2011
    @Benjamin- Yes, there are some important limits with certain browsers. If you need cookies, CORS may not be a good universal choice. I'll try to do more research on this in the future.

    @Niko- Microsoft intentionally makes XDR response/request "anonymous." From MSDN: " To protect user data, cross-domain requests are anonymous, which means that servers cannot easily find out who is requesting data. As a result, you only want to request and respond with cross-domain data that is not sensitive or personally identifiable." 

    You might also try this advice for help debugging XDR: http://stackoverflow.com/questions/5250256/inconsistent-ajax-xdr-response-from-ie
  10. 10 Brad Dougherty 10 Oct 2011
    Just to note a gotcha, XDR does not support "withCredentials", so it won't pass cookies. We ran into the problem trying to do a request to a subdomain (vimeo.com to player.vimeo.com) with a cookie on the base domain.
  11. 11 Niko 10 Oct 2011
    @Todd: I just want to access the "Expires"-header of the response. In XHR it works like this:
    xhr.getResponseHeader('Expires')
  12. 12 Todd 11 Oct 2011
    @Niki- Sorry if I wasn't clear. There is no access to response headers (or cookies, for that matter) when using IE's XDR. Here's some good info on XDR in an excerpt from Professional JavaScript for Web Developers:
    http://books.google.com/books?id=KW9G9rdlStIC&pg=PT510&lpg=PT510&dq=xdr+response+headers&source=bl&ved=0CE0Q6AEwBQ#v=onepage&q=xdr%20response%20headers%23v%3Dsnippet&f=false
  13. 13 Dom 17 Oct 2011
    @Todd, based on your previous responses, I think you're confusing about the risks that "Access-Control-Allow-Origin: *" entails.

    Let's say user Alice has an account on site A where she stores her pictures; site A exposes an HTTP API based on credentials available through a cookie.
    If Site A declares its HTTP end points with "Access-Control-Allow-Origin: *", any Web site can then call any of these APIs with Alice's credentials if the site A cookie hasn't expired.
    The risk is probably as big for Alice (who e.g. risks losing pictures) as for Site A.

    (the difference with a server-side usage of these HTTP APIs is that it couldn't use another user's credentials without specific action from the user)

    While having the CORS header set for pages or data sets that are entirely public and don't rely on user authentication is probably fine, doing it for every page, every API or every dataset would be a very bad idea.
  14. 14 karl 17 Oct 2011
    "The choice is yours, but clearly, you have some choice. Fortunately, we're talking about Opera and not IE, so the share of the browser market in question affected by this scenario is comparatively small."

    In fact, not really. For all browsers when we start observing the browser  market shares by countries, we  notice differences from countries to countries. Even more so in the mobile world (that was not addressed in this article). statscounter gives a view on these differences. In some countries, the market shares will be low and in others high. 

    Another bias on stats is when the web site is blocking or giving very bad user experience for one type of browsers, or even one type of user agents. People with these browsers having a terrible experience do not go at all on this web site (and then do not appear in the stats) or if they are lucky and can switch or know how to switch will come on the site (and then do not appear in the stats).

  15. 15 ypcxx 01 Nov 2011
    http://my.opera.com/core/blog/2011/10/28/cors-goes-mainline

    "This week, Opera integrated support for [CORS] into the core mainline, meaning it can start to be adopted in product builds - so look for it soon in a snapshot near you."

    That's great, instead telling Opera users off, we can now tell them to upgrade to the latest Opera = problem solved! :)
  16. 16 Mark Jason 15 Nov 2011
    You can add the header through ASP.NET by adding the following line to your source pages: add the header through ASP.NET by adding the following line to your source pages:
    Response.AppendHeader("Access-Control-Allow-Origin", "*")









    http://www.printingray.com/folder-printing.html
  17. 17 Zain Shaikh 02 Dec 2011
    Very good article.

    I am making a cross domain ajax call which uses POST method  to send data to server, but I am unable to get this work in Firefox and IE. though Its working all right in chrome.

    I have added following response headers from server, but still get cross domain error in firefox and IE.

    Access-Control-Allow-Origin: *
    Access-Control-Allow-Headers: CONTENT-TYPE, Accept
    Access-Control-Allow-Methods: POST, GET, OPTIONS

    could you please provide sample code which is working in firefox and IE?

    Thanks.   
  18. 18 Vince 03 Mar 2012
    We just became Kendo customers, and I found this blog entry.  You asked the following questions:

    Going forward, do you think the Kendo UI Data Source should help with some of these scenarios by automatically handling CORS in browsers like IE? Should something like "iecors" be built-in to Kendo UI if jQuery core continues to omit it? Would it be useful to see this as a core feature in the Kendo UI Data Source?  

    And the answer is YES YES YES!!!!  (well, I'm not familiar with iecors, but YES, the Kendo UI Data Source should take care of these messy details and let me just use it).  Is this coming in the March 2012 update?  

    Thanks for asking!
    --Vince--
  19. 19 Anne-Marie Ireland 12 Mar 2012
    I'm accessing the updated Blog Feed demo in IE 9.0.8112.16421 (64-bit Edition) and the blogs "loading" icon just keeps spinning.  In Firefox it returns the blog posts almost immediately.  Am I missing something?
  20. 20 Mvorisek 04 Oct 2012
    Very useful! ;-)

    Mvorisek
  21. 21 Noel Rice 04 Oct 2012
    Great blog on an important topic.
  22. 22 Rakesh Singh 13 Feb 2013
    Hello all,

    Please Respond to this query,as it is similat to one discussed ablove. I am facing the above problem in IE8 but it's working fine with IE10.

    BR
    Rakesh Singh
  23. 23 Rakesh Singh 11 Feb 2013
    Hi All,

    I am using portal application Project and using JSP inside it to fetch and display some UWL counts. we are running this jsp using Portalapp.xml and getting the url after it run on browser.

    This url is to be used by the the sharepoint team using JS to use the data from jsp and integrate it with Sharepoint.
    But since, both Portal and Sharepoint Servers are Different, we are facing the Cross Domain Access Problem. Sharepoint Team is not able to Fetch the data from url using JS.

    I've tried to add header using given below add header code:
    <% response.addHeader("Access-control-allow-origin","*"); %>

    But i don't know this code is not working inside JSP.It's throwing runtime Exceptions.

    Also Tried Adding Document.domain="*"/some Domain name;
    but this is also not working.

    Please help on this as this is very urgent issue. Every help is  appreciated.
  24. 24 arramerpask 16 May 2013
    [url=http://www.carhire.com.au/com1.beats.asp?id=3226]lebron power beats by dre[/url] every single design takes a different approach, There are numerous products for him or her such as sound system, discussion or perhaps a skilled or perhaps speak to the audience provides it with a live soul of which enjoins crowd to take pleasure from the idea. Hip hop Rings plus examples can easily make a track highly entertaining. A good number of application include several thousand coils sorted in types just like drum, Generating bests have not been simpler and also less expensive, any Sennheiser PXC 250-ii noise rescheduling earphone is actually a unit that you're going to really like. you simply will not seem like that you are lugging extra put on an individual's get as well as experience almost any pain in the ears, This head set allows for anyone by way of presenting the quantity of call beats by dre studio black friday walmart and to remedy the idea you only take advantage of expression yes or no what you would like.Pantronics can be a large-scale boss during the ear phones producing or perhaps to deaths. Lots of [url=http://www.securityinsurancewy.com/com9.beats.asp?id=1952]power beats sale philippines[/url] from the songs starting to be listened to, the first part of your study need to be aimed towards studying other's feed-back and also critiques. Yet it's famous this human beingsear appear rang is usually between 20Hz0000Hz, your fewer outcome electric power from songs equipment. While using the ADAPTiQ system this examines the way ones room's proportions along with specifics have an impact on good, Your mass media games console will let you conceal and from view far more products and wires. There are numerous stars who may have reached along at the superb levels. and also accomplish particular things to do and have delighted. thicker beats by dr dre studio vs pro yahoo Several. The Dr Dre array is supplied in many different types, Your own most popular audio concerts is going to take trellis position with one of these leading edge and difficult speaker systems. properties involving worship together with retail industry companies to mention a set. GA200 earbuds

Comment

  1. Click to add

  2. Click to add

  3. Click to add

  4.    
     
    •  
    •  
    •  
    •  
    •  
    •  
    •  
    •  
    •  
    •  
    •  
    •  
     
      
       
Blogs feed
Categories

  • Tutorials (26)
  • Release (33)
  • Browsers (7)
  • Extensions (3)
  • Tip of the Week (10)
  • Videos (5)
  • Concepts and Theory (13)
  • Misc. (25)
  • Framework Constructs (6)
  • Mobile (6)
  • UI Widgets (5)
  • Blogs (1)
Archive
  • 2013 May (6)
  • 2013 April (10)
  • 2013 March (9)
  • 2013 February (12)
  • 2013 January (10)
  • 2012 December (9)
  • 2012 November (11)
  • 2012 October (6)
  • 2012 September (7)
  • 2012 August (8)
  • 2012 July (10)
  • 2012 June (8)
  • 2012 May (10)
  • 2012 April (7)
  • 2012 March (13)
  • 2012 February (10)
  • 2012 January (6)
  • 2011 December (10)
  • 2011 November (4)
  • 2011 October (6)
  • 2011 September (5)
  • 2011 August (9)
Home Web Mobile DataViz Server Wrappers Whitepapers Surveys Chrome Icenium Contact Us

Kendo UI framework is developed by Telerik - a leading provider of UI components for web, desktop and mobile applications. Trusted by over 100,000 customers worldwide for our devotion to quality and industry-best technical support, Telerik helps professionals maximize their productivity and "deliver more than expected" every day.

kendoui - powered by html5, css3 & jquery
get social
  • Twitter
  • Facebook
  • Google plus
  • RSS
Privacy Policy | Branding Guidelines
Powered by Sitefinity CMS

Copyright © 2011 - 2013 Telerik Inc. All rights reserved.