gecko-dev/dom/workers/XMLHttpRequest.cpp
Ben Turner 10cef6dc44 Bug 718202. r=jst.
--HG--
extra : transplant_source : %1En%B7%8CN%F4kl%A8%3D%8C%8A%99%9A%10%F7%F4o%01l
2012-01-18 10:05:38 -08:00

940 lines
26 KiB
C++

/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Web Workers.
*
* The Initial Developer of the Original Code is
* The Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Ben Turner <bent.mozilla@gmail.com> (Original Author)
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "XMLHttpRequest.h"
#include "jsapi.h"
#include "jsfriendapi.h"
#include "Exceptions.h"
#include "WorkerPrivate.h"
#include "XMLHttpRequestPrivate.h"
#include "WorkerInlines.h"
#define PROPERTY_FLAGS \
JSPROP_ENUMERATE | JSPROP_SHARED
#define FUNCTION_FLAGS \
JSPROP_ENUMERATE
#define CONSTANT_FLAGS \
JSPROP_ENUMERATE | JSPROP_SHARED | JSPROP_PERMANENT | JSPROP_READONLY
USING_WORKERS_NAMESPACE
using mozilla::dom::workers::xhr::XMLHttpRequestPrivate;
namespace {
class XMLHttpRequestUpload : public events::EventTarget
{
static JSClass sClass;
static JSPropertySpec sProperties[];
enum
{
STRING_onabort = 0,
STRING_onerror,
STRING_onload,
STRING_onloadstart,
STRING_onprogress,
STRING_onloadend,
STRING_COUNT
};
static const char* const sEventStrings[STRING_COUNT];
enum SLOT {
SLOT_xhrParent = 0,
SLOT_COUNT
};
public:
static JSClass*
Class()
{
return &sClass;
}
static JSObject*
InitClass(JSContext* aCx, JSObject* aObj, JSObject* aParentProto)
{
return JS_InitClass(aCx, aObj, aParentProto, &sClass, Construct, 0,
sProperties, NULL, NULL, NULL);
}
static JSObject*
Create(JSContext* aCx, JSObject* aParentObj)
{
JS_ASSERT(aParentObj);
JSObject* obj = JS_NewObject(aCx, &sClass, NULL, NULL);
if (obj) {
XMLHttpRequestUpload* priv = new XMLHttpRequestUpload();
if (!JS_SetReservedSlot(aCx, obj, SLOT_xhrParent,
OBJECT_TO_JSVAL(aParentObj)) ||
!SetJSPrivateSafeish(aCx, obj, priv)) {
delete priv;
return NULL;
}
}
return obj;
}
static bool
UpdateState(JSContext* aCx, JSObject* aObj, const xhr::StateData& aNewState);
private:
XMLHttpRequestUpload()
{
MOZ_COUNT_CTOR(mozilla::dom::workers::xhr::XMLHttpRequestUpload);
}
~XMLHttpRequestUpload()
{
MOZ_COUNT_DTOR(mozilla::dom::workers::xhr::XMLHttpRequestUpload);
}
static XMLHttpRequestUpload*
GetPrivate(JSContext* aCx, JSObject* aObj)
{
if (aObj) {
JSClass* classPtr = JS_GET_CLASS(aCx, aObj);
if (classPtr == &sClass) {
return GetJSPrivateSafeish<XMLHttpRequestUpload>(aCx, aObj);
}
}
return NULL;
}
static XMLHttpRequestUpload*
GetInstancePrivate(JSContext* aCx, JSObject* aObj, const char* aFunctionName)
{
JSClass* classPtr = NULL;
if (aObj) {
XMLHttpRequestUpload* priv = GetPrivate(aCx, aObj);
if (priv) {
return priv;
}
classPtr = JS_GET_CLASS(aCx, aObj);
}
JS_ReportErrorNumber(aCx, js_GetErrorMessage, NULL,
JSMSG_INCOMPATIBLE_PROTO, sClass.name, aFunctionName,
classPtr ? classPtr->name : "object");
return NULL;
}
static JSBool
Construct(JSContext* aCx, uintN aArgc, jsval* aVp)
{
JS_ReportErrorNumber(aCx, js_GetErrorMessage, NULL, JSMSG_WRONG_CONSTRUCTOR,
sClass.name);
return false;
}
static void
Finalize(JSContext* aCx, JSObject* aObj)
{
JS_ASSERT(JS_GET_CLASS(aCx, aObj) == &sClass);
XMLHttpRequestUpload* priv = GetPrivate(aCx, aObj);
if (priv) {
priv->FinalizeInstance(aCx);
delete priv;
}
}
static void
Trace(JSTracer* aTrc, JSObject* aObj)
{
JS_ASSERT(JS_GET_CLASS(aTrc->context, aObj) == &sClass);
XMLHttpRequestUpload* priv = GetPrivate(aTrc->context, aObj);
if (priv) {
priv->TraceInstance(aTrc);
}
}
static JSBool
GetEventListener(JSContext* aCx, JSObject* aObj, jsid aIdval, jsval* aVp)
{
JS_ASSERT(JSID_IS_INT(aIdval));
JS_ASSERT(JSID_TO_INT(aIdval) >= 0 && JSID_TO_INT(aIdval) < STRING_COUNT);
const char* name = sEventStrings[JSID_TO_INT(aIdval)];
XMLHttpRequestUpload* priv = GetInstancePrivate(aCx, aObj, name);
if (!priv) {
return false;
}
return priv->GetEventListenerOnEventTarget(aCx, name + 2, aVp);
}
static JSBool
SetEventListener(JSContext* aCx, JSObject* aObj, jsid aIdval, JSBool aStrict,
jsval* aVp)
{
JS_ASSERT(JSID_IS_INT(aIdval));
JS_ASSERT(JSID_TO_INT(aIdval) >= 0 && JSID_TO_INT(aIdval) < STRING_COUNT);
const char* name = sEventStrings[JSID_TO_INT(aIdval)];
XMLHttpRequestUpload* priv = GetInstancePrivate(aCx, aObj, name);
if (!priv) {
return false;
}
return priv->SetEventListenerOnEventTarget(aCx, name + 2, aVp);
}
};
JSClass XMLHttpRequestUpload::sClass = {
"XMLHttpRequestUpload",
JSCLASS_HAS_PRIVATE | JSCLASS_HAS_RESERVED_SLOTS(SLOT_COUNT),
JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, Finalize,
NULL, NULL, NULL, NULL, NULL, NULL, Trace, NULL
};
JSPropertySpec XMLHttpRequestUpload::sProperties[] = {
{ sEventStrings[STRING_onabort], STRING_onabort, PROPERTY_FLAGS,
GetEventListener, SetEventListener },
{ sEventStrings[STRING_onerror], STRING_onerror, PROPERTY_FLAGS,
GetEventListener, SetEventListener },
{ sEventStrings[STRING_onload], STRING_onload, PROPERTY_FLAGS,
GetEventListener, SetEventListener },
{ sEventStrings[STRING_onloadstart], STRING_onloadstart, PROPERTY_FLAGS,
GetEventListener, SetEventListener },
{ sEventStrings[STRING_onprogress], STRING_onprogress, PROPERTY_FLAGS,
GetEventListener, SetEventListener },
{ sEventStrings[STRING_onloadend], STRING_onloadend, PROPERTY_FLAGS,
GetEventListener, SetEventListener },
{ 0, 0, 0, NULL, NULL }
};
const char* const XMLHttpRequestUpload::sEventStrings[STRING_COUNT] = {
"onabort",
"onerror",
"onload",
"onloadstart",
"onprogress",
"onloadend"
};
class XMLHttpRequest
{
static JSClass sClass;
static JSPropertySpec sProperties[];
static JSFunctionSpec sFunctions[];
static JSPropertySpec sStaticProperties[];
enum SLOT {
SLOT_channel = 0,
SLOT_responseXML,
SLOT_responseText,
SLOT_status,
SLOT_statusText,
SLOT_readyState,
SLOT_response,
SLOT_multipart,
SLOT_mozBackgroundRequest,
SLOT_withCredentials,
SLOT_upload,
SLOT_responseType,
SLOT_COUNT
};
enum {
UNSENT = 0,
OPENED = 1,
HEADERS_RECEIVED = 2,
LOADING = 3,
DONE = 4
};
enum
{
STRING_onreadystatechange = 0,
STRING_onabort,
STRING_onerror,
STRING_onload,
STRING_onloadstart,
STRING_onprogress,
STRING_onloadend,
STRING_COUNT
};
static const char* const sEventStrings[STRING_COUNT];
public:
static JSClass*
Class()
{
return &sClass;
}
static JSObject*
InitClass(JSContext* aCx, JSObject* aObj, JSObject* aParentProto)
{
JSObject* proto = JS_InitClass(aCx, aObj, aParentProto, &sClass, Construct,
0, sProperties, sFunctions,
sStaticProperties, NULL);
if (proto && !JS_DefineProperties(aCx, proto, sStaticProperties)) {
return NULL;
}
return proto;
}
static bool
UpdateState(JSContext* aCx, JSObject* aObj, const xhr::StateData& aNewState)
{
JS_ASSERT(GetPrivate(aCx, aObj));
#define HANDLE_STATE_VALUE(_member, _slot) \
if (aNewState. _member##Exception || !JSVAL_IS_VOID(aNewState. _member)) { \
if (!JS_SetReservedSlot(aCx, aObj, _slot, aNewState. _member)) { \
return false; \
} \
}
HANDLE_STATE_VALUE(mResponseText, SLOT_responseText)
HANDLE_STATE_VALUE(mStatus, SLOT_status)
HANDLE_STATE_VALUE(mStatusText, SLOT_statusText)
HANDLE_STATE_VALUE(mReadyState, SLOT_readyState)
HANDLE_STATE_VALUE(mResponse, SLOT_response)
#undef HANDLE_STATE_VALUE
return true;
}
private:
// No instance of this class should ever be created so these are explicitly
// left without an implementation to prevent linking in case someone tries to
// make one.
XMLHttpRequest();
~XMLHttpRequest();
static XMLHttpRequestPrivate*
GetPrivate(JSContext* aCx, JSObject* aObj)
{
if (aObj) {
JSClass* classPtr = JS_GET_CLASS(aCx, aObj);
if (classPtr == &sClass) {
return GetJSPrivateSafeish<XMLHttpRequestPrivate>(aCx, aObj);
}
}
return NULL;
}
static XMLHttpRequestPrivate*
GetInstancePrivate(JSContext* aCx, JSObject* aObj, const char* aFunctionName)
{
JSClass* classPtr = NULL;
if (aObj) {
XMLHttpRequestPrivate* priv = GetPrivate(aCx, aObj);
if (priv) {
return priv;
}
classPtr = JS_GET_CLASS(aCx, aObj);
}
JS_ReportErrorNumber(aCx, js_GetErrorMessage, NULL,
JSMSG_INCOMPATIBLE_PROTO, sClass.name, aFunctionName,
classPtr ? classPtr->name : "object");
return NULL;
}
static JSBool
Construct(JSContext* aCx, uintN aArgc, jsval* aVp)
{
JSObject* obj = JS_NewObject(aCx, &sClass, NULL, NULL);
if (!obj) {
return false;
}
JSString* textStr = JS_NewStringCopyN(aCx, "text", 4);
if (!textStr) {
return false;
}
jsval emptyString = JS_GetEmptyStringValue(aCx);
jsval zero = INT_TO_JSVAL(0);
if (!JS_SetReservedSlot(aCx, obj, SLOT_channel, JSVAL_NULL) ||
!JS_SetReservedSlot(aCx, obj, SLOT_responseXML, JSVAL_NULL) ||
!JS_SetReservedSlot(aCx, obj, SLOT_responseText, emptyString) ||
!JS_SetReservedSlot(aCx, obj, SLOT_status, zero) ||
!JS_SetReservedSlot(aCx, obj, SLOT_statusText, emptyString) ||
!JS_SetReservedSlot(aCx, obj, SLOT_readyState, zero) ||
!JS_SetReservedSlot(aCx, obj, SLOT_multipart, JSVAL_FALSE) ||
!JS_SetReservedSlot(aCx, obj, SLOT_mozBackgroundRequest, JSVAL_FALSE) ||
!JS_SetReservedSlot(aCx, obj, SLOT_withCredentials, JSVAL_FALSE) ||
!JS_SetReservedSlot(aCx, obj, SLOT_upload, JSVAL_NULL) ||
!JS_SetReservedSlot(aCx, obj, SLOT_responseType,
STRING_TO_JSVAL(textStr))) {
return false;
}
WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(aCx);
XMLHttpRequestPrivate* priv = new XMLHttpRequestPrivate(obj, workerPrivate);
if (!SetJSPrivateSafeish(aCx, obj, priv)) {
delete priv;
return false;
}
JS_SET_RVAL(aCx, aVp, OBJECT_TO_JSVAL(obj));
return true;
}
static void
Finalize(JSContext* aCx, JSObject* aObj)
{
JS_ASSERT(JS_GET_CLASS(aCx, aObj) == &sClass);
XMLHttpRequestPrivate* priv = GetPrivate(aCx, aObj);
if (priv) {
priv->FinalizeInstance(aCx);
delete priv;
}
}
static void
Trace(JSTracer* aTrc, JSObject* aObj)
{
JS_ASSERT(JS_GET_CLASS(aTrc->context, aObj) == &sClass);
XMLHttpRequestPrivate* priv = GetPrivate(aTrc->context, aObj);
if (priv) {
priv->TraceInstance(aTrc);
}
}
static JSBool
GetProperty(JSContext* aCx, JSObject* aObj, jsid aIdval, jsval* aVp)
{
JS_ASSERT(JSID_IS_INT(aIdval));
int32 slot = JSID_TO_INT(aIdval);
const char*& name = sProperties[slot].name;
if (!GetInstancePrivate(aCx, aObj, name)) {
return false;
}
jsval rval;
if (!JS_GetReservedSlot(aCx, aObj, slot, &rval)) {
return false;
}
if (JSVAL_IS_VOID(rval)) {
// Throw an exception.
exceptions::ThrowDOMExceptionForCode(aCx, INVALID_STATE_ERR);
return false;
}
*aVp = rval;
return true;
}
static JSBool
GetConstant(JSContext* aCx, JSObject* aObj, jsid idval, jsval* aVp)
{
JS_ASSERT(JSID_IS_INT(idval));
JS_ASSERT(JSID_TO_INT(idval) >= UNSENT &&
JSID_TO_INT(idval) <= DONE);
*aVp = INT_TO_JSVAL(JSID_TO_INT(idval));
return true;
}
static JSBool
GetUpload(JSContext* aCx, JSObject* aObj, jsid aIdval, jsval* aVp)
{
JS_ASSERT(JSID_IS_INT(aIdval));
int32 slot = JSID_TO_INT(aIdval);
XMLHttpRequestPrivate* priv =
GetInstancePrivate(aCx, aObj, sProperties[slot].name);
if (!priv) {
return false;
}
jsval uploadVal;
if (!JS_GetReservedSlot(aCx, aObj, slot, &uploadVal)) {
return false;
}
if (JSVAL_IS_NULL(uploadVal)) {
JSObject* uploadObj = XMLHttpRequestUpload::Create(aCx, aObj);
if (!uploadObj) {
return false;
}
uploadVal = OBJECT_TO_JSVAL(uploadObj);
if (!JS_SetReservedSlot(aCx, aObj, slot, uploadVal)) {
return false;
}
priv->SetUploadObject(uploadObj);
}
JS_ASSERT(!JSVAL_IS_PRIMITIVE(uploadVal));
*aVp = uploadVal;
return true;
}
#define IMPL_SETTER(_name) \
static JSBool \
Set##_name (JSContext* aCx, JSObject* aObj, jsid aIdval, JSBool aStrict, \
jsval* aVp) \
{ \
JS_ASSERT(JSID_IS_INT(aIdval)); \
\
int32 slot = JSID_TO_INT(aIdval); \
\
XMLHttpRequestPrivate* priv = \
GetInstancePrivate(aCx, aObj, sProperties[slot].name); \
if (!priv) { \
return false; \
} \
\
jsval oldVal; \
if (!JS_GetReservedSlot(aCx, aObj, slot, &oldVal)) { \
return false; \
} \
\
jsval rval = *aVp; \
if (!priv->Set##_name (aCx, oldVal, &rval) || \
!JS_SetReservedSlot(aCx, aObj, slot, rval)) { \
return false; \
} \
\
*aVp = rval; \
return true; \
}
IMPL_SETTER(Multipart)
IMPL_SETTER(MozBackgroundRequest)
IMPL_SETTER(WithCredentials)
IMPL_SETTER(ResponseType)
#undef IMPL_SETTER
static JSBool
GetEventListener(JSContext* aCx, JSObject* aObj, jsid aIdval, jsval* aVp)
{
JS_ASSERT(JSID_IS_INT(aIdval));
JS_ASSERT(JSID_TO_INT(aIdval) >= 0 && JSID_TO_INT(aIdval) < STRING_COUNT);
const char* name = sEventStrings[JSID_TO_INT(aIdval)];
XMLHttpRequestPrivate* priv = GetInstancePrivate(aCx, aObj, name);
if (!priv) {
return false;
}
return priv->GetEventListenerOnEventTarget(aCx, name + 2, aVp);
}
static JSBool
SetEventListener(JSContext* aCx, JSObject* aObj, jsid aIdval, JSBool aStrict,
jsval* aVp)
{
JS_ASSERT(JSID_IS_INT(aIdval));
JS_ASSERT(JSID_TO_INT(aIdval) >= 0 && JSID_TO_INT(aIdval) < STRING_COUNT);
const char* name = sEventStrings[JSID_TO_INT(aIdval)];
XMLHttpRequestPrivate* priv = GetInstancePrivate(aCx, aObj, name);
if (!priv) {
return false;
}
return priv->SetEventListenerOnEventTarget(aCx, name + 2, aVp);
}
static JSBool
Abort(JSContext* aCx, uintN aArgc, jsval* aVp)
{
JSObject* obj = JS_THIS_OBJECT(aCx, aVp);
if (!obj) {
return false;
}
XMLHttpRequestPrivate* priv =
GetInstancePrivate(aCx, obj, sFunctions[0].name);
if (!priv) {
return false;
}
return priv->Abort(aCx);
}
static JSBool
GetAllResponseHeaders(JSContext* aCx, uintN aArgc, jsval* aVp)
{
JSObject* obj = JS_THIS_OBJECT(aCx, aVp);
if (!obj) {
return false;
}
XMLHttpRequestPrivate* priv =
GetInstancePrivate(aCx, obj, sFunctions[1].name);
if (!priv) {
return false;
}
JSString* responseHeaders = priv->GetAllResponseHeaders(aCx);
if (!responseHeaders) {
return false;
}
JS_SET_RVAL(aCx, aVp, STRING_TO_JSVAL(responseHeaders));
return true;
}
static JSBool
GetResponseHeader(JSContext* aCx, uintN aArgc, jsval* aVp)
{
JSObject* obj = JS_THIS_OBJECT(aCx, aVp);
if (!obj) {
return false;
}
XMLHttpRequestPrivate* priv =
GetInstancePrivate(aCx, obj, sFunctions[2].name);
if (!priv) {
return false;
}
jsval headerVal;
if (!JS_ConvertArguments(aCx, aArgc, JS_ARGV(aCx, aVp), "v", &headerVal)) {
return false;
}
JSString* header;
if (JSVAL_IS_NULL(headerVal)) {
header = JSVAL_TO_STRING(JS_GetEmptyStringValue(aCx));
}
else {
header = JS_ValueToString(aCx, headerVal);
if (!header) {
return false;
}
}
JSString* value = priv->GetResponseHeader(aCx, header);
if (!value) {
return false;
}
JS_SET_RVAL(aCx, aVp, STRING_TO_JSVAL(value));
return true;
}
static JSBool
Open(JSContext* aCx, uintN aArgc, jsval* aVp)
{
JSObject* obj = JS_THIS_OBJECT(aCx, aVp);
if (!obj) {
return false;
}
XMLHttpRequestPrivate* priv =
GetInstancePrivate(aCx, obj, sFunctions[3].name);
if (!priv) {
return false;
}
JSString* method, *url;
JSBool async = true;
JSString* user = JS_GetEmptyString(JS_GetRuntime(aCx));
JSString* password = user;
if (!JS_ConvertArguments(aCx, aArgc, JS_ARGV(aCx, aVp), "SS/bSS", &method,
&url, &async, &user, &password)) {
return false;
}
return priv->Open(aCx, method, url, async, user, password);
}
static JSBool
Send(JSContext* aCx, uintN aArgc, jsval* aVp)
{
JSObject* obj = JS_THIS_OBJECT(aCx, aVp);
if (!obj) {
return false;
}
XMLHttpRequestPrivate* priv =
GetInstancePrivate(aCx, obj, sFunctions[4].name);
if (!priv) {
return false;
}
jsval body = aArgc ? JS_ARGV(aCx, aVp)[0] : JSVAL_VOID;
return priv->Send(aCx, !!aArgc, body);
}
static JSBool
SendAsBinary(JSContext* aCx, uintN aArgc, jsval* aVp)
{
JSObject* obj = JS_THIS_OBJECT(aCx, aVp);
if (!obj) {
return false;
}
XMLHttpRequestPrivate* priv =
GetInstancePrivate(aCx, obj, sFunctions[5].name);
if (!priv) {
return false;
}
jsval bodyVal;
if (!JS_ConvertArguments(aCx, aArgc, JS_ARGV(aCx, aVp), "v", &bodyVal)) {
return false;
}
JSString* body;
if (JSVAL_IS_NULL(bodyVal)) {
body = JSVAL_TO_STRING(JS_GetEmptyStringValue(aCx));
}
else {
body = JS_ValueToString(aCx, bodyVal);
if (!body) {
return false;
}
}
return priv->SendAsBinary(aCx, body);
}
static JSBool
SetRequestHeader(JSContext* aCx, uintN aArgc, jsval* aVp)
{
JSObject* obj = JS_THIS_OBJECT(aCx, aVp);
if (!obj) {
return false;
}
XMLHttpRequestPrivate* priv =
GetInstancePrivate(aCx, obj, sFunctions[6].name);
if (!priv) {
return false;
}
JSString* header, *value;
if (!JS_ConvertArguments(aCx, aArgc, JS_ARGV(aCx, aVp), "SS", &header,
&value)) {
return false;
}
return priv->SetRequestHeader(aCx, header, value);
}
static JSBool
OverrideMimeType(JSContext* aCx, uintN aArgc, jsval* aVp)
{
JSObject* obj = JS_THIS_OBJECT(aCx, aVp);
if (!obj) {
return false;
}
XMLHttpRequestPrivate* priv =
GetInstancePrivate(aCx, obj, sFunctions[7].name);
if (!priv) {
return false;
}
JSString* mimeType;
if (!JS_ConvertArguments(aCx, aArgc, JS_ARGV(aCx, aVp), "S", &mimeType)) {
return false;
}
return priv->OverrideMimeType(aCx, mimeType);
}
};
JSClass XMLHttpRequest::sClass = {
"XMLHttpRequest",
JSCLASS_HAS_PRIVATE | JSCLASS_HAS_RESERVED_SLOTS(SLOT_COUNT),
JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, Finalize,
NULL, NULL, NULL, NULL, NULL, NULL, Trace, NULL
};
JSPropertySpec XMLHttpRequest::sProperties[] = {
#define GENERIC_READONLY_PROPERTY(_name) \
{ #_name, SLOT_##_name, PROPERTY_FLAGS, GetProperty, \
js_GetterOnlyPropertyStub },
GENERIC_READONLY_PROPERTY(channel)
GENERIC_READONLY_PROPERTY(responseXML)
GENERIC_READONLY_PROPERTY(responseText)
GENERIC_READONLY_PROPERTY(status)
GENERIC_READONLY_PROPERTY(statusText)
GENERIC_READONLY_PROPERTY(readyState)
GENERIC_READONLY_PROPERTY(response)
{ "multipart", SLOT_multipart, PROPERTY_FLAGS, GetProperty, SetMultipart },
{ "mozBackgroundRequest", SLOT_mozBackgroundRequest, PROPERTY_FLAGS,
GetProperty, SetMozBackgroundRequest },
{ "withCredentials", SLOT_withCredentials, PROPERTY_FLAGS, GetProperty,
SetWithCredentials },
{ "upload", SLOT_upload, PROPERTY_FLAGS, GetUpload,
js_GetterOnlyPropertyStub },
{ "responseType", SLOT_responseType, PROPERTY_FLAGS, GetProperty,
SetResponseType },
{ sEventStrings[STRING_onreadystatechange], STRING_onreadystatechange,
PROPERTY_FLAGS, GetEventListener, SetEventListener },
{ sEventStrings[STRING_onabort], STRING_onabort, PROPERTY_FLAGS,
GetEventListener, SetEventListener },
{ sEventStrings[STRING_onerror], STRING_onerror, PROPERTY_FLAGS,
GetEventListener, SetEventListener },
{ sEventStrings[STRING_onload], STRING_onload, PROPERTY_FLAGS,
GetEventListener, SetEventListener },
{ sEventStrings[STRING_onloadstart], STRING_onloadstart, PROPERTY_FLAGS,
GetEventListener, SetEventListener },
{ sEventStrings[STRING_onprogress], STRING_onprogress, PROPERTY_FLAGS,
GetEventListener, SetEventListener },
{ sEventStrings[STRING_onloadend], STRING_onloadend, PROPERTY_FLAGS,
GetEventListener, SetEventListener },
#undef GENERIC_READONLY_PROPERTY
{ 0, 0, 0, NULL, NULL }
};
JSFunctionSpec XMLHttpRequest::sFunctions[] = {
JS_FN("abort", Abort, 0, FUNCTION_FLAGS),
JS_FN("getAllResponseHeaders", GetAllResponseHeaders, 0, FUNCTION_FLAGS),
JS_FN("getResponseHeader", GetResponseHeader, 1, FUNCTION_FLAGS),
JS_FN("open", Open, 2, FUNCTION_FLAGS),
JS_FN("send", Send, 0, FUNCTION_FLAGS),
JS_FN("sendAsBinary", SendAsBinary, 1, FUNCTION_FLAGS),
JS_FN("setRequestHeader", SetRequestHeader, 2, FUNCTION_FLAGS),
JS_FN("overrideMimeType", OverrideMimeType, 1, FUNCTION_FLAGS),
JS_FS_END
};
JSPropertySpec XMLHttpRequest::sStaticProperties[] = {
{ "UNSENT", UNSENT, CONSTANT_FLAGS, GetConstant, NULL },
{ "OPENED", OPENED, CONSTANT_FLAGS, GetConstant, NULL },
{ "HEADERS_RECEIVED", HEADERS_RECEIVED, CONSTANT_FLAGS, GetConstant, NULL },
{ "LOADING", LOADING, CONSTANT_FLAGS, GetConstant, NULL },
{ "DONE", DONE, CONSTANT_FLAGS, GetConstant, NULL },
{ 0, 0, 0, NULL, NULL }
};
const char* const XMLHttpRequest::sEventStrings[STRING_COUNT] = {
"onreadystatechange",
"onabort",
"onerror",
"onload",
"onloadstart",
"onprogress",
"onloadend"
};
// static
bool
XMLHttpRequestUpload::UpdateState(JSContext* aCx, JSObject* aObj,
const xhr::StateData& aNewState)
{
JS_ASSERT(JS_GET_CLASS(aCx, aObj) == &sClass);
jsval parentVal;
if (!JS_GetReservedSlot(aCx, aObj, SLOT_xhrParent, &parentVal)) {
return false;
}
if (!JSVAL_IS_PRIMITIVE(parentVal)) {
return XMLHttpRequest::UpdateState(aCx, JSVAL_TO_OBJECT(parentVal),
aNewState);
}
return true;
}
} // anonymous namespace
BEGIN_WORKERS_NAMESPACE
namespace xhr {
bool
InitClasses(JSContext* aCx, JSObject* aGlobal, JSObject* aProto)
{
return XMLHttpRequest::InitClass(aCx, aGlobal, aProto) &&
XMLHttpRequestUpload::InitClass(aCx, aGlobal, aProto);
}
bool
UpdateXHRState(JSContext* aCx, JSObject* aObj, bool aIsUpload,
const StateData& aNewState)
{
return aIsUpload ?
XMLHttpRequestUpload::UpdateState(aCx, aObj, aNewState) :
XMLHttpRequest::UpdateState(aCx, aObj, aNewState);
}
} // namespace xhr
bool
ClassIsXMLHttpRequest(JSClass* aClass)
{
return XMLHttpRequest::Class() == aClass ||
XMLHttpRequestUpload::Class() == aClass;
}
END_WORKERS_NAMESPACE