Fixes #2994. Not finding a transport now fires the error callbacks and doesn't make...
[jquery.git] / src / ajax.js
index 645163a..5c4d469 100644 (file)
@@ -306,30 +306,35 @@ jQuery.extend({
                                // (match is used internally)
                                getResponseHeader: function( key , match ) {
 
-                                       if ( state !== 2 ) {
-                                               return null;
-                                       }
+                                       if ( state === 2 ) {
 
-                                       if ( responseHeaders === undefined ) {
+                                               if ( responseHeaders === undefined ) {
 
-                                               responseHeaders = {};
+                                                       responseHeaders = {};
 
-                                               if ( typeof responseHeadersString === "string" ) {
+                                                       if ( typeof responseHeadersString === "string" ) {
 
-                                                       while( ( match = rheaders.exec( responseHeadersString ) ) ) {
-                                                               responseHeaders[ match[ 1 ].toLowerCase() ] = match[ 2 ];
+                                                               while( ( match = rheaders.exec( responseHeadersString ) ) ) {
+                                                                       responseHeaders[ match[ 1 ].toLowerCase() ] = match[ 2 ];
+                                                               }
                                                        }
                                                }
+                                               match = responseHeaders[ key.toLowerCase() ];
+
+                                       } else {
+
+                                               match = null;
                                        }
-                                       return responseHeaders[ key.toLowerCase() ];
+
+                                       return match;
                                },
 
                                // Cancel the request
                                abort: function( statusText ) {
-                                       if ( transport && state !== 2 ) {
+                                       if ( transport ) {
                                                transport.abort( statusText || "abort" );
-                                               done( 0 , statusText );
                                        }
+                                       done( 0 , statusText );
                                        return this;
                                }
                        };
@@ -347,6 +352,10 @@ jQuery.extend({
                        // State is "done" now
                        state = 2;
 
+                       // Dereference transport for early garbage collection
+                       // (no matter how long the jXHR transport will be used
+                       transport = 0;
+
                        // Set readyState
                        jXHR.readyState = status ? 4 : 0;
 
@@ -599,84 +608,87 @@ jQuery.extend({
                        s.data = jQuery.param( s.data , s.traditional );
                }
 
-               // Get transport
-               transport = jQuery.ajaxPrefilter( s , options ).ajaxTransport( s );
+               // Apply prefilters
+               jQuery.ajaxPrefilter( s , options );
 
                // Watch for a new set of requests
                if ( s.global && jQuery.active++ === 0 ) {
                        jQuery.event.trigger( "ajaxStart" );
                }
 
-               // If no transport, we auto-abort
-               if ( ! transport ) {
-
-                       done( 0 , "transport not found" );
-                       jXHR = false;
+               // More options handling for requests with no content
+               if ( ! s.hasContent ) {
 
-               } else {
+                       // If data is available, append data to url
+                       if ( s.data ) {
+                               s.url += ( rquery.test( s.url ) ? "&" : "?" ) + s.data;
+                       }
 
-                       // More options handling for requests with no content
-                       if ( ! s.hasContent ) {
+                       // Add anti-cache in url if needed
+                       if ( s.cache === false ) {
 
-                               // If data is available, append data to url
-                               if ( s.data ) {
-                                       s.url += ( rquery.test( s.url ) ? "&" : "?" ) + s.data;
-                               }
+                               var ts = jQuery.now(),
+                                       // try replacing _= if it is there
+                                       ret = s.url.replace( rts , "$1_=" + ts );
 
-                               // Add anti-cache in url if needed
-                               if ( s.cache === false ) {
+                               // if nothing was replaced, add timestamp to the end
+                               s.url = ret + ( (ret == s.url ) ? ( rquery.test( s.url ) ? "&" : "?" ) + "_=" + ts : "");
+                       }
+               }
 
-                                       var ts = jQuery.now(),
-                                               // try replacing _= if it is there
-                                               ret = s.url.replace( rts , "$1_=" + ts );
+               // Set the correct header, if data is being sent
+               if ( s.data && s.hasContent && s.contentType !== false || options.contentType ) {
+                       requestHeaders[ "content-type" ] = s.contentType;
+               }
 
-                                       // if nothing was replaced, add timestamp to the end
-                                       s.url = ret + ( (ret == s.url ) ? ( rquery.test( s.url ) ? "&" : "?" ) + "_=" + ts : "");
-                               }
+               // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
+               if ( s.ifModified ) {
+                       if ( jQuery_lastModified[ s.url ] ) {
+                               requestHeaders[ "if-modified-since" ] = jQuery_lastModified[ s.url ];
                        }
-
-                       // Set the correct header, if data is being sent
-                       if ( s.data && s.hasContent && s.contentType !== false || options.contentType ) {
-                               requestHeaders[ "content-type" ] = s.contentType;
+                       if ( jQuery_etag[ s.url ] ) {
+                               requestHeaders[ "if-none-match" ] = jQuery_etag[ s.url ];
                        }
+               }
 
-                       // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
-                       if ( s.ifModified ) {
-                               if ( jQuery_lastModified[ s.url ] ) {
-                                       requestHeaders[ "if-modified-since" ] = jQuery_lastModified[ s.url ];
-                               }
-                               if ( jQuery_etag[ s.url ] ) {
-                                       requestHeaders[ "if-none-match" ] = jQuery_etag[ s.url ];
-                               }
-                       }
+               // Set the Accepts header for the server, depending on the dataType
+               requestHeaders.accept = s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[ 0 ] ] ?
+                       s.accepts[ s.dataTypes[ 0 ] ] + ( s.dataTypes[ 0 ] !== "*" ? ", */*; q=0.01" : "" ) :
+                       s.accepts[ "*" ];
+
+               // Check for headers option
+               for ( i in s.headers ) {
+                       requestHeaders[ i.toLowerCase() ] = s.headers[ i ];
+               }
 
-                       // Set the Accepts header for the server, depending on the dataType
-                       requestHeaders.accept = s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[ 0 ] ] ?
-                               s.accepts[ s.dataTypes[ 0 ] ] + ( s.dataTypes[ 0 ] !== "*" ? ", */*; q=0.01" : "" ) :
-                               s.accepts[ "*" ];
+               // Allow custom headers/mimetypes and early abort
+               if ( s.beforeSend && ( s.beforeSend.call( callbackContext , jXHR , s ) === false || state === 2 ) ) {
 
-                       // Check for headers option
-                       for ( i in s.headers ) {
-                               requestHeaders[ i.toLowerCase() ] = s.headers[ i ];
+                               // Abort if not done already
+                               done( 0 , "abort" );
+
+                               // Return false
+                               jXHR = false;
+
+               } else {
+
+                       // Install callbacks on deferreds
+                       for ( i in { success:1, error:1, complete:1 } ) {
+                               jXHR[ i ]( s[ i ] );
                        }
 
-                       // Allow custom headers/mimetypes and early abort
-                       if ( s.beforeSend && ( s.beforeSend.call( callbackContext , jXHR , s ) === false || state === 2 ) ) {
+                       // Get transport
+                       transport = jQuery.ajaxTransport( s );
 
-                                       // Abort if not done already
-                                       done( 0 , "abort" );
-                                       jXHR = false;
+                       // If no transport, we auto-abort
+                       if ( ! transport ) {
+
+                               done( 0 , "notransport" );
 
                        } else {
 
                                // Set state as sending
-                               state = 1;
-                               jXHR.readyState = 1;
-
-                               // Install callbacks on deferreds
-                               for ( i in { success:1, error:1, complete:1 } ) {
-                                       jXHR[ i ]( s[ i ] );
-                               }
+                               state = jXHR.readyState = 1;
 
                                // Send global event
                                if ( s.global ) {