var XHR = window.XMLHttpRequest || function() { try { return new ActiveXObject("Msxml2.XMLHTTP.6.0"); } catch (e1) {} try { return new ActiveXObject("Msxml2.XMLHTTP.3.0"); } catch (e2) {} try { return new ActiveXObject("Msxml2.XMLHTTP"); } catch (e3) {} throw minErr('$httpBackend')('noxhr', "This browser does not support XMLHttpRequest."); }; /** * @ngdoc object * @name ng.$httpBackend * @requires $browser * @requires $window * @requires $document * * @description * HTTP backend used by the {@link ng.$http service} that delegates to * XMLHttpRequest object or JSONP and deals with browser incompatibilities. * * You should never need to use this service directly, instead use the higher-level abstractions: * {@link ng.$http $http} or {@link ngResource.$resource $resource}. * * During testing this implementation is swapped with {@link ngMock.$httpBackend mock * $httpBackend} which can be trained with responses. */ function $HttpBackendProvider() { this.$get = ['$browser', '$window', '$document', function($browser, $window, $document) { return createHttpBackend($browser, XHR, $browser.defer, $window.angular.callbacks, $document[0], $window.location.protocol.replace(':', '')); }]; } function createHttpBackend($browser, XHR, $browserDefer, callbacks, rawDocument, locationProtocol) { // TODO(vojta): fix the signature return function(method, url, post, callback, headers, timeout, withCredentials, responseType) { var status; $browser.$$incOutstandingRequestCount(); url = url || $browser.url(); if (lowercase(method) == 'jsonp') { var callbackId = '_' + (callbacks.counter++).toString(36); callbacks[callbackId] = function(data) { callbacks[callbackId].data = data; }; var jsonpDone = jsonpReq(url.replace('JSON_CALLBACK', 'angular.callbacks.' + callbackId), function() { if (callbacks[callbackId].data) { completeRequest(callback, 200, callbacks[callbackId].data); } else { completeRequest(callback, status || -2); } delete callbacks[callbackId]; }); } else { var xhr = new XHR(); xhr.open(method, url, true); forEach(headers, function(value, key) { if (value) xhr.setRequestHeader(key, value); }); // In IE6 and 7, this might be called synchronously when xhr.send below is called and the // response is in the cache. the promise api will ensure that to the app code the api is // always async xhr.onreadystatechange = function() { if (xhr.readyState == 4) { var responseHeaders = xhr.getAllResponseHeaders(); // TODO(vojta): remove once Firefox 21 gets released. // begin: workaround to overcome Firefox CORS http response headers bug // https://bugzilla.mozilla.org/show_bug.cgi?id=608735 // Firefox already patched in nightly. Should land in Firefox 21. // CORS "simple response headers" http://www.w3.org/TR/cors/ var value, simpleHeaders = ["Cache-Control", "Content-Language", "Content-Type", "Expires", "Last-Modified", "Pragma"]; if (!responseHeaders) { responseHeaders = ""; forEach(simpleHeaders, function (header) { var value = xhr.getResponseHeader(header); if (value) { responseHeaders += header + ": " + value + "\n"; } }); } // end of the workaround. // responseText is the old-school way of retrieving response (supported by IE8 & 9) // response and responseType properties were introduced in XHR Level2 spec (supported by IE10) completeRequest(callback, status || xhr.status, (xhr.responseType ? xhr.response : xhr.responseText), responseHeaders); } }; if (withCredentials) { xhr.withCredentials = true; } if (responseType) { xhr.responseType = responseType; } xhr.send(post || ''); } if (timeout > 0) { var timeoutId = $browserDefer(timeoutRequest, timeout); } else if (timeout && timeout.then) { timeout.then(timeoutRequest); } function timeoutRequest() { status = -1; jsonpDone && jsonpDone(); xhr && xhr.abort(); } function completeRequest(callback, status, response, headersString) { // URL_MATCH is defined in src/service/location.js var protocol = (url.match(SERVER_MATCH) || ['', locationProtocol])[1]; // cancel timeout and subsequent timeout promise resolution timeoutId && $browserDefer.cancel(timeoutId); jsonpDone = xhr = null; // fix status code for file protocol (it's always 0) status = (protocol == 'file') ? (response ? 200 : 404) : status; // normalize IE bug (http://bugs.jquery.com/ticket/1450) status = status == 1223 ? 204 : status; callback(status, response, headersString); $browser.$$completeOutstandingRequest(noop); } }; function jsonpReq(url, done) { // we can't use jQuery/jqLite here because jQuery does crazy shit with script elements, e.g.: // - fetches local scripts via XHR and evals them // - adds and immediately removes script elements from the document var script = rawDocument.createElement('script'), doneWrapper = function() { rawDocument.body.removeChild(script); if (done) done(); }; script.type = 'text/javascript'; script.src = url; if (msie) { script.onreadystatechange = function() { if (/loaded|complete/.test(script.readyState)) doneWrapper(); }; } else { script.onload = script.onerror = doneWrapper; } rawDocument.body.appendChild(script); return doneWrapper; } } ='#n71'>71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254