Fix #11586. Ajax DELETE ain't got no body, so data goes to its URL.
[jquery.git] / src / ajax.js
blob04b8a2536a80dce555996bd02ba2752f54a77a29
1 var // Document location
2         ajaxLocation,
3         // Document location segments
4         ajaxLocParts,
6         rhash = /#.*$/,
7         rheaders = /^(.*?):[ \t]*([^\r\n]*)\r?$/mg, // IE leaves an \r character at EOL
8         // #7653, #8125, #8152: local protocol detection
9         rlocalProtocol = /^(?:about|app|app\-storage|.+\-extension|file|res|widget):$/,
10         rnoContent = /^(?:GET|HEAD|DELETE)$/,
11         rprotocol = /^\/\//,
12         rquery = /\?/,
13         rscript = /<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi,
14         rts = /([?&])_=[^&]*/,
15         rurl = /^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+)|)|)/,
17         // Keep a copy of the old load method
18         _load = jQuery.fn.load,
20         /* Prefilters
21          * 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example)
22          * 2) These are called:
23          *    - BEFORE asking for a transport
24          *    - AFTER param serialization (s.data is a string if s.processData is true)
25          * 3) key is the dataType
26          * 4) the catchall symbol "*" can be used
27          * 5) execution will start with transport dataType and THEN continue down to "*" if needed
28          */
29         prefilters = {},
31         /* Transports bindings
32          * 1) key is the dataType
33          * 2) the catchall symbol "*" can be used
34          * 3) selection will start with transport dataType and THEN go to "*" if needed
35          */
36         transports = {},
38         // Avoid comment-prolog char sequence (#10098); must appease lint and evade compression
39         allTypes = ["*/"] + ["*"];
41 // #8138, IE may throw an exception when accessing
42 // a field from window.location if document.domain has been set
43 try {
44         ajaxLocation = location.href;
45 } catch( e ) {
46         // Use the href attribute of an A element
47         // since IE will modify it given document.location
48         ajaxLocation = document.createElement( "a" );
49         ajaxLocation.href = "";
50         ajaxLocation = ajaxLocation.href;
53 // Segment location into parts
54 ajaxLocParts = rurl.exec( ajaxLocation.toLowerCase() ) || [];
56 // Base "constructor" for jQuery.ajaxPrefilter and jQuery.ajaxTransport
57 function addToPrefiltersOrTransports( structure ) {
59         // dataTypeExpression is optional and defaults to "*"
60         return function( dataTypeExpression, func ) {
62                 if ( typeof dataTypeExpression !== "string" ) {
63                         func = dataTypeExpression;
64                         dataTypeExpression = "*";
65                 }
67                 var dataType, list, placeBefore,
68                         dataTypes = dataTypeExpression.toLowerCase().split( core_rspace ),
69                         i = 0,
70                         length = dataTypes.length;
72                 if ( jQuery.isFunction( func ) ) {
73                         // For each dataType in the dataTypeExpression
74                         for ( ; i < length; i++ ) {
75                                 dataType = dataTypes[ i ];
76                                 // We control if we're asked to add before
77                                 // any existing element
78                                 placeBefore = /^\+/.test( dataType );
79                                 if ( placeBefore ) {
80                                         dataType = dataType.substr( 1 ) || "*";
81                                 }
82                                 list = structure[ dataType ] = structure[ dataType ] || [];
83                                 // then we add to the structure accordingly
84                                 list[ placeBefore ? "unshift" : "push" ]( func );
85                         }
86                 }
87         };
90 // Base inspection function for prefilters and transports
91 function inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR,
92                 dataType /* internal */, inspected /* internal */ ) {
94         dataType = dataType || options.dataTypes[ 0 ];
95         inspected = inspected || {};
97         inspected[ dataType ] = true;
99         var selection,
100                 list = structure[ dataType ],
101                 i = 0,
102                 length = list ? list.length : 0,
103                 executeOnly = ( structure === prefilters );
105         for ( ; i < length && ( executeOnly || !selection ); i++ ) {
106                 selection = list[ i ]( options, originalOptions, jqXHR );
107                 // If we got redirected to another dataType
108                 // we try there if executing only and not done already
109                 if ( typeof selection === "string" ) {
110                         if ( !executeOnly || inspected[ selection ] ) {
111                                 selection = undefined;
112                         } else {
113                                 options.dataTypes.unshift( selection );
114                                 selection = inspectPrefiltersOrTransports(
115                                                 structure, options, originalOptions, jqXHR, selection, inspected );
116                         }
117                 }
118         }
119         // If we're only executing or nothing was selected
120         // we try the catchall dataType if not done already
121         if ( ( executeOnly || !selection ) && !inspected[ "*" ] ) {
122                 selection = inspectPrefiltersOrTransports(
123                                 structure, options, originalOptions, jqXHR, "*", inspected );
124         }
125         // unnecessary when only executing (prefilters)
126         // but it'll be ignored by the caller in that case
127         return selection;
130 // A special extend for ajax options
131 // that takes "flat" options (not to be deep extended)
132 // Fixes #9887
133 function ajaxExtend( target, src ) {
134         var key, deep,
135                 flatOptions = jQuery.ajaxSettings.flatOptions || {};
136         for ( key in src ) {
137                 if ( src[ key ] !== undefined ) {
138                         ( flatOptions[ key ] ? target : ( deep || ( deep = {} ) ) )[ key ] = src[ key ];
139                 }
140         }
141         if ( deep ) {
142                 jQuery.extend( true, target, deep );
143         }
146 jQuery.fn.load = function( url, params, callback ) {
147         if ( typeof url !== "string" && _load ) {
148                 return _load.apply( this, arguments );
149         }
151         // Don't do a request if no elements are being requested
152         if ( !this.length ) {
153                 return this;
154         }
156         var selector, type, response,
157                 self = this,
158                 off = url.indexOf(" ");
160         if ( off >= 0 ) {
161                 selector = url.slice( off, url.length );
162                 url = url.slice( 0, off );
163         }
165         // If it's a function
166         if ( jQuery.isFunction( params ) ) {
168                 // We assume that it's the callback
169                 callback = params;
170                 params = undefined;
172         // Otherwise, build a param string
173         } else if ( params && typeof params === "object" ) {
174                 type = "POST";
175         }
177         // Request the remote document
178         jQuery.ajax({
179                 url: url,
181                 // if "type" variable is undefined, then "GET" method will be used
182                 type: type,
183                 dataType: "html",
184                 data: params,
185                 complete: function( jqXHR, status ) {
186                         if ( callback ) {
187                                 self.each( callback, response || [ jqXHR.responseText, status, jqXHR ] );
188                         }
189                 }
190         }).done(function( responseText ) {
192                 // Save response for use in complete callback
193                 response = arguments;
195                 // See if a selector was specified
196                 self.html( selector ?
198                         // Create a dummy div to hold the results
199                         jQuery("<div>")
201                                 // inject the contents of the document in, removing the scripts
202                                 // to avoid any 'Permission Denied' errors in IE
203                                 .append( responseText.replace( rscript, "" ) )
205                                 // Locate the specified elements
206                                 .find( selector ) :
208                         // If not, just inject the full result
209                         responseText );
211         });
213         return this;
216 // Attach a bunch of functions for handling common AJAX events
217 jQuery.each( "ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split( " " ), function( i, o ){
218         jQuery.fn[ o ] = function( f ){
219                 return this.on( o, f );
220         };
223 jQuery.each( [ "get", "post" ], function( i, method ) {
224         jQuery[ method ] = function( url, data, callback, type ) {
225                 // shift arguments if data argument was omitted
226                 if ( jQuery.isFunction( data ) ) {
227                         type = type || callback;
228                         callback = data;
229                         data = undefined;
230                 }
232                 return jQuery.ajax({
233                         type: method,
234                         url: url,
235                         data: data,
236                         success: callback,
237                         dataType: type
238                 });
239         };
242 jQuery.extend({
244         getScript: function( url, callback ) {
245                 return jQuery.get( url, undefined, callback, "script" );
246         },
248         getJSON: function( url, data, callback ) {
249                 return jQuery.get( url, data, callback, "json" );
250         },
252         // Creates a full fledged settings object into target
253         // with both ajaxSettings and settings fields.
254         // If target is omitted, writes into ajaxSettings.
255         ajaxSetup: function( target, settings ) {
256                 if ( settings ) {
257                         // Building a settings object
258                         ajaxExtend( target, jQuery.ajaxSettings );
259                 } else {
260                         // Extending ajaxSettings
261                         settings = target;
262                         target = jQuery.ajaxSettings;
263                 }
264                 ajaxExtend( target, settings );
265                 return target;
266         },
268         ajaxSettings: {
269                 url: ajaxLocation,
270                 isLocal: rlocalProtocol.test( ajaxLocParts[ 1 ] ),
271                 global: true,
272                 type: "GET",
273                 contentType: "application/x-www-form-urlencoded; charset=UTF-8",
274                 processData: true,
275                 async: true,
276                 /*
277                 timeout: 0,
278                 data: null,
279                 dataType: null,
280                 username: null,
281                 password: null,
282                 cache: null,
283                 throws: false,
284                 traditional: false,
285                 headers: {},
286                 */
288                 accepts: {
289                         xml: "application/xml, text/xml",
290                         html: "text/html",
291                         text: "text/plain",
292                         json: "application/json, text/javascript",
293                         "*": allTypes
294                 },
296                 contents: {
297                         xml: /xml/,
298                         html: /html/,
299                         json: /json/
300                 },
302                 responseFields: {
303                         xml: "responseXML",
304                         text: "responseText"
305                 },
307                 // List of data converters
308                 // 1) key format is "source_type destination_type" (a single space in-between)
309                 // 2) the catchall symbol "*" can be used for source_type
310                 converters: {
312                         // Convert anything to text
313                         "* text": window.String,
315                         // Text to html (true = no transformation)
316                         "text html": true,
318                         // Evaluate text as a json expression
319                         "text json": jQuery.parseJSON,
321                         // Parse text as xml
322                         "text xml": jQuery.parseXML
323                 },
325                 // For options that shouldn't be deep extended:
326                 // you can add your own custom options here if
327                 // and when you create one that shouldn't be
328                 // deep extended (see ajaxExtend)
329                 flatOptions: {
330                         context: true,
331                         url: true
332                 }
333         },
335         ajaxPrefilter: addToPrefiltersOrTransports( prefilters ),
336         ajaxTransport: addToPrefiltersOrTransports( transports ),
338         // Main method
339         ajax: function( url, options ) {
341                 // If url is an object, simulate pre-1.5 signature
342                 if ( typeof url === "object" ) {
343                         options = url;
344                         url = undefined;
345                 }
347                 // Force options to be an object
348                 options = options || {};
350                 var // ifModified key
351                         ifModifiedKey,
352                         // Response headers
353                         responseHeadersString,
354                         responseHeaders,
355                         // transport
356                         transport,
357                         // timeout handle
358                         timeoutTimer,
359                         // Cross-domain detection vars
360                         parts,
361                         // To know if global events are to be dispatched
362                         fireGlobals,
363                         // Loop variable
364                         i,
365                         // Create the final options object
366                         s = jQuery.ajaxSetup( {}, options ),
367                         // Callbacks context
368                         callbackContext = s.context || s,
369                         // Context for global events
370                         // It's the callbackContext if one was provided in the options
371                         // and if it's a DOM node or a jQuery collection
372                         globalEventContext = callbackContext !== s &&
373                                 ( callbackContext.nodeType || callbackContext instanceof jQuery ) ?
374                                                 jQuery( callbackContext ) : jQuery.event,
375                         // Deferreds
376                         deferred = jQuery.Deferred(),
377                         completeDeferred = jQuery.Callbacks( "once memory" ),
378                         // Status-dependent callbacks
379                         statusCode = s.statusCode || {},
380                         // Headers (they are sent all at once)
381                         requestHeaders = {},
382                         requestHeadersNames = {},
383                         // The jqXHR state
384                         state = 0,
385                         // Default abort message
386                         strAbort = "canceled",
387                         // Fake xhr
388                         jqXHR = {
390                                 readyState: 0,
392                                 // Caches the header
393                                 setRequestHeader: function( name, value ) {
394                                         if ( !state ) {
395                                                 var lname = name.toLowerCase();
396                                                 name = requestHeadersNames[ lname ] = requestHeadersNames[ lname ] || name;
397                                                 requestHeaders[ name ] = value;
398                                         }
399                                         return this;
400                                 },
402                                 // Raw string
403                                 getAllResponseHeaders: function() {
404                                         return state === 2 ? responseHeadersString : null;
405                                 },
407                                 // Builds headers hashtable if needed
408                                 getResponseHeader: function( key ) {
409                                         var match;
410                                         if ( state === 2 ) {
411                                                 if ( !responseHeaders ) {
412                                                         responseHeaders = {};
413                                                         while( ( match = rheaders.exec( responseHeadersString ) ) ) {
414                                                                 responseHeaders[ match[1].toLowerCase() ] = match[ 2 ];
415                                                         }
416                                                 }
417                                                 match = responseHeaders[ key.toLowerCase() ];
418                                         }
419                                         return match === undefined ? null : match;
420                                 },
422                                 // Overrides response content-type header
423                                 overrideMimeType: function( type ) {
424                                         if ( !state ) {
425                                                 s.mimeType = type;
426                                         }
427                                         return this;
428                                 },
430                                 // Cancel the request
431                                 abort: function( statusText ) {
432                                         statusText = statusText || strAbort;
433                                         if ( transport ) {
434                                                 transport.abort( statusText );
435                                         }
436                                         done( 0, statusText );
437                                         return this;
438                                 }
439                         };
441                 // Callback for when everything is done
442                 // It is defined here because jslint complains if it is declared
443                 // at the end of the function (which would be more logical and readable)
444                 function done( status, nativeStatusText, responses, headers ) {
445                         var isSuccess, success, error, response, modified,
446                                 statusText = nativeStatusText;
448                         // Called once
449                         if ( state === 2 ) {
450                                 return;
451                         }
453                         // State is "done" now
454                         state = 2;
456                         // Clear timeout if it exists
457                         if ( timeoutTimer ) {
458                                 clearTimeout( timeoutTimer );
459                         }
461                         // Dereference transport for early garbage collection
462                         // (no matter how long the jqXHR object will be used)
463                         transport = undefined;
465                         // Cache response headers
466                         responseHeadersString = headers || "";
468                         // Set readyState
469                         jqXHR.readyState = status > 0 ? 4 : 0;
471                         // Get response data
472                         if ( responses ) {
473                                 response = ajaxHandleResponses( s, jqXHR, responses );
474                         }
476                         // If successful, handle type chaining
477                         if ( status >= 200 && status < 300 || status === 304 ) {
479                                 // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
480                                 if ( s.ifModified ) {
482                                         modified = jqXHR.getResponseHeader("Last-Modified");
483                                         if ( modified ) {
484                                                 jQuery.lastModified[ ifModifiedKey ] = modified;
485                                         }
486                                         modified = jqXHR.getResponseHeader("Etag");
487                                         if ( modified ) {
488                                                 jQuery.etag[ ifModifiedKey ] = modified;
489                                         }
490                                 }
492                                 // If not modified
493                                 if ( status === 304 ) {
495                                         statusText = "notmodified";
496                                         isSuccess = true;
498                                 // If we have data
499                                 } else {
501                                         isSuccess = ajaxConvert( s, response );
502                                         statusText = isSuccess.state;
503                                         success = isSuccess.data;
504                                         error = isSuccess.error;
505                                         isSuccess = !error;
506                                 }
507                         } else {
508                                 // We extract error from statusText
509                                 // then normalize statusText and status for non-aborts
510                                 error = statusText;
511                                 if ( !statusText || status ) {
512                                         statusText = "error";
513                                         if ( status < 0 ) {
514                                                 status = 0;
515                                         }
516                                 }
517                         }
519                         // Set data for the fake xhr object
520                         jqXHR.status = status;
521                         jqXHR.statusText = "" + ( nativeStatusText || statusText );
523                         // Success/Error
524                         if ( isSuccess ) {
525                                 deferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] );
526                         } else {
527                                 deferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] );
528                         }
530                         // Status-dependent callbacks
531                         jqXHR.statusCode( statusCode );
532                         statusCode = undefined;
534                         if ( fireGlobals ) {
535                                 globalEventContext.trigger( "ajax" + ( isSuccess ? "Success" : "Error" ),
536                                                 [ jqXHR, s, isSuccess ? success : error ] );
537                         }
539                         // Complete
540                         completeDeferred.fireWith( callbackContext, [ jqXHR, statusText ] );
542                         if ( fireGlobals ) {
543                                 globalEventContext.trigger( "ajaxComplete", [ jqXHR, s ] );
544                                 // Handle the global AJAX counter
545                                 if ( !( --jQuery.active ) ) {
546                                         jQuery.event.trigger( "ajaxStop" );
547                                 }
548                         }
549                 }
551                 // Attach deferreds
552                 deferred.promise( jqXHR );
553                 jqXHR.success = jqXHR.done;
554                 jqXHR.error = jqXHR.fail;
555                 jqXHR.complete = completeDeferred.add;
557                 // Status-dependent callbacks
558                 jqXHR.statusCode = function( map ) {
559                         if ( map ) {
560                                 var tmp;
561                                 if ( state < 2 ) {
562                                         for ( tmp in map ) {
563                                                 statusCode[ tmp ] = [ statusCode[tmp], map[tmp] ];
564                                         }
565                                 } else {
566                                         tmp = map[ jqXHR.status ];
567                                         jqXHR.always( tmp );
568                                 }
569                         }
570                         return this;
571                 };
573                 // Remove hash character (#7531: and string promotion)
574                 // Add protocol if not provided (#5866: IE7 issue with protocol-less urls)
575                 // We also use the url parameter if available
576                 s.url = ( ( url || s.url ) + "" ).replace( rhash, "" ).replace( rprotocol, ajaxLocParts[ 1 ] + "//" );
578                 // Extract dataTypes list
579                 s.dataTypes = jQuery.trim( s.dataType || "*" ).toLowerCase().split( core_rspace );
581                 // Determine if a cross-domain request is in order
582                 if ( s.crossDomain == null ) {
583                         parts = rurl.exec( s.url.toLowerCase() );
584                         s.crossDomain = !!( parts &&
585                                 ( parts[ 1 ] != ajaxLocParts[ 1 ] || parts[ 2 ] != ajaxLocParts[ 2 ] ||
586                                         ( parts[ 3 ] || ( parts[ 1 ] === "http:" ? 80 : 443 ) ) !=
587                                                 ( ajaxLocParts[ 3 ] || ( ajaxLocParts[ 1 ] === "http:" ? 80 : 443 ) ) )
588                         );
589                 }
591                 // Convert data if not already a string
592                 if ( s.data && s.processData && typeof s.data !== "string" ) {
593                         s.data = jQuery.param( s.data, s.traditional );
594                 }
596                 // Apply prefilters
597                 inspectPrefiltersOrTransports( prefilters, s, options, jqXHR );
599                 // If request was aborted inside a prefilter, stop there
600                 if ( state === 2 ) {
601                         return jqXHR;
602                 }
604                 // We can fire global events as of now if asked to
605                 fireGlobals = s.global;
607                 // Uppercase the type
608                 s.type = s.type.toUpperCase();
610                 // Determine if request has content
611                 s.hasContent = !rnoContent.test( s.type );
613                 // Watch for a new set of requests
614                 if ( fireGlobals && jQuery.active++ === 0 ) {
615                         jQuery.event.trigger( "ajaxStart" );
616                 }
618                 // More options handling for requests with no content
619                 if ( !s.hasContent ) {
621                         // If data is available, append data to url
622                         if ( s.data ) {
623                                 s.url += ( rquery.test( s.url ) ? "&" : "?" ) + s.data;
624                                 // #9682: remove data so that it's not used in an eventual retry
625                                 delete s.data;
626                         }
628                         // Get ifModifiedKey before adding the anti-cache parameter
629                         ifModifiedKey = s.url;
631                         // Add anti-cache in url if needed
632                         if ( s.cache === false ) {
634                                 var ts = jQuery.now(),
635                                         // try replacing _= if it is there
636                                         ret = s.url.replace( rts, "$1_=" + ts );
638                                 // if nothing was replaced, add timestamp to the end
639                                 s.url = ret + ( ( ret === s.url ) ? ( rquery.test( s.url ) ? "&" : "?" ) + "_=" + ts : "" );
640                         }
641                 }
643                 // Set the correct header, if data is being sent
644                 if ( s.data && s.hasContent && s.contentType !== false || options.contentType ) {
645                         jqXHR.setRequestHeader( "Content-Type", s.contentType );
646                 }
648                 // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
649                 if ( s.ifModified ) {
650                         ifModifiedKey = ifModifiedKey || s.url;
651                         if ( jQuery.lastModified[ ifModifiedKey ] ) {
652                                 jqXHR.setRequestHeader( "If-Modified-Since", jQuery.lastModified[ ifModifiedKey ] );
653                         }
654                         if ( jQuery.etag[ ifModifiedKey ] ) {
655                                 jqXHR.setRequestHeader( "If-None-Match", jQuery.etag[ ifModifiedKey ] );
656                         }
657                 }
659                 // Set the Accepts header for the server, depending on the dataType
660                 jqXHR.setRequestHeader(
661                         "Accept",
662                         s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[0] ] ?
663                                 s.accepts[ s.dataTypes[0] ] + ( s.dataTypes[ 0 ] !== "*" ? ", " + allTypes + "; q=0.01" : "" ) :
664                                 s.accepts[ "*" ]
665                 );
667                 // Check for headers option
668                 for ( i in s.headers ) {
669                         jqXHR.setRequestHeader( i, s.headers[ i ] );
670                 }
672                 // Allow custom headers/mimetypes and early abort
673                 if ( s.beforeSend && ( s.beforeSend.call( callbackContext, jqXHR, s ) === false || state === 2 ) ) {
674                                 // Abort if not done already and return
675                                 return jqXHR.abort();
677                 }
679                 // aborting is no longer a cancellation
680                 strAbort = "abort";
682                 // Install callbacks on deferreds
683                 for ( i in { success: 1, error: 1, complete: 1 } ) {
684                         jqXHR[ i ]( s[ i ] );
685                 }
687                 // Get transport
688                 transport = inspectPrefiltersOrTransports( transports, s, options, jqXHR );
690                 // If no transport, we auto-abort
691                 if ( !transport ) {
692                         done( -1, "No Transport" );
693                 } else {
694                         jqXHR.readyState = 1;
695                         // Send global event
696                         if ( fireGlobals ) {
697                                 globalEventContext.trigger( "ajaxSend", [ jqXHR, s ] );
698                         }
699                         // Timeout
700                         if ( s.async && s.timeout > 0 ) {
701                                 timeoutTimer = setTimeout( function(){
702                                         jqXHR.abort( "timeout" );
703                                 }, s.timeout );
704                         }
706                         try {
707                                 state = 1;
708                                 transport.send( requestHeaders, done );
709                         } catch (e) {
710                                 // Propagate exception as error if not done
711                                 if ( state < 2 ) {
712                                         done( -1, e );
713                                 // Simply rethrow otherwise
714                                 } else {
715                                         throw e;
716                                 }
717                         }
718                 }
720                 return jqXHR;
721         },
723         // Counter for holding the number of active queries
724         active: 0,
726         // Last-Modified header cache for next request
727         lastModified: {},
728         etag: {}
732 /* Handles responses to an ajax request:
733  * - sets all responseXXX fields accordingly
734  * - finds the right dataType (mediates between content-type and expected dataType)
735  * - returns the corresponding response
736  */
737 function ajaxHandleResponses( s, jqXHR, responses ) {
739         var ct, type, finalDataType, firstDataType,
740                 contents = s.contents,
741                 dataTypes = s.dataTypes,
742                 responseFields = s.responseFields;
744         // Fill responseXXX fields
745         for ( type in responseFields ) {
746                 if ( type in responses ) {
747                         jqXHR[ responseFields[type] ] = responses[ type ];
748                 }
749         }
751         // Remove auto dataType and get content-type in the process
752         while( dataTypes[ 0 ] === "*" ) {
753                 dataTypes.shift();
754                 if ( ct === undefined ) {
755                         ct = s.mimeType || jqXHR.getResponseHeader( "content-type" );
756                 }
757         }
759         // Check if we're dealing with a known content-type
760         if ( ct ) {
761                 for ( type in contents ) {
762                         if ( contents[ type ] && contents[ type ].test( ct ) ) {
763                                 dataTypes.unshift( type );
764                                 break;
765                         }
766                 }
767         }
769         // Check to see if we have a response for the expected dataType
770         if ( dataTypes[ 0 ] in responses ) {
771                 finalDataType = dataTypes[ 0 ];
772         } else {
773                 // Try convertible dataTypes
774                 for ( type in responses ) {
775                         if ( !dataTypes[ 0 ] || s.converters[ type + " " + dataTypes[0] ] ) {
776                                 finalDataType = type;
777                                 break;
778                         }
779                         if ( !firstDataType ) {
780                                 firstDataType = type;
781                         }
782                 }
783                 // Or just use first one
784                 finalDataType = finalDataType || firstDataType;
785         }
787         // If we found a dataType
788         // We add the dataType to the list if needed
789         // and return the corresponding response
790         if ( finalDataType ) {
791                 if ( finalDataType !== dataTypes[ 0 ] ) {
792                         dataTypes.unshift( finalDataType );
793                 }
794                 return responses[ finalDataType ];
795         }
798 // Chain conversions given the request and the original response
799 function ajaxConvert( s, response ) {
801         var conv, conv2, current, tmp,
802                 // Work with a copy of dataTypes in case we need to modify it for conversion
803                 dataTypes = s.dataTypes.slice(),
804                 prev = dataTypes[ 0 ],
805                 converters = {},
806                 i = 0;
808         // Apply the dataFilter if provided
809         if ( s.dataFilter ) {
810                 response = s.dataFilter( response, s.dataType );
811         }
813         // Create converters map with lowercased keys
814         if ( dataTypes[ 1 ] ) {
815                 for ( conv in s.converters ) {
816                         converters[ conv.toLowerCase() ] = s.converters[ conv ];
817                 }
818         }
820         // Convert to each sequential dataType, tolerating list modification
821         for ( ; (current = dataTypes[++i]); ) {
823                 // There's only work to do if current dataType is non-auto
824                 if ( current !== "*" ) {
826                         // Convert response if prev dataType is non-auto and differs from current
827                         if ( prev !== "*" && prev !== current ) {
829                                 // Seek a direct converter
830                                 conv = converters[ prev + " " + current ] || converters[ "* " + current ];
832                                 // If none found, seek a pair
833                                 if ( !conv ) {
834                                         for ( conv2 in converters ) {
836                                                 // If conv2 outputs current
837                                                 tmp = conv2.split(" ");
838                                                 if ( tmp[ 1 ] === current ) {
840                                                         // If prev can be converted to accepted input
841                                                         conv = converters[ prev + " " + tmp[ 0 ] ] ||
842                                                                 converters[ "* " + tmp[ 0 ] ];
843                                                         if ( conv ) {
844                                                                 // Condense equivalence converters
845                                                                 if ( conv === true ) {
846                                                                         conv = converters[ conv2 ];
848                                                                 // Otherwise, insert the intermediate dataType
849                                                                 } else if ( converters[ conv2 ] !== true ) {
850                                                                         current = tmp[ 0 ];
851                                                                         dataTypes.splice( i--, 0, current );
852                                                                 }
854                                                                 break;
855                                                         }
856                                                 }
857                                         }
858                                 }
860                                 // Apply converter (if not an equivalence)
861                                 if ( conv !== true ) {
863                                         // Unless errors are allowed to bubble, catch and return them
864                                         if ( conv && s["throws"] ) {
865                                                 response = conv( response );
866                                         } else {
867                                                 try {
868                                                         response = conv( response );
869                                                 } catch ( e ) {
870                                                         return { state: "parsererror", error: conv ? e : "No conversion from " + prev + " to " + current };
871                                                 }
872                                         }
873                                 }
874                         }
876                         // Update prev for next iteration
877                         prev = current;
878                 }
879         }
881         return { state: "success", data: response };