Request.js 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429
  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. * @requires OpenLayers/Events.js
  7. * @requires OpenLayers/Request/XMLHttpRequest.js
  8. */
  9. /**
  10. * TODO: deprecate me
  11. * Use OpenLayers.Request.proxy instead.
  12. */
  13. OpenLayers.ProxyHost = "";
  14. /**
  15. * Namespace: OpenLayers.Request
  16. * The OpenLayers.Request namespace contains convenience methods for working
  17. * with XMLHttpRequests. These methods work with a cross-browser
  18. * W3C compliant <OpenLayers.Request.XMLHttpRequest> class.
  19. */
  20. if (!OpenLayers.Request) {
  21. /**
  22. * This allows for OpenLayers/Request/XMLHttpRequest.js to be included
  23. * before or after this script.
  24. */
  25. OpenLayers.Request = {};
  26. }
  27. OpenLayers.Util.extend(OpenLayers.Request, {
  28. /**
  29. * Constant: DEFAULT_CONFIG
  30. * {Object} Default configuration for all requests.
  31. */
  32. DEFAULT_CONFIG: {
  33. method: "GET",
  34. url: window.location.href,
  35. async: true,
  36. user: undefined,
  37. password: undefined,
  38. params: null,
  39. proxy: OpenLayers.ProxyHost,
  40. headers: {},
  41. data: null,
  42. callback: function() {},
  43. success: null,
  44. failure: null,
  45. scope: null
  46. },
  47. /**
  48. * Constant: URL_SPLIT_REGEX
  49. */
  50. URL_SPLIT_REGEX: /([^:]*:)\/\/([^:]*:?[^@]*@)?([^:\/\?]*):?([^\/\?]*)/,
  51. /**
  52. * APIProperty: events
  53. * {<OpenLayers.Events>} An events object that handles all
  54. * events on the {<OpenLayers.Request>} object.
  55. *
  56. * All event listeners will receive an event object with three properties:
  57. * request - {<OpenLayers.Request.XMLHttpRequest>} The request object.
  58. * config - {Object} The config object sent to the specific request method.
  59. * requestUrl - {String} The request url.
  60. *
  61. * Supported event types:
  62. * complete - Triggered when we have a response from the request, if a
  63. * listener returns false, no further response processing will take
  64. * place.
  65. * success - Triggered when the HTTP response has a success code (200-299).
  66. * failure - Triggered when the HTTP response does not have a success code.
  67. */
  68. events: new OpenLayers.Events(this),
  69. /**
  70. * Method: makeSameOrigin
  71. * Using the specified proxy, returns a same origin url of the provided url.
  72. *
  73. * Parameters:
  74. * url - {String} An arbitrary url
  75. * proxy {String|Function} The proxy to use to make the provided url a
  76. * same origin url.
  77. *
  78. * Returns
  79. * {String} the same origin url. If no proxy is provided, the returned url
  80. * will be the same as the provided url.
  81. */
  82. makeSameOrigin: function(url, proxy) {
  83. var sameOrigin = url.indexOf("http") !== 0;
  84. var urlParts = !sameOrigin && url.match(this.URL_SPLIT_REGEX);
  85. if (urlParts) {
  86. var location = window.location;
  87. sameOrigin =
  88. urlParts[1] == location.protocol &&
  89. urlParts[3] == location.hostname;
  90. var uPort = urlParts[4], lPort = location.port;
  91. if (uPort != 80 && uPort != "" || lPort != "80" && lPort != "") {
  92. sameOrigin = sameOrigin && uPort == lPort;
  93. }
  94. }
  95. if (!sameOrigin) {
  96. if (proxy) {
  97. if (typeof proxy == "function") {
  98. url = proxy(url);
  99. } else {
  100. url = proxy + encodeURIComponent(url);
  101. }
  102. }
  103. }
  104. return url;
  105. },
  106. /**
  107. * APIMethod: issue
  108. * Create a new XMLHttpRequest object, open it, set any headers, bind
  109. * a callback to done state, and send any data. It is recommended that
  110. * you use one <GET>, <POST>, <PUT>, <DELETE>, <OPTIONS>, or <HEAD>.
  111. * This method is only documented to provide detail on the configuration
  112. * options available to all request methods.
  113. *
  114. * Parameters:
  115. * config - {Object} Object containing properties for configuring the
  116. * request. Allowed configuration properties are described below.
  117. * This object is modified and should not be reused.
  118. *
  119. * Allowed config properties:
  120. * method - {String} One of GET, POST, PUT, DELETE, HEAD, or
  121. * OPTIONS. Default is GET.
  122. * url - {String} URL for the request.
  123. * async - {Boolean} Open an asynchronous request. Default is true.
  124. * user - {String} User for relevant authentication scheme. Set
  125. * to null to clear current user.
  126. * password - {String} Password for relevant authentication scheme.
  127. * Set to null to clear current password.
  128. * proxy - {String} Optional proxy. Defaults to
  129. * <OpenLayers.ProxyHost>.
  130. * params - {Object} Any key:value pairs to be appended to the
  131. * url as a query string. Assumes url doesn't already include a query
  132. * string or hash. Typically, this is only appropriate for <GET>
  133. * requests where the query string will be appended to the url.
  134. * Parameter values that are arrays will be
  135. * concatenated with a comma (note that this goes against form-encoding)
  136. * as is done with <OpenLayers.Util.getParameterString>.
  137. * headers - {Object} Object with header:value pairs to be set on
  138. * the request.
  139. * data - {String | Document} Optional data to send with the request.
  140. * Typically, this is only used with <POST> and <PUT> requests.
  141. * Make sure to provide the appropriate "Content-Type" header for your
  142. * data. For <POST> and <PUT> requests, the content type defaults to
  143. * "application-xml". If your data is a different content type, or
  144. * if you are using a different HTTP method, set the "Content-Type"
  145. * header to match your data type.
  146. * callback - {Function} Function to call when request is done.
  147. * To determine if the request failed, check request.status (200
  148. * indicates success).
  149. * success - {Function} Optional function to call if request status is in
  150. * the 200s. This will be called in addition to callback above and
  151. * would typically only be used as an alternative.
  152. * failure - {Function} Optional function to call if request status is not
  153. * in the 200s. This will be called in addition to callback above and
  154. * would typically only be used as an alternative.
  155. * scope - {Object} If callback is a public method on some object,
  156. * set the scope to that object.
  157. *
  158. * Returns:
  159. * {XMLHttpRequest} Request object. To abort the request before a response
  160. * is received, call abort() on the request object.
  161. */
  162. issue: function(config) {
  163. // apply default config - proxy host may have changed
  164. var defaultConfig = OpenLayers.Util.extend(
  165. this.DEFAULT_CONFIG,
  166. {proxy: OpenLayers.ProxyHost}
  167. );
  168. config = config || {};
  169. config.headers = config.headers || {};
  170. config = OpenLayers.Util.applyDefaults(config, defaultConfig);
  171. config.headers = OpenLayers.Util.applyDefaults(config.headers, defaultConfig.headers);
  172. // Always set the "X-Requested-With" header to signal that this request
  173. // was issued through the XHR-object. Since header keys are case
  174. // insensitive and we want to allow overriding of the "X-Requested-With"
  175. // header through the user we cannot use applyDefaults, but have to
  176. // check manually whether we were called with a "X-Requested-With"
  177. // header.
  178. var customRequestedWithHeader = false,
  179. headerKey;
  180. for(headerKey in config.headers) {
  181. if (config.headers.hasOwnProperty( headerKey )) {
  182. if (headerKey.toLowerCase() === 'x-requested-with') {
  183. customRequestedWithHeader = true;
  184. }
  185. }
  186. }
  187. if (customRequestedWithHeader === false) {
  188. // we did not have a custom "X-Requested-With" header
  189. config.headers['X-Requested-With'] = 'XMLHttpRequest';
  190. }
  191. // create request, open, and set headers
  192. var request = new OpenLayers.Request.XMLHttpRequest();
  193. var url = OpenLayers.Util.urlAppend(config.url,
  194. OpenLayers.Util.getParameterString(config.params || {}));
  195. url = OpenLayers.Request.makeSameOrigin(url, config.proxy);
  196. request.open(
  197. config.method, url, config.async, config.user, config.password
  198. );
  199. for(var header in config.headers) {
  200. request.setRequestHeader(header, config.headers[header]);
  201. }
  202. var events = this.events;
  203. // we want to execute runCallbacks with "this" as the
  204. // execution scope
  205. var self = this;
  206. request.onreadystatechange = function() {
  207. if(request.readyState == OpenLayers.Request.XMLHttpRequest.DONE) {
  208. var proceed = events.triggerEvent(
  209. "complete",
  210. {request: request, config: config, requestUrl: url}
  211. );
  212. if(proceed !== false) {
  213. self.runCallbacks(
  214. {request: request, config: config, requestUrl: url}
  215. );
  216. }
  217. }
  218. };
  219. // send request (optionally with data) and return
  220. // call in a timeout for asynchronous requests so the return is
  221. // available before readyState == 4 for cached docs
  222. if(config.async === false) {
  223. request.send(config.data);
  224. } else {
  225. window.setTimeout(function(){
  226. if (request.readyState !== 0) { // W3C: 0-UNSENT
  227. request.send(config.data);
  228. }
  229. }, 0);
  230. }
  231. return request;
  232. },
  233. /**
  234. * Method: runCallbacks
  235. * Calls the complete, success and failure callbacks. Application
  236. * can listen to the "complete" event, have the listener
  237. * display a confirm window and always return false, and
  238. * execute OpenLayers.Request.runCallbacks if the user
  239. * hits "yes" in the confirm window.
  240. *
  241. * Parameters:
  242. * options - {Object} Hash containing request, config and requestUrl keys
  243. */
  244. runCallbacks: function(options) {
  245. var request = options.request;
  246. var config = options.config;
  247. // bind callbacks to readyState 4 (done)
  248. var complete = (config.scope) ?
  249. OpenLayers.Function.bind(config.callback, config.scope) :
  250. config.callback;
  251. // optional success callback
  252. var success;
  253. if(config.success) {
  254. success = (config.scope) ?
  255. OpenLayers.Function.bind(config.success, config.scope) :
  256. config.success;
  257. }
  258. // optional failure callback
  259. var failure;
  260. if(config.failure) {
  261. failure = (config.scope) ?
  262. OpenLayers.Function.bind(config.failure, config.scope) :
  263. config.failure;
  264. }
  265. if (OpenLayers.Util.createUrlObject(config.url).protocol == "file:" &&
  266. request.responseText) {
  267. request.status = 200;
  268. }
  269. complete(request);
  270. if (!request.status || (request.status >= 200 && request.status < 300)) {
  271. this.events.triggerEvent("success", options);
  272. if(success) {
  273. success(request);
  274. }
  275. }
  276. if(request.status && (request.status < 200 || request.status >= 300)) {
  277. this.events.triggerEvent("failure", options);
  278. if(failure) {
  279. failure(request);
  280. }
  281. }
  282. },
  283. /**
  284. * APIMethod: GET
  285. * Send an HTTP GET request. Additional configuration properties are
  286. * documented in the <issue> method, with the method property set
  287. * to GET.
  288. *
  289. * Parameters:
  290. * config - {Object} Object with properties for configuring the request.
  291. * See the <issue> method for documentation of allowed properties.
  292. * This object is modified and should not be reused.
  293. *
  294. * Returns:
  295. * {XMLHttpRequest} Request object.
  296. */
  297. GET: function(config) {
  298. config = OpenLayers.Util.extend(config, {method: "GET"});
  299. return OpenLayers.Request.issue(config);
  300. },
  301. /**
  302. * APIMethod: POST
  303. * Send a POST request. Additional configuration properties are
  304. * documented in the <issue> method, with the method property set
  305. * to POST and "Content-Type" header set to "application/xml".
  306. *
  307. * Parameters:
  308. * config - {Object} Object with properties for configuring the request.
  309. * See the <issue> method for documentation of allowed properties. The
  310. * default "Content-Type" header will be set to "application-xml" if
  311. * none is provided. This object is modified and should not be reused.
  312. *
  313. * Returns:
  314. * {XMLHttpRequest} Request object.
  315. */
  316. POST: function(config) {
  317. config = OpenLayers.Util.extend(config, {method: "POST"});
  318. // set content type to application/xml if it isn't already set
  319. config.headers = config.headers ? config.headers : {};
  320. if(!("CONTENT-TYPE" in OpenLayers.Util.upperCaseObject(config.headers))) {
  321. config.headers["Content-Type"] = "application/xml";
  322. }
  323. return OpenLayers.Request.issue(config);
  324. },
  325. /**
  326. * APIMethod: PUT
  327. * Send an HTTP PUT request. Additional configuration properties are
  328. * documented in the <issue> method, with the method property set
  329. * to PUT and "Content-Type" header set to "application/xml".
  330. *
  331. * Parameters:
  332. * config - {Object} Object with properties for configuring the request.
  333. * See the <issue> method for documentation of allowed properties. The
  334. * default "Content-Type" header will be set to "application-xml" if
  335. * none is provided. This object is modified and should not be reused.
  336. *
  337. * Returns:
  338. * {XMLHttpRequest} Request object.
  339. */
  340. PUT: function(config) {
  341. config = OpenLayers.Util.extend(config, {method: "PUT"});
  342. // set content type to application/xml if it isn't already set
  343. config.headers = config.headers ? config.headers : {};
  344. if(!("CONTENT-TYPE" in OpenLayers.Util.upperCaseObject(config.headers))) {
  345. config.headers["Content-Type"] = "application/xml";
  346. }
  347. return OpenLayers.Request.issue(config);
  348. },
  349. /**
  350. * APIMethod: DELETE
  351. * Send an HTTP DELETE request. Additional configuration properties are
  352. * documented in the <issue> method, with the method property set
  353. * to DELETE.
  354. *
  355. * Parameters:
  356. * config - {Object} Object with properties for configuring the request.
  357. * See the <issue> method for documentation of allowed properties.
  358. * This object is modified and should not be reused.
  359. *
  360. * Returns:
  361. * {XMLHttpRequest} Request object.
  362. */
  363. DELETE: function(config) {
  364. config = OpenLayers.Util.extend(config, {method: "DELETE"});
  365. return OpenLayers.Request.issue(config);
  366. },
  367. /**
  368. * APIMethod: HEAD
  369. * Send an HTTP HEAD request. Additional configuration properties are
  370. * documented in the <issue> method, with the method property set
  371. * to HEAD.
  372. *
  373. * Parameters:
  374. * config - {Object} Object with properties for configuring the request.
  375. * See the <issue> method for documentation of allowed properties.
  376. * This object is modified and should not be reused.
  377. *
  378. * Returns:
  379. * {XMLHttpRequest} Request object.
  380. */
  381. HEAD: function(config) {
  382. config = OpenLayers.Util.extend(config, {method: "HEAD"});
  383. return OpenLayers.Request.issue(config);
  384. },
  385. /**
  386. * APIMethod: OPTIONS
  387. * Send an HTTP OPTIONS request. Additional configuration properties are
  388. * documented in the <issue> method, with the method property set
  389. * to OPTIONS.
  390. *
  391. * Parameters:
  392. * config - {Object} Object with properties for configuring the request.
  393. * See the <issue> method for documentation of allowed properties.
  394. * This object is modified and should not be reused.
  395. *
  396. * Returns:
  397. * {XMLHttpRequest} Request object.
  398. */
  399. OPTIONS: function(config) {
  400. config = OpenLayers.Util.extend(config, {method: "OPTIONS"});
  401. return OpenLayers.Request.issue(config);
  402. }
  403. });