More variable renaming to avoid conflicts when module closures are removed.
[jquery.git] / src / xhr.js
1 (function( jQuery ) {
2
3 var rquery_xhr = /\?/,
4         rhash = /#.*$/,
5         rheaders = /^(.*?):\s*(.*?)\r?$/mg, // IE leaves an \r character at EOL
6         rnoContent = /^(?:GET|HEAD)$/,
7         rts = /([?&])_=[^&]*/,
8         rurl = /^(\w+:)?\/\/([^\/?#]+)/,
9         
10         sliceFunc = Array.prototype.slice,
11         
12         isFunction = jQuery.isFunction;
13         
14 // Creates a jQuery xhr object
15 jQuery.xhr = function( _native ) {
16         
17         if ( _native ) {
18                 return jQuery.ajaxSettings.xhr();
19         }
20         
21         function reset(force) {
22                 
23                 // We only need to reset if we went through the init phase
24                 // (with the exception of object creation)
25                 if ( force || internal ) {
26                 
27                         // Reset callbacks lists
28                         callbacksLists = {
29                                 success: createCBList(),
30                                 error: createCBList(),
31                                 complete: createCBList()
32                         };
33                         
34                         // Reset private variables
35                         requestHeaders = {};
36                         responseHeadersString = responseHeaders = internal = done = timeoutTimer = s = undefined;
37                         
38                         // Reset state
39                         xhr.readyState = 0;
40                         sendFlag = 0;
41                         
42                         // Remove responseX fields
43                         for ( var name in xhr ) {
44                                 if ( /^response/.test(name) ) {
45                                         delete xhr[name];
46                                 }
47                         }
48                 }
49         }
50         
51         function init() {
52                 
53                 var // Options extraction
54                 
55                         // Remove hash character (#7531: first for string promotion)
56                         url = s.url = ( "" + s.url ).replace( rhash , "" ),
57                         
58                         // Uppercase the type
59                         type = s.type = s.type.toUpperCase(),
60                         
61                         // Determine if request has content
62                         hasContent = s.hasContent = ! rnoContent.test( type ),
63                         
64                         // Extract dataTypes list
65                         dataType = s.dataType,
66                         dataTypes = s.dataTypes = dataType ? jQuery.trim(dataType).toLowerCase().split(/\s+/) : ["*"],
67                         
68                         // Determine if a cross-domain request is in order
69                         parts = rurl.exec( url.toLowerCase() ),
70                         loc = location,
71                         crossDomain = s.crossDomain = !!( parts && ( parts[1] && parts[1] != loc.protocol || parts[2] != loc.host ) ),
72                         
73                         // Get other options locally
74                         data = s.data,
75                         originalContentType = s.contentType,
76                         prefilters = s.prefilters,
77                         accepts = s.accepts,
78                         headers = s.headers,
79                         
80                         // Other Variables
81                         transportDataType,
82                         i;
83                         
84                 // Convert data if not already a string
85                 if ( data && s.processData && typeof data != "string" ) {
86                         data = s.data = jQuery.param( data , s.traditional );
87                 }
88                 
89                 // Apply option prefilters
90                 for (i in prefilters) {
91                         prefilters[i](s);
92                 }
93                 
94                 // Get internal
95                 internal = selectTransport( s );
96                 
97                 // Re-actualize url & data
98                 url = s.url;
99                 data = s.data;
100                 
101                 // If internal was found
102                 if ( internal ) {
103                         
104                         // Get transportDataType
105                         transportDataType = dataTypes[0];
106                         
107                         // More options handling for requests with no content
108                         if ( ! hasContent ) {
109                                 
110                                 // If data is available, append data to url
111                                 if ( data ) {
112                                         url += (rquery_xhr.test(url) ? "&" : "?") + data;
113                                 }
114                                                                 
115                                 // Add anti-cache in url if needed
116                                 if ( s.cache === false ) {
117                                         
118                                         var ts = jQuery.now(),
119                                                 // try replacing _= if it is there
120                                                 ret = url.replace(rts, "$1_=" + ts );
121                                                 
122                                         // if nothing was replaced, add timestamp to the end
123                                         url = ret + ((ret == url) ? (rquery_xhr.test(url) ? "&" : "?") + "_=" + ts : "");
124                                 }
125                                 
126                                 s.url = url;
127                         }
128                         
129                         // Set the correct header, if data is being sent
130                         if ( ( data && hasContent ) || originalContentType ) {
131                                 requestHeaders["content-type"] = s.contentType;
132                         }
133                 
134                         // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
135                         if ( s.ifModified ) {
136                                 if ( jQuery_lastModified[url] ) { 
137                                         requestHeaders["if-modified-since"] = jQuery_lastModified[url];
138                                 }
139                                 if ( jQuery_etag[url] ) {
140                                         requestHeaders["if-none-match"] = jQuery_etag[url];
141                                 }
142                         }
143                 
144                         // Set the Accepts header for the server, depending on the dataType
145                         requestHeaders.accept = transportDataType && accepts[ transportDataType ] ?
146                                 accepts[ transportDataType ] + ( transportDataType !== "*" ? ", */*; q=0.01" : "" ) :
147                                 accepts[ "*" ];
148                                 
149                         // Check for headers option
150                         for ( i in headers ) {
151                                 requestHeaders[ i.toLowerCase() ] = headers[ i ];
152                         }                       
153                 }
154                         
155                 callbackContext = s.context || s;
156                 globalEventContext = s.context ? jQuery(s.context) : jQuery.event;
157                 
158                 for ( i in callbacksLists ) {
159                         callbacksLists[i].bind(s[i]);
160                 }
161                 
162                 // Watch for a new set of requests
163                 if ( s.global && jQuery.active++ === 0 ) {
164                         jQuery.event.trigger( "ajaxStart" );
165                 }
166                 
167                 done = whenDone;
168         }
169         
170         function whenDone(status, statusText, response, headers) {
171                 
172                 // Called once
173                 done = undefined;
174                 
175                 // Reset sendFlag
176                 sendFlag = 0;
177                 
178                 // Cache response headers
179                 responseHeadersString = headers || "";
180
181                 // Clear timeout if it exists
182                 if ( timeoutTimer ) {
183                         clearTimeout(timeoutTimer);
184                 }
185                 
186                 var // Reference url
187                         url = s.url,
188                         // and ifModified status
189                         ifModified = s.ifModified,
190                         
191                         // Is it a success?
192                         isSuccess = 0,
193                         // Stored success
194                         success,
195                         // Stored error
196                         error = statusText;
197
198                 // If not timeout, force a jQuery-compliant status text
199                 if ( statusText != "timeout" ) {
200                         statusText = ( status >= 200 && status < 300 ) ? 
201                                 "success" :
202                                 ( status === 304 ? "notmodified" : "error" );
203                 }
204                 
205                 // If successful, handle type chaining
206                 if ( statusText === "success" || statusText === "notmodified" ) {
207                         
208                         // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
209                         if ( ifModified ) {
210                                 var lastModified = xhr.getResponseHeader("Last-Modified"),
211                                         etag = xhr.getResponseHeader("Etag");
212                                         
213                                 if (lastModified) {
214                                         jQuery_lastModified[url] = lastModified;
215                                 }
216                                 if (etag) {
217                                         jQuery_etag[url] = etag;
218                                 }
219                         }
220                         
221                         if ( ifModified && statusText === "notmodified" ) {
222                                 
223                                 success = null;
224                                 isSuccess = 1;
225                                 
226                         } else {
227                                 // Chain data conversions and determine the final value
228                                 // (if an exception is thrown in the process, it'll be notified as an error)
229                                 try {
230                                         
231                                         function checkData(data) {
232                                                 if ( data !== undefined ) {
233                                                         var testFunction = s.dataCheckers[srcDataType];
234                                                         if ( isFunction( testFunction ) ) {
235                                                                 testFunction(data);
236                                                         }
237                                                 }
238                                         }
239                                         
240                                         function convertData (data) {
241                                                 var conversionFunction = dataConverters[srcDataType+" => "+destDataType] ||
242                                                                 dataConverters["* => "+destDataType],
243                                                         noFunction = ! isFunction( conversionFunction );
244                                                 if ( noFunction ) {
245                                                         if ( srcDataType != "text" && destDataType != "text" ) {
246                                                                 // We try to put text inbetween
247                                                                 var first = dataConverters[srcDataType+" => text"] ||
248                                                                                 dataConverters["* => text"],
249                                                                         second = dataConverters["text => "+destDataType] ||
250                                                                                 dataConverters["* => "+destDataType],
251                                                                         areFunctions = isFunction( first ) && isFunction( second );
252                                                                 if ( areFunctions ) {
253                                                                         conversionFunction = function (data) {
254                                                                                 return second( first ( data ) );
255                                                                         };
256                                                                 }
257                                                                 noFunction = ! areFunctions;
258                                                         }
259                                                         if ( noFunction ) {
260                                                                 jQuery.error( "no data converter between " + srcDataType + " and " + destDataType );
261                                                         }
262                                                         
263                                                 }
264                                                 return conversionFunction(data);
265                                         }
266                                         
267                                         var dataTypes = s.dataTypes,
268                                                 i,
269                                                 length,
270                                                 data = response,
271                                                 dataConverters = s.dataConverters,
272                                                 srcDataType,
273                                                 destDataType,
274                                                 responseTypes = s.xhrResponseFields;
275                                                 
276                                         for ( i = 0, length = dataTypes.length ; i < length ; i++ ) {
277         
278                                                 destDataType = dataTypes[i];
279                                                 
280                                                 if ( !srcDataType ) { // First time
281                                                         
282                                                         // Copy type
283                                                         srcDataType = destDataType;
284                                                         // Check
285                                                         checkData(data);
286                                                         // Apply dataFilter
287                                                         if ( isFunction( s.dataFilter ) ) {
288                                                                 data = s.dataFilter(data, s.dataType);
289                                                                 // Recheck data
290                                                                 checkData(data);
291                                                         }
292                                                         
293                                                 } else { // Subsequent times
294                                                         
295                                                         // handle auto
296                                                         // JULIAN: for reasons unknown to me === doesn't work here
297                                                         if (destDataType == "*") {
298         
299                                                                 destDataType = srcDataType;
300                                                                 
301                                                         } else if ( srcDataType != destDataType ) {
302                                                                 
303                                                                 // Convert
304                                                                 data = convertData(data);
305                                                                 // Copy type & check
306                                                                 srcDataType = destDataType;
307                                                                 checkData(data);
308                                                                 
309                                                         }
310                                                         
311                                                 }
312         
313                                                 // Copy response into the xhr if it hasn't been already
314                                                 var responseDataType,
315                                                         responseType = responseTypes[srcDataType];
316                                                 
317                                                 if ( responseType ) {
318                                                         
319                                                         responseDataType = srcDataType;
320                                                         
321                                                 } else {
322                                                         
323                                                         responseType = responseTypes[ responseDataType = "text" ];
324                                                         
325                                                 }
326                                                         
327                                                 if ( responseType !== 1 ) {
328                                                         xhr[ "response" + responseType ] = data;
329                                                         responseTypes[ responseType ] = 1;
330                                                 }
331                                                 
332                                         }
333         
334                                         // We have a real success
335                                         success = data;
336                                         isSuccess = 1;
337                                         
338                                 } catch(e) {
339                                         
340                                         statusText = "parsererror";
341                                         error = "" + e;
342                                         
343                                 }
344                         }
345                         
346                 } else { // if not success, mark it as an error
347                         
348                                 error = error || statusText;
349                                 
350                 }
351                         
352                 // Set data for the fake xhr object
353                 xhr.status = status;
354                 xhr.statusText = statusText;
355                 
356                 // Keep local copies of vars in case callbacks re-use the xhr
357                 var _s = s,
358                         _callbacksLists = callbacksLists,
359                         _callbackContext = callbackContext,
360                         _globalEventContext = globalEventContext;
361                         
362                 // Set state if the xhr hasn't been re-used
363                 function _setState( value ) {
364                         if ( xhr.readyState && s === _s ) {
365                                 setState( value );
366                         }
367                 }
368                                 
369                 // Really completed?
370                 if ( status && s.async ) {
371                         setState( 2 );
372                         _setState( 3 );
373                 }
374                 
375                 // We're done
376                 _setState( 4 );
377                 
378                 // Success
379                 _callbacksLists.success.fire( isSuccess , _callbackContext , success, statusText, xhr);
380                 if ( isSuccess && _s.global ) {
381                         _globalEventContext.trigger( "ajaxSuccess", [xhr, _s, success] );
382                 }
383                 // Error
384                 _callbacksLists.error.fire( ! isSuccess , _callbackContext , xhr, statusText, error);
385                 if ( !isSuccess && _s.global ) {
386                         _globalEventContext.trigger( "ajaxError", [xhr, _s, error] );   
387                 }
388                 // Complete
389                 _callbacksLists.complete.fire( 1 , _callbackContext, xhr, statusText);
390                 if ( _s.global ) {
391                         _globalEventContext.trigger( "ajaxComplete", [xhr, _s] );
392                         // Handle the global AJAX counter
393                         if ( ! --jQuery.active ) {
394                                 jQuery.event.trigger( "ajaxStop" );
395                         }
396                 }
397         }
398         
399         // Ready state control
400         function checkState( expected , test ) {
401                 if ( expected !== true && ( expected === false || test === false || xhr.readyState !== expected ) ) {
402                         jQuery.error("INVALID_STATE_ERR");
403                 }
404         }
405         
406         // Ready state change
407         function setState( value ) {
408                 xhr.readyState = value;
409                 if ( isFunction( xhr.onreadystatechange ) ) {
410                         xhr.onreadystatechange();
411                 }
412         }
413         
414         var // jQuery lists
415                 jQuery_lastModified = jQuery.lastModified,
416                 jQuery_etag = jQuery.etag,
417                 // Options object
418                 s,
419                 // Callback stuff
420                 callbackContext,
421                 globalEventContext,
422                 callbacksLists,
423                 // Headers (they are sent all at once)
424                 requestHeaders,
425                 // Response headers
426                 responseHeadersString,
427                 responseHeaders,
428                 // Done callback
429                 done,
430                 // transport
431                 internal,
432                 // timeout handle
433                 timeoutTimer,
434                 // The send flag
435                 sendFlag,
436                 // Fake xhr
437                 xhr = {
438                         // state
439                         readyState: 0,
440                         
441                         // Callback
442                         onreadystatechange: null,
443                         
444                         // Open
445                         open: function(type, url, async, username, password) {
446                                 
447                                 xhr.abort();
448                                 reset();
449                                 
450                                 s = {
451                                         type: type,
452                                         url: url,
453                                         async: async,
454                                         username: username,
455                                         password: password
456                                 };
457                                 
458                                 setState(1);
459                                 
460                                 return xhr;
461                         },
462                         
463                         // Send
464                         send: function(data, moreOptions) {
465                                 
466                                 checkState(1 , !sendFlag);
467                                 
468                                 s.data = data;
469                                 
470                                 s = jQuery.extend( true,
471                                         {},
472                                         jQuery.ajaxSettings,
473                                         s,
474                                         moreOptions || ( moreOptions === false ? { global: false } : {} ) );
475                                         
476                                 if ( moreOptions ) {
477                                         // We force the original context
478                                         // (plain objects used as context get extended)
479                                         s.context = moreOptions.context;
480                                 }
481                                 
482                                 init();
483                                 
484                                 // If not internal, abort
485                                 if ( ! internal ) {
486                                         done( 0 , "transport not found" );
487                                         return false;
488                                 }
489                                 
490                                 // Allow custom headers/mimetypes and early abort
491                                 if ( s.beforeSend ) {
492                                         
493                                         var _s = s;
494                                         
495                                         if ( s.beforeSend.call(callbackContext, xhr, s) === false || ! xhr.readyState || _s !== s ) {
496                                                 
497                                                 // Abort if not done
498                                                 if ( xhr.readyState && _s === s ) {
499                                                         xhr.abort();
500                                                 }
501         
502                                                 // Handle the global AJAX counter
503                                                 if ( _s.global && ! --jQuery.active ) {
504                                                         jQuery.event.trigger( "ajaxStop" );
505                                                 }
506                                                 
507                                                 return false;
508                                         }
509                                 }
510                                 
511                                 sendFlag = 1;
512                                 
513                                 // Send global event
514                                 if ( s.global ) {
515                                         globalEventContext.trigger("ajaxSend", [xhr, s]);
516                                 }
517                                 
518                                 // Timeout
519                                 if ( s.async && s.timeout > 0 ) {
520                                         timeoutTimer = setTimeout(function(){
521                                                 xhr.abort("timeout");
522                                         }, s.timeout);
523                                 }
524                                 
525                                 if ( s.async ) {
526                                         setState(1);
527                                 }
528                                 
529                                 try {
530                                         
531                                         internal.send(requestHeaders, done);
532                                         return xhr;
533                                                                                         
534                                 } catch (e) {
535                                         
536                                         if ( done ) {
537                                                 
538                                                 done(0, "error", "" + e);
539                                                 
540                                         } else {
541                                                 
542                                                 jQuery.error(e);
543                                                 
544                                         }
545                                 }
546                                 
547                                 return false;
548                         },
549                         
550                         // Caches the header
551                         setRequestHeader: function(name,value) {
552                                 checkState(1, !sendFlag);
553                                 requestHeaders[ name.toLowerCase() ] = value;
554                                 return xhr;
555                         },
556                         
557                         // Raw string
558                         getAllResponseHeaders: function() {
559                                 return xhr.readyState <= 1 ? "" : responseHeadersString;
560                         },
561                         
562                         // Builds headers hashtable if needed
563                         getResponseHeader: function( key ) {
564                                 
565                                 if ( xhr.readyState <= 1 ) {
566                                         
567                                         return null;
568                                         
569                                 }
570                                 
571                                 if ( responseHeaders === undefined ) {
572                                         
573                                         responseHeaders = {};
574                                         
575                                         if ( typeof responseHeadersString === "string" ) {
576                                                 
577                                                 var match;
578                                                 
579                                                 while( ( match = rheaders.exec( responseHeadersString ) ) ) {
580                                                         responseHeaders[ match[ 1 ].toLowerCase() ] = match[ 2 ];
581                                                 }
582                                         }
583                                 }
584                                 return responseHeaders[ key.toLowerCase() ];
585                         },
586                         
587                         // Cancel the request
588                         abort: function(statusText) {
589                                 if (internal) {
590                                         internal.abort( statusText || "abort" );
591                                 }
592                                 xhr.readyState = 0;
593                         }
594                 };
595                 
596         // Init data (so that we can bind callbacks early
597         reset(1);
598
599         // Install callbacks related methods
600         jQuery.each(["bind","unbind"], function(_, name) {
601                 xhr[name] = function(type) {
602                         
603                         var functors = sliceFunc.call(arguments,1),
604                                 list;
605                                 
606                         jQuery.each(type.split(/\s+/g), function() {
607                                 list = callbacksLists[this];
608                                 if ( list ) {
609                                         list[name].apply(list, functors );
610                                 }
611                         });
612                         
613                         return this;
614                 };
615         });
616
617         jQuery.each(callbacksLists, function(name) {
618                 var list;
619                 xhr[name] = function() {
620                         list = callbacksLists[name];
621                         if ( list ) {
622                                 list.bind.apply(list, arguments );
623                         }
624                         return this;
625                 };
626         });
627         
628         // Return the xhr emulation
629         return xhr;
630 };
631
632 // Create a callback list
633 function createCBList() {
634         
635         var functors = [],
636                 autoFire = 0,
637                 fireArgs,
638                 list = {
639                 
640                         fire: function( flag , context ) {
641                                 
642                                 // Save info for later bindings
643                                 fireArgs = arguments;
644                                 
645                                 // Remove autoFire to keep bindings in order
646                                 autoFire = 0;
647                                         
648                                 var args = sliceFunc.call( fireArgs , 2 );
649                                         
650                                 // Execute callbacks
651                                 while ( flag && functors.length ) {
652                                         flag = functors.shift().apply( context , args ) !== false;
653                                 }
654                                         
655                                 // Clean if asked to stop
656                                 if ( ! flag ) {
657                                         clean();
658                                 }
659                                                 
660                                 // Set autoFire
661                                 autoFire = 1;                                   
662                         },
663                         
664                         bind: function() {
665                                 
666                                 var args = arguments,
667                                         i = 0,
668                                         length = args.length,
669                                         func;
670                                 
671                                 for ( ; i < length ; i++ ) {
672                                         
673                                         func = args[ i ];
674                                         
675                                         if ( jQuery.isArray(func) ) {
676                                                 
677                                                 list.bind.apply( list , func );
678                                                 
679                                         } else if ( isFunction(func) ) {
680                                                 
681                                                 // Add if not already in
682                                                 if ( ! pos( func ) ) {
683                                                         functors.push( func );
684                                                 }
685                                         }
686                                 }
687                                 
688                                 if ( autoFire ) {
689                                         list.fire.apply( list , fireArgs );
690                                 }
691                         },
692                         
693                         unbind: function() {
694                                 
695                                 var i = 0,
696                                         args = arguments,
697                                         length = args.length,
698                                         func,                                   
699                                         position;
700                                         
701                                 if ( length ) {
702                                                 
703                                         for( ; i < length ; i++ ) {
704                                                 func = args[i];
705                                                 if ( jQuery.isArray(func) ) {
706                                                         list.unbind.apply(list,func);
707                                                 } else if ( isFunction(func) ) {
708                                                         position = pos(func);
709                                                         if ( position ) {
710                                                                 functors.splice(position-1,1);
711                                                         }
712                                                 }
713                                         }
714                                 
715                                 } else {
716                                         
717                                         functors = [];
718                                 
719                                 }
720
721                         }
722                         
723                 };
724
725         // Get the index of the functor in the list (1-based)
726         function pos( func ) {
727                 for (var i = 0, length = functors.length; i < length && functors[i] !== func; i++) {
728                 }
729                 return i < length ? ( i + 1 ) : 0;
730         }
731                 
732         // Clean the object
733         function clean() {
734                 // Empty callbacks list
735                 functors = [];
736                 // Inhibit methods
737                 for (var i in list) {
738                         list[i] = jQuery.noop;
739                 }
740         }
741                                 
742         return list;
743 }
744
745 jQuery.extend(jQuery.xhr, {
746         
747         // Add new prefilter
748         prefilter: function (functor) {
749                 if ( isFunction(functor) ) {
750                         jQuery.ajaxSettings.prefilters.push( functor );
751                 }
752                 return this;
753         },
754         
755         // Bind a transport to one or more dataTypes
756         bindTransport: function () {
757                 
758                 var args = arguments,
759                         i,
760                         start = 0,
761                         length = args.length,
762                         dataTypes = [ "*" ],
763                         functors = [],
764                         functor,
765                         first,
766                         append,
767                         list,
768                         transports = jQuery.ajaxSettings.transports;
769                         
770                 if ( length ) {
771                                 
772                         if ( ! isFunction( args[ 0 ] ) ) {
773                                 
774                                 dataTypes = args[ 0 ].toLowerCase().split(/\s+/);
775                                 start = 1;
776                                 
777                         }
778                         
779                         if ( dataTypes.length && start < length ) {
780                                 
781                                 for ( i = start; i < length; i++ ) {
782                                         functor = args[i];
783                                         if ( isFunction(functor) ) {
784                                                 functors.push( functor );
785                                         }
786                                 }
787                                                 
788                                 if ( functors.length ) {
789                                                         
790                                         jQuery.each ( dataTypes, function( _ , dataType ) {
791                                                 
792                                                 first = /^\+/.test( dataType );
793                                                 
794                                                 if (first) {
795                                                         dataType = dataType.substr(1);
796                                                 }
797                                                 
798                                                 if ( dataType !== "" ) {
799                                                 
800                                                         append = Array.prototype[ first ? "unshift" : "push" ];
801                                                         
802                                                         list = transports[ dataType ];
803                                         
804                                                         jQuery.each ( functors, function( _ , functor ) {
805                                                                         
806                                                                 if ( ! list ) {
807                                                                         
808                                                                         list = transports[ dataType ] = [ functor ];
809                                                                         
810                                                                 } else {
811                                                                         
812                                                                         append.call( list , functor );
813                                                                 }
814                                                         } );
815                                                 }
816                                                                         
817                                         } );
818                                 }
819                         }
820                 }
821                 
822                 return this;
823         }
824
825         
826 });
827
828 // Select a transport given options
829 function selectTransport( s ) {
830
831         var dataTypes = s.dataTypes,
832                 transportDataType,
833                 transportsList,
834                 transport,
835                 i,
836                 length,
837                 checked = {},
838                 flag;
839                 
840         function initSearch( dataType ) {
841
842                 flag = transportDataType !== dataType && ! checked[ dataType ];
843                 
844                 if ( flag ) {
845                         
846                         checked[ dataType ] = 1;
847                         transportDataType = dataType;
848                         transportsList = s.transports[ dataType ];
849                         i = -1;
850                         length = transportsList ? transportsList.length : 0 ;
851                 }
852
853                 return flag;
854         }
855         
856         initSearch( dataTypes[ 0 ] );
857
858         for ( i = 0 ; ! transport && i <= length ; i++ ) {
859                 
860                 if ( i === length ) {
861                         
862                         initSearch( "*" );
863                         
864                 } else {
865
866                         transport = transportsList[ i ]( s , determineDataType );
867
868                         // If we got redirected to another dataType
869                         // Search there (if not in progress or already tried)
870                         if ( typeof( transport ) === "string" &&
871                                 initSearch( transport ) ) {
872
873                                 dataTypes.unshift( transport );
874                                 transport = 0;
875                         }
876                 }
877         }
878
879         return transport;
880 }
881         
882 // Utility function that handles dataType when response is received
883 // (for those transports that can give text or xml responses)
884 function determineDataType( s , ct , text , xml ) {
885         
886         var autoDataType = s.autoDataType,
887                 type,
888                 regexp,
889                 dataTypes = s.dataTypes,
890                 transportDataType = dataTypes[0],
891                 response;
892         
893         // Auto (xml, json, script or text determined given headers)
894         if ( transportDataType === "*" ) {
895
896                 for ( type in autoDataType ) {
897                         if ( ( regexp = autoDataType[ type ] ) && regexp.test( ct ) ) {
898                                 transportDataType = dataTypes[0] = type;
899                                 break;
900                         }
901                 }                       
902         } 
903         
904         // xml and parsed as such
905         if ( transportDataType === "xml" &&
906                 xml &&
907                 xml.documentElement /* #4958 */ ) {
908                 
909                 response = xml;
910         
911         // Text response was provided
912         } else {
913                 
914                 response = text;
915                 
916                 // If it's not really text, defer to dataConverters
917                 if ( transportDataType !== "text" ) {
918                         dataTypes.unshift( "text" );
919                 }
920                 
921         }
922         
923         return response;
924 }       
925
926 })( jQuery );