r25048: From the archives (patch found in one of my old working trees):
[jelmer/samba4-debian.git] / webapps / qooxdoo-0.6.5-sdk / frontend / framework / source / class / qx / io / remote / Request.js
1 /* ************************************************************************
2
3    qooxdoo - the new era of web development
4
5    http://qooxdoo.org
6
7    Copyright:
8      2004-2007 1&1 Internet AG, Germany, http://www.1and1.org
9      2006 Derrell Lipman
10
11    License:
12      LGPL: http://www.gnu.org/licenses/lgpl.html
13      EPL: http://www.eclipse.org/org/documents/epl-v10.php
14      See the LICENSE file in the project's top-level directory for details.
15
16    Authors:
17      * Sebastian Werner (wpbasti)
18      * Andreas Ecker (ecker)
19      * Derrell Lipman (derrell)
20
21 ************************************************************************ */
22
23 /* ************************************************************************
24
25 #module(io_remote)
26 #require(qx.net.Http)
27 #require(qx.util.Mime)
28
29 ************************************************************************ */
30
31 /**
32  * This class is used to send HTTP requests to the server.
33  *
34  * @event created {qx.event.type.Event}
35  * @event configured {qx.event.type.Event}
36  * @event sending {qx.event.type.Event}
37  * @event receiving {qx.event.type.Event}
38  * @event completed {qx.event.type.Event}
39  * @event failed {qx.event.type.Event}
40  * @event aborted {qx.event.type.Event}
41  * @event timeout {qx.event.type.Event}
42  *
43  * @param vUrl {String} Target url to issue the request to.
44  * @param vMethod {String} Determines that type of request to issue (GET or POST). Default is GET.
45  * @param vResponseType {String} The mime type of the response. Default is text/plain {@link qx.util.Mime}.
46  */
47 qx.OO.defineClass("qx.io.remote.Request", qx.core.Target,
48 function(vUrl, vMethod, vResponseType)
49 {
50   qx.core.Target.call(this);
51
52   this._requestHeaders = {};
53   this._parameters = {};
54
55   this.setUrl(vUrl);
56   this.setMethod(vMethod || qx.net.Http.METHOD_GET);
57   this.setResponseType(vResponseType || qx.util.Mime.TEXT);
58
59   this.setProhibitCaching(true);
60
61   // Prototype-Style Request Headers
62   this.setRequestHeader("X-Requested-With", "qooxdoo");
63   this.setRequestHeader("X-Qooxdoo-Version", qx.core.Version.toString());
64
65   // Get the next sequence number for this request
66   this._seqNum = ++qx.io.remote.Request._seqNum;
67 });
68
69
70
71
72 /*
73 ---------------------------------------------------------------------------
74   PROPERTIES
75 ---------------------------------------------------------------------------
76 */
77 /*!
78   Target url to issue the request to.
79 */
80 qx.OO.addProperty({ name : "url", type : "string" });
81 /*!
82   Determines what type of request to issue (GET or POST).
83 */
84 qx.OO.addProperty(
85 {
86   name           : "method",
87   type           : "string",
88   possibleValues : [
89                    qx.net.Http.METHOD_GET, qx.net.Http.METHOD_POST,
90                    qx.net.Http.METHOD_PUT, qx.net.Http.METHOD_HEAD,
91                    qx.net.Http.METHOD_DELETE
92                    ]
93 });
94 /*!
95   Set the request to asynchronous.
96 */
97 qx.OO.addProperty({ name : "asynchronous", type : "boolean", defaultValue : true,
98                     getAlias: "isAsynchronous" });
99 /*!
100   Set the data to be sent via this request
101 */
102 qx.OO.addProperty({ name : "data", type : "string" });
103 /*!
104   Username to use for HTTP authentication. Null if HTTP authentication
105   is not used.
106 */
107 qx.OO.addProperty({ name : "username", type : "string" });
108 /*!
109   Password to use for HTTP authentication. Null if HTTP authentication
110   is not used.
111 */
112 qx.OO.addProperty({ name : "password", type : "string" });
113 qx.OO.addProperty(
114 {
115   name           : "state",
116   type           : "string",
117   possibleValues : [
118                    "configured", "queued",
119                    "sending", "receiving",
120                    "completed", "aborted",
121                    "timeout", "failed"
122                    ],
123   defaultValue   : "configured"
124 });
125 /*
126   Response type of request.
127
128   The response type is a MIME type, default is text/plain. Other
129   supported MIME types are text/javascript, text/html, application/json,
130   application/xml.
131
132   @see qx.util.Mime
133 */
134 qx.OO.addProperty({
135   name           : "responseType",
136   type           : "string",
137   possibleValues : [
138                    qx.util.Mime.TEXT,
139                    qx.util.Mime.JAVASCRIPT, qx.util.Mime.JSON,
140                    qx.util.Mime.XML, qx.util.Mime.HTML
141                    ]
142 });
143 /*!
144   Number of millieseconds before the request is being timed out.
145
146   If this property is null, the timeout for the request comes is the
147   qx.io.remote.RequestQueue's property defaultTimeout.
148 */
149 qx.OO.addProperty({ name : "timeout", type : "number" });
150
151 /*!
152   Prohibit request from being cached.
153
154   Setting the value to true adds a parameter "nocache" to the request
155   with a value of the current time. Setting the value to false removes
156   the parameter.
157 */
158 qx.OO.addProperty({ name : "prohibitCaching", type : "boolean" });
159 /*!
160   Indicate that the request is cross domain.
161
162   A request is cross domain if the request's URL points to a host other
163   than the local host. This switches the concrete implementation that
164   is used for sending the request from qx.io.remote.XmlHttpTransport to
165   qx.io.remote.ScriptTransport, because only the latter can handle cross domain
166   requests.
167 */
168 qx.OO.addProperty({ name : "crossDomain", type : "boolean", defaultValue : false });
169 /*!
170   Indicate that the request will be used for a file upload.
171
172   The request will be used for a file upload.  This switches the concrete
173   implementation that is used for sending the request from
174   qx.io.remote.XmlHttpTransport to qx.io.remote.IFrameTransport, because only
175   the latter can handle file uploads.
176 */
177 qx.OO.addProperty({ name : "fileUpload", type : "boolean", defaultValue : false });
178 /*!
179   The transport instance used for the request.
180
181   This is necessary to be able to abort an asynchronous request.
182 */
183 qx.OO.addProperty({ name : "transport", type : "object", instance : "qx.io.remote.Exchange" });
184 /*!
185   Use Basic HTTP Authentication
186 */
187 qx.OO.addProperty({ name : "useBasicHttpAuth", type : "boolean" });
188
189
190
191
192
193
194 /*
195 ---------------------------------------------------------------------------
196   CORE METHODS
197 ---------------------------------------------------------------------------
198 */
199 /*!
200   Schedule this request for transport to server.
201
202   The request is added to the singleton class qx.io.remote.RequestQueue's list of
203   pending requests.
204 */
205 qx.Proto.send = function() {
206   qx.io.remote.RequestQueue.getInstance().add(this);
207 }
208
209 /*!
210   Abort sending this request.
211
212   The request is removed from the singleton class qx.io.remote.RequestQueue's
213   list of pending events. If the request haven't been scheduled this
214   method is a noop.
215 */
216 qx.Proto.abort = function() {
217   qx.io.remote.RequestQueue.getInstance().abort(this);
218 }
219
220 qx.Proto.reset = function()
221 {
222   switch(this.getState())
223   {
224     case "sending":
225     case "receiving":
226       this.error("Aborting already sent request!");
227       // no break
228
229     case "queued":
230       this.abort();
231       break;
232   }
233 }
234
235
236
237
238
239
240
241 /*
242 ---------------------------------------------------------------------------
243   STATE ALIASES
244 ---------------------------------------------------------------------------
245 */
246
247 qx.Proto.isConfigured = function() {
248   return this.getState() === "configured";
249 }
250
251 qx.Proto.isQueued = function() {
252   return this.getState() === "queued";
253 }
254
255 qx.Proto.isSending = function() {
256   return this.getState() === "sending";
257 }
258
259 qx.Proto.isReceiving = function() {
260   return this.getState() === "receiving";
261 }
262
263 qx.Proto.isCompleted = function() {
264   return this.getState() === "completed";
265 }
266
267 qx.Proto.isAborted = function() {
268   return this.getState() === "aborted";
269 }
270
271 qx.Proto.isTimeout = function() {
272   return this.getState() === "timeout";
273 }
274
275 /*!
276   Return true if the request is in the failed state
277   ("failed").
278 */
279 qx.Proto.isFailed = function() {
280   return this.getState() === "failed";
281 }
282
283
284
285
286
287
288
289 /*
290 ---------------------------------------------------------------------------
291   EVENT HANDLER
292 ---------------------------------------------------------------------------
293 */
294
295 qx.Proto._onqueued = function(e)
296 {
297   // Modify internal state
298   this.setState("queued");
299
300   // Bubbling up
301   this.dispatchEvent(e);
302 }
303
304 qx.Proto._onsending = function(e)
305 {
306   // Modify internal state
307   this.setState("sending");
308
309   // Bubbling up
310   this.dispatchEvent(e);
311 }
312
313 qx.Proto._onreceiving = function(e)
314 {
315   // Modify internal state
316   this.setState("receiving");
317
318   // Bubbling up
319   this.dispatchEvent(e);
320 }
321
322 qx.Proto._oncompleted = function(e)
323 {
324   // Modify internal state
325   this.setState("completed");
326
327   // Bubbling up
328   this.dispatchEvent(e);
329
330   // Automatically dispose after event completion
331   this.dispose();
332 }
333
334 qx.Proto._onaborted = function(e)
335 {
336   // Modify internal state
337   this.setState("aborted");
338
339   // Bubbling up
340   this.dispatchEvent(e);
341
342   // Automatically dispose after event completion
343   this.dispose();
344 }
345
346 qx.Proto._ontimeout = function(e)
347 {
348 /*
349   // User's handler can block until timeout.
350   switch(this.getState())
351   {
352     // If we're no longer running...
353     case "completed":
354     case "timeout":
355     case "aborted":
356     case "failed":
357       // then don't bubble up the timeout event
358       return;
359   }
360 */
361
362   // Modify internal state
363   this.setState("timeout");
364
365   // Bubbling up
366   this.dispatchEvent(e);
367
368   // Automatically dispose after event completion
369   this.dispose();
370 }
371
372 qx.Proto._onfailed = function(e)
373 {
374   // Modify internal state
375   this.setState("failed");
376
377   // Bubbling up
378   this.dispatchEvent(e);
379
380   // Automatically dispose after event completion
381   this.dispose();
382 }
383
384
385
386
387
388
389
390
391 /*
392 ---------------------------------------------------------------------------
393   MODIFIER
394 ---------------------------------------------------------------------------
395 */
396
397 qx.Proto._modifyState = function(propValue, propOldValue, propData)
398 {
399   if (qx.Settings.getValueOfClass("qx.io.remote.Exchange", "enableDebug")) {
400     this.debug("State: " + propValue);
401   }
402
403   return true;
404 }
405
406 qx.Proto._modifyProhibitCaching = function(propValue, propOldValue, propData)
407 {
408   propValue ? this.setParameter("nocache", new Date().valueOf()) : this.removeParameter("nocache");
409
410   return true;
411 }
412
413 qx.Proto._modifyMethod = function(propValue, propOldValue, propData)
414 {
415   if (propValue === qx.net.Http.METHOD_POST) {
416     this.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
417   }
418
419   return true;
420 }
421
422 qx.Proto._modifyResponseType = function(propValue, propOldValue, propData)
423 {
424   this.setRequestHeader("X-Qooxdoo-Response-Type", propValue);
425   return true;
426 }
427
428
429
430
431
432
433
434 /*
435 ---------------------------------------------------------------------------
436   REQUEST HEADER
437 ---------------------------------------------------------------------------
438 */
439 /*!
440   Add a request header to the request.
441
442   Example: request.setRequestHeader("Content-Type", qx.util.Mime.HTML)
443 */
444 qx.Proto.setRequestHeader = function(vId, vValue) {
445   this._requestHeaders[vId] = vValue;
446 }
447
448 qx.Proto.removeRequestHeader = function(vId) {
449   delete this._requestHeaders[vId];
450 }
451
452 qx.Proto.getRequestHeader = function(vId) {
453   return this._requestHeaders[vId] || null;
454 }
455
456 qx.Proto.getRequestHeaders = function() {
457   return this._requestHeaders;
458 }
459
460
461
462
463
464
465
466
467
468 /*
469 ---------------------------------------------------------------------------
470   PARAMETERS
471 ---------------------------------------------------------------------------
472 */
473 /*!
474   Add a parameter to the request.
475
476   @param vId String identifier of the parameter to add.
477   @param vValue Value of parameter. May be a string (for one parameter) or an
478          array of strings (for setting multiple parameter values with the same
479          parameter name).
480 */
481 qx.Proto.setParameter = function(vId, vValue) {
482   this._parameters[vId] = vValue;
483 }
484
485 /*!
486   Remove a parameter from the request.
487
488   @param vId String identifier of the parameter to remove.
489 */
490 qx.Proto.removeParameter = function(vId) {
491   delete this._parameters[vId];
492 }
493
494 /*!
495   Get a parameter in the request.
496
497   @param vId String identifier of the parameter to get.
498 */
499 qx.Proto.getParameter = function(vId) {
500   return this._parameters[vId] || null;
501 }
502
503 /*!
504   Returns an object containg all parameters for the request.
505 */
506 qx.Proto.getParameters = function() {
507   return this._parameters;
508 }
509
510
511
512
513
514
515
516
517 /*
518 ---------------------------------------------------------------------------
519   SEQUENCE NUMBER
520 ---------------------------------------------------------------------------
521 */
522
523 /*
524  * Sequence (id) number of a request, used to associate a response or error
525  * with its initiating request.
526  */
527 qx.io.remote.Request._seqNum = 0;
528
529 /**
530  * Obtain the sequence (id) number used for this request
531  */
532 qx.Proto.getSequenceNumber = function() {
533   return this._seqNum;
534 }
535
536
537
538
539
540
541 /*
542 ---------------------------------------------------------------------------
543   DISPOSER
544 ---------------------------------------------------------------------------
545 */
546
547 qx.Proto.dispose = function()
548 {
549   if (this.getDisposed()) {
550     return;
551   }
552
553   this._requestHeaders = null;
554   this._parameters = null;
555
556   this.setTransport(null);
557
558   return qx.core.Target.prototype.dispose.call(this);
559 }