xhr.js (4355B)
1 define( [ 2 "../core", 3 "../var/support", 4 "../ajax" 5 ], function( jQuery, support ) { 6 7 "use strict"; 8 9 jQuery.ajaxSettings.xhr = function() { 10 try { 11 return new window.XMLHttpRequest(); 12 } catch ( e ) {} 13 }; 14 15 var xhrSuccessStatus = { 16 17 // File protocol always yields status code 0, assume 200 18 0: 200, 19 20 // Support: IE <=9 only 21 // trac-1450: sometimes IE returns 1223 when it should be 204 22 1223: 204 23 }, 24 xhrSupported = jQuery.ajaxSettings.xhr(); 25 26 support.cors = !!xhrSupported && ( "withCredentials" in xhrSupported ); 27 support.ajax = xhrSupported = !!xhrSupported; 28 29 jQuery.ajaxTransport( function( options ) { 30 var callback, errorCallback; 31 32 // Cross domain only allowed if supported through XMLHttpRequest 33 if ( support.cors || xhrSupported && !options.crossDomain ) { 34 return { 35 send: function( headers, complete ) { 36 var i, 37 xhr = options.xhr(); 38 39 xhr.open( 40 options.type, 41 options.url, 42 options.async, 43 options.username, 44 options.password 45 ); 46 47 // Apply custom fields if provided 48 if ( options.xhrFields ) { 49 for ( i in options.xhrFields ) { 50 xhr[ i ] = options.xhrFields[ i ]; 51 } 52 } 53 54 // Override mime type if needed 55 if ( options.mimeType && xhr.overrideMimeType ) { 56 xhr.overrideMimeType( options.mimeType ); 57 } 58 59 // X-Requested-With header 60 // For cross-domain requests, seeing as conditions for a preflight are 61 // akin to a jigsaw puzzle, we simply never set it to be sure. 62 // (it can always be set on a per-request basis or even using ajaxSetup) 63 // For same-domain requests, won't change header if already provided. 64 if ( !options.crossDomain && !headers[ "X-Requested-With" ] ) { 65 headers[ "X-Requested-With" ] = "XMLHttpRequest"; 66 } 67 68 // Set headers 69 for ( i in headers ) { 70 xhr.setRequestHeader( i, headers[ i ] ); 71 } 72 73 // Callback 74 callback = function( type ) { 75 return function() { 76 if ( callback ) { 77 callback = errorCallback = xhr.onload = 78 xhr.onerror = xhr.onabort = xhr.ontimeout = 79 xhr.onreadystatechange = null; 80 81 if ( type === "abort" ) { 82 xhr.abort(); 83 } else if ( type === "error" ) { 84 85 // Support: IE <=9 only 86 // On a manual native abort, IE9 throws 87 // errors on any property access that is not readyState 88 if ( typeof xhr.status !== "number" ) { 89 complete( 0, "error" ); 90 } else { 91 complete( 92 93 // File: protocol always yields status 0; see trac-8605, trac-14207 94 xhr.status, 95 xhr.statusText 96 ); 97 } 98 } else { 99 complete( 100 xhrSuccessStatus[ xhr.status ] || xhr.status, 101 xhr.statusText, 102 103 // Support: IE <=9 only 104 // IE9 has no XHR2 but throws on binary (trac-11426) 105 // For XHR2 non-text, let the caller handle it (gh-2498) 106 ( xhr.responseType || "text" ) !== "text" || 107 typeof xhr.responseText !== "string" ? 108 { binary: xhr.response } : 109 { text: xhr.responseText }, 110 xhr.getAllResponseHeaders() 111 ); 112 } 113 } 114 }; 115 }; 116 117 // Listen to events 118 xhr.onload = callback(); 119 errorCallback = xhr.onerror = xhr.ontimeout = callback( "error" ); 120 121 // Support: IE 9 only 122 // Use onreadystatechange to replace onabort 123 // to handle uncaught aborts 124 if ( xhr.onabort !== undefined ) { 125 xhr.onabort = errorCallback; 126 } else { 127 xhr.onreadystatechange = function() { 128 129 // Check readyState before timeout as it changes 130 if ( xhr.readyState === 4 ) { 131 132 // Allow onerror to be called first, 133 // but that will not handle a native abort 134 // Also, save errorCallback to a variable 135 // as xhr.onerror cannot be accessed 136 window.setTimeout( function() { 137 if ( callback ) { 138 errorCallback(); 139 } 140 } ); 141 } 142 }; 143 } 144 145 // Create the abort callback 146 callback = callback( "abort" ); 147 148 try { 149 150 // Do send the request (this may raise an exception) 151 xhr.send( options.hasContent && options.data || null ); 152 } catch ( e ) { 153 154 // trac-14683: Only rethrow if this hasn't been notified as an error yet 155 if ( callback ) { 156 throw e; 157 } 158 } 159 }, 160 161 abort: function() { 162 if ( callback ) { 163 callback(); 164 } 165 } 166 }; 167 } 168 } ); 169 170 } );