зеркало из https://github.com/mozilla/gecko-dev.git
Bug 658178 - 'Make XHR2 response/responseType work in Web Workers'. r=jst+sicking+mrbkap.
This commit is contained in:
Родитель
6bf243becc
Коммит
408f05bed8
|
@ -5442,10 +5442,15 @@ void
|
|||
nsContentUtils::CheckCCWrapperTraversal(nsISupports* aScriptObjectHolder,
|
||||
nsWrapperCache* aCache)
|
||||
{
|
||||
JSObject* wrapper = aCache->GetWrapper();
|
||||
if (!wrapper) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsXPCOMCycleCollectionParticipant* participant;
|
||||
CallQueryInterface(aScriptObjectHolder, &participant);
|
||||
|
||||
DebugWrapperTraversalCallback callback(aCache->GetWrapper());
|
||||
DebugWrapperTraversalCallback callback(wrapper);
|
||||
|
||||
participant->Traverse(aScriptObjectHolder, callback);
|
||||
NS_ASSERTION(callback.mFound,
|
||||
|
@ -5907,10 +5912,12 @@ nsContentUtils::TraceWrapper(nsWrapperCache* aCache, TraceCallback aCallback,
|
|||
void *aClosure)
|
||||
{
|
||||
if (aCache->PreservingWrapper()) {
|
||||
aCallback(nsIProgrammingLanguage::JAVASCRIPT,
|
||||
aCache->GetWrapperPreserveColor(),
|
||||
JSObject *wrapper = aCache->GetWrapperPreserveColor();
|
||||
if (wrapper) {
|
||||
aCallback(nsIProgrammingLanguage::JAVASCRIPT, wrapper,
|
||||
"Preserved wrapper", aClosure);
|
||||
}
|
||||
}
|
||||
else {
|
||||
JSObject *expando = aCache->GetExpandoObjectPreserveColor();
|
||||
if (expando) {
|
||||
|
|
|
@ -453,6 +453,14 @@ nsXMLHttpRequest::~nsXMLHttpRequest()
|
|||
NS_ABORT_IF_FALSE(!(mState & XML_HTTP_REQUEST_SYNCLOOPING), "we rather crash than hang");
|
||||
mState &= ~XML_HTTP_REQUEST_SYNCLOOPING;
|
||||
|
||||
// This can happen if the XHR was only used by C++ (and so never created a JS
|
||||
// wrapper) that also made an ArrayBuffer.
|
||||
if (PreservingWrapper()) {
|
||||
nsContentUtils::ReleaseWrapper(
|
||||
static_cast<nsIDOMEventTarget*>(
|
||||
static_cast<nsDOMEventTargetHelper*>(this)), this);
|
||||
}
|
||||
|
||||
nsLayoutStatics::Release();
|
||||
}
|
||||
|
||||
|
|
|
@ -538,6 +538,13 @@ struct MainThreadChromeWorkerStructuredCloneCallbacks
|
|||
AssertIsOnMainThread();
|
||||
|
||||
JSObject* clone =
|
||||
MainThreadWorkerStructuredCloneCallbacks::Read(aCx, aReader, aTag, aData,
|
||||
aClosure);
|
||||
if (clone) {
|
||||
return clone;
|
||||
}
|
||||
|
||||
clone =
|
||||
ChromeWorkerStructuredCloneCallbacks::Read(aCx, aReader, aTag, aData,
|
||||
aClosure);
|
||||
if (clone) {
|
||||
|
@ -554,14 +561,15 @@ struct MainThreadChromeWorkerStructuredCloneCallbacks
|
|||
{
|
||||
AssertIsOnMainThread();
|
||||
|
||||
JSBool ok =
|
||||
ChromeWorkerStructuredCloneCallbacks::Write(aCx, aWriter, aObj, aClosure);
|
||||
if (ok) {
|
||||
return ok;
|
||||
if (MainThreadWorkerStructuredCloneCallbacks::Write(aCx, aWriter, aObj,
|
||||
aClosure) ||
|
||||
ChromeWorkerStructuredCloneCallbacks::Write(aCx, aWriter, aObj,
|
||||
aClosure) ||
|
||||
NS_DOMWriteStructuredClone(aCx, aWriter, aObj, nsnull)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
JS_ClearPendingException(aCx);
|
||||
return NS_DOMWriteStructuredClone(aCx, aWriter, aObj, nsnull);
|
||||
return false;
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
|
@ -42,6 +42,7 @@
|
|||
#include "jscntxt.h"
|
||||
#include "jsfriendapi.h"
|
||||
|
||||
#include "Exceptions.h"
|
||||
#include "WorkerPrivate.h"
|
||||
#include "XMLHttpRequestPrivate.h"
|
||||
|
||||
|
@ -275,10 +276,12 @@ class XMLHttpRequest
|
|||
SLOT_status,
|
||||
SLOT_statusText,
|
||||
SLOT_readyState,
|
||||
SLOT_response,
|
||||
SLOT_multipart,
|
||||
SLOT_mozBackgroundRequest,
|
||||
SLOT_withCredentials,
|
||||
SLOT_upload,
|
||||
SLOT_responseType,
|
||||
|
||||
SLOT_COUNT
|
||||
};
|
||||
|
@ -342,6 +345,7 @@ public:
|
|||
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
|
||||
|
||||
|
@ -395,6 +399,11 @@ private:
|
|||
return false;
|
||||
}
|
||||
|
||||
JSString* textStr = JS_NewStringCopyN(aCx, "text", 4);
|
||||
if (!textStr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
jsval emptyString = JS_GetEmptyStringValue(aCx);
|
||||
jsval zero = INT_TO_JSVAL(0);
|
||||
|
||||
|
@ -407,7 +416,9 @@ private:
|
|||
!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_upload, JSVAL_NULL) ||
|
||||
!JS_SetReservedSlot(aCx, obj, SLOT_responseType,
|
||||
STRING_TO_JSVAL(textStr))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -462,7 +473,7 @@ private:
|
|||
|
||||
if (JSVAL_IS_VOID(rval)) {
|
||||
// Throw an exception.
|
||||
JS_ReportError(aCx, "Unable to retrieve %s property", name);
|
||||
exceptions::ThrowDOMExceptionForCode(aCx, INVALID_STATE_ERR);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -535,8 +546,13 @@ private:
|
|||
return false; \
|
||||
} \
|
||||
\
|
||||
jsval oldVal; \
|
||||
if (!JS_GetReservedSlot(aCx, aObj, slot, &oldVal)) { \
|
||||
return false; \
|
||||
} \
|
||||
\
|
||||
jsval rval = *aVp; \
|
||||
if (!priv->Set##_name (aCx, &rval) || \
|
||||
if (!priv->Set##_name (aCx, oldVal, &rval) || \
|
||||
!JS_SetReservedSlot(aCx, aObj, slot, rval)) { \
|
||||
return false; \
|
||||
} \
|
||||
|
@ -548,6 +564,7 @@ private:
|
|||
IMPL_SETTER(Multipart)
|
||||
IMPL_SETTER(MozBackgroundRequest)
|
||||
IMPL_SETTER(WithCredentials)
|
||||
IMPL_SETTER(ResponseType)
|
||||
|
||||
#undef IMPL_SETTER
|
||||
|
||||
|
@ -783,13 +800,17 @@ JSPropertySpec XMLHttpRequest::sProperties[] = {
|
|||
GENERIC_READONLY_PROPERTY(status)
|
||||
GENERIC_READONLY_PROPERTY(statusText)
|
||||
GENERIC_READONLY_PROPERTY(readyState)
|
||||
GENERIC_READONLY_PROPERTY(response)
|
||||
|
||||
{ "multipart", 7, PROPERTY_FLAGS, GetProperty, SetMultipart },
|
||||
{ "mozBackgroundRequest", 8, PROPERTY_FLAGS, GetProperty,
|
||||
SetMozBackgroundRequest },
|
||||
{ "withCredentials", 9, PROPERTY_FLAGS, GetProperty, SetWithCredentials },
|
||||
{ "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,
|
||||
|
|
|
@ -56,10 +56,12 @@ struct StateData
|
|||
jsval mStatus;
|
||||
jsval mStatusText;
|
||||
jsval mReadyState;
|
||||
jsval mResponse;
|
||||
bool mResponseTextException;
|
||||
bool mStatusException;
|
||||
bool mStatusTextException;
|
||||
bool mReadyStateException;
|
||||
bool mResponseException;
|
||||
};
|
||||
|
||||
bool
|
||||
|
|
|
@ -41,7 +41,6 @@
|
|||
#include "nsIDOMEvent.h"
|
||||
#include "nsIDOMEventListener.h"
|
||||
#include "nsIDOMProgressEvent.h"
|
||||
#include "nsIJSContextStack.h"
|
||||
#include "nsIRunnable.h"
|
||||
#include "nsIXMLHttpRequest.h"
|
||||
#include "nsIXPConnect.h"
|
||||
|
@ -88,7 +87,6 @@ public:
|
|||
bool mSeenUploadLoadStart;
|
||||
|
||||
// Only touched on the main thread.
|
||||
nsString mPreviousResponseText;
|
||||
nsCString mPreviousStatusText;
|
||||
PRUint32 mSyncQueueKey;
|
||||
PRUint32 mSyncEventResponseSyncQueueKey;
|
||||
|
@ -158,7 +156,6 @@ public:
|
|||
{
|
||||
AssertIsOnMainThread();
|
||||
|
||||
mPreviousResponseText.Truncate();
|
||||
mPreviousStatusText.Truncate();
|
||||
|
||||
if (mUploadEventListenersAttached) {
|
||||
|
@ -439,7 +436,10 @@ NS_IMPL_ISUPPORTS2(LoadStartDetectionRunnable, nsIRunnable, nsIDOMEventListener)
|
|||
class EventRunnable : public MainThreadProxyRunnable
|
||||
{
|
||||
nsString mType;
|
||||
nsString mResponseText;
|
||||
nsString mResponseType;
|
||||
JSAutoStructuredCloneBuffer mResponseBuffer;
|
||||
nsTArray<nsCOMPtr<nsISupports> > mClonedObjects;
|
||||
jsval mResponse;
|
||||
nsCString mStatusText;
|
||||
PRUint64 mLoaded;
|
||||
PRUint64 mTotal;
|
||||
|
@ -453,25 +453,28 @@ class EventRunnable : public MainThreadProxyRunnable
|
|||
bool mStatusException;
|
||||
bool mStatusTextException;
|
||||
bool mReadyStateException;
|
||||
bool mResponseException;
|
||||
|
||||
public:
|
||||
EventRunnable(Proxy* aProxy, bool aUploadEvent, const nsString& aType,
|
||||
bool aLengthComputable, PRUint64 aLoaded, PRUint64 aTotal)
|
||||
: MainThreadProxyRunnable(aProxy->mWorkerPrivate, aProxy), mType(aType),
|
||||
mLoaded(aLoaded), mTotal(aTotal), mChannelId(aProxy->mInnerChannelId),
|
||||
mStatus(0), mReadyState(0), mUploadEvent(aUploadEvent),
|
||||
mProgressEvent(true), mLengthComputable(aLengthComputable),
|
||||
mResponseTextException(false), mStatusException(false),
|
||||
mStatusTextException(false), mReadyStateException(false)
|
||||
mResponse(JSVAL_VOID), mLoaded(aLoaded), mTotal(aTotal),
|
||||
mChannelId(aProxy->mInnerChannelId), mStatus(0), mReadyState(0),
|
||||
mUploadEvent(aUploadEvent), mProgressEvent(true),
|
||||
mLengthComputable(aLengthComputable), mResponseTextException(false),
|
||||
mStatusException(false), mStatusTextException(false),
|
||||
mReadyStateException(false), mResponseException(false)
|
||||
{ }
|
||||
|
||||
EventRunnable(Proxy* aProxy, bool aUploadEvent, const nsString& aType)
|
||||
: MainThreadProxyRunnable(aProxy->mWorkerPrivate, aProxy), mType(aType),
|
||||
mLoaded(0), mTotal(0), mChannelId(aProxy->mInnerChannelId), mStatus(0),
|
||||
mReadyState(0), mUploadEvent(aUploadEvent), mProgressEvent(false),
|
||||
mLengthComputable(0), mResponseTextException(false),
|
||||
mStatusException(false), mStatusTextException(false),
|
||||
mReadyStateException(false)
|
||||
mResponse(JSVAL_VOID), mLoaded(0), mTotal(0),
|
||||
mChannelId(aProxy->mInnerChannelId), mStatus(0), mReadyState(0),
|
||||
mUploadEvent(aUploadEvent), mProgressEvent(false), mLengthComputable(0),
|
||||
mResponseTextException(false), mStatusException(false),
|
||||
mStatusTextException(false), mReadyStateException(false),
|
||||
mResponseException(false)
|
||||
{ }
|
||||
|
||||
bool
|
||||
|
@ -480,18 +483,40 @@ public:
|
|||
nsRefPtr<nsXMLHttpRequest>& xhr = mProxy->mXHR;
|
||||
NS_ASSERTION(xhr, "Must have an XHR here!");
|
||||
|
||||
if (NS_SUCCEEDED(xhr->GetResponseText(mResponseText))) {
|
||||
if (mResponseText == mProxy->mPreviousResponseText) {
|
||||
mResponseText.SetIsVoid(true);
|
||||
if (NS_FAILED(xhr->GetResponseType(mResponseType))) {
|
||||
NS_ERROR("This should never fail!");
|
||||
}
|
||||
|
||||
jsval response;
|
||||
if (NS_SUCCEEDED(xhr->GetResponse(aCx, &response))) {
|
||||
if (JSVAL_IS_UNIVERSAL(response)) {
|
||||
mResponse = response;
|
||||
}
|
||||
else {
|
||||
mProxy->mPreviousResponseText = mResponseText;
|
||||
}
|
||||
mResponseTextException = false;
|
||||
// Anything subject to GC must be cloned.
|
||||
JSStructuredCloneCallbacks* callbacks =
|
||||
aWorkerPrivate->IsChromeWorker() ?
|
||||
ChromeWorkerStructuredCloneCallbacks(true) :
|
||||
WorkerStructuredCloneCallbacks(true);
|
||||
|
||||
nsTArray<nsCOMPtr<nsISupports> > clonedObjects;
|
||||
|
||||
if (mResponseBuffer.write(aCx, response, callbacks, &clonedObjects)) {
|
||||
mClonedObjects.SwapElements(clonedObjects);
|
||||
}
|
||||
else {
|
||||
mResponseTextException = true;
|
||||
NS_ASSERTION(JS_IsExceptionPending(aCx),
|
||||
"This should really never fail unless OOM!");
|
||||
mResponseException = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
mResponseException = true;
|
||||
}
|
||||
|
||||
nsString responseText;
|
||||
mResponseTextException = NS_FAILED(xhr->GetResponseText(responseText));
|
||||
|
||||
mStatusException = NS_FAILED(xhr->GetStatus(&mStatus));
|
||||
|
||||
|
@ -566,21 +591,44 @@ public:
|
|||
|
||||
xhr::StateData state;
|
||||
|
||||
state.mResponseTextException = mResponseTextException;
|
||||
if (mResponseTextException || mResponseText.IsVoid()) {
|
||||
state.mResponseText = JSVAL_VOID;
|
||||
}
|
||||
else if (mResponseText.IsEmpty()) {
|
||||
state.mResponseText = JS_GetEmptyStringValue(aCx);
|
||||
}
|
||||
else {
|
||||
JSString* responseText = JS_NewUCStringCopyN(aCx, mResponseText.get(),
|
||||
mResponseText.Length());
|
||||
if (!responseText) {
|
||||
state.mResponseException = mResponseException;
|
||||
if (!mResponseException) {
|
||||
if (mResponseBuffer.data()) {
|
||||
NS_ASSERTION(JSVAL_IS_VOID(mResponse), "Huh?!");
|
||||
|
||||
JSStructuredCloneCallbacks* callbacks =
|
||||
aWorkerPrivate->IsChromeWorker() ?
|
||||
ChromeWorkerStructuredCloneCallbacks(false) :
|
||||
WorkerStructuredCloneCallbacks(false);
|
||||
|
||||
nsTArray<nsCOMPtr<nsISupports> > clonedObjects;
|
||||
clonedObjects.SwapElements(mClonedObjects);
|
||||
|
||||
jsval response;
|
||||
if (!mResponseBuffer.read(aCx, &response, callbacks, &clonedObjects)) {
|
||||
return false;
|
||||
}
|
||||
mResponseText.Truncate();
|
||||
state.mResponseText = STRING_TO_JSVAL(responseText);
|
||||
|
||||
mResponseBuffer.clear();
|
||||
state.mResponse = response;
|
||||
}
|
||||
else {
|
||||
state.mResponse = mResponse;
|
||||
}
|
||||
}
|
||||
|
||||
// This logic is all based on the assumption that mResponseTextException
|
||||
// should be set if the responseType isn't "text". Otherwise we're going to
|
||||
// hand out the wrong result if someone gets the responseText property.
|
||||
state.mResponseTextException = mResponseTextException;
|
||||
if (!mResponseTextException) {
|
||||
NS_ASSERTION(JSVAL_IS_STRING(state.mResponse) ||
|
||||
JSVAL_IS_NULL(state.mResponse),
|
||||
"Bad response!");
|
||||
state.mResponseText = state.mResponse;
|
||||
}
|
||||
else {
|
||||
state.mResponseText = JSVAL_VOID;
|
||||
}
|
||||
|
||||
state.mStatusException = mStatusException;
|
||||
|
@ -631,6 +679,19 @@ public:
|
|||
JS_ReportPendingException(aCx);
|
||||
}
|
||||
|
||||
// After firing the event set mResponse to JSVAL_NULL for chunked response
|
||||
// types.
|
||||
if (StringBeginsWith(mResponseType, NS_LITERAL_STRING("moz-chunked-"))) {
|
||||
xhr::StateData newState = {
|
||||
JSVAL_NULL, JSVAL_VOID, JSVAL_VOID, JSVAL_VOID, JSVAL_NULL,
|
||||
false, false, false, false, false
|
||||
};
|
||||
|
||||
if (!xhr::UpdateXHRState(aCx, target, mUploadEvent, newState)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
@ -783,6 +844,34 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
class SetResponseTypeRunnable : public WorkerThreadProxySyncRunnable
|
||||
{
|
||||
nsString mResponseType;
|
||||
|
||||
public:
|
||||
SetResponseTypeRunnable(WorkerPrivate* aWorkerPrivate, Proxy* aProxy,
|
||||
const nsAString& aResponseType)
|
||||
: WorkerThreadProxySyncRunnable(aWorkerPrivate, aProxy),
|
||||
mResponseType(aResponseType)
|
||||
{ }
|
||||
|
||||
intN
|
||||
MainThreadRun()
|
||||
{
|
||||
nsresult rv = mProxy->mXHR->SetResponseType(mResponseType);
|
||||
mResponseType.Truncate();
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
rv = mProxy->mXHR->GetResponseType(mResponseType);
|
||||
}
|
||||
return GetDOMExceptionCodeFromResult(rv);
|
||||
}
|
||||
|
||||
void
|
||||
GetResponseType(nsAString& aResponseType) {
|
||||
aResponseType.Assign(mResponseType);
|
||||
}
|
||||
};
|
||||
|
||||
class AbortRunnable : public WorkerThreadProxySyncRunnable
|
||||
{
|
||||
public:
|
||||
|
@ -911,10 +1000,12 @@ public:
|
|||
}
|
||||
|
||||
mProxy->mInnerChannelId++;
|
||||
mProxy->mPreviousResponseText.Truncate();
|
||||
mProxy->mPreviousStatusText.Truncate();
|
||||
|
||||
rv = mProxy->mXHR->Open(mMethod, mURL, true, mUser, mPassword, 1);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
rv = mProxy->mXHR->SetResponseType(NS_LITERAL_STRING("text"));
|
||||
}
|
||||
return GetDOMExceptionCodeFromResult(rv);
|
||||
}
|
||||
};
|
||||
|
@ -1175,7 +1266,10 @@ Proxy::HandleEvent(nsIDOMEvent* aEvent)
|
|||
runnable = new EventRunnable(this, !!uploadTarget, type);
|
||||
}
|
||||
|
||||
runnable->Dispatch(nsnull);
|
||||
{
|
||||
RuntimeService::AutoSafeJSContext cx;
|
||||
runnable->Dispatch(cx);
|
||||
}
|
||||
|
||||
if (!uploadTarget) {
|
||||
if (type.EqualsASCII(sEventStrings[STRING_loadstart])) {
|
||||
|
@ -1276,7 +1370,7 @@ XMLHttpRequestPrivate::Notify(JSContext* aCx, Status aStatus)
|
|||
}
|
||||
|
||||
bool
|
||||
XMLHttpRequestPrivate::SetMultipart(JSContext* aCx, jsval *aVp)
|
||||
XMLHttpRequestPrivate::SetMultipart(JSContext* aCx, jsval aOldVal, jsval *aVp)
|
||||
{
|
||||
mWorkerPrivate->AssertIsOnWorkerThread();
|
||||
|
||||
|
@ -1306,7 +1400,8 @@ XMLHttpRequestPrivate::SetMultipart(JSContext* aCx, jsval *aVp)
|
|||
}
|
||||
|
||||
bool
|
||||
XMLHttpRequestPrivate::SetMozBackgroundRequest(JSContext* aCx, jsval *aVp)
|
||||
XMLHttpRequestPrivate::SetMozBackgroundRequest(JSContext* aCx, jsval aOldVal,
|
||||
jsval *aVp)
|
||||
{
|
||||
mWorkerPrivate->AssertIsOnWorkerThread();
|
||||
|
||||
|
@ -1336,7 +1431,8 @@ XMLHttpRequestPrivate::SetMozBackgroundRequest(JSContext* aCx, jsval *aVp)
|
|||
}
|
||||
|
||||
bool
|
||||
XMLHttpRequestPrivate::SetWithCredentials(JSContext* aCx, jsval *aVp)
|
||||
XMLHttpRequestPrivate::SetWithCredentials(JSContext* aCx, jsval aOldVal,
|
||||
jsval *aVp)
|
||||
{
|
||||
mWorkerPrivate->AssertIsOnWorkerThread();
|
||||
|
||||
|
@ -1365,6 +1461,68 @@ XMLHttpRequestPrivate::SetWithCredentials(JSContext* aCx, jsval *aVp)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
XMLHttpRequestPrivate::SetResponseType(JSContext* aCx, jsval aOldVal,
|
||||
jsval *aVp)
|
||||
{
|
||||
mWorkerPrivate->AssertIsOnWorkerThread();
|
||||
|
||||
if (mCanceled) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!mProxy || SendInProgress()) {
|
||||
ThrowDOMExceptionForCode(aCx, INVALID_STATE_ERR);
|
||||
return false;
|
||||
}
|
||||
|
||||
JSString* jsstr = JS_ValueToString(aCx, *aVp);
|
||||
if (!jsstr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
nsDependentJSString responseType;
|
||||
if (!responseType.init(aCx, jsstr)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// "document" is fine for the main thread but not for a worker. Short-circuit
|
||||
// that here.
|
||||
if (responseType.EqualsLiteral("document")) {
|
||||
*aVp = aOldVal;
|
||||
return true;
|
||||
}
|
||||
|
||||
nsRefPtr<SetResponseTypeRunnable> runnable =
|
||||
new SetResponseTypeRunnable(mWorkerPrivate, mProxy, responseType);
|
||||
if (!runnable->Dispatch(aCx)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
nsString acceptedResponseType;
|
||||
runnable->GetResponseType(acceptedResponseType);
|
||||
|
||||
|
||||
if (acceptedResponseType == responseType) {
|
||||
// Leave *aVp unchanged.
|
||||
}
|
||||
else if (acceptedResponseType.IsEmpty()) {
|
||||
// Empty string.
|
||||
*aVp = JS_GetEmptyStringValue(aCx);
|
||||
}
|
||||
else {
|
||||
// Some other string.
|
||||
jsstr = JS_NewUCStringCopyN(aCx, acceptedResponseType.get(),
|
||||
acceptedResponseType.Length());
|
||||
if (!jsstr) {
|
||||
return false;
|
||||
}
|
||||
*aVp = STRING_TO_JSVAL(jsstr);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
XMLHttpRequestPrivate::Abort(JSContext* aCx)
|
||||
{
|
||||
|
@ -1680,8 +1838,8 @@ XMLHttpRequestPrivate::MaybeDispatchPrematureAbortEvents(JSContext* aCx,
|
|||
NS_ASSERTION(mProxy, "Must have a proxy here!");
|
||||
|
||||
xhr::StateData state = {
|
||||
JSVAL_VOID, JSVAL_VOID, JSVAL_VOID, INT_TO_JSVAL(4),
|
||||
false, false, false, false
|
||||
JSVAL_VOID, JSVAL_VOID, JSVAL_VOID, INT_TO_JSVAL(4), JSVAL_VOID,
|
||||
false, false, false, false, false
|
||||
};
|
||||
|
||||
if (mProxy->mSeenUploadLoadStart) {
|
||||
|
|
|
@ -111,13 +111,16 @@ public:
|
|||
Notify(JSContext* aCx, Status aStatus);
|
||||
|
||||
bool
|
||||
SetMultipart(JSContext* aCx, jsval *aVp);
|
||||
SetMultipart(JSContext* aCx, jsval aOldVal, jsval *aVp);
|
||||
|
||||
bool
|
||||
SetMozBackgroundRequest(JSContext* aCx, jsval *aVp);
|
||||
SetMozBackgroundRequest(JSContext* aCx, jsval aOldVal, jsval *aVp);
|
||||
|
||||
bool
|
||||
SetWithCredentials(JSContext* aCx, jsval *aVp);
|
||||
SetWithCredentials(JSContext* aCx, jsval aOldVal, jsval *aVp);
|
||||
|
||||
bool
|
||||
SetResponseType(JSContext* aCx, jsval aOldVal, jsval *aVp);
|
||||
|
||||
bool
|
||||
Abort(JSContext* aCx);
|
||||
|
|
|
@ -104,6 +104,8 @@ _TEST_FILES = \
|
|||
throwingOnerror_worker.js \
|
||||
test_xhr.html \
|
||||
xhr_worker.js \
|
||||
test_xhr2.html \
|
||||
xhr2_worker.js \
|
||||
test_xhrAbort.html \
|
||||
xhrAbort_worker.js \
|
||||
testXHR.txt \
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/
|
||||
-->
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
Tests of DOM Worker Threads XHR(Bug 450452 )
|
||||
-->
|
||||
<head>
|
||||
<title>Test for DOM Worker Threads XHR (Bug 450452 )</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=450452">DOM Worker Threads XHR (Bug 450452)</a>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none">
|
||||
|
||||
</div>
|
||||
<pre id="test">
|
||||
<script class="testbody" type="text/javascript">
|
||||
|
||||
var worker = new Worker("xhr2_worker.js");
|
||||
|
||||
worker.onmessage = function(event) {
|
||||
is(event.data, "done", "Got correct result");
|
||||
SimpleTest.finish();
|
||||
}
|
||||
worker.postMessage("testXHR.txt");
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,155 @@
|
|||
/**
|
||||
* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/
|
||||
*/
|
||||
|
||||
onmessage = function(event) {
|
||||
const url = event.data;
|
||||
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open("GET", url, false);
|
||||
xhr.send();
|
||||
|
||||
const refText = xhr.responseText;
|
||||
|
||||
function getResponse(type) {
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open("GET", url, false);
|
||||
if (type !== undefined) {
|
||||
xhr.responseType = type;
|
||||
}
|
||||
xhr.send();
|
||||
return xhr.response;
|
||||
}
|
||||
|
||||
if (getResponse() != refText) {
|
||||
throw new Error("unset responseType failed");
|
||||
}
|
||||
|
||||
if (getResponse("") != refText) {
|
||||
throw new Error("'' responseType failed");
|
||||
}
|
||||
|
||||
if (getResponse("text") != refText) {
|
||||
throw new Error("'text' responseType failed");
|
||||
}
|
||||
|
||||
var array = new Uint8Array(getResponse("arraybuffer"));
|
||||
if (String.fromCharCode.apply(String, array) != refText) {
|
||||
throw new Error("'arraybuffer' responseType failed");
|
||||
}
|
||||
|
||||
var blob = getResponse("blob");
|
||||
if (new FileReaderSync().readAsText(blob) != refText) {
|
||||
throw new Error("'blob' responseType failed");
|
||||
}
|
||||
|
||||
// Make sure that we get invalid state exceptions when getting the wrong
|
||||
// property.
|
||||
|
||||
function testResponseTextException(type) {
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open("GET", url, false);
|
||||
xhr.responseType = type;
|
||||
xhr.send();
|
||||
|
||||
var exception;
|
||||
|
||||
try {
|
||||
xhr.responseText;
|
||||
}
|
||||
catch(e) {
|
||||
exception = e;
|
||||
}
|
||||
|
||||
if (!exception || exception.code != DOMException.INVALID_STATE_ERR) {
|
||||
throw new Error("Failed to throw when getting responseText on '" + type +
|
||||
"' type");
|
||||
}
|
||||
}
|
||||
|
||||
testResponseTextException("arraybuffer");
|
||||
testResponseTextException("blob");
|
||||
|
||||
// Make sure "document" works, but returns text.
|
||||
xhr = new XMLHttpRequest();
|
||||
|
||||
if (xhr.responseType != "text") {
|
||||
throw new Error("Default value for responseType is wrong!");
|
||||
}
|
||||
|
||||
xhr.open("GET", url, false);
|
||||
xhr.responseType = "document";
|
||||
xhr.send();
|
||||
|
||||
if (xhr.responseText != refText) {
|
||||
throw new Error("'document' type not working correctly");
|
||||
}
|
||||
|
||||
// Make sure setting responseType before open or after send fails.
|
||||
var exception;
|
||||
|
||||
xhr = new XMLHttpRequest();
|
||||
try {
|
||||
xhr.responseType = "arraybuffer";
|
||||
}
|
||||
catch(e) {
|
||||
exception = e;
|
||||
}
|
||||
|
||||
if (!exception || exception.code != DOMException.INVALID_STATE_ERR) {
|
||||
throw new Error("Failed to throw when setting responseType before " +
|
||||
"calling open()");
|
||||
}
|
||||
|
||||
xhr.open("GET", url);
|
||||
xhr.responseType = "text";
|
||||
xhr.onload = function(event) {
|
||||
if (event.target.response != refText) {
|
||||
throw new Error("Bad response!");
|
||||
}
|
||||
|
||||
xhr = new XMLHttpRequest();
|
||||
xhr.open("GET", url);
|
||||
xhr.responseType = "moz-chunked-text";
|
||||
|
||||
var lastIndex = 0;
|
||||
xhr.onprogress = function(event) {
|
||||
if (refText.substr(lastIndex, xhr.response.length) != xhr.response) {
|
||||
throw new Error("Bad chunk!");
|
||||
}
|
||||
|
||||
lastIndex += xhr.response.length;
|
||||
};
|
||||
|
||||
xhr.onload = function(event) {
|
||||
if (lastIndex != refText.length) {
|
||||
throw new Error("Didn't see all the data!");
|
||||
}
|
||||
|
||||
setTimeout(function() {
|
||||
if (xhr.response !== null) {
|
||||
throw new Error("Should have gotten null response outside of event!");
|
||||
}
|
||||
postMessage("done");
|
||||
}, 0);
|
||||
}
|
||||
|
||||
xhr.send(null);
|
||||
};
|
||||
xhr.send();
|
||||
|
||||
exception = null;
|
||||
|
||||
try {
|
||||
xhr.responseType = "arraybuffer";
|
||||
}
|
||||
catch(e) {
|
||||
exception = e;
|
||||
}
|
||||
|
||||
if (!exception || exception.code != DOMException.INVALID_STATE_ERR) {
|
||||
throw new Error("Failed to throw when setting responseType after " +
|
||||
"calling send()");
|
||||
}
|
||||
}
|
|
@ -1647,6 +1647,16 @@ extern JS_PUBLIC_DATA(jsid) JSID_EMPTY;
|
|||
# define JSID_EMPTY ((jsid)JSID_TYPE_OBJECT)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Returns true iff the given jsval is immune to GC and can be used across
|
||||
* multiple JSRuntimes without requiring any conversion API.
|
||||
*/
|
||||
static JS_ALWAYS_INLINE JSBool
|
||||
JSVAL_IS_UNIVERSAL(jsval v)
|
||||
{
|
||||
return !JSVAL_IS_GCTHING(v);
|
||||
}
|
||||
|
||||
/************************************************************************/
|
||||
|
||||
/* Lock and unlock the GC thing held by a jsval. */
|
||||
|
|
Загрузка…
Ссылка в новой задаче