зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1591579 - XMLWorker takes data from XMLMainThread without calling GetResponse(), r=smaug
Differential Revision: https://phabricator.services.mozilla.com/D50921 --HG-- extra : moz-landing-system : lando
This commit is contained in:
Родитель
cff9f77d8c
Коммит
8add24034e
|
@ -546,6 +546,8 @@ nsresult XMLHttpRequestMainThread::AppendToResponseText(
|
|||
|
||||
void XMLHttpRequestMainThread::GetResponseText(DOMString& aResponseText,
|
||||
ErrorResult& aRv) {
|
||||
MOZ_DIAGNOSTIC_ASSERT(!mForWorker);
|
||||
|
||||
XMLHttpRequestStringSnapshot snapshot;
|
||||
GetResponseText(snapshot, aRv);
|
||||
if (aRv.Failed()) {
|
||||
|
@ -660,6 +662,8 @@ void XMLHttpRequestMainThread::SetResponseType(
|
|||
|
||||
void XMLHttpRequestMainThread::GetResponse(
|
||||
JSContext* aCx, JS::MutableHandle<JS::Value> aResponse, ErrorResult& aRv) {
|
||||
MOZ_DIAGNOSTIC_ASSERT(!mForWorker);
|
||||
|
||||
switch (mResponseType) {
|
||||
case XMLHttpRequestResponseType::_empty:
|
||||
case XMLHttpRequestResponseType::Text: {
|
||||
|
@ -705,7 +709,10 @@ void XMLHttpRequestMainThread::GetResponse(
|
|||
mResponseBlob = Blob::Create(GetOwnerGlobal(), mResponseBlobImpl);
|
||||
}
|
||||
|
||||
GetOrCreateDOMReflector(aCx, mResponseBlob, aResponse);
|
||||
if (!GetOrCreateDOMReflector(aCx, mResponseBlob, aResponse)) {
|
||||
aResponse.setNull();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
case XMLHttpRequestResponseType::Document: {
|
||||
|
|
|
@ -44,9 +44,42 @@
|
|||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
/* static */
|
||||
void XMLHttpRequestWorker::StateData::trace(JSTracer* aTrc) {
|
||||
JS::TraceEdge(aTrc, &mResponse, "XMLHttpRequestWorker::StateData::mResponse");
|
||||
void XMLHttpRequestWorker::StateData::Unlink() {
|
||||
MOZ_DIAGNOSTIC_ASSERT(mResponseData);
|
||||
mResponseData->Unlink();
|
||||
}
|
||||
|
||||
void XMLHttpRequestWorker::ResponseData::Unlink() {
|
||||
mResponseBlobImpl = nullptr;
|
||||
mResponseBlob = nullptr;
|
||||
mResponseArrayBufferBuilder = nullptr;
|
||||
mResponseArrayBufferValue = nullptr;
|
||||
mResponseJSONValue.setUndefined();
|
||||
}
|
||||
|
||||
void XMLHttpRequestWorker::StateData::Trace(const TraceCallbacks& aCallbacks,
|
||||
void* aClosure) {
|
||||
MOZ_DIAGNOSTIC_ASSERT(mResponseData);
|
||||
mResponseData->Trace(aCallbacks, aClosure);
|
||||
}
|
||||
|
||||
void XMLHttpRequestWorker::ResponseData::Trace(const TraceCallbacks& aCallbacks,
|
||||
void* aClosure) {
|
||||
ResponseData* tmp = this;
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mResponseArrayBufferValue)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mResponseJSONValue)
|
||||
}
|
||||
|
||||
void XMLHttpRequestWorker::StateData::Traverse(
|
||||
nsCycleCollectionTraversalCallback& cb) {
|
||||
MOZ_DIAGNOSTIC_ASSERT(mResponseData);
|
||||
mResponseData->Traverse(cb);
|
||||
}
|
||||
|
||||
void XMLHttpRequestWorker::ResponseData::Traverse(
|
||||
nsCycleCollectionTraversalCallback& cb) {
|
||||
ResponseData* tmp = this;
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mResponseBlob)
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -131,7 +164,6 @@ class Proxy final : public nsIDOMEventListener {
|
|||
bool mUploadEventListenersAttached;
|
||||
bool mMainThreadSeenLoadStart;
|
||||
bool mInOpen;
|
||||
bool mArrayBufferResponseWasTransferred;
|
||||
|
||||
public:
|
||||
Proxy(XMLHttpRequestWorker* aXHRPrivate, const ClientInfo& aClientInfo,
|
||||
|
@ -160,8 +192,7 @@ class Proxy final : public nsIDOMEventListener {
|
|||
mSeenUploadLoadStart(false),
|
||||
mUploadEventListenersAttached(false),
|
||||
mMainThreadSeenLoadStart(false),
|
||||
mInOpen(false),
|
||||
mArrayBufferResponseWasTransferred(false) {}
|
||||
mInOpen(false) {}
|
||||
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
NS_DECL_NSIDOMEVENTLISTENER
|
||||
|
@ -446,12 +477,9 @@ class LoadStartDetectionRunnable final : public Runnable,
|
|||
~LoadStartDetectionRunnable() { AssertIsOnMainThread(); }
|
||||
};
|
||||
|
||||
class EventRunnable final : public MainThreadProxyRunnable,
|
||||
public StructuredCloneHolder {
|
||||
class EventRunnable final : public MainThreadProxyRunnable {
|
||||
nsString mType;
|
||||
nsString mResponseType;
|
||||
JS::Heap<JS::Value> mResponse;
|
||||
XMLHttpRequestStringSnapshot mResponseText;
|
||||
UniquePtr<XMLHttpRequestWorker::ResponseData> mResponseData;
|
||||
nsString mResponseURL;
|
||||
nsCString mStatusText;
|
||||
uint64_t mLoaded;
|
||||
|
@ -462,10 +490,7 @@ class EventRunnable final : public MainThreadProxyRunnable,
|
|||
bool mUploadEvent;
|
||||
bool mProgressEvent;
|
||||
bool mLengthComputable;
|
||||
bool mUseCachedArrayBufferResponse;
|
||||
nsresult mResponseTextResult;
|
||||
nsresult mStatusResult;
|
||||
nsresult mResponseResult;
|
||||
// mScopeObj is used in PreDispatch only. We init it in our constructor, and
|
||||
// reset() in PreDispatch, to ensure that it's not still linked into the
|
||||
// runtime once we go off-thread.
|
||||
|
@ -476,10 +501,8 @@ class EventRunnable final : public MainThreadProxyRunnable,
|
|||
bool aLengthComputable, uint64_t aLoaded, uint64_t aTotal,
|
||||
JS::Handle<JSObject*> aScopeObj)
|
||||
: MainThreadProxyRunnable(aProxy->mWorkerPrivate, aProxy),
|
||||
StructuredCloneHolder(CloningSupported, TransferringNotSupported,
|
||||
StructuredCloneScope::SameProcessDifferentThread),
|
||||
mType(aType),
|
||||
mResponse(JS::UndefinedValue()),
|
||||
mResponseData(new XMLHttpRequestWorker::ResponseData()),
|
||||
mLoaded(aLoaded),
|
||||
mTotal(aTotal),
|
||||
mEventStreamId(aProxy->mInnerEventStreamId),
|
||||
|
@ -488,19 +511,14 @@ class EventRunnable final : public MainThreadProxyRunnable,
|
|||
mUploadEvent(aUploadEvent),
|
||||
mProgressEvent(true),
|
||||
mLengthComputable(aLengthComputable),
|
||||
mUseCachedArrayBufferResponse(false),
|
||||
mResponseTextResult(NS_OK),
|
||||
mStatusResult(NS_OK),
|
||||
mResponseResult(NS_OK),
|
||||
mScopeObj(RootingCx(), aScopeObj) {}
|
||||
|
||||
EventRunnable(Proxy* aProxy, bool aUploadEvent, const nsString& aType,
|
||||
JS::Handle<JSObject*> aScopeObj)
|
||||
: MainThreadProxyRunnable(aProxy->mWorkerPrivate, aProxy),
|
||||
StructuredCloneHolder(CloningSupported, TransferringNotSupported,
|
||||
StructuredCloneScope::SameProcessDifferentThread),
|
||||
mType(aType),
|
||||
mResponse(JS::UndefinedValue()),
|
||||
mResponseData(new XMLHttpRequestWorker::ResponseData()),
|
||||
mLoaded(0),
|
||||
mTotal(0),
|
||||
mEventStreamId(aProxy->mInnerEventStreamId),
|
||||
|
@ -509,10 +527,7 @@ class EventRunnable final : public MainThreadProxyRunnable,
|
|||
mUploadEvent(aUploadEvent),
|
||||
mProgressEvent(false),
|
||||
mLengthComputable(0),
|
||||
mUseCachedArrayBufferResponse(false),
|
||||
mResponseTextResult(NS_OK),
|
||||
mStatusResult(NS_OK),
|
||||
mResponseResult(NS_OK),
|
||||
mScopeObj(RootingCx(), aScopeObj) {}
|
||||
|
||||
private:
|
||||
|
@ -1027,64 +1042,37 @@ bool EventRunnable::PreDispatch(WorkerPrivate* /* unused */) {
|
|||
RefPtr<XMLHttpRequestMainThread>& xhr = mProxy->mXHR;
|
||||
MOZ_ASSERT(xhr);
|
||||
|
||||
mResponseType.AssignASCII(
|
||||
XMLHttpRequestResponseTypeValues::GetString(xhr->ResponseType()));
|
||||
mResponseData->mResponseType = xhr->ResponseType();
|
||||
|
||||
ErrorResult rv;
|
||||
xhr->GetResponseText(mResponseText, rv);
|
||||
mResponseTextResult = rv.StealNSResult();
|
||||
|
||||
if (NS_SUCCEEDED(mResponseTextResult)) {
|
||||
mResponseResult = mResponseTextResult;
|
||||
if (mResponseText.IsVoid()) {
|
||||
mResponse.setNull();
|
||||
switch (mResponseData->mResponseType) {
|
||||
case XMLHttpRequestResponseType::_empty:
|
||||
case XMLHttpRequestResponseType::Text: {
|
||||
xhr->GetResponseText(mResponseData->mResponseText, rv);
|
||||
mResponseData->mResponseResult = rv.StealNSResult();
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
JS::Rooted<JS::Value> response(cx);
|
||||
xhr->GetResponse(cx, &response, rv);
|
||||
mResponseResult = rv.StealNSResult();
|
||||
if (NS_SUCCEEDED(mResponseResult)) {
|
||||
if (!response.isGCThing()) {
|
||||
mResponse = response;
|
||||
} else {
|
||||
bool doClone = true;
|
||||
JS::Rooted<JS::Value> transferable(cx);
|
||||
JS::Rooted<JSObject*> obj(
|
||||
cx, response.isObject() ? &response.toObject() : nullptr);
|
||||
if (obj && JS::IsArrayBufferObject(obj)) {
|
||||
// Use cached response if the arraybuffer has been transfered.
|
||||
if (mProxy->mArrayBufferResponseWasTransferred) {
|
||||
MOZ_ASSERT(JS::IsDetachedArrayBufferObject(obj));
|
||||
mUseCachedArrayBufferResponse = true;
|
||||
doClone = false;
|
||||
} else {
|
||||
MOZ_ASSERT(!JS::IsDetachedArrayBufferObject(obj));
|
||||
JS::AutoValueArray<1> argv(cx);
|
||||
argv[0].set(response);
|
||||
obj = JS_NewArrayObject(cx, argv);
|
||||
if (obj) {
|
||||
transferable.setObject(*obj);
|
||||
// Only cache the response when the readyState is DONE.
|
||||
if (xhr->ReadyState() == 4) {
|
||||
mProxy->mArrayBufferResponseWasTransferred = true;
|
||||
}
|
||||
} else {
|
||||
mResponseResult = NS_ERROR_OUT_OF_MEMORY;
|
||||
doClone = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (doClone) {
|
||||
Write(cx, response, transferable, JS::CloneDataPolicy(), rv);
|
||||
if (NS_WARN_IF(rv.Failed())) {
|
||||
NS_WARNING("Failed to clone response!");
|
||||
mResponseResult = rv.StealNSResult();
|
||||
mProxy->mArrayBufferResponseWasTransferred = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
case XMLHttpRequestResponseType::Blob: {
|
||||
mResponseData->mResponseBlobImpl = xhr->GetResponseBlobImpl();
|
||||
break;
|
||||
}
|
||||
|
||||
case XMLHttpRequestResponseType::Arraybuffer: {
|
||||
mResponseData->mResponseArrayBufferBuilder =
|
||||
xhr->GetResponseArrayBufferBuilder();
|
||||
break;
|
||||
}
|
||||
|
||||
case XMLHttpRequestResponseType::Json: {
|
||||
mResponseData->mResponseResult =
|
||||
xhr->GetResponseTextForJSON(mResponseData->mResponseJSON);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
MOZ_CRASH("Invalid response type");
|
||||
break;
|
||||
}
|
||||
|
||||
mStatus = xhr->GetStatus(rv);
|
||||
|
@ -1148,44 +1136,10 @@ bool EventRunnable::WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) {
|
|||
}
|
||||
}
|
||||
|
||||
JS::Rooted<UniquePtr<XMLHttpRequestWorker::StateData>> state(
|
||||
aCx, new XMLHttpRequestWorker::StateData());
|
||||
UniquePtr<XMLHttpRequestWorker::StateData> state(
|
||||
new XMLHttpRequestWorker::StateData());
|
||||
|
||||
state->mResponseTextResult = mResponseTextResult;
|
||||
|
||||
state->mResponseText = mResponseText;
|
||||
|
||||
if (NS_SUCCEEDED(mResponseTextResult)) {
|
||||
MOZ_ASSERT(mResponse.isUndefined() || mResponse.isNull());
|
||||
state->mResponseResult = mResponseTextResult;
|
||||
state->mResponse = mResponse;
|
||||
} else {
|
||||
state->mResponseResult = mResponseResult;
|
||||
|
||||
if (NS_SUCCEEDED(mResponseResult)) {
|
||||
if (HasData()) {
|
||||
MOZ_ASSERT(mResponse.isUndefined());
|
||||
|
||||
ErrorResult rv;
|
||||
JS::Rooted<JS::Value> response(aCx);
|
||||
|
||||
GlobalObject globalObj(aCx,
|
||||
aWorkerPrivate->GlobalScope()->GetWrapper());
|
||||
nsCOMPtr<nsIGlobalObject> global =
|
||||
do_QueryInterface(globalObj.GetAsSupports());
|
||||
|
||||
Read(global, aCx, &response, rv);
|
||||
if (NS_WARN_IF(rv.Failed())) {
|
||||
rv.SuppressException();
|
||||
return false;
|
||||
}
|
||||
|
||||
state->mResponse = response;
|
||||
} else {
|
||||
state->mResponse = mResponse;
|
||||
}
|
||||
}
|
||||
}
|
||||
state->mResponseData = std::move(mResponseData);
|
||||
|
||||
state->mStatusResult = mStatusResult;
|
||||
state->mStatus = mStatus;
|
||||
|
@ -1197,7 +1151,7 @@ bool EventRunnable::WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) {
|
|||
state->mResponseURL = mResponseURL;
|
||||
|
||||
XMLHttpRequestWorker* xhr = mProxy->mXMLHttpRequestPrivate;
|
||||
xhr->UpdateState(*state.get(), mUseCachedArrayBufferResponse);
|
||||
xhr->UpdateState(std::move(state));
|
||||
|
||||
if (mUploadEvent && !xhr->GetUploadObjectNoCreate()) {
|
||||
return true;
|
||||
|
@ -1238,11 +1192,6 @@ bool EventRunnable::WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) {
|
|||
|
||||
target->DispatchEvent(*event);
|
||||
|
||||
// After firing the event set mResponse to null for chunked response types.
|
||||
if (StringBeginsWith(mResponseType, NS_LITERAL_STRING("moz-chunked-"))) {
|
||||
xhr->NullResponseText();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1423,8 +1372,6 @@ void SendRunnable::RunOnMainThread(ErrorResult& aRv) {
|
|||
}
|
||||
}
|
||||
|
||||
mProxy->mArrayBufferResponseWasTransferred = false;
|
||||
|
||||
mProxy->mInnerChannelId++;
|
||||
|
||||
mProxy->mXHR->Send(nullptr, payload, aRv);
|
||||
|
@ -1446,6 +1393,7 @@ void SendRunnable::RunOnMainThread(ErrorResult& aRv) {
|
|||
XMLHttpRequestWorker::XMLHttpRequestWorker(WorkerPrivate* aWorkerPrivate)
|
||||
: mWorkerPrivate(aWorkerPrivate),
|
||||
mResponseType(XMLHttpRequestResponseType::_empty),
|
||||
mStateData(new StateData()),
|
||||
mTimeout(0),
|
||||
mBackgroundRequest(false),
|
||||
mWithCredentials(false),
|
||||
|
@ -1479,18 +1427,19 @@ NS_IMPL_CYCLE_COLLECTION_CLASS(XMLHttpRequestWorker)
|
|||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(XMLHttpRequestWorker,
|
||||
XMLHttpRequestEventTarget)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mUpload)
|
||||
tmp->mStateData->Traverse(cb);
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(XMLHttpRequestWorker,
|
||||
XMLHttpRequestEventTarget)
|
||||
tmp->ReleaseProxy(XHRIsGoingAway);
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mUpload)
|
||||
tmp->mStateData.mResponse.setUndefined();
|
||||
tmp->mStateData->Unlink();
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(XMLHttpRequestWorker,
|
||||
XMLHttpRequestEventTarget)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mStateData.mResponse)
|
||||
tmp->mStateData->Trace(aCallbacks, aClosure);
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_END
|
||||
|
||||
/* static */
|
||||
|
@ -1586,10 +1535,10 @@ void XMLHttpRequestWorker::MaybeDispatchPrematureAbortEvents(ErrorResult& aRv) {
|
|||
|
||||
// Only send readystatechange event when state changed.
|
||||
bool isStateChanged = false;
|
||||
if ((mStateData.mReadyState == 1 && mStateData.mFlagSend) ||
|
||||
mStateData.mReadyState == 2 || mStateData.mReadyState == 3) {
|
||||
if ((mStateData->mReadyState == 1 && mStateData->mFlagSend) ||
|
||||
mStateData->mReadyState == 2 || mStateData->mReadyState == 3) {
|
||||
isStateChanged = true;
|
||||
mStateData.mReadyState = 4;
|
||||
mStateData->mReadyState = 4;
|
||||
}
|
||||
|
||||
if (mProxy->mSeenUploadLoadStart) {
|
||||
|
@ -1730,7 +1679,7 @@ void XMLHttpRequestWorker::SendInternal(SendRunnable* aRunnable,
|
|||
aRunnable->SetSyncLoopTarget(syncLoopTarget);
|
||||
aRunnable->SetHaveUploadListeners(hasUploadListeners);
|
||||
|
||||
mStateData.mFlagSend = true;
|
||||
mStateData->mFlagSend = true;
|
||||
|
||||
aRunnable->Dispatch(Canceling, aRv);
|
||||
if (aRv.Failed()) {
|
||||
|
@ -1751,7 +1700,7 @@ void XMLHttpRequestWorker::SendInternal(SendRunnable* aRunnable,
|
|||
autoUnpin.Clear();
|
||||
|
||||
bool succeeded = autoSyncLoop->Run();
|
||||
mStateData.mFlagSend = false;
|
||||
mStateData->mFlagSend = false;
|
||||
|
||||
// Don't clobber an existing exception that we may have thrown on aRv
|
||||
// already... though can there really be one? In any case, it seems to me
|
||||
|
@ -1946,7 +1895,7 @@ void XMLHttpRequestWorker::Send(
|
|||
return;
|
||||
}
|
||||
|
||||
if (!mProxy || mStateData.mFlagSend) {
|
||||
if (!mProxy || mStateData->mFlagSend) {
|
||||
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
return;
|
||||
}
|
||||
|
@ -2078,13 +2027,13 @@ void XMLHttpRequestWorker::Abort(ErrorResult& aRv) {
|
|||
// Set our status to 0 and statusText to "" if we
|
||||
// will be aborting an ongoing fetch, so the upcoming
|
||||
// abort events we dispatch have the correct info.
|
||||
if ((mStateData.mReadyState == XMLHttpRequest_Binding::OPENED &&
|
||||
mStateData.mFlagSend) ||
|
||||
mStateData.mReadyState == XMLHttpRequest_Binding::HEADERS_RECEIVED ||
|
||||
mStateData.mReadyState == XMLHttpRequest_Binding::LOADING ||
|
||||
mStateData.mReadyState == XMLHttpRequest_Binding::DONE) {
|
||||
mStateData.mStatus = 0;
|
||||
mStateData.mStatusText.Truncate();
|
||||
if ((mStateData->mReadyState == XMLHttpRequest_Binding::OPENED &&
|
||||
mStateData->mFlagSend) ||
|
||||
mStateData->mReadyState == XMLHttpRequest_Binding::HEADERS_RECEIVED ||
|
||||
mStateData->mReadyState == XMLHttpRequest_Binding::LOADING ||
|
||||
mStateData->mReadyState == XMLHttpRequest_Binding::DONE) {
|
||||
mStateData->mStatus = 0;
|
||||
mStateData->mStatusText.Truncate();
|
||||
}
|
||||
|
||||
MaybeDispatchPrematureAbortEvents(aRv);
|
||||
|
@ -2092,10 +2041,10 @@ void XMLHttpRequestWorker::Abort(ErrorResult& aRv) {
|
|||
return;
|
||||
}
|
||||
|
||||
if (mStateData.mReadyState == 4) {
|
||||
if (mStateData->mReadyState == 4) {
|
||||
// No one did anything to us while we fired abort events, so reset our state
|
||||
// to "unsent"
|
||||
mStateData.mReadyState = 0;
|
||||
mStateData->mReadyState = 0;
|
||||
}
|
||||
|
||||
mProxy->mOuterEventStreamId++;
|
||||
|
@ -2165,8 +2114,8 @@ void XMLHttpRequestWorker::OverrideMimeType(const nsAString& aMimeType,
|
|||
}
|
||||
|
||||
// We're supposed to throw if the state is LOADING or DONE.
|
||||
if (mStateData.mReadyState == XMLHttpRequest_Binding::LOADING ||
|
||||
mStateData.mReadyState == XMLHttpRequest_Binding::DONE) {
|
||||
if (mStateData->mReadyState == XMLHttpRequest_Binding::LOADING ||
|
||||
mStateData->mReadyState == XMLHttpRequest_Binding::DONE) {
|
||||
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
return;
|
||||
}
|
||||
|
@ -2197,8 +2146,8 @@ void XMLHttpRequestWorker::SetResponseType(
|
|||
return;
|
||||
}
|
||||
|
||||
if (mStateData.mReadyState == XMLHttpRequest_Binding::LOADING ||
|
||||
mStateData.mReadyState == XMLHttpRequest_Binding::DONE) {
|
||||
if (mStateData->mReadyState == XMLHttpRequest_Binding::LOADING ||
|
||||
mStateData->mReadyState == XMLHttpRequest_Binding::DONE) {
|
||||
aRv.Throw(
|
||||
NS_ERROR_DOM_INVALID_STATE_XHR_MUST_NOT_BE_LOADING_OR_DONE_RESPONSE_TYPE);
|
||||
return;
|
||||
|
@ -2214,62 +2163,131 @@ void XMLHttpRequestWorker::SetResponseType(
|
|||
mResponseType = runnable->ResponseType();
|
||||
}
|
||||
|
||||
void XMLHttpRequestWorker::GetResponse(JSContext* /* unused */,
|
||||
void XMLHttpRequestWorker::GetResponse(JSContext* aCx,
|
||||
JS::MutableHandle<JS::Value> aResponse,
|
||||
ErrorResult& aRv) {
|
||||
if (NS_SUCCEEDED(mStateData.mResponseTextResult) &&
|
||||
mStateData.mResponse.isUndefined()) {
|
||||
MOZ_ASSERT(NS_SUCCEEDED(mStateData.mResponseResult));
|
||||
if (NS_FAILED(mStateData->mResponseData->mResponseResult)) {
|
||||
aRv.Throw(mStateData->mResponseData->mResponseResult);
|
||||
return;
|
||||
}
|
||||
|
||||
if (mStateData.mResponseText.IsEmpty()) {
|
||||
mStateData.mResponse =
|
||||
JS_GetEmptyStringValue(mWorkerPrivate->GetJSContext());
|
||||
} else {
|
||||
XMLHttpRequestStringSnapshotReaderHelper helper(mStateData.mResponseText);
|
||||
switch (mStateData->mResponseData->mResponseType) {
|
||||
case XMLHttpRequestResponseType::_empty:
|
||||
case XMLHttpRequestResponseType::Text: {
|
||||
JSString* str;
|
||||
|
||||
JSString* str = JS_NewUCStringCopyN(mWorkerPrivate->GetJSContext(),
|
||||
helper.Buffer(), helper.Length());
|
||||
if (mStateData->mResponseData->mResponseText.IsEmpty()) {
|
||||
aResponse.set(JS_GetEmptyStringValue(aCx));
|
||||
return;
|
||||
}
|
||||
|
||||
XMLHttpRequestStringSnapshotReaderHelper helper(
|
||||
mStateData->mResponseData->mResponseText);
|
||||
|
||||
str = JS_NewUCStringCopyN(aCx, helper.Buffer(), helper.Length());
|
||||
if (!str) {
|
||||
aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
|
||||
return;
|
||||
}
|
||||
|
||||
mStateData.mResponse.setString(str);
|
||||
aResponse.setString(str);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
aRv = mStateData.mResponseResult;
|
||||
aResponse.set(mStateData.mResponse);
|
||||
case XMLHttpRequestResponseType::Arraybuffer: {
|
||||
if (!mStateData->mResponseData->mResponseArrayBufferBuilder) {
|
||||
aResponse.setNull();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!mStateData->mResponseData->mResponseArrayBufferValue) {
|
||||
mStateData->mResponseData->mResponseArrayBufferValue =
|
||||
mStateData->mResponseData->mResponseArrayBufferBuilder
|
||||
->GetArrayBuffer(aCx);
|
||||
if (!mStateData->mResponseData->mResponseArrayBufferValue) {
|
||||
aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
aResponse.setObject(
|
||||
*mStateData->mResponseData->mResponseArrayBufferValue);
|
||||
return;
|
||||
}
|
||||
|
||||
case XMLHttpRequestResponseType::Blob: {
|
||||
if (!mStateData->mResponseData->mResponseBlobImpl) {
|
||||
aResponse.setNull();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!mStateData->mResponseData->mResponseBlob) {
|
||||
mStateData->mResponseData->mResponseBlob = Blob::Create(
|
||||
GetOwnerGlobal(), mStateData->mResponseData->mResponseBlobImpl);
|
||||
}
|
||||
|
||||
if (!GetOrCreateDOMReflector(
|
||||
aCx, mStateData->mResponseData->mResponseBlob, aResponse)) {
|
||||
aResponse.setNull();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
case XMLHttpRequestResponseType::Json: {
|
||||
if (mStateData->mResponseData->mResponseJSON.IsVoid()) {
|
||||
aResponse.setNull();
|
||||
return;
|
||||
}
|
||||
|
||||
if (mStateData->mResponseData->mResponseJSONValue.isUndefined()) {
|
||||
// The Unicode converter has already zapped the BOM if there was one
|
||||
JS::Rooted<JS::Value> value(aCx);
|
||||
if (!JS_ParseJSON(
|
||||
aCx, mStateData->mResponseData->mResponseJSON.BeginReading(),
|
||||
mStateData->mResponseData->mResponseJSON.Length(), &value)) {
|
||||
JS_ClearPendingException(aCx);
|
||||
mStateData->mResponseData->mResponseJSONValue.setNull();
|
||||
} else {
|
||||
mStateData->mResponseData->mResponseJSONValue = value;
|
||||
}
|
||||
|
||||
mStateData->mResponseData->mResponseJSON.Truncate();
|
||||
}
|
||||
|
||||
aResponse.set(mStateData->mResponseData->mResponseJSONValue);
|
||||
return;
|
||||
}
|
||||
|
||||
default:
|
||||
MOZ_CRASH("Invalid type");
|
||||
aResponse.setNull();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void XMLHttpRequestWorker::GetResponseText(DOMString& aResponseText,
|
||||
ErrorResult& aRv) {
|
||||
aRv = mStateData.mResponseTextResult;
|
||||
if (aRv.Failed()) {
|
||||
MOZ_DIAGNOSTIC_ASSERT(mStateData->mResponseData);
|
||||
|
||||
if (mStateData->mResponseData->mResponseType !=
|
||||
XMLHttpRequestResponseType::_empty &&
|
||||
mStateData->mResponseData->mResponseType !=
|
||||
XMLHttpRequestResponseType::Text) {
|
||||
aRv.Throw(
|
||||
NS_ERROR_DOM_INVALID_STATE_XHR_HAS_WRONG_RESPONSETYPE_FOR_RESPONSETEXT);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!mStateData.mResponseText.GetAsString(aResponseText)) {
|
||||
if (!mStateData->mResponseData->mResponseText.GetAsString(aResponseText)) {
|
||||
aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void XMLHttpRequestWorker::UpdateState(const StateData& aStateData,
|
||||
bool aUseCachedArrayBufferResponse) {
|
||||
if (aUseCachedArrayBufferResponse) {
|
||||
MOZ_ASSERT(mStateData.mResponse.isObject() &&
|
||||
JS::IsArrayBufferObject(&mStateData.mResponse.toObject()));
|
||||
|
||||
JS::Rooted<JS::Value> response(mWorkerPrivate->GetJSContext(),
|
||||
mStateData.mResponse);
|
||||
mStateData = aStateData;
|
||||
mStateData.mResponse = response;
|
||||
} else {
|
||||
mStateData = aStateData;
|
||||
}
|
||||
|
||||
void XMLHttpRequestWorker::UpdateState(UniquePtr<StateData>&& aStateData) {
|
||||
mStateData->Unlink();
|
||||
mStateData = std::move(aStateData);
|
||||
XMLHttpRequest_Binding::ClearCachedResponseTextValue(this);
|
||||
}
|
||||
|
||||
|
|
|
@ -22,28 +22,56 @@ class WorkerPrivate;
|
|||
|
||||
class XMLHttpRequestWorker final : public XMLHttpRequest {
|
||||
public:
|
||||
struct StateData {
|
||||
// This defines the xhr.response value.
|
||||
struct ResponseData {
|
||||
XMLHttpRequestResponseType mResponseType;
|
||||
nsresult mResponseResult;
|
||||
|
||||
// responseType is empty or text.
|
||||
XMLHttpRequestStringSnapshot mResponseText;
|
||||
|
||||
// responseType is blob
|
||||
RefPtr<BlobImpl> mResponseBlobImpl;
|
||||
RefPtr<Blob> mResponseBlob;
|
||||
|
||||
// responseType is arrayBuffer;
|
||||
RefPtr<ArrayBufferBuilder> mResponseArrayBufferBuilder;
|
||||
JS::Heap<JSObject*> mResponseArrayBufferValue;
|
||||
|
||||
// responseType is json
|
||||
nsString mResponseJSON;
|
||||
JS::Heap<JS::Value> mResponseJSONValue;
|
||||
|
||||
ResponseData()
|
||||
: mResponseType(XMLHttpRequestResponseType::_empty),
|
||||
mResponseResult(NS_OK),
|
||||
mResponseArrayBufferValue(nullptr),
|
||||
mResponseJSONValue(JS::UndefinedValue()) {}
|
||||
|
||||
void Unlink();
|
||||
void Trace(const TraceCallbacks& aCallbacks, void* aClosure);
|
||||
void Traverse(nsCycleCollectionTraversalCallback& aCb);
|
||||
};
|
||||
|
||||
struct StateData {
|
||||
UniquePtr<ResponseData> mResponseData;
|
||||
nsString mResponseURL;
|
||||
uint32_t mStatus;
|
||||
nsCString mStatusText;
|
||||
uint16_t mReadyState;
|
||||
bool mFlagSend;
|
||||
JS::Heap<JS::Value> mResponse;
|
||||
nsresult mResponseTextResult;
|
||||
nsresult mStatusResult;
|
||||
nsresult mResponseResult;
|
||||
|
||||
StateData()
|
||||
: mStatus(0),
|
||||
: mResponseData(new ResponseData()),
|
||||
mStatus(0),
|
||||
mReadyState(0),
|
||||
mFlagSend(false),
|
||||
mResponse(JS::UndefinedValue()),
|
||||
mResponseTextResult(NS_OK),
|
||||
mStatusResult(NS_OK),
|
||||
mResponseResult(NS_OK) {}
|
||||
mStatusResult(NS_OK) {}
|
||||
|
||||
void trace(JSTracer* trc);
|
||||
void Unlink();
|
||||
void Trace(const TraceCallbacks& aCallbacks, void* aClosure);
|
||||
void Traverse(nsCycleCollectionTraversalCallback& aCb);
|
||||
};
|
||||
|
||||
private:
|
||||
|
@ -52,7 +80,8 @@ class XMLHttpRequestWorker final : public XMLHttpRequest {
|
|||
RefPtr<StrongWorkerRef> mWorkerRef;
|
||||
RefPtr<Proxy> mProxy;
|
||||
XMLHttpRequestResponseType mResponseType;
|
||||
StateData mStateData;
|
||||
|
||||
UniquePtr<StateData> mStateData;
|
||||
|
||||
uint32_t mTimeout;
|
||||
|
||||
|
@ -77,7 +106,7 @@ class XMLHttpRequestWorker final : public XMLHttpRequest {
|
|||
void Unpin();
|
||||
|
||||
virtual uint16_t ReadyState() const override {
|
||||
return mStateData.mReadyState;
|
||||
return mStateData->mReadyState;
|
||||
}
|
||||
|
||||
virtual void Open(const nsACString& aMethod, const nsAString& aUrl,
|
||||
|
@ -141,17 +170,17 @@ class XMLHttpRequestWorker final : public XMLHttpRequest {
|
|||
virtual void Abort(ErrorResult& aRv) override;
|
||||
|
||||
virtual void GetResponseURL(nsAString& aUrl) override {
|
||||
aUrl = mStateData.mResponseURL;
|
||||
aUrl = mStateData->mResponseURL;
|
||||
}
|
||||
|
||||
uint32_t GetStatus(ErrorResult& aRv) override {
|
||||
aRv = mStateData.mStatusResult;
|
||||
return mStateData.mStatus;
|
||||
aRv = mStateData->mStatusResult;
|
||||
return mStateData->mStatus;
|
||||
}
|
||||
|
||||
virtual void GetStatusText(nsACString& aStatusText,
|
||||
ErrorResult& aRv) override {
|
||||
aStatusText = mStateData.mStatusText;
|
||||
aStatusText = mStateData->mStatusText;
|
||||
}
|
||||
|
||||
virtual void GetResponseHeader(const nsACString& aHeader,
|
||||
|
@ -195,13 +224,7 @@ class XMLHttpRequestWorker final : public XMLHttpRequest {
|
|||
|
||||
XMLHttpRequestUpload* GetUploadObjectNoCreate() const { return mUpload; }
|
||||
|
||||
void UpdateState(const StateData& aStateData,
|
||||
bool aUseCachedArrayBufferResponse);
|
||||
|
||||
void NullResponseText() {
|
||||
mStateData.mResponseText.SetVoid();
|
||||
mStateData.mResponse.setNull();
|
||||
}
|
||||
void UpdateState(UniquePtr<StateData>&& aStateData);
|
||||
|
||||
virtual uint16_t ErrorCode() const override {
|
||||
return 0; // eOK
|
||||
|
|
Загрузка…
Ссылка в новой задаче