diff --git a/src/ajax.js b/src/ajax.js index 89d60e1d..592f297f 100644 --- a/src/ajax.js +++ b/src/ajax.js @@ -7,15 +7,13 @@ var r20 = /%20/g, rheaders = /^(.*?):\s*(.*?)\r?$/mg, // IE leaves an \r character at EOL rinput = /^(?:color|date|datetime|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i, rnoContent = /^(?:GET|HEAD)$/, + rprotocol = /^\/\//, rquery = /\?/, rscript = /)<[^<]*)*<\/script>/gi, rselectTextarea = /^(?:select|textarea)/i, rspacesAjax = /\s+/, rts = /([?&])_=[^&]*/, - rurl = /^(\w+:)?\/\/([^\/?#:]+)(?::(\d+))?/, - - // Slice function - sliceFunc = Array.prototype.slice, + rurl = /^(\w+:)\/\/([^\/?#:]+)(?::(\d+))?/, // Keep a copy of the old load method _load = jQuery.fn.load, @@ -75,7 +73,7 @@ function addToPrefiltersOrTransports( structure ) { } //Base inspection function for prefilters and transports -function inspectPrefiltersOrTransports( structure, options, originalOptions, +function inspectPrefiltersOrTransports( structure, options, originalOptions, jXHR, dataType /* internal */, inspected /* internal */ ) { dataType = dataType || options.dataTypes[ 0 ]; @@ -99,7 +97,7 @@ function inspectPrefiltersOrTransports( structure, options, originalOptions, } else { options.dataTypes.unshift( selection ); selection = inspectPrefiltersOrTransports( - structure, options, originalOptions, selection, inspected ); + structure, options, originalOptions, jXHR, selection, inspected ); } } } @@ -107,7 +105,7 @@ function inspectPrefiltersOrTransports( structure, options, originalOptions, // we try the catchall dataType if not done already if ( ( executeOnly || !selection ) && !inspected[ "*" ] ) { selection = inspectPrefiltersOrTransports( - structure, options, originalOptions, "*", inspected ); + structure, options, originalOptions, jXHR, "*", inspected ); } // unnecessary when only executing (prefilters) // but it'll be ignored by the caller in that case @@ -400,8 +398,9 @@ jQuery.extend({ // Cancel the request abort: function( statusText ) { + statusText = statusText || "abort"; if ( transport ) { - transport.abort( statusText || "abort" ); + transport.abort( statusText ); } done( 0, statusText ); return this; @@ -438,7 +437,7 @@ jQuery.extend({ var isSuccess, success, - error = ( statusText = statusText || "error" ), + error, response = responses ? ajaxHandleResponses( s, jXHR, responses ) : undefined, lastModified, etag; @@ -476,6 +475,16 @@ jQuery.extend({ error = "" + e; } } + } else { + // We extract error from statusText + // then normalize statusText and status for non-aborts + error = statusText; + if( status ) { + statusText = "error"; + if ( status < 0 ) { + status = 0; + } + } } // Set data for the fake xhr object @@ -533,8 +542,9 @@ jQuery.extend({ }; // Remove hash character (#7531: and string promotion) + // Add protocol if not provided (#5866: IE7 issue with protocol-less urls) // We also use the url parameter if available - s.url = ( "" + ( url || s.url ) ).replace( rhash, "" ); + s.url = ( "" + ( url || s.url ) ).replace( rhash, "" ).replace( rprotocol, protocol + "//" ); // Extract dataTypes list s.dataTypes = jQuery.trim( s.dataType || "*" ).toLowerCase().split( rspacesAjax ); @@ -542,12 +552,10 @@ jQuery.extend({ // Determine if a cross-domain request is in order if ( !s.crossDomain ) { parts = rurl.exec( s.url.toLowerCase() ); - s.crossDomain = !!( - parts && - ( parts[ 1 ] && parts[ 1 ] != protocol || - parts[ 2 ] != loc.hostname || - ( parts[ 3 ] || ( ( parts[ 1 ] || protocol ) === "http:" ? 80 : 443 ) ) != - ( loc.port || ( protocol === "http:" ? 80 : 443 ) ) ) + s.crossDomain = !!( parts && + ( parts[ 1 ] != protocol || parts[ 2 ] != loc.hostname || + ( parts[ 3 ] || ( parts[ 1 ] === "http:" ? 80 : 443 ) ) != + ( loc.port || ( protocol === "http:" ? 80 : 443 ) ) ) ); } @@ -557,7 +565,7 @@ jQuery.extend({ } // Apply prefilters - inspectPrefiltersOrTransports( prefilters, s, options ); + inspectPrefiltersOrTransports( prefilters, s, options, jXHR ); // Uppercase the type s.type = s.type.toUpperCase(); @@ -630,11 +638,11 @@ jQuery.extend({ } // Get transport - transport = inspectPrefiltersOrTransports( transports, s, options ); + transport = inspectPrefiltersOrTransports( transports, s, options, jXHR ); // If no transport, we auto-abort if ( !transport ) { - done( 0, "notransport" ); + done( -1, "No Transport" ); } else { // Set state as sending state = jXHR.readyState = 1; @@ -653,9 +661,8 @@ jQuery.extend({ transport.send( requestHeaders, done ); } catch (e) { // Propagate exception as error if not done - if ( status === 1 ) { - done( 0, "error", "" + e ); - jXHR = false; + if ( status < 2 ) { + done( -1, "" + e ); // Simply rethrow otherwise } else { jQuery.error( e ); diff --git a/src/ajax/jsonp.js b/src/ajax/jsonp.js index f5742d99..16a4c2fd 100644 --- a/src/ajax/jsonp.js +++ b/src/ajax/jsonp.js @@ -1,7 +1,7 @@ (function( jQuery ) { var jsc = jQuery.now(), - jsre = /(\=)(?:\?|%3F)(&|$)|()(?:\?\?|%3F%3F)()/i; + jsre = /(\=)\?(&|$)|()\?\?()/i; // Default jsonp settings jQuery.ajaxSetup({ diff --git a/src/ajax/xhr.js b/src/ajax/xhr.js index 5629dcd6..b8206423 100644 --- a/src/ajax/xhr.js +++ b/src/ajax/xhr.js @@ -108,12 +108,9 @@ if ( jQuery.support.ajax ) { } catch( _ ) {} // Do send the request - try { - xhr.send( ( s.hasContent && s.data ) || null ); - } catch( e ) { - complete( 0, "error", "" + e ); - return; - } + // This may raise an exception which is actually + // handled in jQuery.ajax (so no try/catch here) + xhr.send( ( s.hasContent && s.data ) || null ); // Listener callback = function( _, isAbort ) { diff --git a/src/core.js b/src/core.js index 520db45e..43d46e9e 100644 --- a/src/core.js +++ b/src/core.js @@ -26,9 +26,6 @@ var jQuery = function( selector, context ) { trimLeft = /^\s+/, trimRight = /\s+$/, - // Check for non-word characters - rnonword = /\W/, - // Check for digits rdigit = /\d/, diff --git a/test/unit/ajax.js b/test/unit/ajax.js index b44f0773..2624b558 100644 --- a/test/unit/ajax.js +++ b/test/unit/ajax.js @@ -240,6 +240,47 @@ test("jQuery.ajax() - error callbacks", function() { }); }); +test("jQuery.ajax() - textStatus and errorThrown values", function() { + + var nb = 3; + + expect( 2 * nb ); + stop(); + + function startN() { + if ( !( --nb ) ) { + start(); + } + } + + jQuery.ajax({ + url: url("data/nonExistingURL"), + error: function( _ , textStatus , errorThrown ){ + strictEqual( textStatus, "error", "textStatus is 'error' for 404" ); + strictEqual( errorThrown, "Not Found", "errorThrown is 'Not Found' for 404"); + startN(); + } + }); + + jQuery.ajax({ + url: url("data/name.php?wait=5"), + error: function( _ , textStatus , errorThrown ){ + strictEqual( textStatus, "abort", "textStatus is 'abort' for abort" ); + strictEqual( errorThrown, "abort", "errorThrown is 'abort' for abort"); + startN(); + } + }).abort(); + + jQuery.ajax({ + url: url("data/name.php?wait=5"), + error: function( _ , textStatus , errorThrown ){ + strictEqual( textStatus, "mystatus", "textStatus is 'mystatus' for abort('mystatus')" ); + strictEqual( errorThrown, "mystatus", "errorThrown is 'mystatus' for abort('mystatus')"); + startN(); + } + }).abort( "mystatus" ); +}); + test("jQuery.ajax() - responseText on error", function() { expect( 1 ); @@ -374,6 +415,18 @@ test(".ajax() - contentType" , function() { }); +test(".ajax() - protocol-less urls", function() { + expect(1); + + jQuery.ajax({ + url: "//somedomain.com", + beforeSend: function( xhr, settings ) { + equals(settings.url, location.protocol + "//somedomain.com", "Make sure that the protocol is added."); + return false; + } + }); +}); + test(".ajax() - hash", function() { expect(3); @@ -1158,10 +1211,10 @@ test("jQuery.getScript(String, Function) - no callback", function() { jQuery.each( [ "Same Domain", "Cross Domain" ] , function( crossDomain , label ) { test("jQuery.ajax() - JSONP, " + label, function() { - expect(17); + expect(16); var count = 0; - function plus(){ if ( ++count == 17 ) start(); } + function plus(){ if ( ++count == 16 ) start(); } stop(); @@ -1265,23 +1318,6 @@ jQuery.each( [ "Same Domain", "Cross Domain" ] , function( crossDomain , label ) } }); - jQuery.ajax({ - url: "data/jsonp.php", - dataType: "jsonp", - crossDomain: crossDomain, - data: { - callback: "?" - }, - success: function(data){ - ok( data.data, "JSON results returned (GET, processed data callback)" ); - plus(); - }, - error: function(data){ - ok( false, "Ajax error JSON (GET, processed data callback)" ); - plus(); - } - }); - jQuery.ajax({ url: "data/jsonp.php", dataType: "jsonp",