1 : /* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
2 : /* ***** BEGIN LICENSE BLOCK *****
3 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 : *
5 : * The contents of this file are subject to the Mozilla Public License Version
6 : * 1.1 (the "License"); you may not use this file except in compliance with
7 : * the License. You may obtain a copy of the License at
8 : * http://www.mozilla.org/MPL/
9 : *
10 : * Software distributed under the License is distributed on an "AS IS" basis,
11 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 : * for the specific language governing rights and limitations under the
13 : * License.
14 : *
15 : * The Original Code is Web Workers.
16 : *
17 : * The Initial Developer of the Original Code is
18 : * The Mozilla Foundation.
19 : * Portions created by the Initial Developer are Copyright (C) 2011
20 : * the Initial Developer. All Rights Reserved.
21 : *
22 : * Contributor(s):
23 : * Ben Turner <bent.mozilla@gmail.com> (Original Author)
24 : *
25 : * Alternatively, the contents of this file may be used under the terms of
26 : * either the GNU General Public License Version 2 or later (the "GPL"), or
27 : * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28 : * in which case the provisions of the GPL or the LGPL are applicable instead
29 : * of those above. If you wish to allow use of your version of this file only
30 : * under the terms of either the GPL or the LGPL, and not to allow others to
31 : * use your version of this file under the terms of the MPL, indicate your
32 : * decision by deleting the provisions above and replace them with the notice
33 : * and other provisions required by the GPL or the LGPL. If you do not delete
34 : * the provisions above, a recipient may use your version of this file under
35 : * the terms of any one of the MPL, the GPL or the LGPL.
36 : *
37 : * ***** END LICENSE BLOCK ***** */
38 :
39 : #include "XMLHttpRequest.h"
40 :
41 : #include "jsapi.h"
42 : #include "jsfriendapi.h"
43 :
44 : #include "Exceptions.h"
45 : #include "WorkerPrivate.h"
46 : #include "XMLHttpRequestPrivate.h"
47 :
48 : #include "WorkerInlines.h"
49 :
50 : #define PROPERTY_FLAGS \
51 : (JSPROP_ENUMERATE | JSPROP_SHARED)
52 :
53 : #define FUNCTION_FLAGS \
54 : JSPROP_ENUMERATE
55 :
56 : #define CONSTANT_FLAGS \
57 : (JSPROP_ENUMERATE | JSPROP_SHARED | JSPROP_PERMANENT | JSPROP_READONLY)
58 :
59 : USING_WORKERS_NAMESPACE
60 :
61 : using mozilla::dom::workers::xhr::XMLHttpRequestPrivate;
62 :
63 : namespace {
64 :
65 : class XMLHttpRequestUpload : public events::EventTarget
66 : {
67 : static JSClass sClass;
68 : static JSPropertySpec sProperties[];
69 :
70 : enum
71 : {
72 : STRING_onabort = 0,
73 : STRING_onerror,
74 : STRING_onload,
75 : STRING_onloadstart,
76 : STRING_onprogress,
77 : STRING_onloadend,
78 : STRING_ontimeout,
79 :
80 : STRING_COUNT
81 : };
82 :
83 : static const char* const sEventStrings[STRING_COUNT];
84 :
85 : enum SLOT {
86 : SLOT_xhrParent = 0,
87 :
88 : SLOT_COUNT
89 : };
90 :
91 : public:
92 : static JSClass*
93 0 : Class()
94 : {
95 0 : return &sClass;
96 : }
97 :
98 : static JSObject*
99 0 : InitClass(JSContext* aCx, JSObject* aObj, JSObject* aParentProto)
100 : {
101 : return JS_InitClass(aCx, aObj, aParentProto, &sClass, Construct, 0,
102 0 : sProperties, NULL, NULL, NULL);
103 : }
104 :
105 : static JSObject*
106 0 : Create(JSContext* aCx, JSObject* aParentObj)
107 : {
108 0 : JS_ASSERT(aParentObj);
109 :
110 0 : JSObject* obj = JS_NewObject(aCx, &sClass, NULL, NULL);
111 0 : if (obj) {
112 0 : JS_SetReservedSlot(obj, SLOT_xhrParent, OBJECT_TO_JSVAL(aParentObj));
113 0 : XMLHttpRequestUpload* priv = new XMLHttpRequestUpload();
114 0 : SetJSPrivateSafeish(obj, priv);
115 : }
116 0 : return obj;
117 : }
118 :
119 : static bool
120 : UpdateState(JSContext* aCx, JSObject* aObj, const xhr::StateData& aNewState);
121 :
122 : private:
123 0 : XMLHttpRequestUpload()
124 0 : {
125 0 : MOZ_COUNT_CTOR(mozilla::dom::workers::xhr::XMLHttpRequestUpload);
126 0 : }
127 :
128 0 : ~XMLHttpRequestUpload()
129 0 : {
130 0 : MOZ_COUNT_DTOR(mozilla::dom::workers::xhr::XMLHttpRequestUpload);
131 0 : }
132 :
133 : static XMLHttpRequestUpload*
134 0 : GetPrivate(JSObject* aObj)
135 : {
136 0 : if (aObj) {
137 0 : JSClass* classPtr = JS_GetClass(aObj);
138 0 : if (classPtr == &sClass) {
139 0 : return GetJSPrivateSafeish<XMLHttpRequestUpload>(aObj);
140 : }
141 : }
142 0 : return NULL;
143 : }
144 :
145 : static XMLHttpRequestUpload*
146 0 : GetInstancePrivate(JSContext* aCx, JSObject* aObj, const char* aFunctionName)
147 : {
148 0 : XMLHttpRequestUpload* priv = GetPrivate(aObj);
149 0 : if (priv) {
150 0 : return priv;
151 : }
152 :
153 : JS_ReportErrorNumber(aCx, js_GetErrorMessage, NULL,
154 : JSMSG_INCOMPATIBLE_PROTO, sClass.name, aFunctionName,
155 0 : JS_GetClass(aObj)->name);
156 0 : return NULL;
157 : }
158 :
159 : static JSBool
160 0 : Construct(JSContext* aCx, unsigned aArgc, jsval* aVp)
161 : {
162 : JS_ReportErrorNumber(aCx, js_GetErrorMessage, NULL, JSMSG_WRONG_CONSTRUCTOR,
163 0 : sClass.name);
164 0 : return false;
165 : }
166 :
167 : static void
168 0 : Finalize(JSContext* aCx, JSObject* aObj)
169 : {
170 0 : JS_ASSERT(JS_GetClass(aObj) == &sClass);
171 0 : XMLHttpRequestUpload* priv = GetPrivate(aObj);
172 0 : if (priv) {
173 0 : priv->FinalizeInstance(aCx);
174 0 : delete priv;
175 : }
176 0 : }
177 :
178 : static void
179 0 : Trace(JSTracer* aTrc, JSObject* aObj)
180 : {
181 0 : JS_ASSERT(JS_GetClass(aObj) == &sClass);
182 0 : XMLHttpRequestUpload* priv = GetPrivate(aObj);
183 0 : if (priv) {
184 0 : priv->TraceInstance(aTrc);
185 : }
186 0 : }
187 :
188 : static JSBool
189 0 : GetEventListener(JSContext* aCx, JSObject* aObj, jsid aIdval, jsval* aVp)
190 : {
191 0 : JS_ASSERT(JSID_IS_INT(aIdval));
192 0 : JS_ASSERT(JSID_TO_INT(aIdval) >= 0 && JSID_TO_INT(aIdval) < STRING_COUNT);
193 :
194 0 : const char* name = sEventStrings[JSID_TO_INT(aIdval)];
195 :
196 0 : XMLHttpRequestUpload* priv = GetInstancePrivate(aCx, aObj, name);
197 0 : if (!priv) {
198 0 : return false;
199 : }
200 :
201 0 : return priv->GetEventListenerOnEventTarget(aCx, name + 2, aVp);
202 : }
203 :
204 : static JSBool
205 0 : SetEventListener(JSContext* aCx, JSObject* aObj, jsid aIdval, JSBool aStrict,
206 : jsval* aVp)
207 : {
208 0 : JS_ASSERT(JSID_IS_INT(aIdval));
209 0 : JS_ASSERT(JSID_TO_INT(aIdval) >= 0 && JSID_TO_INT(aIdval) < STRING_COUNT);
210 :
211 0 : const char* name = sEventStrings[JSID_TO_INT(aIdval)];
212 :
213 0 : XMLHttpRequestUpload* priv = GetInstancePrivate(aCx, aObj, name);
214 0 : if (!priv) {
215 0 : return false;
216 : }
217 :
218 0 : return priv->SetEventListenerOnEventTarget(aCx, name + 2, aVp);
219 : }
220 : };
221 :
222 : JSClass XMLHttpRequestUpload::sClass = {
223 : "XMLHttpRequestUpload",
224 : JSCLASS_HAS_PRIVATE | JSCLASS_IMPLEMENTS_BARRIERS | JSCLASS_HAS_RESERVED_SLOTS(SLOT_COUNT),
225 : JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
226 : JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, Finalize,
227 : NULL, NULL, NULL, NULL, Trace
228 : };
229 :
230 : JSPropertySpec XMLHttpRequestUpload::sProperties[] = {
231 1464 : { sEventStrings[STRING_onabort], STRING_onabort, PROPERTY_FLAGS,
232 : GetEventListener, SetEventListener },
233 1464 : { sEventStrings[STRING_onerror], STRING_onerror, PROPERTY_FLAGS,
234 : GetEventListener, SetEventListener },
235 1464 : { sEventStrings[STRING_onload], STRING_onload, PROPERTY_FLAGS,
236 : GetEventListener, SetEventListener },
237 1464 : { sEventStrings[STRING_onloadstart], STRING_onloadstart, PROPERTY_FLAGS,
238 : GetEventListener, SetEventListener },
239 1464 : { sEventStrings[STRING_onprogress], STRING_onprogress, PROPERTY_FLAGS,
240 : GetEventListener, SetEventListener },
241 1464 : { sEventStrings[STRING_onloadend], STRING_onloadend, PROPERTY_FLAGS,
242 : GetEventListener, SetEventListener },
243 1464 : { sEventStrings[STRING_ontimeout], STRING_ontimeout, PROPERTY_FLAGS,
244 : GetEventListener, SetEventListener },
245 : { 0, 0, 0, NULL, NULL }
246 10248 : };
247 :
248 : const char* const XMLHttpRequestUpload::sEventStrings[STRING_COUNT] = {
249 : "onabort",
250 : "onerror",
251 : "onload",
252 : "onloadstart",
253 : "onprogress",
254 : "onloadend",
255 : "ontimeout"
256 : };
257 :
258 : class XMLHttpRequest
259 : {
260 : static JSClass sClass;
261 : static JSPropertySpec sProperties[];
262 : static JSFunctionSpec sFunctions[];
263 : static JSPropertySpec sStaticProperties[];
264 :
265 : enum SLOT {
266 : SLOT_channel = 0,
267 : SLOT_responseXML,
268 : SLOT_responseText,
269 : SLOT_status,
270 : SLOT_statusText,
271 : SLOT_readyState,
272 : SLOT_response,
273 : SLOT_multipart,
274 : SLOT_mozBackgroundRequest,
275 : SLOT_withCredentials,
276 : SLOT_upload,
277 : SLOT_responseType,
278 : SLOT_timeout,
279 :
280 : SLOT_COUNT
281 : };
282 :
283 : enum {
284 : UNSENT = 0,
285 : OPENED = 1,
286 : HEADERS_RECEIVED = 2,
287 : LOADING = 3,
288 : DONE = 4
289 : };
290 :
291 : enum
292 : {
293 : STRING_onreadystatechange = 0,
294 : STRING_onabort,
295 : STRING_onerror,
296 : STRING_onload,
297 : STRING_onloadstart,
298 : STRING_onprogress,
299 : STRING_onloadend,
300 : STRING_ontimeout,
301 :
302 : STRING_COUNT
303 : };
304 :
305 : static const char* const sEventStrings[STRING_COUNT];
306 :
307 : public:
308 : static JSClass*
309 0 : Class()
310 : {
311 0 : return &sClass;
312 : }
313 :
314 : static JSObject*
315 0 : InitClass(JSContext* aCx, JSObject* aObj, JSObject* aParentProto)
316 : {
317 : JSObject* proto = JS_InitClass(aCx, aObj, aParentProto, &sClass, Construct,
318 : 0, sProperties, sFunctions,
319 0 : sStaticProperties, NULL);
320 0 : if (proto && !JS_DefineProperties(aCx, proto, sStaticProperties)) {
321 0 : return NULL;
322 : }
323 :
324 0 : return proto;
325 : }
326 :
327 : static bool
328 0 : UpdateState(JSContext* aCx, JSObject* aObj, const xhr::StateData& aNewState)
329 : {
330 0 : JS_ASSERT(GetPrivate(aObj));
331 :
332 : #define HANDLE_STATE_VALUE(_member, _slot) \
333 : if (aNewState. _member##Exception || !JSVAL_IS_VOID(aNewState. _member)) { \
334 : JS_SetReservedSlot(aObj, _slot, aNewState. _member); \
335 : }
336 :
337 0 : HANDLE_STATE_VALUE(mResponseText, SLOT_responseText)
338 0 : HANDLE_STATE_VALUE(mStatus, SLOT_status)
339 0 : HANDLE_STATE_VALUE(mStatusText, SLOT_statusText)
340 0 : HANDLE_STATE_VALUE(mReadyState, SLOT_readyState)
341 0 : HANDLE_STATE_VALUE(mResponse, SLOT_response)
342 :
343 : #undef HANDLE_STATE_VALUE
344 :
345 0 : return true;
346 : }
347 :
348 : private:
349 : // No instance of this class should ever be created so these are explicitly
350 : // left without an implementation to prevent linking in case someone tries to
351 : // make one.
352 : XMLHttpRequest();
353 : ~XMLHttpRequest();
354 :
355 : static XMLHttpRequestPrivate*
356 0 : GetPrivate(JSObject* aObj)
357 : {
358 0 : if (aObj) {
359 0 : JSClass* classPtr = JS_GetClass(aObj);
360 0 : if (classPtr == &sClass) {
361 0 : return GetJSPrivateSafeish<XMLHttpRequestPrivate>(aObj);
362 : }
363 : }
364 0 : return NULL;
365 : }
366 :
367 : static XMLHttpRequestPrivate*
368 0 : GetInstancePrivate(JSContext* aCx, JSObject* aObj, const char* aFunctionName)
369 : {
370 0 : XMLHttpRequestPrivate* priv = GetPrivate(aObj);
371 0 : if (priv) {
372 0 : return priv;
373 : }
374 :
375 : JS_ReportErrorNumber(aCx, js_GetErrorMessage, NULL,
376 : JSMSG_INCOMPATIBLE_PROTO, sClass.name, aFunctionName,
377 0 : JS_GetClass(aObj)->name);
378 0 : return NULL;
379 : }
380 :
381 : static JSBool
382 0 : Construct(JSContext* aCx, unsigned aArgc, jsval* aVp)
383 : {
384 0 : JSObject* obj = JS_NewObject(aCx, &sClass, NULL, NULL);
385 0 : if (!obj) {
386 0 : return false;
387 : }
388 :
389 0 : JSString* textStr = JS_NewStringCopyN(aCx, "text", 4);
390 0 : if (!textStr) {
391 0 : return false;
392 : }
393 :
394 0 : jsval emptyString = JS_GetEmptyStringValue(aCx);
395 0 : jsval zero = INT_TO_JSVAL(0);
396 :
397 0 : JS_SetReservedSlot(obj, SLOT_channel, JSVAL_NULL);
398 0 : JS_SetReservedSlot(obj, SLOT_responseXML, JSVAL_NULL);
399 0 : JS_SetReservedSlot(obj, SLOT_responseText, emptyString);
400 0 : JS_SetReservedSlot(obj, SLOT_status, zero);
401 0 : JS_SetReservedSlot(obj, SLOT_statusText, emptyString);
402 0 : JS_SetReservedSlot(obj, SLOT_readyState, zero);
403 0 : JS_SetReservedSlot(obj, SLOT_multipart, JSVAL_FALSE);
404 0 : JS_SetReservedSlot(obj, SLOT_mozBackgroundRequest, JSVAL_FALSE);
405 0 : JS_SetReservedSlot(obj, SLOT_withCredentials, JSVAL_FALSE);
406 0 : JS_SetReservedSlot(obj, SLOT_upload, JSVAL_NULL);
407 0 : JS_SetReservedSlot(obj, SLOT_responseType, STRING_TO_JSVAL(textStr));
408 0 : JS_SetReservedSlot(obj, SLOT_timeout, zero);
409 :
410 0 : WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(aCx);
411 0 : XMLHttpRequestPrivate* priv = new XMLHttpRequestPrivate(obj, workerPrivate);
412 0 : SetJSPrivateSafeish(obj, priv);
413 :
414 0 : JS_SET_RVAL(aCx, aVp, OBJECT_TO_JSVAL(obj));
415 0 : return true;
416 : }
417 :
418 : static void
419 0 : Finalize(JSContext* aCx, JSObject* aObj)
420 : {
421 0 : JS_ASSERT(JS_GetClass(aObj) == &sClass);
422 0 : XMLHttpRequestPrivate* priv = GetPrivate(aObj);
423 0 : if (priv) {
424 0 : priv->FinalizeInstance(aCx);
425 0 : delete priv;
426 : }
427 0 : }
428 :
429 : static void
430 0 : Trace(JSTracer* aTrc, JSObject* aObj)
431 : {
432 0 : JS_ASSERT(JS_GetClass(aObj) == &sClass);
433 0 : XMLHttpRequestPrivate* priv = GetPrivate(aObj);
434 0 : if (priv) {
435 0 : priv->TraceInstance(aTrc);
436 : }
437 0 : }
438 :
439 : static JSBool
440 0 : GetProperty(JSContext* aCx, JSObject* aObj, jsid aIdval, jsval* aVp)
441 : {
442 0 : JS_ASSERT(JSID_IS_INT(aIdval));
443 :
444 0 : int32 slot = JSID_TO_INT(aIdval);
445 0 : const char*& name = sProperties[slot].name;
446 :
447 0 : if (!GetInstancePrivate(aCx, aObj, name)) {
448 0 : return false;
449 : }
450 :
451 0 : jsval rval = JS_GetReservedSlot(aObj, slot);
452 :
453 0 : if (JSVAL_IS_VOID(rval)) {
454 : // Throw an exception.
455 0 : exceptions::ThrowDOMExceptionForCode(aCx, INVALID_STATE_ERR);
456 0 : return false;
457 : }
458 :
459 0 : *aVp = rval;
460 0 : return true;
461 : }
462 :
463 : static JSBool
464 0 : GetConstant(JSContext* aCx, JSObject* aObj, jsid idval, jsval* aVp)
465 : {
466 0 : JS_ASSERT(JSID_IS_INT(idval));
467 0 : JS_ASSERT(JSID_TO_INT(idval) >= UNSENT &&
468 0 : JSID_TO_INT(idval) <= DONE);
469 :
470 0 : *aVp = INT_TO_JSVAL(JSID_TO_INT(idval));
471 0 : return true;
472 : }
473 :
474 : static JSBool
475 0 : GetUpload(JSContext* aCx, JSObject* aObj, jsid aIdval, jsval* aVp)
476 : {
477 0 : JS_ASSERT(JSID_IS_INT(aIdval));
478 :
479 0 : int32 slot = JSID_TO_INT(aIdval);
480 :
481 : XMLHttpRequestPrivate* priv =
482 0 : GetInstancePrivate(aCx, aObj, sProperties[slot].name);
483 0 : if (!priv) {
484 0 : return false;
485 : }
486 :
487 0 : jsval uploadVal = JS_GetReservedSlot(aObj, slot);
488 :
489 0 : if (JSVAL_IS_NULL(uploadVal)) {
490 0 : JSObject* uploadObj = XMLHttpRequestUpload::Create(aCx, aObj);
491 0 : if (!uploadObj) {
492 0 : return false;
493 : }
494 :
495 0 : uploadVal = OBJECT_TO_JSVAL(uploadObj);
496 :
497 0 : JS_SetReservedSlot(aObj, slot, uploadVal);
498 :
499 0 : priv->SetUploadObject(uploadObj);
500 : }
501 :
502 0 : JS_ASSERT(!JSVAL_IS_PRIMITIVE(uploadVal));
503 :
504 0 : *aVp = uploadVal;
505 0 : return true;
506 : }
507 :
508 : #define IMPL_SETTER(_name) \
509 : static JSBool \
510 : Set##_name (JSContext* aCx, JSObject* aObj, jsid aIdval, JSBool aStrict, \
511 : jsval* aVp) \
512 : { \
513 : JS_ASSERT(JSID_IS_INT(aIdval)); \
514 : \
515 : int32 slot = JSID_TO_INT(aIdval); \
516 : \
517 : XMLHttpRequestPrivate* priv = \
518 : GetInstancePrivate(aCx, aObj, sProperties[slot].name); \
519 : if (!priv) { \
520 : return false; \
521 : } \
522 : \
523 : jsval oldVal = JS_GetReservedSlot(aObj, slot); \
524 : \
525 : jsval rval = *aVp; \
526 : if (!priv->Set##_name (aCx, oldVal, &rval)) \
527 : return false; \
528 : JS_SetReservedSlot(aObj, slot, rval); \
529 : \
530 : *aVp = rval; \
531 : return true; \
532 : }
533 :
534 0 : IMPL_SETTER(Multipart)
535 0 : IMPL_SETTER(MozBackgroundRequest)
536 0 : IMPL_SETTER(WithCredentials)
537 0 : IMPL_SETTER(ResponseType)
538 0 : IMPL_SETTER(Timeout)
539 :
540 : #undef IMPL_SETTER
541 :
542 : static JSBool
543 0 : GetEventListener(JSContext* aCx, JSObject* aObj, jsid aIdval, jsval* aVp)
544 : {
545 0 : JS_ASSERT(JSID_IS_INT(aIdval));
546 0 : JS_ASSERT(JSID_TO_INT(aIdval) >= 0 && JSID_TO_INT(aIdval) < STRING_COUNT);
547 :
548 0 : const char* name = sEventStrings[JSID_TO_INT(aIdval)];
549 :
550 0 : XMLHttpRequestPrivate* priv = GetInstancePrivate(aCx, aObj, name);
551 0 : if (!priv) {
552 0 : return false;
553 : }
554 :
555 0 : return priv->GetEventListenerOnEventTarget(aCx, name + 2, aVp);
556 : }
557 :
558 : static JSBool
559 0 : SetEventListener(JSContext* aCx, JSObject* aObj, jsid aIdval, JSBool aStrict,
560 : jsval* aVp)
561 : {
562 0 : JS_ASSERT(JSID_IS_INT(aIdval));
563 0 : JS_ASSERT(JSID_TO_INT(aIdval) >= 0 && JSID_TO_INT(aIdval) < STRING_COUNT);
564 :
565 0 : const char* name = sEventStrings[JSID_TO_INT(aIdval)];
566 :
567 0 : XMLHttpRequestPrivate* priv = GetInstancePrivate(aCx, aObj, name);
568 0 : if (!priv) {
569 0 : return false;
570 : }
571 :
572 0 : return priv->SetEventListenerOnEventTarget(aCx, name + 2, aVp);
573 : }
574 :
575 : static JSBool
576 0 : Abort(JSContext* aCx, unsigned aArgc, jsval* aVp)
577 : {
578 0 : JSObject* obj = JS_THIS_OBJECT(aCx, aVp);
579 0 : if (!obj) {
580 0 : return false;
581 : }
582 :
583 : XMLHttpRequestPrivate* priv =
584 0 : GetInstancePrivate(aCx, obj, sFunctions[0].name);
585 0 : if (!priv) {
586 0 : return false;
587 : }
588 :
589 0 : return priv->Abort(aCx);
590 : }
591 :
592 : static JSBool
593 0 : GetAllResponseHeaders(JSContext* aCx, unsigned aArgc, jsval* aVp)
594 : {
595 0 : JSObject* obj = JS_THIS_OBJECT(aCx, aVp);
596 0 : if (!obj) {
597 0 : return false;
598 : }
599 :
600 : XMLHttpRequestPrivate* priv =
601 0 : GetInstancePrivate(aCx, obj, sFunctions[1].name);
602 0 : if (!priv) {
603 0 : return false;
604 : }
605 :
606 0 : JSString* responseHeaders = priv->GetAllResponseHeaders(aCx);
607 0 : if (!responseHeaders) {
608 0 : return false;
609 : }
610 :
611 0 : JS_SET_RVAL(aCx, aVp, STRING_TO_JSVAL(responseHeaders));
612 0 : return true;
613 : }
614 :
615 : static JSBool
616 0 : GetResponseHeader(JSContext* aCx, unsigned aArgc, jsval* aVp)
617 : {
618 0 : JSObject* obj = JS_THIS_OBJECT(aCx, aVp);
619 0 : if (!obj) {
620 0 : return false;
621 : }
622 :
623 : XMLHttpRequestPrivate* priv =
624 0 : GetInstancePrivate(aCx, obj, sFunctions[2].name);
625 0 : if (!priv) {
626 0 : return false;
627 : }
628 :
629 : jsval headerVal;
630 0 : if (!JS_ConvertArguments(aCx, aArgc, JS_ARGV(aCx, aVp), "v", &headerVal)) {
631 0 : return false;
632 : }
633 :
634 : JSString* header;
635 0 : if (JSVAL_IS_NULL(headerVal)) {
636 0 : header = JSVAL_TO_STRING(JS_GetEmptyStringValue(aCx));
637 : }
638 : else {
639 0 : header = JS_ValueToString(aCx, headerVal);
640 0 : if (!header) {
641 0 : return false;
642 : }
643 : }
644 :
645 0 : JSString* value = priv->GetResponseHeader(aCx, header);
646 0 : if (!value) {
647 0 : return false;
648 : }
649 :
650 0 : JS_SET_RVAL(aCx, aVp, STRING_TO_JSVAL(value));
651 0 : return true;
652 : }
653 :
654 : static JSBool
655 0 : Open(JSContext* aCx, unsigned aArgc, jsval* aVp)
656 : {
657 0 : JSObject* obj = JS_THIS_OBJECT(aCx, aVp);
658 0 : if (!obj) {
659 0 : return false;
660 : }
661 :
662 : XMLHttpRequestPrivate* priv =
663 0 : GetInstancePrivate(aCx, obj, sFunctions[3].name);
664 0 : if (!priv) {
665 0 : return false;
666 : }
667 :
668 : JSString* method, *url;
669 0 : JSBool async = true;
670 0 : JSString* user = JS_GetEmptyString(JS_GetRuntime(aCx));
671 0 : JSString* password = user;
672 0 : if (!JS_ConvertArguments(aCx, aArgc, JS_ARGV(aCx, aVp), "SS/bSS", &method,
673 0 : &url, &async, &user, &password)) {
674 0 : return false;
675 : }
676 :
677 0 : return priv->Open(aCx, method, url, async, user, password);
678 : }
679 :
680 : static JSBool
681 0 : Send(JSContext* aCx, unsigned aArgc, jsval* aVp)
682 : {
683 0 : JSObject* obj = JS_THIS_OBJECT(aCx, aVp);
684 0 : if (!obj) {
685 0 : return false;
686 : }
687 :
688 : XMLHttpRequestPrivate* priv =
689 0 : GetInstancePrivate(aCx, obj, sFunctions[4].name);
690 0 : if (!priv) {
691 0 : return false;
692 : }
693 :
694 0 : jsval body = aArgc ? JS_ARGV(aCx, aVp)[0] : JSVAL_VOID;
695 :
696 0 : return priv->Send(aCx, !!aArgc, body);
697 : }
698 :
699 : static JSBool
700 0 : SendAsBinary(JSContext* aCx, unsigned aArgc, jsval* aVp)
701 : {
702 0 : JSObject* obj = JS_THIS_OBJECT(aCx, aVp);
703 0 : if (!obj) {
704 0 : return false;
705 : }
706 :
707 : XMLHttpRequestPrivate* priv =
708 0 : GetInstancePrivate(aCx, obj, sFunctions[5].name);
709 0 : if (!priv) {
710 0 : return false;
711 : }
712 :
713 : jsval bodyVal;
714 0 : if (!JS_ConvertArguments(aCx, aArgc, JS_ARGV(aCx, aVp), "v", &bodyVal)) {
715 0 : return false;
716 : }
717 :
718 : JSString* body;
719 0 : if (JSVAL_IS_NULL(bodyVal)) {
720 0 : body = JSVAL_TO_STRING(JS_GetEmptyStringValue(aCx));
721 : }
722 : else {
723 0 : body = JS_ValueToString(aCx, bodyVal);
724 0 : if (!body) {
725 0 : return false;
726 : }
727 : }
728 :
729 0 : return priv->SendAsBinary(aCx, body);
730 : }
731 :
732 : static JSBool
733 0 : SetRequestHeader(JSContext* aCx, unsigned aArgc, jsval* aVp)
734 : {
735 0 : JSObject* obj = JS_THIS_OBJECT(aCx, aVp);
736 0 : if (!obj) {
737 0 : return false;
738 : }
739 :
740 : XMLHttpRequestPrivate* priv =
741 0 : GetInstancePrivate(aCx, obj, sFunctions[6].name);
742 0 : if (!priv) {
743 0 : return false;
744 : }
745 :
746 : JSString* header, *value;
747 0 : if (!JS_ConvertArguments(aCx, aArgc, JS_ARGV(aCx, aVp), "SS", &header,
748 0 : &value)) {
749 0 : return false;
750 : }
751 :
752 0 : return priv->SetRequestHeader(aCx, header, value);
753 : }
754 :
755 : static JSBool
756 0 : OverrideMimeType(JSContext* aCx, unsigned aArgc, jsval* aVp)
757 : {
758 0 : JSObject* obj = JS_THIS_OBJECT(aCx, aVp);
759 0 : if (!obj) {
760 0 : return false;
761 : }
762 :
763 : XMLHttpRequestPrivate* priv =
764 0 : GetInstancePrivate(aCx, obj, sFunctions[7].name);
765 0 : if (!priv) {
766 0 : return false;
767 : }
768 :
769 : JSString* mimeType;
770 0 : if (!JS_ConvertArguments(aCx, aArgc, JS_ARGV(aCx, aVp), "S", &mimeType)) {
771 0 : return false;
772 : }
773 :
774 0 : return priv->OverrideMimeType(aCx, mimeType);
775 : }
776 : };
777 :
778 : JSClass XMLHttpRequest::sClass = {
779 : "XMLHttpRequest",
780 : JSCLASS_HAS_PRIVATE | JSCLASS_IMPLEMENTS_BARRIERS | JSCLASS_HAS_RESERVED_SLOTS(SLOT_COUNT),
781 : JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
782 : JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, Finalize,
783 : NULL, NULL, NULL, NULL, Trace
784 : };
785 :
786 : JSPropertySpec XMLHttpRequest::sProperties[] = {
787 :
788 : #define GENERIC_READONLY_PROPERTY(_name) \
789 : { #_name, SLOT_##_name, PROPERTY_FLAGS, GetProperty, \
790 : js_GetterOnlyPropertyStub },
791 :
792 : GENERIC_READONLY_PROPERTY(channel)
793 : GENERIC_READONLY_PROPERTY(responseXML)
794 : GENERIC_READONLY_PROPERTY(responseText)
795 : GENERIC_READONLY_PROPERTY(status)
796 : GENERIC_READONLY_PROPERTY(statusText)
797 : GENERIC_READONLY_PROPERTY(readyState)
798 : GENERIC_READONLY_PROPERTY(response)
799 :
800 : { "multipart", SLOT_multipart, PROPERTY_FLAGS, GetProperty, SetMultipart },
801 : { "mozBackgroundRequest", SLOT_mozBackgroundRequest, PROPERTY_FLAGS,
802 : GetProperty, SetMozBackgroundRequest },
803 : { "withCredentials", SLOT_withCredentials, PROPERTY_FLAGS, GetProperty,
804 : SetWithCredentials },
805 : { "upload", SLOT_upload, PROPERTY_FLAGS, GetUpload,
806 : js_GetterOnlyPropertyStub },
807 : { "responseType", SLOT_responseType, PROPERTY_FLAGS, GetProperty,
808 : SetResponseType },
809 : { "timeout", SLOT_timeout, PROPERTY_FLAGS, GetProperty,
810 : SetTimeout },
811 1464 : { sEventStrings[STRING_onreadystatechange], STRING_onreadystatechange,
812 : PROPERTY_FLAGS, GetEventListener, SetEventListener },
813 1464 : { sEventStrings[STRING_onabort], STRING_onabort, PROPERTY_FLAGS,
814 : GetEventListener, SetEventListener },
815 1464 : { sEventStrings[STRING_onerror], STRING_onerror, PROPERTY_FLAGS,
816 : GetEventListener, SetEventListener },
817 1464 : { sEventStrings[STRING_onload], STRING_onload, PROPERTY_FLAGS,
818 : GetEventListener, SetEventListener },
819 1464 : { sEventStrings[STRING_onloadstart], STRING_onloadstart, PROPERTY_FLAGS,
820 : GetEventListener, SetEventListener },
821 1464 : { sEventStrings[STRING_onprogress], STRING_onprogress, PROPERTY_FLAGS,
822 : GetEventListener, SetEventListener },
823 1464 : { sEventStrings[STRING_onloadend], STRING_onloadend, PROPERTY_FLAGS,
824 : GetEventListener, SetEventListener },
825 1464 : { sEventStrings[STRING_ontimeout], STRING_ontimeout, PROPERTY_FLAGS,
826 : GetEventListener, SetEventListener },
827 :
828 : #undef GENERIC_READONLY_PROPERTY
829 :
830 : { 0, 0, 0, NULL, NULL }
831 11712 : };
832 :
833 : JSFunctionSpec XMLHttpRequest::sFunctions[] = {
834 : JS_FN("abort", Abort, 0, FUNCTION_FLAGS),
835 : JS_FN("getAllResponseHeaders", GetAllResponseHeaders, 0, FUNCTION_FLAGS),
836 : JS_FN("getResponseHeader", GetResponseHeader, 1, FUNCTION_FLAGS),
837 : JS_FN("open", Open, 2, FUNCTION_FLAGS),
838 : JS_FN("send", Send, 0, FUNCTION_FLAGS),
839 : JS_FN("sendAsBinary", SendAsBinary, 1, FUNCTION_FLAGS),
840 : JS_FN("setRequestHeader", SetRequestHeader, 2, FUNCTION_FLAGS),
841 : JS_FN("overrideMimeType", OverrideMimeType, 1, FUNCTION_FLAGS),
842 : JS_FS_END
843 : };
844 :
845 : JSPropertySpec XMLHttpRequest::sStaticProperties[] = {
846 : { "UNSENT", UNSENT, CONSTANT_FLAGS, GetConstant, NULL },
847 : { "OPENED", OPENED, CONSTANT_FLAGS, GetConstant, NULL },
848 : { "HEADERS_RECEIVED", HEADERS_RECEIVED, CONSTANT_FLAGS, GetConstant, NULL },
849 : { "LOADING", LOADING, CONSTANT_FLAGS, GetConstant, NULL },
850 : { "DONE", DONE, CONSTANT_FLAGS, GetConstant, NULL },
851 : { 0, 0, 0, NULL, NULL }
852 : };
853 :
854 : const char* const XMLHttpRequest::sEventStrings[STRING_COUNT] = {
855 : "onreadystatechange",
856 : "onabort",
857 : "onerror",
858 : "onload",
859 : "onloadstart",
860 : "onprogress",
861 : "onloadend",
862 : "ontimeout"
863 : };
864 :
865 : // static
866 : bool
867 0 : XMLHttpRequestUpload::UpdateState(JSContext* aCx, JSObject* aObj,
868 : const xhr::StateData& aNewState)
869 : {
870 0 : JS_ASSERT(JS_GetClass(aObj) == &sClass);
871 :
872 0 : jsval parentVal = JS_GetReservedSlot(aObj, SLOT_xhrParent);
873 :
874 0 : if (!JSVAL_IS_PRIMITIVE(parentVal)) {
875 : return XMLHttpRequest::UpdateState(aCx, JSVAL_TO_OBJECT(parentVal),
876 0 : aNewState);
877 : }
878 :
879 0 : return true;
880 : }
881 :
882 : } // anonymous namespace
883 :
884 : BEGIN_WORKERS_NAMESPACE
885 :
886 : namespace xhr {
887 :
888 : bool
889 0 : InitClasses(JSContext* aCx, JSObject* aGlobal, JSObject* aProto)
890 : {
891 0 : return XMLHttpRequest::InitClass(aCx, aGlobal, aProto) &&
892 0 : XMLHttpRequestUpload::InitClass(aCx, aGlobal, aProto);
893 : }
894 :
895 : bool
896 0 : UpdateXHRState(JSContext* aCx, JSObject* aObj, bool aIsUpload,
897 : const StateData& aNewState)
898 : {
899 : return aIsUpload ?
900 : XMLHttpRequestUpload::UpdateState(aCx, aObj, aNewState) :
901 0 : XMLHttpRequest::UpdateState(aCx, aObj, aNewState);
902 : }
903 :
904 : } // namespace xhr
905 :
906 : bool
907 0 : ClassIsXMLHttpRequest(JSClass* aClass)
908 : {
909 0 : return XMLHttpRequest::Class() == aClass ||
910 0 : XMLHttpRequestUpload::Class() == aClass;
911 : }
912 :
913 4392 : END_WORKERS_NAMESPACE
|