forked from angular/angular.js
-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy pathhttpBackend.js
130 lines (110 loc) · 4.38 KB
/
httpBackend.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
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
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 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) {
$browser.$$incOutstandingRequestCount();
url = url || $browser.url();
if (lowercase(method) == 'jsonp') {
var callbackId = url.indexOf('JSON_SINGLE_CALLBACK') === -1 ? '_' + (callbacks.counter++).toString(36) : 'single';
callbacks[callbackId] = function(data) {
callbacks[callbackId].data = data;
};
jsonpReq(url.replace('JSON_CALLBACK', 'angular.callbacks.' + callbackId).replace('JSON_SINGLE_CALLBACK', 'angular.callbacks.single'),
function() {
if (callbacks[callbackId].data) {
completeRequest(callback, 200, callbacks[callbackId].data);
} else {
completeRequest(callback, -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);
});
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.response || xhr.responseText,
xhr.getAllResponseHeaders());
}
};
if (withCredentials) {
xhr.withCredentials = true;
}
if (responseType) {
xhr.responseType = responseType;
}
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);
}
};
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);
}
}