Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

xdomain breaks mixpanel JS client library when loaded later in IE 8/IE 9 ("Access is Denied") #21

Closed
stevenyxu opened this issue Nov 6, 2013 · 12 comments

Comments

@stevenyxu
Copy link

From an implementation perspective, it may be an xhook issue, but it manifests in xdomain. In particular, the facade object that xhook's replaced XMLHttpRequest constructor returns includes the withCredentials property. This "breaks" mixpanel, which uses the presence of withCredentials (namely, something like 'withCredentials' in (new XMLHttpRequest)) to determine whether to use XHRs instead of image beacons.

The result is that mixpanel wrongly infers based on the presence of the withCredentials property that the user agent supports CORS XHRs, and the subsequent XHR to mixpanel breaks things ('Access is Denied' on XHR#open).

I'll whip up a working PoC later today. Just wanted to set up a placeholder issue with the report so I can link to something in my hack fix.

@jpillora
Copy link
Owner

jpillora commented Nov 7, 2013

Edit: I misunderstood the problem, see comment below and possible solution

So withCredentials is set for exactly this purpose, to trick the user agent into thinking that it supports CORS XHR, this is done in with the proviso that XDomain will transparently work. The Access is denied is caused by attempting CORS XHR on native XMLHttpRequest in IE, so XHook is not hooking for some reason or another. You mentioned: "when loaded later" so you're loading mixpanel later?

Will take a look if you can get a demo up 👍

@machard
Copy link

machard commented Jan 20, 2014

it happens here http://run.plnkr.co/NCxHjAwncn8WfbiS/ (tested with IE9)
In chrome this raise a warning "event.returnValue is deprecated. Please use the standard event.preventDefault() instead. "

@jpillora
Copy link
Owner

You've got your slave set to the wrong origin. The mixpanel script is using http://api.mixpanel.com, whereas your script is using http://app.tracktl.com. Since you have no slave set for the origin, XDomain sends the request through unmodified. It's working on chrome because it's using CORS. Also, it's not actually http, mixpanel is using the protocol of the page ("https:"==r.location.protocol?"https://":"http://").

The warning in chrome is caused by XDomain copying event objects, it will have no effect on your code. I'll make a special case for chrome in the next version.

@jpillora
Copy link
Owner

jpillora commented Feb 1, 2014

Hey @cairo140 I just released 0.6, give this a try again and report back :) I've implemented abort() and events. See http://jpillora.com/s3hook/ for it in action (S3 Account keys required). If it still doesn't work, do xdomain.debug = true and let me know what you see

@jhdavids8
Copy link

So, I see this too, and after reading this thread, I'm a little unclear on how to fix and/or if this is expected behavior. Here's the debug output:

LOG: xdomain (https://example.com): no slave matching: 'https://api.mixpanel.com' 
Error: Access is denied.
undefined 

In my example, I have a link that sends an event to Mixpanel when clicked. When I remove the event and click the link, everything works swimmingly, but with the event added in, things go crazy and my Angular page fails to load properly.

Please let me know what else you need from me!

@jpillora
Copy link
Owner

So my bad everyone. I thought mixpanel was something related to wordpress, where you have control of the server. Looked into the mixpanel script, it's using the same feature detect as jQuery, so by removing it, I'd be breaking jQuery cross-domain AJAX support. So until we find a better fix, I've added a switch to XHook. Just do: xhook.addWithCredentials = false; (defaults to true). This should fix mixpanel, though will break cross-domain AJAX with jQuery.

@jhdavids8
Copy link

Thanks! I'm using Angular for most my AJAX, although I do use jQuery via Typeahead. But I'll try to make this work.

FYI, just noticed Intercom (another client-side script embed) broke before this change. So I'm assuming this issue may exist across a lot of client-side scripts when embedded in a page using XDomain.

@jpillora
Copy link
Owner

So here's the general problem, jQuery is doing:

jQuery.support.cors = !!xhrSupported && ( "withCredentials" in xhrSupported );

If support.cors is true, it will attempt to use standard XHR for crossdomain.

However, in libraries like Mixpanel and Intercom (haven't seen the source yet though), they're using a similar check:

USE_XHR  = (window.XMLHttpRequest && 'withCredentials' in new XMLHttpRequest())

Also to determine whether they can use standard XHR for crossdomain. Since XHook adds withCredentials for jQuery, the problem is that it's also adding it for all other libraries. Normal browsers should see that there is no slave and fallback to CORS. However, Internet Explorer has no CORS and fails with Access Denied.

Question: Are you guys only finding breaks under IE?

Possible solution: Include these libraries that perform the withCredentials check before you include XHook (XDomain). This might cause the check to correctly fail under IE. Needs testing though.

Another possible solution: Insert this IE8/9 CORS polyfill for cases where a proxy.html cannot be installed and CORS is actually required.

@jhdavids8
Copy link

Hey Jaime,

I'm actually only using XDomain for IE9. I control my API and have implemented CORS server-side, but Angular doesn't play well with CORS in IE9, so I threw in XDomain for that case.

Including the libraries before XDomain doesn't appear to have an effect, at least in my test.

I'm hoping to stay away from the polyfill for the moment. XDomain is already a polyfill for me for my special IE9 case, don't want to add another to the mix :)

That said, I feel like there's a solution staring me in the face that I can't quite see yet. I'll sleep on it and let you know if anything comes to mind. Thanks for looking into this!

Cheers,
Jamie

@jpillora
Copy link
Owner

jpillora commented Mar 3, 2014

Hey Jamie,

So another thing you can do is:

//fix trackers
xhook.addWithCredentials = false;
//fix jquery cors
jQuery.support.cors = true;

This should allow mixpanel, intercom, angular and jquery all to work - tested briefly using the demo page, though please test yourself and report back :)

Cheers,
Jaime

@jhdavids8
Copy link

Yep, that seemed to do it. Thanks for the help!

@jpillora
Copy link
Owner

jpillora commented Mar 4, 2014

Cool, will close, though reopen if necessary

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants