Skip to content
This repository

Add option to trigger xhr.withCredentials without http auth #2486

Merged
merged 4 commits into from 14 days ago

5 participants

Craig Campbell Derek Buitenhuis Nathan Reed Sergio Crisostomo Olmo Maldonado
Craig Campbell

Firefox sends the username for auth even though a password was not supplied
which causes Firefox to abort before sending a preflight request for Cross-Origin
requests.

This pull request adds a withCredentials request option that allows you to set xhr.withCredentials without sending http authentication.

See http://stackoverflow.com/questions/11255173/firefox-wont-send-cross-origin-resource-sharing-pre-flight

Derek Buitenhuis

Ping. It's been three months without so much as a reply.

Nathan Reed

Its sad this hasn't been merged in. Such a small changed :/

If you need to support CORS and don't want to change the source, you can easily create a new class that supports withCredentials like so:

Request.CORS = new Class({
    Extends: Request.JSON,

    initialize: function(options) {
        this.parent(options);

        if(options && options.withCredentials === true && this.xhr && 'withCredentials' in this.xhr) {
            this.xhr.withCredentials = true;
        }
    }
});
Sergio Crisostomo
Collaborator

LGTM.

@arian @ibolmo Can I merge this with a docs update on the options with:

withCredentials - (boolean: defaults to false) allows you to set xhr.withCredentials without sending http authentication.

Source/Request/Request.js
... ... @@ -197,7 +198,7 @@ var Request = this.Request = new Class({
197 198 }
198 199
199 200 xhr.open(method.toUpperCase(), url, this.options.async, this.options.user, this.options.password);
200   - if (this.options.user && 'withCredentials' in xhr) xhr.withCredentials = true;
  201 + if ((this.options.user || this.options.withCredentials) && 'withCredentials' in xhr) xhr.withCredentials = true;
3
Olmo Maldonado Owner
ibolmo added a note

Why not just:

if (this.options.user && this.options.password && 'withCredentials' in xhr) ...
Craig Campbell
ccampbell added a note

@ibolmo I think you are missing the point of this pull request. xhr.withCredentials does not require http authentication (as the current Mootools code suggests). You should be able to specify this flag without providing a username or password.

From the spec

The term user credentials for the purposes of this specification means cookies, HTTP authentication, and client-side SSL certificates. Specifically it does not refer to proxy authentication or the Origin header.

Olmo Maldonado Owner
ibolmo added a note
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Olmo Maldonado
Owner
ibolmo commented

After reading https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest#open()

Looks like we should deprecate the if (this.options.user and just have a withCredentials option. Could you modify your PR so that it reads:

 if ((/*<1.4compat>*/this.options.user || /*</1.4compat>*/this.options.withCredentials) && 'withCredentials' in xhr) xhr.withCredentials = true;

We'll also need a spec to ensure that:

  1. withCredentials is set for 1.4 compliance for this.options.user usage
  2. withCredentials is not set for 1.5 for this.options.user usage
  3. withCredentials is set for this.options.withCredentials is true
Craig Campbell

@ibolmo should be good to go

Olmo Maldonado
Owner
ibolmo commented

Awesome. Just waiting on Travis CI, but afterwards will merge.

Olmo Maldonado
Owner
ibolmo commented

Ahh, and just nit picking but could you add a note in the Request.md documentation?

Craig Campbell

Okay all good!

Sergio Crisostomo
Collaborator

@ccampbell awesome work indeed.
Wish we would have such complete PRs more often.
Thank you!

Olmo Maldonado ibolmo merged commit ccc36c2 into from
Olmo Maldonado ibolmo closed this
Sergio Crisostomo SergioCrisostomo commented on the diff
Specs/Request/Request.js
((22 lines not shown))
138 156
  157 + var dit = /*<1.4compat>*/xit || /*</1.4compat>*/it; // don't run unless no compat
  158 + dit('should not set xhr.withCredentials flag in 1.5 for this.options.user', function(){
  159 + var request = new Request({
  160 + url: '/something/or/other',
  161 + user: 'someone'
  162 + }).send();
  163 +
  164 + expect(request.xhr.withCredentials).toBe(false);
5
Sergio Crisostomo Collaborator

@ibolmo this is failing in some browsers with Expected undefined to be false.

Can we cast to boolean and use expect(!!request.xhr.withCredentials).toBe(false); ?

Craig Campbell
ccampbell added a note

Ah, sorry, I was actually thinking about that, but all the tests passed in the build (from using the fake XHR object I suspect)

Craig Campbell
ccampbell added a note

Could also wrap the expect in

if (request.xhr.hasOwnProperty('withCredentials')) { ...
Sergio Crisostomo Collaborator

@ccampbell we have encrypted user/pass to sauce labs testing. That means pull requests are only tested against PhantomJS on Travis. We should maybe change that so that pull requests actually get tested in browsers and not only after merge.

Anyway, this is a detail, I am really happy you proposed this fix.

Sergio Crisostomo Collaborator

@ccampbell Olmo just fixed it with .toBeFalsy()
Thanks again, cheers.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
This page is out of date. Refresh to see the latest.
3  Docs/Request/Request.md
Source Rendered
@@ -35,8 +35,9 @@ An XMLHttpRequest Wrapper.
35 35 * isSuccess - (*function*) Overrides the built-in isSuccess function.
36 36 * evalScripts - (*boolean*: defaults to *false*) If set to true, `script` tags inside the response will be evaluated.
37 37 * evalResponse - (*boolean*: defaults to *false*) If set to true, the entire response will be evaluated. Responses with javascript content-type will be evaluated automatically.
38   -* user - (*string*: defaults to *null*) When username is set the Request will open with credentials and try to authenticate.
  38 +* user - (*string*: defaults to *null*) The username to use for http basic authentication.
39 39 * password - (*string*: defaults to *null*) You can use this option together with the `user` option to set authentication credentials when necessary. Note that the password will be passed as plain text and is therefore readable by anyone through the source code. It is therefore encouraged to use this option carefully
  40 +* withCredentials - (*boolean*: defaults to *false*) If set to true, xhr.withCredentials will be set to true allowing cookies/auth to be passed for cross origin requests
40 41
41 42 ### Events:
42 43
5 Source/Request/Request.js
@@ -34,7 +34,8 @@ var Request = this.Request = new Class({
34 34 onException: function(headerName, value){},
35 35 onTimeout: function(){},
36 36 user: '',
37   - password: '',*/
  37 + password: '',
  38 + withCredentials: false,*/
38 39 url: '',
39 40 data: '',
40 41 headers: {
@@ -197,7 +198,7 @@ var Request = this.Request = new Class({
197 198 }
198 199
199 200 xhr.open(method.toUpperCase(), url, this.options.async, this.options.user, this.options.password);
200   - if (this.options.user && 'withCredentials' in xhr) xhr.withCredentials = true;
  201 + if ((/*<1.4compat>*/this.options.user || /*</1.4compat>*/this.options.withCredentials) && 'withCredentials' in xhr) xhr.withCredentials = true;
201 202
202 203 xhr.onreadystatechange = this.onStateChange.bind(this);
203 204
36 Specs/Request/Request.js
@@ -135,5 +135,41 @@ describe('Request', function(){
135 135
136 136 });
137 137
  138 + it('should not set xhr.withCredentials flag by default', function(){
  139 + var request = new Request({
  140 + url: '/something/or/other'
  141 + }).send();
  142 +
  143 + expect(request.xhr.withCredentials).toBe(false);
  144 + });
  145 +
  146 + /*<1.4compat>*/
  147 + it('should set xhr.withCredentials flag in 1.4 for this.options.user', function(){
  148 + var request = new Request({
  149 + url: '/something/or/other',
  150 + user: 'someone'
  151 + }).send();
  152 +
  153 + expect(request.xhr.withCredentials).toBe(true);
  154 + });
  155 + /*</1.4compat>*/
138 156
  157 + var dit = /*<1.4compat>*/xit || /*</1.4compat>*/it; // don't run unless no compat
  158 + dit('should not set xhr.withCredentials flag in 1.5 for this.options.user', function(){
  159 + var request = new Request({
  160 + url: '/something/or/other',
  161 + user: 'someone'
  162 + }).send();
  163 +
  164 + expect(request.xhr.withCredentials).toBe(false);
  165 + });
  166 +
  167 + dit('should set xhr.withCredentials flag if options.withCredentials is set', function(){
  168 + var request = new Request({
  169 + url: '/something/or/other',
  170 + withCredentials: true
  171 + }).send();
  172 +
  173 + expect(request.xhr.withCredentials).toBe(true);
  174 + });
139 175 });

Tip: You can add notes to lines in a file. Hover to the left of a line to make a note

Something went wrong with that request. Please try again.