From b091fdbafac33123cba329e6bb48b9281323ca38 Mon Sep 17 00:00:00 2001 From: Ben Toews Date: Sat, 22 Nov 2014 18:29:13 -0700 Subject: [PATCH] Ajax: use anchor tag for parsing urls Fixes gh-1875 Closes gh-1880 --- src/ajax.js | 45 ++++++++++++++++++++++++++------------------- test/unit/ajax.js | 6 +++++- 2 files changed, 31 insertions(+), 20 deletions(-) diff --git a/src/ajax.js b/src/ajax.js index dad2f82825..9765e95d61 100644 --- a/src/ajax.js +++ b/src/ajax.js @@ -17,7 +17,6 @@ var rlocalProtocol = /^(?:about|app|app-storage|.+-extension|file|res|widget):$/, rnoContent = /^(?:GET|HEAD)$/, rprotocol = /^\/\//, - rurl = /^([\w.+-]+:)(?:\/\/(?:[^\/?#]*@|)([^\/?#:]*)(?::(\d+)|)|)/, /* Prefilters * 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example) @@ -40,11 +39,9 @@ var // Avoid comment-prolog char sequence (#10098); must appease lint and evade compression allTypes = "*/".concat( "*" ), - // Document location - ajaxLocation = location.href, - - // Segment location into parts - ajaxLocParts = rurl.exec( ajaxLocation.toLowerCase() ) || []; + // Anchor tag for parsing the document origin + originAnchor = document.createElement( "a" ); + originAnchor.href = location.href; // Base "constructor" for jQuery.ajaxPrefilter and jQuery.ajaxTransport function addToPrefiltersOrTransports( structure ) { @@ -288,9 +285,9 @@ jQuery.extend({ etag: {}, ajaxSettings: { - url: ajaxLocation, + url: location.href, type: "GET", - isLocal: rlocalProtocol.test( ajaxLocParts[ 1 ] ), + isLocal: rlocalProtocol.test( location.protocol ), global: true, processData: true, async: true, @@ -390,8 +387,8 @@ jQuery.extend({ responseHeaders, // timeout handle timeoutTimer, - // Cross-domain detection vars - parts, + // Url cleanup var + urlAnchor, // To know if global events are to be dispatched fireGlobals, // Loop variable @@ -496,8 +493,8 @@ jQuery.extend({ // Add protocol if not provided (prefilters might expect it) // Handle falsy url in the settings object (#10093: consistency with old signature) // We also use the url parameter if available - s.url = ( ( url || s.url || ajaxLocation ) + "" ).replace( rhash, "" ) - .replace( rprotocol, ajaxLocParts[ 1 ] + "//" ); + s.url = ( ( url || s.url || location.href ) + "" ).replace( rhash, "" ) + .replace( rprotocol, location.protocol + "//" ); // Alias method option to type as per ticket #12004 s.type = options.method || options.type || s.method || s.type; @@ -505,14 +502,24 @@ jQuery.extend({ // Extract dataTypes list s.dataTypes = jQuery.trim( s.dataType || "*" ).toLowerCase().match( rnotwhite ) || [ "" ]; - // A cross-domain request is in order when we have a protocol:host:port mismatch + // A cross-domain request is in order when the origin doesn't match the current origin. if ( s.crossDomain == null ) { - parts = rurl.exec( s.url.toLowerCase() ); - s.crossDomain = !!( parts && - ( parts[ 1 ] !== ajaxLocParts[ 1 ] || parts[ 2 ] !== ajaxLocParts[ 2 ] || - ( parts[ 3 ] || ( parts[ 1 ] === "http:" ? "80" : "443" ) ) !== - ( ajaxLocParts[ 3 ] || ( ajaxLocParts[ 1 ] === "http:" ? "80" : "443" ) ) ) - ); + urlAnchor = document.createElement( "a" ); + + // Support: IE8-11+ + // IE throws exception if url is malformed, e.g. http://example.com:80x/ + try { + urlAnchor.href = s.url; + // Support: IE8-11+ + // Anchor's host property isn't correctly set when s.url is relative + urlAnchor.href = urlAnchor.href; + s.crossDomain = originAnchor.protocol + "//" + originAnchor.host !== + urlAnchor.protocol + "//" + urlAnchor.host; + } catch ( e ) { + // If there is an error parsing the URL, assume it is crossDomain, + // it can be rejected by the transport if it is invalid + s.crossDomain = true; + } } // Convert data if not already a string diff --git a/test/unit/ajax.js b/test/unit/ajax.js index 6f3bacebe2..468d384598 100644 --- a/test/unit/ajax.js +++ b/test/unit/ajax.js @@ -301,7 +301,7 @@ module( "ajax", { } ]); - ajaxTest( "jQuery.ajax() - cross-domain detection", 7, function() { + ajaxTest( "jQuery.ajax() - cross-domain detection", 8, function() { function request( url, title, crossDomainOrOptions ) { return jQuery.extend( { dataType: "jsonp", @@ -351,6 +351,10 @@ module( "ajax", { { crossDomain: true } + ), + request( + " http://otherdomain.com", + "Cross-domain url with leading space is detected as cross-domain" ) ]; });