1 define("dojo/request/xhr", [
2 '../errors/RequestError',
8 '../_base/declare' =====*/
9 ], function(RequestError, watch, handlers, util, has/*=====, request, declare =====*/){
10 has.add('native-xhr', function(){
11 // if true, the environment has a native XHR implementation
12 return typeof XMLHttpRequest !== 'undefined';
14 has.add('dojo-force-activex-xhr', function(){
15 return has('activex') && !document.addEventListener && window.location.protocol === 'file:';
18 has.add('native-xhr2', function(){
19 if(!has('native-xhr')){ return; }
20 var x = new XMLHttpRequest();
21 return typeof x['addEventListener'] !== 'undefined' &&
22 (typeof opera === 'undefined' || typeof x['upload'] !== 'undefined');
25 has.add('native-formdata', function(){
26 // if true, the environment has a native FormData implementation
27 return typeof FormData === 'function';
30 function handleResponse(response, error){
31 var _xhr = response.xhr;
32 response.status = response.xhr.status;
33 response.text = _xhr.responseText;
35 if(response.options.handleAs === 'xml'){
36 response.data = _xhr.responseXML;
49 }else if(util.checkStatus(_xhr.status)){
50 this.resolve(response);
52 error = new RequestError('Unable to load ' + response.url + ' status: ' + _xhr.status, response);
58 var isValid, isReady, addListeners, cancel;
59 if(has('native-xhr2')){
60 // Any platform with XHR2 will only use the watch mechanism for timeout.
62 isValid = function(response){
64 // Check to see if the request should be taken out of the watch queue
65 return !this.isFulfilled();
67 cancel = function(dfd, response){
69 // Canceler for deferred
72 addListeners = function(_xhr, dfd, response){
74 // Adds event listeners to the XMLHttpRequest object
76 dfd.handleResponse(response);
78 function onError(evt){
79 var _xhr = evt.target;
80 var error = new RequestError('Unable to load ' + response.url + ' status: ' + _xhr.status, response);
81 dfd.handleResponse(response, error);
84 function onProgress(evt){
85 if(evt.lengthComputable){
86 response.loaded = evt.loaded;
87 response.total = evt.total;
88 dfd.progress(response);
92 _xhr.addEventListener('load', onLoad, false);
93 _xhr.addEventListener('error', onError, false);
94 _xhr.addEventListener('progress', onProgress, false);
97 _xhr.removeEventListener('load', onLoad, false);
98 _xhr.removeEventListener('error', onError, false);
99 _xhr.removeEventListener('progress', onProgress, false);
103 isValid = function(response){
104 return response.xhr.readyState; //boolean
106 isReady = function(response){
107 return 4 === response.xhr.readyState; //boolean
109 cancel = function(dfd, response){
111 // canceller function for util.deferred call.
112 var xhr = response.xhr;
113 var _at = typeof xhr.abort;
114 if(_at === 'function' || _at === 'object' || _at === 'unknown'){
127 'Content-Type': 'application/x-www-form-urlencoded'
130 function xhr(url, options, returnDeferred){
131 var response = util.parseArgs(
133 util.deepCreate(defaultOptions, options),
134 has('native-formdata') && options && options.data && options.data instanceof FormData
137 options = response.options;
141 remover && remover();
144 //Make the Deferred object for this xhr request.
145 var dfd = util.deferred(
153 var _xhr = response.xhr = xhr._create();
156 // If XHR factory somehow returns nothings,
157 // cancel the deferred.
158 dfd.cancel(new RequestError('XHR was not created'));
159 return returnDeferred ? dfd : dfd.promise;
162 response.getHeader = function(headerName){
163 return this.xhr.getResponseHeader(headerName);
167 remover = addListeners(_xhr, dfd, response);
170 var data = options.data,
171 async = !options.sync,
172 method = options.method;
175 // IE6 won't let you call apply() on the native function.
176 _xhr.open(method, url, async, options.user || undefined, options.password || undefined);
178 if(options.withCredentials){
179 _xhr.withCredentials = options.withCredentials;
182 var headers = options.headers,
185 for(var hdr in headers){
186 if(hdr.toLowerCase() === 'content-type'){
187 contentType = headers[hdr];
188 }else if(headers[hdr]){
189 //Only add header if it has a value. This allows for instance, skipping
190 //insertion of X-Requested-With by specifying empty value.
191 _xhr.setRequestHeader(hdr, headers[hdr]);
196 if(contentType && contentType !== false){
197 _xhr.setRequestHeader('Content-Type', contentType);
199 if(!headers || !('X-Requested-With' in headers)){
200 _xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
204 util.notify.emit('send', response, dfd.promise.cancel);
214 return returnDeferred ? dfd : dfd.promise;
218 xhr = function(url, options){
220 // Sends a request using XMLHttpRequest with the given URL and options.
223 // options: dojo/request/xhr.__Options?
224 // Options for the request.
225 // returns: dojo/request.__Promise
227 xhr.__BaseOptions = declare(request.__BaseOptions, {
229 // Whether to make a synchronous request or not. Default
230 // is `false` (asynchronous).
231 // data: String|Object|FormData?
232 // Data to transfer. This is ignored for GET and DELETE
235 // Headers to use for the request.
237 // Username to use during the request.
239 // Password to use during the request.
240 // withCredentials: Boolean?
241 // For cross-site requests, whether to send credentials
244 xhr.__MethodOptions = declare(null, {
246 // The HTTP method to use to make the request. Must be
247 // uppercase. Default is `"GET"`.
249 xhr.__Options = declare([xhr.__BaseOptions, xhr.__MethodOptions]);
251 xhr.get = function(url, options){
253 // Send an HTTP GET request using XMLHttpRequest with the given URL and options.
256 // options: dojo/request/xhr.__BaseOptions?
257 // Options for the request.
258 // returns: dojo/request.__Promise
260 xhr.post = function(url, options){
262 // Send an HTTP POST request using XMLHttpRequest with the given URL and options.
265 // options: dojo/request/xhr.__BaseOptions?
266 // Options for the request.
267 // returns: dojo/request.__Promise
269 xhr.put = function(url, options){
271 // Send an HTTP PUT request using XMLHttpRequest with the given URL and options.
274 // options: dojo/request/xhr.__BaseOptions?
275 // Options for the request.
276 // returns: dojo/request.__Promise
278 xhr.del = function(url, options){
280 // Send an HTTP DELETE request using XMLHttpRequest with the given URL and options.
283 // options: dojo/request/xhr.__BaseOptions?
284 // Options for the request.
285 // returns: dojo/request.__Promise
288 xhr._create = function(){
290 // does the work of portably generating a new XMLHTTPRequest object.
291 throw new Error('XMLHTTP not available');
293 if(has('native-xhr') && !has('dojo-force-activex-xhr')){
294 xhr._create = function(){
295 return new XMLHttpRequest();
297 }else if(has('activex')){
299 new ActiveXObject('Msxml2.XMLHTTP');
300 xhr._create = function(){
301 return new ActiveXObject('Msxml2.XMLHTTP');
305 new ActiveXObject('Microsoft.XMLHTTP');
306 xhr._create = function(){
307 return new ActiveXObject('Microsoft.XMLHTTP');
313 util.addCommonMethods(xhr);