Request.js 15 KB

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