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:
Andrea Marchesini 2019-11-04 15:38:08 +00:00
Родитель cb9efcf21b
Коммит 6c4f3e3599
3 изменённых файлов: 249 добавлений и 201 удалений

Просмотреть файл

@ -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