Project

General

Profile

Download (16.5 KB) Statistics
| Branch: | Tag: | Revision:
1
/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for
2
 * full list of contributors). Published under the 2-clause BSD license.
3
 * See license.txt in the OpenLayers distribution or repository for the
4
 * full text of the license. */
5

    
6
/**
7
 * @requires OpenLayers/Events.js
8
 * @requires OpenLayers/Request/XMLHttpRequest.js
9
 */
10

    
11
/**
12
 * TODO: deprecate me
13
 * Use OpenLayers.Request.proxy instead.
14
 */
15
OpenLayers.ProxyHost = "";
16

    
17
/**
18
 * Namespace: OpenLayers.Request
19
 * The OpenLayers.Request namespace contains convenience methods for working
20
 *     with XMLHttpRequests.  These methods work with a cross-browser
21
 *     W3C compliant <OpenLayers.Request.XMLHttpRequest> class.
22
 */
23
if (!OpenLayers.Request) {
24
    /**
25
     * This allows for OpenLayers/Request/XMLHttpRequest.js to be included
26
     * before or after this script.
27
     */
28
    OpenLayers.Request = {};
29
}
30
OpenLayers.Util.extend(OpenLayers.Request, {
31
    
32
    /**
33
     * Constant: DEFAULT_CONFIG
34
     * {Object} Default configuration for all requests.
35
     */
36
    DEFAULT_CONFIG: {
37
        method: "GET",
38
        url: window.location.href,
39
        async: true,
40
        user: undefined,
41
        password: undefined,
42
        params: null,
43
        proxy: OpenLayers.ProxyHost,
44
        headers: {},
45
        data: null,
46
        callback: function() {},
47
        success: null,
48
        failure: null,
49
        scope: null
50
    },
51
    
52
    /**
53
     * Constant: URL_SPLIT_REGEX
54
     */
55
    URL_SPLIT_REGEX: /([^:]*:)\/\/([^:]*:?[^@]*@)?([^:\/\?]*):?([^\/\?]*)/,
56
    
57
    /**
58
     * APIProperty: events
59
     * {<OpenLayers.Events>} An events object that handles all 
60
     *     events on the {<OpenLayers.Request>} object.
61
     *
62
     * All event listeners will receive an event object with three properties:
63
     * request - {<OpenLayers.Request.XMLHttpRequest>} The request object.
64
     * config - {Object} The config object sent to the specific request method.
65
     * requestUrl - {String} The request url.
66
     * 
67
     * Supported event types:
68
     * complete - Triggered when we have a response from the request, if a
69
     *     listener returns false, no further response processing will take
70
     *     place.
71
     * success - Triggered when the HTTP response has a success code (200-299).
72
     * failure - Triggered when the HTTP response does not have a success code.
73
     */
74
    events: new OpenLayers.Events(this),
75
    
76
    /**
77
     * Method: makeSameOrigin
78
     * Using the specified proxy, returns a same origin url of the provided url.
79
     *
80
     * Parameters:
81
     * url - {String} An arbitrary url
82
     * proxy {String|Function} The proxy to use to make the provided url a
83
     *     same origin url.
84
     *
85
     * Returns
86
     * {String} the same origin url. If no proxy is provided, the returned url
87
     *     will be the same as the provided url.
88
     */
89
    makeSameOrigin: function(url, proxy) {
90
        var sameOrigin = url.indexOf("http") !== 0;
91
        var urlParts = !sameOrigin && url.match(this.URL_SPLIT_REGEX);
92
        if (urlParts) {
93
            var location = window.location;
94
            sameOrigin =
95
                urlParts[1] == location.protocol &&
96
                urlParts[3] == location.hostname;
97
            var uPort = urlParts[4], lPort = location.port;
98
            if (uPort != 80 && uPort != "" || lPort != "80" && lPort != "") {
99
                sameOrigin = sameOrigin && uPort == lPort;
100
            }
101
        }
102
        if (!sameOrigin) {
103
            if (proxy) {
104
                if (typeof proxy == "function") {
105
                    url = proxy(url);
106
                } else {
107
                    url = proxy + encodeURIComponent(url);
108
                }
109
            }
110
        }
111
        return url;
112
    },
113

    
114
    /**
115
     * APIMethod: issue
116
     * Create a new XMLHttpRequest object, open it, set any headers, bind
117
     *     a callback to done state, and send any data.  It is recommended that
118
     *     you use one <GET>, <POST>, <PUT>, <DELETE>, <OPTIONS>, or <HEAD>.
119
     *     This method is only documented to provide detail on the configuration
120
     *     options available to all request methods.
121
     *
122
     * Parameters:
123
     * config - {Object} Object containing properties for configuring the
124
     *     request.  Allowed configuration properties are described below.
125
     *     This object is modified and should not be reused.
126
     *
127
     * Allowed config properties:
128
     * method - {String} One of GET, POST, PUT, DELETE, HEAD, or
129
     *     OPTIONS.  Default is GET.
130
     * url - {String} URL for the request.
131
     * async - {Boolean} Open an asynchronous request.  Default is true.
132
     * user - {String} User for relevant authentication scheme.  Set
133
     *     to null to clear current user.
134
     * password - {String} Password for relevant authentication scheme.
135
     *     Set to null to clear current password.
136
     * proxy - {String} Optional proxy.  Defaults to
137
     *     <OpenLayers.ProxyHost>.
138
     * params - {Object} Any key:value pairs to be appended to the
139
     *     url as a query string.  Assumes url doesn't already include a query
140
     *     string or hash.  Typically, this is only appropriate for <GET>
141
     *     requests where the query string will be appended to the url.
142
     *     Parameter values that are arrays will be
143
     *     concatenated with a comma (note that this goes against form-encoding)
144
     *     as is done with <OpenLayers.Util.getParameterString>.
145
     * headers - {Object} Object with header:value pairs to be set on
146
     *     the request.
147
     * data - {String | Document} Optional data to send with the request.
148
     *     Typically, this is only used with <POST> and <PUT> requests.
149
     *     Make sure to provide the appropriate "Content-Type" header for your
150
     *     data.  For <POST> and <PUT> requests, the content type defaults to
151
     *     "application-xml".  If your data is a different content type, or
152
     *     if you are using a different HTTP method, set the "Content-Type"
153
     *     header to match your data type.
154
     * callback - {Function} Function to call when request is done.
155
     *     To determine if the request failed, check request.status (200
156
     *     indicates success).
157
     * success - {Function} Optional function to call if request status is in
158
     *     the 200s.  This will be called in addition to callback above and
159
     *     would typically only be used as an alternative.
160
     * failure - {Function} Optional function to call if request status is not
161
     *     in the 200s.  This will be called in addition to callback above and
162
     *     would typically only be used as an alternative.
163
     * scope - {Object} If callback is a public method on some object,
164
     *     set the scope to that object.
165
     *
166
     * Returns:
167
     * {XMLHttpRequest} Request object.  To abort the request before a response
168
     *     is received, call abort() on the request object.
169
     */
170
    issue: function(config) {        
171
        // apply default config - proxy host may have changed
172
        var defaultConfig = OpenLayers.Util.extend(
173
            this.DEFAULT_CONFIG,
174
            {proxy: OpenLayers.ProxyHost}
175
        );
176
        config = config || {};
177
        config.headers = config.headers || {};
178
        config = OpenLayers.Util.applyDefaults(config, defaultConfig);
179
        config.headers = OpenLayers.Util.applyDefaults(config.headers, defaultConfig.headers);
180
        // Always set the "X-Requested-With" header to signal that this request
181
        // was issued through the XHR-object. Since header keys are case 
182
        // insensitive and we want to allow overriding of the "X-Requested-With"
183
        // header through the user we cannot use applyDefaults, but have to 
184
        // check manually whether we were called with a "X-Requested-With"
185
        // header.
186
        var customRequestedWithHeader = false,
187
            headerKey;
188
        for(headerKey in config.headers) {
189
            if (config.headers.hasOwnProperty( headerKey )) {
190
                if (headerKey.toLowerCase() === 'x-requested-with') {
191
                    customRequestedWithHeader = true;
192
                }
193
            }
194
        }
195
        if (customRequestedWithHeader === false) {
196
            // we did not have a custom "X-Requested-With" header
197
            config.headers['X-Requested-With'] = 'XMLHttpRequest';
198
        }
199

    
200
        // create request, open, and set headers
201
        var request = new OpenLayers.Request.XMLHttpRequest();
202
        var url = OpenLayers.Util.urlAppend(config.url, 
203
            OpenLayers.Util.getParameterString(config.params || {}));
204
        url = OpenLayers.Request.makeSameOrigin(url, config.proxy);
205
        request.open(
206
            config.method, url, config.async, config.user, config.password
207
        );
208
        for(var header in config.headers) {
209
            request.setRequestHeader(header, config.headers[header]);
210
        }
211

    
212
        var events = this.events;
213

    
214
        // we want to execute runCallbacks with "this" as the
215
        // execution scope
216
        var self = this;
217
        
218
        request.onreadystatechange = function() {
219
            if(request.readyState == OpenLayers.Request.XMLHttpRequest.DONE) {
220
                var proceed = events.triggerEvent(
221
                    "complete",
222
                    {request: request, config: config, requestUrl: url}
223
                );
224
                if(proceed !== false) {
225
                    self.runCallbacks(
226
                        {request: request, config: config, requestUrl: url}
227
                    );
228
                }
229
            }
230
        };
231
        
232
        // send request (optionally with data) and return
233
        // call in a timeout for asynchronous requests so the return is
234
        // available before readyState == 4 for cached docs
235
        if(config.async === false) {
236
            request.send(config.data);
237
        } else {
238
            window.setTimeout(function(){
239
                if (request.readyState !== 0) { // W3C: 0-UNSENT
240
                    request.send(config.data);
241
                }
242
            }, 0);
243
        }
244
        return request;
245
    },
246
    
247
    /**
248
     * Method: runCallbacks
249
     * Calls the complete, success and failure callbacks. Application
250
     *    can listen to the "complete" event, have the listener 
251
     *    display a confirm window and always return false, and
252
     *    execute OpenLayers.Request.runCallbacks if the user
253
     *    hits "yes" in the confirm window.
254
     *
255
     * Parameters:
256
     * options - {Object} Hash containing request, config and requestUrl keys
257
     */
258
    runCallbacks: function(options) {
259
        var request = options.request;
260
        var config = options.config;
261
        
262
        // bind callbacks to readyState 4 (done)
263
        var complete = (config.scope) ?
264
            OpenLayers.Function.bind(config.callback, config.scope) :
265
            config.callback;
266
        
267
        // optional success callback
268
        var success;
269
        if(config.success) {
270
            success = (config.scope) ?
271
                OpenLayers.Function.bind(config.success, config.scope) :
272
                config.success;
273
        }
274

    
275
        // optional failure callback
276
        var failure;
277
        if(config.failure) {
278
            failure = (config.scope) ?
279
                OpenLayers.Function.bind(config.failure, config.scope) :
280
                config.failure;
281
        }
282

    
283
        if (OpenLayers.Util.createUrlObject(config.url).protocol == "file:" &&
284
                                                        request.responseText) {
285
            request.status = 200;
286
        }
287
        complete(request);
288

    
289
        if (!request.status || (request.status >= 200 && request.status < 300)) {
290
            this.events.triggerEvent("success", options);
291
            if(success) {
292
                success(request);
293
            }
294
        }
295
        if(request.status && (request.status < 200 || request.status >= 300)) {                    
296
            this.events.triggerEvent("failure", options);
297
            if(failure) {
298
                failure(request);
299
            }
300
        }
301
    },
302
    
303
    /**
304
     * APIMethod: GET
305
     * Send an HTTP GET request.  Additional configuration properties are
306
     *     documented in the <issue> method, with the method property set
307
     *     to GET.
308
     *
309
     * Parameters:
310
     * config - {Object} Object with properties for configuring the request.
311
     *     See the <issue> method for documentation of allowed properties.
312
     *     This object is modified and should not be reused.
313
     * 
314
     * Returns:
315
     * {XMLHttpRequest} Request object.
316
     */
317
    GET: function(config) {
318
        config = OpenLayers.Util.extend(config, {method: "GET"});
319
        return OpenLayers.Request.issue(config);
320
    },
321
    
322
    /**
323
     * APIMethod: POST
324
     * Send a POST request.  Additional configuration properties are
325
     *     documented in the <issue> method, with the method property set
326
     *     to POST and "Content-Type" header set to "application/xml".
327
     *
328
     * Parameters:
329
     * config - {Object} Object with properties for configuring the request.
330
     *     See the <issue> method for documentation of allowed properties.  The
331
     *     default "Content-Type" header will be set to "application-xml" if
332
     *     none is provided.  This object is modified and should not be reused.
333
     * 
334
     * Returns:
335
     * {XMLHttpRequest} Request object.
336
     */
337
    POST: function(config) {
338
        config = OpenLayers.Util.extend(config, {method: "POST"});
339
        // set content type to application/xml if it isn't already set
340
        config.headers = config.headers ? config.headers : {};
341
        if(!("CONTENT-TYPE" in OpenLayers.Util.upperCaseObject(config.headers))) {
342
            config.headers["Content-Type"] = "application/xml";
343
        }
344
        return OpenLayers.Request.issue(config);
345
    },
346
    
347
    /**
348
     * APIMethod: PUT
349
     * Send an HTTP PUT request.  Additional configuration properties are
350
     *     documented in the <issue> method, with the method property set
351
     *     to PUT and "Content-Type" header set to "application/xml".
352
     *
353
     * Parameters:
354
     * config - {Object} Object with properties for configuring the request.
355
     *     See the <issue> method for documentation of allowed properties.  The
356
     *     default "Content-Type" header will be set to "application-xml" if
357
     *     none is provided.  This object is modified and should not be reused.
358
     * 
359
     * Returns:
360
     * {XMLHttpRequest} Request object.
361
     */
362
    PUT: function(config) {
363
        config = OpenLayers.Util.extend(config, {method: "PUT"});
364
        // set content type to application/xml if it isn't already set
365
        config.headers = config.headers ? config.headers : {};
366
        if(!("CONTENT-TYPE" in OpenLayers.Util.upperCaseObject(config.headers))) {
367
            config.headers["Content-Type"] = "application/xml";
368
        }
369
        return OpenLayers.Request.issue(config);
370
    },
371
    
372
    /**
373
     * APIMethod: DELETE
374
     * Send an HTTP DELETE request.  Additional configuration properties are
375
     *     documented in the <issue> method, with the method property set
376
     *     to DELETE.
377
     *
378
     * Parameters:
379
     * config - {Object} Object with properties for configuring the request.
380
     *     See the <issue> method for documentation of allowed properties.
381
     *     This object is modified and should not be reused.
382
     * 
383
     * Returns:
384
     * {XMLHttpRequest} Request object.
385
     */
386
    DELETE: function(config) {
387
        config = OpenLayers.Util.extend(config, {method: "DELETE"});
388
        return OpenLayers.Request.issue(config);
389
    },
390
  
391
    /**
392
     * APIMethod: HEAD
393
     * Send an HTTP HEAD request.  Additional configuration properties are
394
     *     documented in the <issue> method, with the method property set
395
     *     to HEAD.
396
     *
397
     * Parameters:
398
     * config - {Object} Object with properties for configuring the request.
399
     *     See the <issue> method for documentation of allowed properties.
400
     *     This object is modified and should not be reused.
401
     * 
402
     * Returns:
403
     * {XMLHttpRequest} Request object.
404
     */
405
    HEAD: function(config) {
406
        config = OpenLayers.Util.extend(config, {method: "HEAD"});
407
        return OpenLayers.Request.issue(config);
408
    },
409
    
410
    /**
411
     * APIMethod: OPTIONS
412
     * Send an HTTP OPTIONS request.  Additional configuration properties are
413
     *     documented in the <issue> method, with the method property set
414
     *     to OPTIONS.
415
     *
416
     * Parameters:
417
     * config - {Object} Object with properties for configuring the request.
418
     *     See the <issue> method for documentation of allowed properties.
419
     *     This object is modified and should not be reused.
420
     * 
421
     * Returns:
422
     * {XMLHttpRequest} Request object.
423
     */
424
    OPTIONS: function(config) {
425
        config = OpenLayers.Util.extend(config, {method: "OPTIONS"});
426
        return OpenLayers.Request.issue(config);
427
    }
428

    
429
});
(21-21/35)