aboutsummaryrefslogtreecommitdiffstats
path: root/src/ng/httpBackend.js
diff options
context:
space:
mode:
Diffstat (limited to 'src/ng/httpBackend.js')
-rw-r--r--src/ng/httpBackend.js99
1 files changed, 99 insertions, 0 deletions
diff --git a/src/ng/httpBackend.js b/src/ng/httpBackend.js
new file mode 100644
index 00000000..201d1a87
--- /dev/null
+++ b/src/ng/httpBackend.js
@@ -0,0 +1,99 @@
+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 new Error("This browser does not support XMLHttpRequest.");
+};
+
+
+/**
+ * @ngdoc object
+ * @name angular.module.ng.$httpBackend
+ * @requires $browser
+ * @requires $window
+ * @requires $document
+ *
+ * @description
+ * HTTP backend used by the {@link angular.module.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 angular.module.ng.$http $http} or {@link angular.module.ng.$resource $resource}.
+ *
+ * During testing this implementation is swapped with {@link angular.module.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].body, $window.location.protocol.replace(':', ''));
+ }];
+}
+
+function createHttpBackend($browser, XHR, $browserDefer, callbacks, body, locationProtocol) {
+ // TODO(vojta): fix the signature
+ return function(method, url, post, callback, headers, timeout) {
+ $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 script = $browser.addJs(url.replace('JSON_CALLBACK', 'angular.callbacks.' + callbackId),
+ function() {
+ if (callbacks[callbackId].data) {
+ completeRequest(callback, 200, callbacks[callbackId].data);
+ } else {
+ completeRequest(callback, -2);
+ }
+ delete callbacks[callbackId];
+ body.removeChild(script);
+ });
+ } else {
+ var xhr = new XHR();
+ xhr.open(method, url, true);
+ forEach(headers, function(value, key) {
+ if (value) xhr.setRequestHeader(key, value);
+ });
+
+ var status;
+
+ // 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) {
+ completeRequest(
+ callback, status || xhr.status, xhr.responseText, xhr.getAllResponseHeaders());
+ }
+ };
+
+ xhr.send(post || '');
+
+ if (timeout > 0) {
+ $browserDefer(function() {
+ status = -1;
+ xhr.abort();
+ }, timeout);
+ }
+ }
+
+
+ function completeRequest(callback, status, response, headersString) {
+ // URL_MATCH is defined in src/service/location.js
+ var protocol = (url.match(URL_MATCH) || ['', locationProtocol])[1];
+
+ // 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);
+ }
+ };
+}