1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/dom/workers/XMLHttpRequest.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,2313 @@ 1.4 +/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this file, 1.7 + * You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#include "XMLHttpRequest.h" 1.10 + 1.11 +#include "nsIDOMEvent.h" 1.12 +#include "nsIDOMEventListener.h" 1.13 +#include "nsIDOMProgressEvent.h" 1.14 +#include "nsIRunnable.h" 1.15 +#include "nsIVariant.h" 1.16 +#include "nsIXMLHttpRequest.h" 1.17 +#include "nsIXPConnect.h" 1.18 + 1.19 +#include "jsfriendapi.h" 1.20 +#include "mozilla/ArrayUtils.h" 1.21 +#include "mozilla/dom/Exceptions.h" 1.22 +#include "nsComponentManagerUtils.h" 1.23 +#include "nsContentUtils.h" 1.24 +#include "nsCxPusher.h" 1.25 +#include "nsJSUtils.h" 1.26 +#include "nsThreadUtils.h" 1.27 + 1.28 +#include "File.h" 1.29 +#include "RuntimeService.h" 1.30 +#include "WorkerPrivate.h" 1.31 +#include "WorkerRunnable.h" 1.32 +#include "XMLHttpRequestUpload.h" 1.33 + 1.34 +using namespace mozilla; 1.35 + 1.36 +using namespace mozilla::dom; 1.37 +USING_WORKERS_NAMESPACE 1.38 + 1.39 +// XXX Need to figure this out... 1.40 +#define UNCATCHABLE_EXCEPTION NS_ERROR_OUT_OF_MEMORY 1.41 + 1.42 +/** 1.43 + * XMLHttpRequest in workers 1.44 + * 1.45 + * XHR in workers is implemented by proxying calls/events/etc between the 1.46 + * worker thread and an nsXMLHttpRequest on the main thread. The glue 1.47 + * object here is the Proxy, which lives on both threads. All other objects 1.48 + * live on either the main thread (the nsXMLHttpRequest) or the worker thread 1.49 + * (the worker and XHR private objects). 1.50 + * 1.51 + * The main thread XHR is always operated in async mode, even for sync XHR 1.52 + * in workers. Calls made on the worker thread are proxied to the main thread 1.53 + * synchronously (meaning the worker thread is blocked until the call 1.54 + * returns). Each proxied call spins up a sync queue, which captures any 1.55 + * synchronously dispatched events and ensures that they run synchronously 1.56 + * on the worker as well. Asynchronously dispatched events are posted to the 1.57 + * worker thread to run asynchronously. Some of the XHR state is mirrored on 1.58 + * the worker thread to avoid needing a cross-thread call on every property 1.59 + * access. 1.60 + * 1.61 + * The XHR private is stored in the private slot of the XHR JSObject on the 1.62 + * worker thread. It is destroyed when that JSObject is GCd. The private 1.63 + * roots its JSObject while network activity is in progress. It also 1.64 + * adds itself as a feature to the worker to give itself a chance to clean up 1.65 + * if the worker goes away during an XHR call. It is important that the 1.66 + * rooting and feature registration (collectively called pinning) happens at 1.67 + * the proper times. If we pin for too long we can cause memory leaks or even 1.68 + * shutdown hangs. If we don't pin for long enough we introduce a GC hazard. 1.69 + * 1.70 + * The XHR is pinned from the time Send is called to roughly the time loadend 1.71 + * is received. There are some complications involved with Abort and XHR 1.72 + * reuse. We maintain a counter on the main thread of how many times Send was 1.73 + * called on this XHR, and we decrement the counter every time we receive a 1.74 + * loadend event. When the counter reaches zero we dispatch a runnable to the 1.75 + * worker thread to unpin the XHR. We only decrement the counter if the 1.76 + * dispatch was successful, because the worker may no longer be accepting 1.77 + * regular runnables. In the event that we reach Proxy::Teardown and there 1.78 + * the outstanding Send count is still non-zero, we dispatch a control 1.79 + * runnable which is guaranteed to run. 1.80 + * 1.81 + * NB: Some of this could probably be simplified now that we have the 1.82 + * inner/outer channel ids. 1.83 + */ 1.84 + 1.85 +BEGIN_WORKERS_NAMESPACE 1.86 + 1.87 +class Proxy MOZ_FINAL : public nsIDOMEventListener 1.88 +{ 1.89 +public: 1.90 + // Read on multiple threads. 1.91 + WorkerPrivate* mWorkerPrivate; 1.92 + XMLHttpRequest* mXMLHttpRequestPrivate; 1.93 + 1.94 + // XHR Params: 1.95 + bool mMozAnon; 1.96 + bool mMozSystem; 1.97 + 1.98 + // Only touched on the main thread. 1.99 + nsRefPtr<nsXMLHttpRequest> mXHR; 1.100 + nsCOMPtr<nsIXMLHttpRequestUpload> mXHRUpload; 1.101 + nsCOMPtr<nsIEventTarget> mSyncLoopTarget; 1.102 + nsCOMPtr<nsIEventTarget> mSyncEventResponseTarget; 1.103 + uint32_t mInnerEventStreamId; 1.104 + uint32_t mInnerChannelId; 1.105 + uint32_t mOutstandingSendCount; 1.106 + 1.107 + // Only touched on the worker thread. 1.108 + uint32_t mOuterEventStreamId; 1.109 + uint32_t mOuterChannelId; 1.110 + uint64_t mLastLoaded; 1.111 + uint64_t mLastTotal; 1.112 + uint64_t mLastUploadLoaded; 1.113 + uint64_t mLastUploadTotal; 1.114 + bool mIsSyncXHR; 1.115 + bool mLastLengthComputable; 1.116 + bool mLastUploadLengthComputable; 1.117 + bool mSeenLoadStart; 1.118 + bool mSeenUploadLoadStart; 1.119 + 1.120 + // Only touched on the main thread. 1.121 + bool mUploadEventListenersAttached; 1.122 + bool mMainThreadSeenLoadStart; 1.123 + bool mInOpen; 1.124 + 1.125 +public: 1.126 + Proxy(XMLHttpRequest* aXHRPrivate, bool aMozAnon, bool aMozSystem) 1.127 + : mWorkerPrivate(nullptr), mXMLHttpRequestPrivate(aXHRPrivate), 1.128 + mMozAnon(aMozAnon), mMozSystem(aMozSystem), 1.129 + mInnerEventStreamId(0), mInnerChannelId(0), mOutstandingSendCount(0), 1.130 + mOuterEventStreamId(0), mOuterChannelId(0), mLastLoaded(0), mLastTotal(0), 1.131 + mLastUploadLoaded(0), mLastUploadTotal(0), mIsSyncXHR(false), 1.132 + mLastLengthComputable(false), mLastUploadLengthComputable(false), 1.133 + mSeenLoadStart(false), mSeenUploadLoadStart(false), 1.134 + mUploadEventListenersAttached(false), mMainThreadSeenLoadStart(false), 1.135 + mInOpen(false) 1.136 + { } 1.137 + 1.138 + NS_DECL_THREADSAFE_ISUPPORTS 1.139 + NS_DECL_NSIDOMEVENTLISTENER 1.140 + 1.141 + bool 1.142 + Init(); 1.143 + 1.144 + void 1.145 + Teardown(); 1.146 + 1.147 + bool 1.148 + AddRemoveEventListeners(bool aUpload, bool aAdd); 1.149 + 1.150 + void 1.151 + Reset() 1.152 + { 1.153 + AssertIsOnMainThread(); 1.154 + 1.155 + if (mUploadEventListenersAttached) { 1.156 + AddRemoveEventListeners(true, false); 1.157 + } 1.158 + } 1.159 + 1.160 + already_AddRefed<nsIEventTarget> 1.161 + GetEventTarget() 1.162 + { 1.163 + AssertIsOnMainThread(); 1.164 + 1.165 + nsCOMPtr<nsIEventTarget> target = mSyncEventResponseTarget ? 1.166 + mSyncEventResponseTarget : 1.167 + mSyncLoopTarget; 1.168 + return target.forget(); 1.169 + } 1.170 + 1.171 +private: 1.172 + ~Proxy() 1.173 + { 1.174 + MOZ_ASSERT(!mXHR); 1.175 + MOZ_ASSERT(!mXHRUpload); 1.176 + MOZ_ASSERT(!mOutstandingSendCount); 1.177 + } 1.178 +}; 1.179 + 1.180 +END_WORKERS_NAMESPACE 1.181 + 1.182 +namespace { 1.183 + 1.184 +inline void 1.185 +ConvertResponseTypeToString(XMLHttpRequestResponseType aType, 1.186 + nsString& aString) 1.187 +{ 1.188 + using namespace 1.189 + mozilla::dom::XMLHttpRequestResponseTypeValues; 1.190 + 1.191 + size_t index = static_cast<size_t>(aType); 1.192 + MOZ_ASSERT(index < ArrayLength(strings), "Codegen gave us a bad value!"); 1.193 + 1.194 + aString.AssignASCII(strings[index].value, strings[index].length); 1.195 +} 1.196 + 1.197 +inline XMLHttpRequestResponseType 1.198 +ConvertStringToResponseType(const nsAString& aString) 1.199 +{ 1.200 + using namespace 1.201 + mozilla::dom::XMLHttpRequestResponseTypeValues; 1.202 + 1.203 + for (size_t index = 0; index < ArrayLength(strings) - 1; index++) { 1.204 + if (aString.EqualsASCII(strings[index].value, strings[index].length)) { 1.205 + return static_cast<XMLHttpRequestResponseType>(index); 1.206 + } 1.207 + } 1.208 + 1.209 + MOZ_ASSUME_UNREACHABLE("Don't know anything about this response type!"); 1.210 +} 1.211 + 1.212 +enum 1.213 +{ 1.214 + STRING_abort = 0, 1.215 + STRING_error, 1.216 + STRING_load, 1.217 + STRING_loadstart, 1.218 + STRING_progress, 1.219 + STRING_timeout, 1.220 + STRING_readystatechange, 1.221 + STRING_loadend, 1.222 + 1.223 + STRING_COUNT, 1.224 + 1.225 + STRING_LAST_XHR = STRING_loadend, 1.226 + STRING_LAST_EVENTTARGET = STRING_timeout 1.227 +}; 1.228 + 1.229 +static_assert(STRING_LAST_XHR >= STRING_LAST_EVENTTARGET, "Bad string setup!"); 1.230 +static_assert(STRING_LAST_XHR == STRING_COUNT - 1, "Bad string setup!"); 1.231 + 1.232 +const char* const sEventStrings[] = { 1.233 + // nsIXMLHttpRequestEventTarget event types, supported by both XHR and Upload. 1.234 + "abort", 1.235 + "error", 1.236 + "load", 1.237 + "loadstart", 1.238 + "progress", 1.239 + "timeout", 1.240 + 1.241 + // nsIXMLHttpRequest event types, supported only by XHR. 1.242 + "readystatechange", 1.243 + "loadend", 1.244 +}; 1.245 + 1.246 +static_assert(MOZ_ARRAY_LENGTH(sEventStrings) == STRING_COUNT, 1.247 + "Bad string count!"); 1.248 + 1.249 +class MainThreadProxyRunnable : public MainThreadWorkerSyncRunnable 1.250 +{ 1.251 +protected: 1.252 + nsRefPtr<Proxy> mProxy; 1.253 + 1.254 + MainThreadProxyRunnable(WorkerPrivate* aWorkerPrivate, Proxy* aProxy) 1.255 + : MainThreadWorkerSyncRunnable(aWorkerPrivate, aProxy->GetEventTarget()), 1.256 + mProxy(aProxy) 1.257 + { 1.258 + MOZ_ASSERT(aProxy); 1.259 + } 1.260 + 1.261 + virtual ~MainThreadProxyRunnable() 1.262 + { } 1.263 +}; 1.264 + 1.265 +class XHRUnpinRunnable MOZ_FINAL : public MainThreadWorkerControlRunnable 1.266 +{ 1.267 + XMLHttpRequest* mXMLHttpRequestPrivate; 1.268 + 1.269 +public: 1.270 + XHRUnpinRunnable(WorkerPrivate* aWorkerPrivate, 1.271 + XMLHttpRequest* aXHRPrivate) 1.272 + : MainThreadWorkerControlRunnable(aWorkerPrivate), 1.273 + mXMLHttpRequestPrivate(aXHRPrivate) 1.274 + { 1.275 + MOZ_ASSERT(aXHRPrivate); 1.276 + } 1.277 + 1.278 +private: 1.279 + ~XHRUnpinRunnable() 1.280 + { } 1.281 + 1.282 + bool 1.283 + WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) 1.284 + { 1.285 + mXMLHttpRequestPrivate->Unpin(); 1.286 + 1.287 + return true; 1.288 + } 1.289 +}; 1.290 + 1.291 +class AsyncTeardownRunnable MOZ_FINAL : public nsRunnable 1.292 +{ 1.293 + nsRefPtr<Proxy> mProxy; 1.294 + 1.295 +public: 1.296 + AsyncTeardownRunnable(Proxy* aProxy) 1.297 + : mProxy(aProxy) 1.298 + { 1.299 + MOZ_ASSERT(aProxy); 1.300 + } 1.301 + 1.302 + NS_DECL_ISUPPORTS_INHERITED 1.303 + 1.304 +private: 1.305 + ~AsyncTeardownRunnable() 1.306 + { } 1.307 + 1.308 + NS_IMETHOD 1.309 + Run() MOZ_OVERRIDE 1.310 + { 1.311 + AssertIsOnMainThread(); 1.312 + 1.313 + mProxy->Teardown(); 1.314 + mProxy = nullptr; 1.315 + 1.316 + return NS_OK; 1.317 + } 1.318 +}; 1.319 + 1.320 +class LoadStartDetectionRunnable MOZ_FINAL : public nsRunnable, 1.321 + public nsIDOMEventListener 1.322 +{ 1.323 + WorkerPrivate* mWorkerPrivate; 1.324 + nsRefPtr<Proxy> mProxy; 1.325 + nsRefPtr<nsXMLHttpRequest> mXHR; 1.326 + XMLHttpRequest* mXMLHttpRequestPrivate; 1.327 + nsString mEventType; 1.328 + uint32_t mChannelId; 1.329 + bool mReceivedLoadStart; 1.330 + 1.331 + class ProxyCompleteRunnable MOZ_FINAL : public MainThreadProxyRunnable 1.332 + { 1.333 + XMLHttpRequest* mXMLHttpRequestPrivate; 1.334 + uint32_t mChannelId; 1.335 + 1.336 + public: 1.337 + ProxyCompleteRunnable(WorkerPrivate* aWorkerPrivate, Proxy* aProxy, 1.338 + XMLHttpRequest* aXHRPrivate, uint32_t aChannelId) 1.339 + : MainThreadProxyRunnable(aWorkerPrivate, aProxy), 1.340 + mXMLHttpRequestPrivate(aXHRPrivate), mChannelId(aChannelId) 1.341 + { } 1.342 + 1.343 + private: 1.344 + ~ProxyCompleteRunnable() 1.345 + { } 1.346 + 1.347 + virtual bool 1.348 + WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) MOZ_OVERRIDE 1.349 + { 1.350 + if (mChannelId != mProxy->mOuterChannelId) { 1.351 + // Threads raced, this event is now obsolete. 1.352 + return true; 1.353 + } 1.354 + 1.355 + if (mSyncLoopTarget) { 1.356 + aWorkerPrivate->StopSyncLoop(mSyncLoopTarget, true); 1.357 + } 1.358 + 1.359 + mXMLHttpRequestPrivate->Unpin(); 1.360 + 1.361 + return true; 1.362 + } 1.363 + 1.364 + NS_IMETHOD 1.365 + Cancel() MOZ_OVERRIDE 1.366 + { 1.367 + // This must run! 1.368 + nsresult rv = MainThreadProxyRunnable::Cancel(); 1.369 + nsresult rv2 = Run(); 1.370 + return NS_FAILED(rv) ? rv : rv2; 1.371 + } 1.372 + }; 1.373 + 1.374 +public: 1.375 + LoadStartDetectionRunnable(Proxy* aProxy, XMLHttpRequest* aXHRPrivate) 1.376 + : mWorkerPrivate(aProxy->mWorkerPrivate), mProxy(aProxy), mXHR(aProxy->mXHR), 1.377 + mXMLHttpRequestPrivate(aXHRPrivate), mChannelId(mProxy->mInnerChannelId), 1.378 + mReceivedLoadStart(false) 1.379 + { 1.380 + AssertIsOnMainThread(); 1.381 + mEventType.AssignWithConversion(sEventStrings[STRING_loadstart]); 1.382 + } 1.383 + 1.384 + NS_DECL_ISUPPORTS_INHERITED 1.385 + NS_DECL_NSIRUNNABLE 1.386 + NS_DECL_NSIDOMEVENTLISTENER 1.387 + 1.388 + bool 1.389 + RegisterAndDispatch() 1.390 + { 1.391 + AssertIsOnMainThread(); 1.392 + 1.393 + if (NS_FAILED(mXHR->AddEventListener(mEventType, this, false, false, 2))) { 1.394 + NS_WARNING("Failed to add event listener!"); 1.395 + return false; 1.396 + } 1.397 + 1.398 + return NS_SUCCEEDED(NS_DispatchToCurrentThread(this)); 1.399 + } 1.400 + 1.401 +private: 1.402 + ~LoadStartDetectionRunnable() 1.403 + { 1.404 + AssertIsOnMainThread(); 1.405 + } 1.406 +}; 1.407 + 1.408 +class EventRunnable MOZ_FINAL : public MainThreadProxyRunnable 1.409 +{ 1.410 + nsString mType; 1.411 + nsString mResponseType; 1.412 + JSAutoStructuredCloneBuffer mResponseBuffer; 1.413 + nsTArray<nsCOMPtr<nsISupports> > mClonedObjects; 1.414 + JS::Heap<JS::Value> mResponse; 1.415 + nsString mResponseText; 1.416 + nsCString mStatusText; 1.417 + uint64_t mLoaded; 1.418 + uint64_t mTotal; 1.419 + uint32_t mEventStreamId; 1.420 + uint32_t mStatus; 1.421 + uint16_t mReadyState; 1.422 + bool mUploadEvent; 1.423 + bool mProgressEvent; 1.424 + bool mLengthComputable; 1.425 + nsresult mResponseTextResult; 1.426 + nsresult mStatusResult; 1.427 + nsresult mResponseResult; 1.428 + 1.429 +public: 1.430 + class StateDataAutoRooter : private JS::CustomAutoRooter 1.431 + { 1.432 + XMLHttpRequest::StateData* mStateData; 1.433 + MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER 1.434 + 1.435 + public: 1.436 + explicit StateDataAutoRooter(JSContext* aCx, XMLHttpRequest::StateData* aData 1.437 + MOZ_GUARD_OBJECT_NOTIFIER_PARAM) 1.438 + : CustomAutoRooter(aCx), mStateData(aData) 1.439 + { 1.440 + MOZ_GUARD_OBJECT_NOTIFIER_INIT; 1.441 + } 1.442 + 1.443 + private: 1.444 + virtual void trace(JSTracer* aTrc) 1.445 + { 1.446 + JS_CallHeapValueTracer(aTrc, &mStateData->mResponse, 1.447 + "XMLHttpRequest::StateData::mResponse"); 1.448 + } 1.449 + }; 1.450 + 1.451 + EventRunnable(Proxy* aProxy, bool aUploadEvent, const nsString& aType, 1.452 + bool aLengthComputable, uint64_t aLoaded, uint64_t aTotal) 1.453 + : MainThreadProxyRunnable(aProxy->mWorkerPrivate, aProxy), mType(aType), 1.454 + mResponse(JSVAL_VOID), mLoaded(aLoaded), mTotal(aTotal), 1.455 + mEventStreamId(aProxy->mInnerEventStreamId), mStatus(0), mReadyState(0), 1.456 + mUploadEvent(aUploadEvent), mProgressEvent(true), 1.457 + mLengthComputable(aLengthComputable), mResponseTextResult(NS_OK), 1.458 + mStatusResult(NS_OK), mResponseResult(NS_OK) 1.459 + { } 1.460 + 1.461 + EventRunnable(Proxy* aProxy, bool aUploadEvent, const nsString& aType) 1.462 + : MainThreadProxyRunnable(aProxy->mWorkerPrivate, aProxy), mType(aType), 1.463 + mResponse(JSVAL_VOID), mLoaded(0), mTotal(0), 1.464 + mEventStreamId(aProxy->mInnerEventStreamId), mStatus(0), mReadyState(0), 1.465 + mUploadEvent(aUploadEvent), mProgressEvent(false), mLengthComputable(0), 1.466 + mResponseTextResult(NS_OK), mStatusResult(NS_OK), mResponseResult(NS_OK) 1.467 + { } 1.468 + 1.469 +private: 1.470 + ~EventRunnable() 1.471 + { } 1.472 + 1.473 + virtual bool 1.474 + PreDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate) MOZ_OVERRIDE; 1.475 + 1.476 + virtual bool 1.477 + WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) MOZ_OVERRIDE; 1.478 +}; 1.479 + 1.480 +class WorkerThreadProxySyncRunnable : public nsRunnable 1.481 +{ 1.482 +protected: 1.483 + WorkerPrivate* mWorkerPrivate; 1.484 + nsRefPtr<Proxy> mProxy; 1.485 + nsCOMPtr<nsIEventTarget> mSyncLoopTarget; 1.486 + 1.487 +private: 1.488 + class ResponseRunnable MOZ_FINAL: public MainThreadStopSyncLoopRunnable 1.489 + { 1.490 + nsRefPtr<Proxy> mProxy; 1.491 + nsresult mErrorCode; 1.492 + 1.493 + public: 1.494 + ResponseRunnable(WorkerPrivate* aWorkerPrivate, Proxy* aProxy, 1.495 + nsresult aErrorCode) 1.496 + : MainThreadStopSyncLoopRunnable(aWorkerPrivate, aProxy->GetEventTarget(), 1.497 + NS_SUCCEEDED(aErrorCode)), 1.498 + mProxy(aProxy), mErrorCode(aErrorCode) 1.499 + { 1.500 + MOZ_ASSERT(aProxy); 1.501 + } 1.502 + 1.503 + private: 1.504 + ~ResponseRunnable() 1.505 + { } 1.506 + 1.507 + virtual void 1.508 + MaybeSetException(JSContext* aCx) MOZ_OVERRIDE 1.509 + { 1.510 + MOZ_ASSERT(NS_FAILED(mErrorCode)); 1.511 + 1.512 + Throw(aCx, mErrorCode); 1.513 + } 1.514 + }; 1.515 + 1.516 +public: 1.517 + WorkerThreadProxySyncRunnable(WorkerPrivate* aWorkerPrivate, Proxy* aProxy) 1.518 + : mWorkerPrivate(aWorkerPrivate), mProxy(aProxy) 1.519 + { 1.520 + MOZ_ASSERT(aWorkerPrivate); 1.521 + MOZ_ASSERT(aProxy); 1.522 + aWorkerPrivate->AssertIsOnWorkerThread(); 1.523 + } 1.524 + 1.525 + NS_DECL_ISUPPORTS_INHERITED 1.526 + 1.527 + bool 1.528 + Dispatch(JSContext* aCx) 1.529 + { 1.530 + mWorkerPrivate->AssertIsOnWorkerThread(); 1.531 + 1.532 + AutoSyncLoopHolder syncLoop(mWorkerPrivate); 1.533 + mSyncLoopTarget = syncLoop.EventTarget(); 1.534 + 1.535 + if (NS_FAILED(NS_DispatchToMainThread(this, NS_DISPATCH_NORMAL))) { 1.536 + JS_ReportError(aCx, "Failed to dispatch to main thread!"); 1.537 + return false; 1.538 + } 1.539 + 1.540 + return syncLoop.Run(); 1.541 + } 1.542 + 1.543 +protected: 1.544 + virtual ~WorkerThreadProxySyncRunnable() 1.545 + { } 1.546 + 1.547 + virtual nsresult 1.548 + MainThreadRun() = 0; 1.549 + 1.550 +private: 1.551 + NS_DECL_NSIRUNNABLE 1.552 +}; 1.553 + 1.554 +class SyncTeardownRunnable MOZ_FINAL : public WorkerThreadProxySyncRunnable 1.555 +{ 1.556 +public: 1.557 + SyncTeardownRunnable(WorkerPrivate* aWorkerPrivate, Proxy* aProxy) 1.558 + : WorkerThreadProxySyncRunnable(aWorkerPrivate, aProxy) 1.559 + { } 1.560 + 1.561 +private: 1.562 + ~SyncTeardownRunnable() 1.563 + { } 1.564 + 1.565 + virtual nsresult 1.566 + MainThreadRun() MOZ_OVERRIDE 1.567 + { 1.568 + mProxy->Teardown(); 1.569 + MOZ_ASSERT(!mProxy->mSyncLoopTarget); 1.570 + return NS_OK; 1.571 + } 1.572 +}; 1.573 + 1.574 +class SetBackgroundRequestRunnable MOZ_FINAL : 1.575 + public WorkerThreadProxySyncRunnable 1.576 +{ 1.577 + bool mValue; 1.578 + 1.579 +public: 1.580 + SetBackgroundRequestRunnable(WorkerPrivate* aWorkerPrivate, Proxy* aProxy, 1.581 + bool aValue) 1.582 + : WorkerThreadProxySyncRunnable(aWorkerPrivate, aProxy), mValue(aValue) 1.583 + { } 1.584 + 1.585 +private: 1.586 + ~SetBackgroundRequestRunnable() 1.587 + { } 1.588 + 1.589 + virtual nsresult 1.590 + MainThreadRun() MOZ_OVERRIDE 1.591 + { 1.592 + return mProxy->mXHR->SetMozBackgroundRequest(mValue); 1.593 + } 1.594 +}; 1.595 + 1.596 +class SetWithCredentialsRunnable MOZ_FINAL : 1.597 + public WorkerThreadProxySyncRunnable 1.598 +{ 1.599 + bool mValue; 1.600 + 1.601 +public: 1.602 + SetWithCredentialsRunnable(WorkerPrivate* aWorkerPrivate, Proxy* aProxy, 1.603 + bool aValue) 1.604 + : WorkerThreadProxySyncRunnable(aWorkerPrivate, aProxy), mValue(aValue) 1.605 + { } 1.606 + 1.607 +private: 1.608 + ~SetWithCredentialsRunnable() 1.609 + { } 1.610 + 1.611 + virtual nsresult 1.612 + MainThreadRun() MOZ_OVERRIDE 1.613 + { 1.614 + return mProxy->mXHR->SetWithCredentials(mValue); 1.615 + } 1.616 +}; 1.617 + 1.618 +class SetResponseTypeRunnable MOZ_FINAL : public WorkerThreadProxySyncRunnable 1.619 +{ 1.620 + nsString mResponseType; 1.621 + 1.622 +public: 1.623 + SetResponseTypeRunnable(WorkerPrivate* aWorkerPrivate, Proxy* aProxy, 1.624 + const nsAString& aResponseType) 1.625 + : WorkerThreadProxySyncRunnable(aWorkerPrivate, aProxy), 1.626 + mResponseType(aResponseType) 1.627 + { } 1.628 + 1.629 + void 1.630 + GetResponseType(nsAString& aResponseType) 1.631 + { 1.632 + aResponseType.Assign(mResponseType); 1.633 + } 1.634 + 1.635 +private: 1.636 + ~SetResponseTypeRunnable() 1.637 + { } 1.638 + 1.639 + virtual nsresult 1.640 + MainThreadRun() MOZ_OVERRIDE 1.641 + { 1.642 + nsresult rv = mProxy->mXHR->SetResponseType(mResponseType); 1.643 + mResponseType.Truncate(); 1.644 + if (NS_SUCCEEDED(rv)) { 1.645 + rv = mProxy->mXHR->GetResponseType(mResponseType); 1.646 + } 1.647 + return rv; 1.648 + } 1.649 +}; 1.650 + 1.651 +class SetTimeoutRunnable MOZ_FINAL : public WorkerThreadProxySyncRunnable 1.652 +{ 1.653 + uint32_t mTimeout; 1.654 + 1.655 +public: 1.656 + SetTimeoutRunnable(WorkerPrivate* aWorkerPrivate, Proxy* aProxy, 1.657 + uint32_t aTimeout) 1.658 + : WorkerThreadProxySyncRunnable(aWorkerPrivate, aProxy), mTimeout(aTimeout) 1.659 + { } 1.660 + 1.661 +private: 1.662 + ~SetTimeoutRunnable() 1.663 + { } 1.664 + 1.665 + virtual nsresult 1.666 + MainThreadRun() MOZ_OVERRIDE 1.667 + { 1.668 + return mProxy->mXHR->SetTimeout(mTimeout); 1.669 + } 1.670 +}; 1.671 + 1.672 +class AbortRunnable MOZ_FINAL : public WorkerThreadProxySyncRunnable 1.673 +{ 1.674 +public: 1.675 + AbortRunnable(WorkerPrivate* aWorkerPrivate, Proxy* aProxy) 1.676 + : WorkerThreadProxySyncRunnable(aWorkerPrivate, aProxy) 1.677 + { } 1.678 + 1.679 +private: 1.680 + ~AbortRunnable() 1.681 + { } 1.682 + 1.683 + virtual nsresult 1.684 + MainThreadRun() MOZ_OVERRIDE; 1.685 +}; 1.686 + 1.687 +class GetAllResponseHeadersRunnable MOZ_FINAL : 1.688 + public WorkerThreadProxySyncRunnable 1.689 +{ 1.690 + nsCString& mResponseHeaders; 1.691 + 1.692 +public: 1.693 + GetAllResponseHeadersRunnable(WorkerPrivate* aWorkerPrivate, Proxy* aProxy, 1.694 + nsCString& aResponseHeaders) 1.695 + : WorkerThreadProxySyncRunnable(aWorkerPrivate, aProxy), 1.696 + mResponseHeaders(aResponseHeaders) 1.697 + { } 1.698 + 1.699 +private: 1.700 + ~GetAllResponseHeadersRunnable() 1.701 + { } 1.702 + 1.703 + virtual nsresult 1.704 + MainThreadRun() MOZ_OVERRIDE 1.705 + { 1.706 + mProxy->mXHR->GetAllResponseHeaders(mResponseHeaders); 1.707 + return NS_OK; 1.708 + } 1.709 +}; 1.710 + 1.711 +class GetResponseHeaderRunnable MOZ_FINAL : public WorkerThreadProxySyncRunnable 1.712 +{ 1.713 + const nsCString mHeader; 1.714 + nsCString& mValue; 1.715 + 1.716 +public: 1.717 + GetResponseHeaderRunnable(WorkerPrivate* aWorkerPrivate, Proxy* aProxy, 1.718 + const nsACString& aHeader, nsCString& aValue) 1.719 + : WorkerThreadProxySyncRunnable(aWorkerPrivate, aProxy), mHeader(aHeader), 1.720 + mValue(aValue) 1.721 + { } 1.722 + 1.723 +private: 1.724 + ~GetResponseHeaderRunnable() 1.725 + { } 1.726 + 1.727 + virtual nsresult 1.728 + MainThreadRun() MOZ_OVERRIDE 1.729 + { 1.730 + return mProxy->mXHR->GetResponseHeader(mHeader, mValue); 1.731 + } 1.732 +}; 1.733 + 1.734 +class OpenRunnable MOZ_FINAL : public WorkerThreadProxySyncRunnable 1.735 +{ 1.736 + nsCString mMethod; 1.737 + nsString mURL; 1.738 + Optional<nsAString> mUser; 1.739 + nsString mUserStr; 1.740 + Optional<nsAString> mPassword; 1.741 + nsString mPasswordStr; 1.742 + bool mBackgroundRequest; 1.743 + bool mWithCredentials; 1.744 + uint32_t mTimeout; 1.745 + 1.746 +public: 1.747 + OpenRunnable(WorkerPrivate* aWorkerPrivate, Proxy* aProxy, 1.748 + const nsACString& aMethod, const nsAString& aURL, 1.749 + const Optional<nsAString>& aUser, 1.750 + const Optional<nsAString>& aPassword, 1.751 + bool aBackgroundRequest, bool aWithCredentials, 1.752 + uint32_t aTimeout) 1.753 + : WorkerThreadProxySyncRunnable(aWorkerPrivate, aProxy), mMethod(aMethod), 1.754 + mURL(aURL), mBackgroundRequest(aBackgroundRequest), 1.755 + mWithCredentials(aWithCredentials), mTimeout(aTimeout) 1.756 + { 1.757 + if (aUser.WasPassed()) { 1.758 + mUserStr = aUser.Value(); 1.759 + mUser = &mUserStr; 1.760 + } 1.761 + if (aPassword.WasPassed()) { 1.762 + mPasswordStr = aPassword.Value(); 1.763 + mPassword = &mPasswordStr; 1.764 + } 1.765 + } 1.766 + 1.767 +private: 1.768 + ~OpenRunnable() 1.769 + { } 1.770 + 1.771 + virtual nsresult 1.772 + MainThreadRun() MOZ_OVERRIDE 1.773 + { 1.774 + WorkerPrivate* oldWorker = mProxy->mWorkerPrivate; 1.775 + mProxy->mWorkerPrivate = mWorkerPrivate; 1.776 + 1.777 + nsresult rv = MainThreadRunInternal(); 1.778 + 1.779 + mProxy->mWorkerPrivate = oldWorker; 1.780 + return rv; 1.781 + } 1.782 + 1.783 + nsresult 1.784 + MainThreadRunInternal(); 1.785 +}; 1.786 + 1.787 +class SendRunnable MOZ_FINAL : public WorkerThreadProxySyncRunnable 1.788 +{ 1.789 + nsString mStringBody; 1.790 + JSAutoStructuredCloneBuffer mBody; 1.791 + nsTArray<nsCOMPtr<nsISupports> > mClonedObjects; 1.792 + nsCOMPtr<nsIEventTarget> mSyncLoopTarget; 1.793 + bool mHasUploadListeners; 1.794 + 1.795 +public: 1.796 + SendRunnable(WorkerPrivate* aWorkerPrivate, Proxy* aProxy, 1.797 + const nsAString& aStringBody, JSAutoStructuredCloneBuffer&& aBody, 1.798 + nsTArray<nsCOMPtr<nsISupports>>& aClonedObjects, 1.799 + nsIEventTarget* aSyncLoopTarget, bool aHasUploadListeners) 1.800 + : WorkerThreadProxySyncRunnable(aWorkerPrivate, aProxy) 1.801 + , mStringBody(aStringBody) 1.802 + , mBody(Move(aBody)) 1.803 + , mSyncLoopTarget(aSyncLoopTarget) 1.804 + , mHasUploadListeners(aHasUploadListeners) 1.805 + { 1.806 + mClonedObjects.SwapElements(aClonedObjects); 1.807 + } 1.808 + 1.809 +private: 1.810 + ~SendRunnable() 1.811 + { } 1.812 + 1.813 + virtual nsresult 1.814 + MainThreadRun() MOZ_OVERRIDE; 1.815 +}; 1.816 + 1.817 +class SetRequestHeaderRunnable MOZ_FINAL : public WorkerThreadProxySyncRunnable 1.818 +{ 1.819 + nsCString mHeader; 1.820 + nsCString mValue; 1.821 + 1.822 +public: 1.823 + SetRequestHeaderRunnable(WorkerPrivate* aWorkerPrivate, Proxy* aProxy, 1.824 + const nsACString& aHeader, const nsACString& aValue) 1.825 + : WorkerThreadProxySyncRunnable(aWorkerPrivate, aProxy), mHeader(aHeader), 1.826 + mValue(aValue) 1.827 + { } 1.828 + 1.829 +private: 1.830 + ~SetRequestHeaderRunnable() 1.831 + { } 1.832 + 1.833 + virtual nsresult 1.834 + MainThreadRun() MOZ_OVERRIDE 1.835 + { 1.836 + return mProxy->mXHR->SetRequestHeader(mHeader, mValue); 1.837 + } 1.838 +}; 1.839 + 1.840 +class OverrideMimeTypeRunnable MOZ_FINAL : public WorkerThreadProxySyncRunnable 1.841 +{ 1.842 + nsString mMimeType; 1.843 + 1.844 +public: 1.845 + OverrideMimeTypeRunnable(WorkerPrivate* aWorkerPrivate, Proxy* aProxy, 1.846 + const nsAString& aMimeType) 1.847 + : WorkerThreadProxySyncRunnable(aWorkerPrivate, aProxy), mMimeType(aMimeType) 1.848 + { } 1.849 + 1.850 +private: 1.851 + ~OverrideMimeTypeRunnable() 1.852 + { } 1.853 + 1.854 + virtual nsresult 1.855 + MainThreadRun() MOZ_OVERRIDE 1.856 + { 1.857 + mProxy->mXHR->OverrideMimeType(mMimeType); 1.858 + return NS_OK; 1.859 + } 1.860 +}; 1.861 + 1.862 +class AutoUnpinXHR 1.863 +{ 1.864 + XMLHttpRequest* mXMLHttpRequestPrivate; 1.865 + 1.866 +public: 1.867 + AutoUnpinXHR(XMLHttpRequest* aXMLHttpRequestPrivate) 1.868 + : mXMLHttpRequestPrivate(aXMLHttpRequestPrivate) 1.869 + { 1.870 + MOZ_ASSERT(aXMLHttpRequestPrivate); 1.871 + } 1.872 + 1.873 + ~AutoUnpinXHR() 1.874 + { 1.875 + if (mXMLHttpRequestPrivate) { 1.876 + mXMLHttpRequestPrivate->Unpin(); 1.877 + } 1.878 + } 1.879 + 1.880 + void Clear() 1.881 + { 1.882 + mXMLHttpRequestPrivate = nullptr; 1.883 + } 1.884 +}; 1.885 + 1.886 +} // anonymous namespace 1.887 + 1.888 +bool 1.889 +Proxy::Init() 1.890 +{ 1.891 + AssertIsOnMainThread(); 1.892 + MOZ_ASSERT(mWorkerPrivate); 1.893 + 1.894 + if (mXHR) { 1.895 + return true; 1.896 + } 1.897 + 1.898 + nsPIDOMWindow* ownerWindow = mWorkerPrivate->GetWindow(); 1.899 + if (ownerWindow) { 1.900 + ownerWindow = ownerWindow->GetOuterWindow(); 1.901 + if (!ownerWindow) { 1.902 + NS_ERROR("No outer window?!"); 1.903 + return false; 1.904 + } 1.905 + 1.906 + nsPIDOMWindow* innerWindow = ownerWindow->GetCurrentInnerWindow(); 1.907 + if (mWorkerPrivate->GetWindow() != innerWindow) { 1.908 + NS_WARNING("Window has navigated, cannot create XHR here."); 1.909 + return false; 1.910 + } 1.911 + } 1.912 + 1.913 + mXHR = new nsXMLHttpRequest(); 1.914 + 1.915 + nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(ownerWindow); 1.916 + if (NS_FAILED(mXHR->Init(mWorkerPrivate->GetPrincipal(), 1.917 + mWorkerPrivate->GetScriptContext(), 1.918 + global, mWorkerPrivate->GetBaseURI()))) { 1.919 + mXHR = nullptr; 1.920 + return false; 1.921 + } 1.922 + 1.923 + mXHR->SetParameters(mMozAnon, mMozSystem); 1.924 + 1.925 + if (NS_FAILED(mXHR->GetUpload(getter_AddRefs(mXHRUpload)))) { 1.926 + mXHR = nullptr; 1.927 + return false; 1.928 + } 1.929 + 1.930 + if (!AddRemoveEventListeners(false, true)) { 1.931 + mXHRUpload = nullptr; 1.932 + mXHR = nullptr; 1.933 + return false; 1.934 + } 1.935 + 1.936 + return true; 1.937 +} 1.938 + 1.939 +void 1.940 +Proxy::Teardown() 1.941 +{ 1.942 + AssertIsOnMainThread(); 1.943 + 1.944 + if (mXHR) { 1.945 + Reset(); 1.946 + 1.947 + // NB: We are intentionally dropping events coming from xhr.abort on the 1.948 + // floor. 1.949 + AddRemoveEventListeners(false, false); 1.950 + mXHR->Abort(); 1.951 + 1.952 + if (mOutstandingSendCount) { 1.953 + nsRefPtr<XHRUnpinRunnable> runnable = 1.954 + new XHRUnpinRunnable(mWorkerPrivate, mXMLHttpRequestPrivate); 1.955 + if (!runnable->Dispatch(nullptr)) { 1.956 + NS_RUNTIMEABORT("We're going to hang at shutdown anyways."); 1.957 + } 1.958 + 1.959 + if (mSyncLoopTarget) { 1.960 + // We have an unclosed sync loop. Fix that now. 1.961 + nsRefPtr<MainThreadStopSyncLoopRunnable> runnable = 1.962 + new MainThreadStopSyncLoopRunnable(mWorkerPrivate, 1.963 + mSyncLoopTarget.forget(), 1.964 + false); 1.965 + if (!runnable->Dispatch(nullptr)) { 1.966 + NS_RUNTIMEABORT("We're going to hang at shutdown anyways."); 1.967 + } 1.968 + } 1.969 + 1.970 + mWorkerPrivate = nullptr; 1.971 + mOutstandingSendCount = 0; 1.972 + } 1.973 + 1.974 + mXHRUpload = nullptr; 1.975 + mXHR = nullptr; 1.976 + } 1.977 + 1.978 + MOZ_ASSERT(!mWorkerPrivate); 1.979 + MOZ_ASSERT(!mSyncLoopTarget); 1.980 +} 1.981 + 1.982 +bool 1.983 +Proxy::AddRemoveEventListeners(bool aUpload, bool aAdd) 1.984 +{ 1.985 + AssertIsOnMainThread(); 1.986 + 1.987 + NS_ASSERTION(!aUpload || 1.988 + (mUploadEventListenersAttached && !aAdd) || 1.989 + (!mUploadEventListenersAttached && aAdd), 1.990 + "Messed up logic for upload listeners!"); 1.991 + 1.992 + nsCOMPtr<nsIDOMEventTarget> target = 1.993 + aUpload ? 1.994 + do_QueryInterface(mXHRUpload) : 1.995 + do_QueryInterface(static_cast<nsIXMLHttpRequest*>(mXHR.get())); 1.996 + NS_ASSERTION(target, "This should never fail!"); 1.997 + 1.998 + uint32_t lastEventType = aUpload ? STRING_LAST_EVENTTARGET : STRING_LAST_XHR; 1.999 + 1.1000 + nsAutoString eventType; 1.1001 + for (uint32_t index = 0; index <= lastEventType; index++) { 1.1002 + eventType = NS_ConvertASCIItoUTF16(sEventStrings[index]); 1.1003 + if (aAdd) { 1.1004 + if (NS_FAILED(target->AddEventListener(eventType, this, false))) { 1.1005 + return false; 1.1006 + } 1.1007 + } 1.1008 + else if (NS_FAILED(target->RemoveEventListener(eventType, this, false))) { 1.1009 + return false; 1.1010 + } 1.1011 + } 1.1012 + 1.1013 + if (aUpload) { 1.1014 + mUploadEventListenersAttached = aAdd; 1.1015 + } 1.1016 + 1.1017 + return true; 1.1018 +} 1.1019 + 1.1020 +NS_IMPL_ISUPPORTS(Proxy, nsIDOMEventListener) 1.1021 + 1.1022 +NS_IMETHODIMP 1.1023 +Proxy::HandleEvent(nsIDOMEvent* aEvent) 1.1024 +{ 1.1025 + AssertIsOnMainThread(); 1.1026 + 1.1027 + if (!mWorkerPrivate || !mXMLHttpRequestPrivate) { 1.1028 + NS_ERROR("Shouldn't get here!"); 1.1029 + return NS_OK; 1.1030 + } 1.1031 + 1.1032 + nsString type; 1.1033 + if (NS_FAILED(aEvent->GetType(type))) { 1.1034 + NS_WARNING("Failed to get event type!"); 1.1035 + return NS_ERROR_FAILURE; 1.1036 + } 1.1037 + 1.1038 + nsCOMPtr<nsIDOMEventTarget> target; 1.1039 + if (NS_FAILED(aEvent->GetTarget(getter_AddRefs(target)))) { 1.1040 + NS_WARNING("Failed to get target!"); 1.1041 + return NS_ERROR_FAILURE; 1.1042 + } 1.1043 + 1.1044 + nsCOMPtr<nsIXMLHttpRequestUpload> uploadTarget = do_QueryInterface(target); 1.1045 + nsCOMPtr<nsIDOMProgressEvent> progressEvent = do_QueryInterface(aEvent); 1.1046 + 1.1047 + nsRefPtr<EventRunnable> runnable; 1.1048 + 1.1049 + if (mInOpen && type.EqualsASCII(sEventStrings[STRING_readystatechange])) { 1.1050 + uint16_t readyState = 0; 1.1051 + if (NS_SUCCEEDED(mXHR->GetReadyState(&readyState)) && 1.1052 + readyState == nsIXMLHttpRequest::OPENED) { 1.1053 + mInnerEventStreamId++; 1.1054 + } 1.1055 + } 1.1056 + 1.1057 + if (progressEvent) { 1.1058 + bool lengthComputable; 1.1059 + uint64_t loaded, total; 1.1060 + if (NS_FAILED(progressEvent->GetLengthComputable(&lengthComputable)) || 1.1061 + NS_FAILED(progressEvent->GetLoaded(&loaded)) || 1.1062 + NS_FAILED(progressEvent->GetTotal(&total))) { 1.1063 + NS_WARNING("Bad progress event!"); 1.1064 + return NS_ERROR_FAILURE; 1.1065 + } 1.1066 + runnable = new EventRunnable(this, !!uploadTarget, type, lengthComputable, 1.1067 + loaded, total); 1.1068 + } 1.1069 + else { 1.1070 + runnable = new EventRunnable(this, !!uploadTarget, type); 1.1071 + } 1.1072 + 1.1073 + { 1.1074 + AutoSafeJSContext cx; 1.1075 + JSAutoRequest ar(cx); 1.1076 + runnable->Dispatch(cx); 1.1077 + } 1.1078 + 1.1079 + if (!uploadTarget) { 1.1080 + if (type.EqualsASCII(sEventStrings[STRING_loadstart])) { 1.1081 + NS_ASSERTION(!mMainThreadSeenLoadStart, "Huh?!"); 1.1082 + mMainThreadSeenLoadStart = true; 1.1083 + } 1.1084 + else if (mMainThreadSeenLoadStart && 1.1085 + type.EqualsASCII(sEventStrings[STRING_loadend])) { 1.1086 + mMainThreadSeenLoadStart = false; 1.1087 + 1.1088 + nsRefPtr<LoadStartDetectionRunnable> runnable = 1.1089 + new LoadStartDetectionRunnable(this, mXMLHttpRequestPrivate); 1.1090 + if (!runnable->RegisterAndDispatch()) { 1.1091 + NS_WARNING("Failed to dispatch LoadStartDetectionRunnable!"); 1.1092 + } 1.1093 + } 1.1094 + } 1.1095 + 1.1096 + return NS_OK; 1.1097 +} 1.1098 + 1.1099 +NS_IMPL_ISUPPORTS_INHERITED0(WorkerThreadProxySyncRunnable, nsRunnable) 1.1100 + 1.1101 +NS_IMPL_ISUPPORTS_INHERITED0(AsyncTeardownRunnable, nsRunnable) 1.1102 + 1.1103 +NS_IMPL_ISUPPORTS_INHERITED(LoadStartDetectionRunnable, nsRunnable, 1.1104 + nsIDOMEventListener) 1.1105 + 1.1106 +NS_IMETHODIMP 1.1107 +LoadStartDetectionRunnable::Run() 1.1108 +{ 1.1109 + AssertIsOnMainThread(); 1.1110 + 1.1111 + if (NS_FAILED(mXHR->RemoveEventListener(mEventType, this, false))) { 1.1112 + NS_WARNING("Failed to remove event listener!"); 1.1113 + } 1.1114 + 1.1115 + if (!mReceivedLoadStart) { 1.1116 + if (mProxy->mOutstandingSendCount > 1) { 1.1117 + mProxy->mOutstandingSendCount--; 1.1118 + } else if (mProxy->mOutstandingSendCount == 1) { 1.1119 + mProxy->Reset(); 1.1120 + 1.1121 + nsRefPtr<ProxyCompleteRunnable> runnable = 1.1122 + new ProxyCompleteRunnable(mWorkerPrivate, mProxy, 1.1123 + mXMLHttpRequestPrivate, mChannelId); 1.1124 + if (runnable->Dispatch(nullptr)) { 1.1125 + mProxy->mWorkerPrivate = nullptr; 1.1126 + mProxy->mSyncLoopTarget = nullptr; 1.1127 + mProxy->mOutstandingSendCount--; 1.1128 + } 1.1129 + } 1.1130 + } 1.1131 + 1.1132 + mProxy = nullptr; 1.1133 + mXHR = nullptr; 1.1134 + mXMLHttpRequestPrivate = nullptr; 1.1135 + return NS_OK; 1.1136 +} 1.1137 + 1.1138 +NS_IMETHODIMP 1.1139 +LoadStartDetectionRunnable::HandleEvent(nsIDOMEvent* aEvent) 1.1140 +{ 1.1141 + AssertIsOnMainThread(); 1.1142 + 1.1143 +#ifdef DEBUG 1.1144 + { 1.1145 + nsString type; 1.1146 + if (NS_SUCCEEDED(aEvent->GetType(type))) { 1.1147 + MOZ_ASSERT(type == mEventType); 1.1148 + } 1.1149 + else { 1.1150 + NS_WARNING("Failed to get event type!"); 1.1151 + } 1.1152 + } 1.1153 +#endif 1.1154 + 1.1155 + mReceivedLoadStart = true; 1.1156 + return NS_OK; 1.1157 +} 1.1158 + 1.1159 +bool 1.1160 +EventRunnable::PreDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate) 1.1161 +{ 1.1162 + AssertIsOnMainThread(); 1.1163 + 1.1164 + nsRefPtr<nsXMLHttpRequest>& xhr = mProxy->mXHR; 1.1165 + MOZ_ASSERT(xhr); 1.1166 + 1.1167 + if (NS_FAILED(xhr->GetResponseType(mResponseType))) { 1.1168 + MOZ_ASSERT(false, "This should never fail!"); 1.1169 + } 1.1170 + 1.1171 + mResponseTextResult = xhr->GetResponseText(mResponseText); 1.1172 + if (NS_SUCCEEDED(mResponseTextResult)) { 1.1173 + mResponseResult = mResponseTextResult; 1.1174 + if (mResponseText.IsVoid()) { 1.1175 + mResponse = JSVAL_NULL; 1.1176 + } 1.1177 + } 1.1178 + else { 1.1179 + JS::Rooted<JS::Value> response(aCx); 1.1180 + mResponseResult = xhr->GetResponse(aCx, &response); 1.1181 + if (NS_SUCCEEDED(mResponseResult)) { 1.1182 + if (JSVAL_IS_UNIVERSAL(response)) { 1.1183 + mResponse = response; 1.1184 + } 1.1185 + else { 1.1186 + // Anything subject to GC must be cloned. 1.1187 + JSStructuredCloneCallbacks* callbacks = 1.1188 + aWorkerPrivate->IsChromeWorker() ? 1.1189 + ChromeWorkerStructuredCloneCallbacks(true) : 1.1190 + WorkerStructuredCloneCallbacks(true); 1.1191 + 1.1192 + nsTArray<nsCOMPtr<nsISupports> > clonedObjects; 1.1193 + 1.1194 + if (mResponseBuffer.write(aCx, response, callbacks, &clonedObjects)) { 1.1195 + mClonedObjects.SwapElements(clonedObjects); 1.1196 + } 1.1197 + else { 1.1198 + NS_WARNING("Failed to clone response!"); 1.1199 + mResponseResult = NS_ERROR_DOM_DATA_CLONE_ERR; 1.1200 + } 1.1201 + } 1.1202 + } 1.1203 + } 1.1204 + 1.1205 + mStatusResult = xhr->GetStatus(&mStatus); 1.1206 + 1.1207 + xhr->GetStatusText(mStatusText); 1.1208 + 1.1209 + mReadyState = xhr->ReadyState(); 1.1210 + 1.1211 + return true; 1.1212 +} 1.1213 + 1.1214 +bool 1.1215 +EventRunnable::WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) 1.1216 +{ 1.1217 + if (mEventStreamId != mProxy->mOuterEventStreamId) { 1.1218 + // Threads raced, this event is now obsolete. 1.1219 + return true; 1.1220 + } 1.1221 + 1.1222 + if (!mProxy->mXMLHttpRequestPrivate) { 1.1223 + // Object was finalized, bail. 1.1224 + return true; 1.1225 + } 1.1226 + 1.1227 + if (mType.EqualsASCII(sEventStrings[STRING_loadstart])) { 1.1228 + if (mUploadEvent) { 1.1229 + mProxy->mSeenUploadLoadStart = true; 1.1230 + } 1.1231 + else { 1.1232 + mProxy->mSeenLoadStart = true; 1.1233 + } 1.1234 + } 1.1235 + else if (mType.EqualsASCII(sEventStrings[STRING_loadend])) { 1.1236 + if (mUploadEvent) { 1.1237 + mProxy->mSeenUploadLoadStart = false; 1.1238 + } 1.1239 + else { 1.1240 + mProxy->mSeenLoadStart = false; 1.1241 + } 1.1242 + } 1.1243 + else if (mType.EqualsASCII(sEventStrings[STRING_abort])) { 1.1244 + if ((mUploadEvent && !mProxy->mSeenUploadLoadStart) || 1.1245 + (!mUploadEvent && !mProxy->mSeenLoadStart)) { 1.1246 + // We've already dispatched premature abort events. 1.1247 + return true; 1.1248 + } 1.1249 + } 1.1250 + else if (mType.EqualsASCII(sEventStrings[STRING_readystatechange])) { 1.1251 + if (mReadyState == 4 && !mUploadEvent && !mProxy->mSeenLoadStart) { 1.1252 + // We've already dispatched premature abort events. 1.1253 + return true; 1.1254 + } 1.1255 + } 1.1256 + 1.1257 + if (mProgressEvent) { 1.1258 + // Cache these for premature abort events. 1.1259 + if (mUploadEvent) { 1.1260 + mProxy->mLastUploadLengthComputable = mLengthComputable; 1.1261 + mProxy->mLastUploadLoaded = mLoaded; 1.1262 + mProxy->mLastUploadTotal = mTotal; 1.1263 + } 1.1264 + else { 1.1265 + mProxy->mLastLengthComputable = mLengthComputable; 1.1266 + mProxy->mLastLoaded = mLoaded; 1.1267 + mProxy->mLastTotal = mTotal; 1.1268 + } 1.1269 + } 1.1270 + 1.1271 + nsAutoPtr<XMLHttpRequest::StateData> state(new XMLHttpRequest::StateData()); 1.1272 + StateDataAutoRooter rooter(aCx, state); 1.1273 + 1.1274 + state->mResponseTextResult = mResponseTextResult; 1.1275 + state->mResponseText = mResponseText; 1.1276 + 1.1277 + if (NS_SUCCEEDED(mResponseTextResult)) { 1.1278 + MOZ_ASSERT(JSVAL_IS_VOID(mResponse) || JSVAL_IS_NULL(mResponse)); 1.1279 + state->mResponseResult = mResponseTextResult; 1.1280 + state->mResponse = mResponse; 1.1281 + } 1.1282 + else { 1.1283 + state->mResponseResult = mResponseResult; 1.1284 + 1.1285 + if (NS_SUCCEEDED(mResponseResult)) { 1.1286 + if (mResponseBuffer.data()) { 1.1287 + MOZ_ASSERT(JSVAL_IS_VOID(mResponse)); 1.1288 + 1.1289 + JSAutoStructuredCloneBuffer responseBuffer(Move(mResponseBuffer)); 1.1290 + 1.1291 + JSStructuredCloneCallbacks* callbacks = 1.1292 + aWorkerPrivate->IsChromeWorker() ? 1.1293 + ChromeWorkerStructuredCloneCallbacks(false) : 1.1294 + WorkerStructuredCloneCallbacks(false); 1.1295 + 1.1296 + nsTArray<nsCOMPtr<nsISupports> > clonedObjects; 1.1297 + clonedObjects.SwapElements(mClonedObjects); 1.1298 + 1.1299 + JS::Rooted<JS::Value> response(aCx); 1.1300 + if (!responseBuffer.read(aCx, &response, callbacks, &clonedObjects)) { 1.1301 + return false; 1.1302 + } 1.1303 + 1.1304 + state->mResponse = response; 1.1305 + } 1.1306 + else { 1.1307 + state->mResponse = mResponse; 1.1308 + } 1.1309 + } 1.1310 + } 1.1311 + 1.1312 + state->mStatusResult = mStatusResult; 1.1313 + state->mStatus = mStatus; 1.1314 + 1.1315 + state->mStatusText = mStatusText; 1.1316 + 1.1317 + state->mReadyState = mReadyState; 1.1318 + 1.1319 + XMLHttpRequest* xhr = mProxy->mXMLHttpRequestPrivate; 1.1320 + xhr->UpdateState(*state); 1.1321 + 1.1322 + if (mUploadEvent && !xhr->GetUploadObjectNoCreate()) { 1.1323 + return true; 1.1324 + } 1.1325 + 1.1326 + JS::Rooted<JSString*> type(aCx, 1.1327 + JS_NewUCStringCopyN(aCx, mType.get(), mType.Length())); 1.1328 + if (!type) { 1.1329 + return false; 1.1330 + } 1.1331 + 1.1332 + nsXHREventTarget* target; 1.1333 + if (mUploadEvent) { 1.1334 + target = xhr->GetUploadObjectNoCreate(); 1.1335 + } 1.1336 + else { 1.1337 + target = xhr; 1.1338 + } 1.1339 + 1.1340 + MOZ_ASSERT(target); 1.1341 + 1.1342 + nsCOMPtr<nsIDOMEvent> event; 1.1343 + if (mProgressEvent) { 1.1344 + NS_NewDOMProgressEvent(getter_AddRefs(event), target, nullptr, nullptr); 1.1345 + nsCOMPtr<nsIDOMProgressEvent> progress = do_QueryInterface(event); 1.1346 + 1.1347 + if (progress) { 1.1348 + progress->InitProgressEvent(mType, false, false, mLengthComputable, 1.1349 + mLoaded, mTotal); 1.1350 + } 1.1351 + } 1.1352 + else { 1.1353 + NS_NewDOMEvent(getter_AddRefs(event), target, nullptr, nullptr); 1.1354 + 1.1355 + if (event) { 1.1356 + event->InitEvent(mType, false, false); 1.1357 + } 1.1358 + } 1.1359 + 1.1360 + if (!event) { 1.1361 + return false; 1.1362 + } 1.1363 + 1.1364 + event->SetTrusted(true); 1.1365 + 1.1366 + target->DispatchDOMEvent(nullptr, event, nullptr, nullptr); 1.1367 + 1.1368 + // After firing the event set mResponse to JSVAL_NULL for chunked response 1.1369 + // types. 1.1370 + if (StringBeginsWith(mResponseType, NS_LITERAL_STRING("moz-chunked-"))) { 1.1371 + xhr->NullResponseText(); 1.1372 + } 1.1373 + 1.1374 + return true; 1.1375 +} 1.1376 + 1.1377 +NS_IMETHODIMP 1.1378 +WorkerThreadProxySyncRunnable::Run() 1.1379 +{ 1.1380 + AssertIsOnMainThread(); 1.1381 + 1.1382 + nsCOMPtr<nsIEventTarget> tempTarget; 1.1383 + mSyncLoopTarget.swap(tempTarget); 1.1384 + 1.1385 + mProxy->mSyncEventResponseTarget.swap(tempTarget); 1.1386 + 1.1387 + nsresult rv = MainThreadRun(); 1.1388 + 1.1389 + nsRefPtr<ResponseRunnable> response = 1.1390 + new ResponseRunnable(mWorkerPrivate, mProxy, rv); 1.1391 + if (!response->Dispatch(nullptr)) { 1.1392 + MOZ_ASSERT(false, "Failed to dispatch response!"); 1.1393 + } 1.1394 + 1.1395 + mProxy->mSyncEventResponseTarget.swap(tempTarget); 1.1396 + 1.1397 + return NS_OK; 1.1398 +} 1.1399 + 1.1400 +nsresult 1.1401 +AbortRunnable::MainThreadRun() 1.1402 +{ 1.1403 + mProxy->mInnerEventStreamId++; 1.1404 + 1.1405 + WorkerPrivate* oldWorker = mProxy->mWorkerPrivate; 1.1406 + mProxy->mWorkerPrivate = mWorkerPrivate; 1.1407 + 1.1408 + mProxy->mXHR->Abort(); 1.1409 + 1.1410 + mProxy->mWorkerPrivate = oldWorker; 1.1411 + 1.1412 + mProxy->Reset(); 1.1413 + 1.1414 + return NS_OK; 1.1415 +} 1.1416 + 1.1417 +nsresult 1.1418 +OpenRunnable::MainThreadRunInternal() 1.1419 +{ 1.1420 + if (!mProxy->Init()) { 1.1421 + return NS_ERROR_DOM_INVALID_STATE_ERR; 1.1422 + } 1.1423 + 1.1424 + nsresult rv; 1.1425 + 1.1426 + if (mBackgroundRequest) { 1.1427 + rv = mProxy->mXHR->SetMozBackgroundRequest(mBackgroundRequest); 1.1428 + NS_ENSURE_SUCCESS(rv, rv); 1.1429 + } 1.1430 + 1.1431 + if (mWithCredentials) { 1.1432 + rv = mProxy->mXHR->SetWithCredentials(mWithCredentials); 1.1433 + NS_ENSURE_SUCCESS(rv, rv); 1.1434 + } 1.1435 + 1.1436 + if (mTimeout) { 1.1437 + rv = mProxy->mXHR->SetTimeout(mTimeout); 1.1438 + NS_ENSURE_SUCCESS(rv, rv); 1.1439 + } 1.1440 + 1.1441 + MOZ_ASSERT(!mProxy->mInOpen); 1.1442 + mProxy->mInOpen = true; 1.1443 + 1.1444 + ErrorResult rv2; 1.1445 + mProxy->mXHR->Open(mMethod, mURL, true, mUser, mPassword, rv2); 1.1446 + 1.1447 + MOZ_ASSERT(mProxy->mInOpen); 1.1448 + mProxy->mInOpen = false; 1.1449 + 1.1450 + if (rv2.Failed()) { 1.1451 + return rv2.ErrorCode(); 1.1452 + } 1.1453 + 1.1454 + return mProxy->mXHR->SetResponseType(NS_LITERAL_STRING("text")); 1.1455 +} 1.1456 + 1.1457 + 1.1458 +nsresult 1.1459 +SendRunnable::MainThreadRun() 1.1460 +{ 1.1461 + nsCOMPtr<nsIVariant> variant; 1.1462 + 1.1463 + if (mBody.data()) { 1.1464 + AutoSafeJSContext cx; 1.1465 + JSAutoRequest ar(cx); 1.1466 + 1.1467 + nsIXPConnect* xpc = nsContentUtils::XPConnect(); 1.1468 + MOZ_ASSERT(xpc); 1.1469 + 1.1470 + nsresult rv = NS_OK; 1.1471 + 1.1472 + JSStructuredCloneCallbacks* callbacks = 1.1473 + mWorkerPrivate->IsChromeWorker() ? 1.1474 + ChromeWorkerStructuredCloneCallbacks(true) : 1.1475 + WorkerStructuredCloneCallbacks(true); 1.1476 + 1.1477 + JS::Rooted<JS::Value> body(cx); 1.1478 + if (mBody.read(cx, &body, callbacks, &mClonedObjects)) { 1.1479 + if (NS_FAILED(xpc->JSValToVariant(cx, body, getter_AddRefs(variant)))) { 1.1480 + rv = NS_ERROR_DOM_INVALID_STATE_ERR; 1.1481 + } 1.1482 + } 1.1483 + else { 1.1484 + rv = NS_ERROR_DOM_DATA_CLONE_ERR; 1.1485 + } 1.1486 + 1.1487 + mBody.clear(); 1.1488 + mClonedObjects.Clear(); 1.1489 + 1.1490 + NS_ENSURE_SUCCESS(rv, rv); 1.1491 + } 1.1492 + else { 1.1493 + nsCOMPtr<nsIWritableVariant> wvariant = 1.1494 + do_CreateInstance(NS_VARIANT_CONTRACTID); 1.1495 + NS_ENSURE_TRUE(wvariant, NS_ERROR_UNEXPECTED); 1.1496 + 1.1497 + if (NS_FAILED(wvariant->SetAsAString(mStringBody))) { 1.1498 + MOZ_ASSERT(false, "This should never fail!"); 1.1499 + } 1.1500 + 1.1501 + variant = wvariant; 1.1502 + } 1.1503 + 1.1504 + MOZ_ASSERT(!mProxy->mWorkerPrivate); 1.1505 + mProxy->mWorkerPrivate = mWorkerPrivate; 1.1506 + 1.1507 + MOZ_ASSERT(!mProxy->mSyncLoopTarget); 1.1508 + mProxy->mSyncLoopTarget.swap(mSyncLoopTarget); 1.1509 + 1.1510 + if (mHasUploadListeners) { 1.1511 + NS_ASSERTION(!mProxy->mUploadEventListenersAttached, "Huh?!"); 1.1512 + if (!mProxy->AddRemoveEventListeners(true, true)) { 1.1513 + MOZ_ASSERT(false, "This should never fail!"); 1.1514 + } 1.1515 + } 1.1516 + 1.1517 + mProxy->mInnerChannelId++; 1.1518 + 1.1519 + nsresult rv = mProxy->mXHR->Send(variant); 1.1520 + 1.1521 + if (NS_SUCCEEDED(rv)) { 1.1522 + mProxy->mOutstandingSendCount++; 1.1523 + 1.1524 + if (!mHasUploadListeners) { 1.1525 + NS_ASSERTION(!mProxy->mUploadEventListenersAttached, "Huh?!"); 1.1526 + if (!mProxy->AddRemoveEventListeners(true, true)) { 1.1527 + MOZ_ASSERT(false, "This should never fail!"); 1.1528 + } 1.1529 + } 1.1530 + } 1.1531 + 1.1532 + return rv; 1.1533 +} 1.1534 + 1.1535 +XMLHttpRequest::XMLHttpRequest(WorkerPrivate* aWorkerPrivate) 1.1536 +: mWorkerPrivate(aWorkerPrivate), 1.1537 + mResponseType(XMLHttpRequestResponseType::Text), mTimeout(0), 1.1538 + mRooted(false), mBackgroundRequest(false), mWithCredentials(false), 1.1539 + mCanceled(false), mMozAnon(false), mMozSystem(false) 1.1540 +{ 1.1541 + mWorkerPrivate->AssertIsOnWorkerThread(); 1.1542 + 1.1543 + SetIsDOMBinding(); 1.1544 + 1.1545 + mozilla::HoldJSObjects(this); 1.1546 +} 1.1547 + 1.1548 +XMLHttpRequest::~XMLHttpRequest() 1.1549 +{ 1.1550 + mWorkerPrivate->AssertIsOnWorkerThread(); 1.1551 + 1.1552 + ReleaseProxy(XHRIsGoingAway); 1.1553 + 1.1554 + MOZ_ASSERT(!mRooted); 1.1555 + 1.1556 + mozilla::DropJSObjects(this); 1.1557 +} 1.1558 + 1.1559 +NS_IMPL_ADDREF_INHERITED(XMLHttpRequest, nsXHREventTarget) 1.1560 +NS_IMPL_RELEASE_INHERITED(XMLHttpRequest, nsXHREventTarget) 1.1561 + 1.1562 +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(XMLHttpRequest) 1.1563 +NS_INTERFACE_MAP_END_INHERITING(nsXHREventTarget) 1.1564 + 1.1565 +NS_IMPL_CYCLE_COLLECTION_CLASS(XMLHttpRequest) 1.1566 + 1.1567 +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(XMLHttpRequest, 1.1568 + nsXHREventTarget) 1.1569 + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mUpload) 1.1570 +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END 1.1571 + 1.1572 +NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(XMLHttpRequest, 1.1573 + nsXHREventTarget) 1.1574 + tmp->ReleaseProxy(XHRIsGoingAway); 1.1575 + NS_IMPL_CYCLE_COLLECTION_UNLINK(mUpload) 1.1576 + tmp->mStateData.mResponse.setUndefined(); 1.1577 +NS_IMPL_CYCLE_COLLECTION_UNLINK_END 1.1578 + 1.1579 +NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(XMLHttpRequest, 1.1580 + nsXHREventTarget) 1.1581 + NS_IMPL_CYCLE_COLLECTION_TRACE_JSVAL_MEMBER_CALLBACK(mStateData.mResponse) 1.1582 +NS_IMPL_CYCLE_COLLECTION_TRACE_END 1.1583 + 1.1584 +JSObject* 1.1585 +XMLHttpRequest::WrapObject(JSContext* aCx) 1.1586 +{ 1.1587 + return XMLHttpRequestBinding_workers::Wrap(aCx, this); 1.1588 +} 1.1589 + 1.1590 +// static 1.1591 +already_AddRefed<XMLHttpRequest> 1.1592 +XMLHttpRequest::Constructor(const GlobalObject& aGlobal, 1.1593 + const MozXMLHttpRequestParameters& aParams, 1.1594 + ErrorResult& aRv) 1.1595 +{ 1.1596 + JSContext* cx = aGlobal.GetContext(); 1.1597 + WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(cx); 1.1598 + MOZ_ASSERT(workerPrivate); 1.1599 + 1.1600 + nsRefPtr<XMLHttpRequest> xhr = new XMLHttpRequest(workerPrivate); 1.1601 + 1.1602 + if (workerPrivate->XHRParamsAllowed()) { 1.1603 + if (aParams.mMozSystem) 1.1604 + xhr->mMozAnon = true; 1.1605 + else 1.1606 + xhr->mMozAnon = aParams.mMozAnon; 1.1607 + xhr->mMozSystem = aParams.mMozSystem; 1.1608 + } 1.1609 + 1.1610 + return xhr.forget(); 1.1611 +} 1.1612 + 1.1613 +void 1.1614 +XMLHttpRequest::ReleaseProxy(ReleaseType aType) 1.1615 +{ 1.1616 + // Can't assert that we're on the worker thread here because mWorkerPrivate 1.1617 + // may be gone. 1.1618 + 1.1619 + if (mProxy) { 1.1620 + if (aType == XHRIsGoingAway) { 1.1621 + // We're in a GC finalizer, so we can't do a sync call here (and we don't 1.1622 + // need to). 1.1623 + nsRefPtr<AsyncTeardownRunnable> runnable = 1.1624 + new AsyncTeardownRunnable(mProxy); 1.1625 + mProxy = nullptr; 1.1626 + 1.1627 + if (NS_FAILED(NS_DispatchToMainThread(runnable))) { 1.1628 + NS_ERROR("Failed to dispatch teardown runnable!"); 1.1629 + } 1.1630 + } else { 1.1631 + // This isn't necessary if the worker is going away or the XHR is going 1.1632 + // away. 1.1633 + if (aType == Default) { 1.1634 + // Don't let any more events run. 1.1635 + mProxy->mOuterEventStreamId++; 1.1636 + } 1.1637 + 1.1638 + // We need to make a sync call here. 1.1639 + nsRefPtr<SyncTeardownRunnable> runnable = 1.1640 + new SyncTeardownRunnable(mWorkerPrivate, mProxy); 1.1641 + mProxy = nullptr; 1.1642 + 1.1643 + if (!runnable->Dispatch(nullptr)) { 1.1644 + NS_ERROR("Failed to dispatch teardown runnable!"); 1.1645 + } 1.1646 + } 1.1647 + } 1.1648 +} 1.1649 + 1.1650 +void 1.1651 +XMLHttpRequest::MaybePin(ErrorResult& aRv) 1.1652 +{ 1.1653 + mWorkerPrivate->AssertIsOnWorkerThread(); 1.1654 + 1.1655 + if (mRooted) { 1.1656 + return; 1.1657 + } 1.1658 + 1.1659 + JSContext* cx = GetCurrentThreadJSContext(); 1.1660 + 1.1661 + if (!mWorkerPrivate->AddFeature(cx, this)) { 1.1662 + aRv.Throw(NS_ERROR_FAILURE); 1.1663 + return; 1.1664 + } 1.1665 + 1.1666 + NS_ADDREF_THIS(); 1.1667 + 1.1668 + mRooted = true; 1.1669 +} 1.1670 + 1.1671 +void 1.1672 +XMLHttpRequest::MaybeDispatchPrematureAbortEvents(ErrorResult& aRv) 1.1673 +{ 1.1674 + mWorkerPrivate->AssertIsOnWorkerThread(); 1.1675 + MOZ_ASSERT(mProxy); 1.1676 + 1.1677 + mStateData.mReadyState = 4; 1.1678 + 1.1679 + if (mProxy->mSeenUploadLoadStart) { 1.1680 + MOZ_ASSERT(mUpload); 1.1681 + 1.1682 + DispatchPrematureAbortEvent(mUpload, NS_LITERAL_STRING("abort"), true, 1.1683 + aRv); 1.1684 + if (aRv.Failed()) { 1.1685 + return; 1.1686 + } 1.1687 + 1.1688 + DispatchPrematureAbortEvent(mUpload, NS_LITERAL_STRING("loadend"), true, 1.1689 + aRv); 1.1690 + if (aRv.Failed()) { 1.1691 + return; 1.1692 + } 1.1693 + 1.1694 + mProxy->mSeenUploadLoadStart = false; 1.1695 + } 1.1696 + 1.1697 + if (mProxy->mSeenLoadStart) { 1.1698 + DispatchPrematureAbortEvent(this, NS_LITERAL_STRING("readystatechange"), 1.1699 + false, aRv); 1.1700 + if (aRv.Failed()) { 1.1701 + return; 1.1702 + } 1.1703 + 1.1704 + DispatchPrematureAbortEvent(this, NS_LITERAL_STRING("abort"), false, aRv); 1.1705 + if (aRv.Failed()) { 1.1706 + return; 1.1707 + } 1.1708 + 1.1709 + DispatchPrematureAbortEvent(this, NS_LITERAL_STRING("loadend"), false, 1.1710 + aRv); 1.1711 + if (aRv.Failed()) { 1.1712 + return; 1.1713 + } 1.1714 + 1.1715 + mProxy->mSeenLoadStart = false; 1.1716 + } 1.1717 +} 1.1718 + 1.1719 +void 1.1720 +XMLHttpRequest::DispatchPrematureAbortEvent(EventTarget* aTarget, 1.1721 + const nsAString& aEventType, 1.1722 + bool aUploadTarget, 1.1723 + ErrorResult& aRv) 1.1724 +{ 1.1725 + mWorkerPrivate->AssertIsOnWorkerThread(); 1.1726 + MOZ_ASSERT(aTarget); 1.1727 + 1.1728 + if (!mProxy) { 1.1729 + aRv.Throw(NS_ERROR_FAILURE); 1.1730 + return; 1.1731 + } 1.1732 + 1.1733 + nsCOMPtr<nsIDOMEvent> event; 1.1734 + if (aEventType.EqualsLiteral("readystatechange")) { 1.1735 + NS_NewDOMEvent(getter_AddRefs(event), aTarget, nullptr, nullptr); 1.1736 + 1.1737 + if (event) { 1.1738 + event->InitEvent(aEventType, false, false); 1.1739 + } 1.1740 + } 1.1741 + else { 1.1742 + NS_NewDOMProgressEvent(getter_AddRefs(event), aTarget, nullptr, nullptr); 1.1743 + 1.1744 + nsCOMPtr<nsIDOMProgressEvent> progress = do_QueryInterface(event); 1.1745 + if (progress) { 1.1746 + if (aUploadTarget) { 1.1747 + progress->InitProgressEvent(aEventType, false, false, 1.1748 + mProxy->mLastUploadLengthComputable, 1.1749 + mProxy->mLastUploadLoaded, 1.1750 + mProxy->mLastUploadTotal); 1.1751 + } 1.1752 + else { 1.1753 + progress->InitProgressEvent(aEventType, false, false, 1.1754 + mProxy->mLastLengthComputable, 1.1755 + mProxy->mLastLoaded, 1.1756 + mProxy->mLastTotal); 1.1757 + } 1.1758 + } 1.1759 + } 1.1760 + 1.1761 + if (!event) { 1.1762 + aRv.Throw(NS_ERROR_FAILURE); 1.1763 + return; 1.1764 + } 1.1765 + 1.1766 + event->SetTrusted(true); 1.1767 + 1.1768 + aTarget->DispatchDOMEvent(nullptr, event, nullptr, nullptr); 1.1769 +} 1.1770 + 1.1771 +void 1.1772 +XMLHttpRequest::Unpin() 1.1773 +{ 1.1774 + mWorkerPrivate->AssertIsOnWorkerThread(); 1.1775 + 1.1776 + MOZ_ASSERT(mRooted, "Mismatched calls to Unpin!"); 1.1777 + 1.1778 + JSContext* cx = GetCurrentThreadJSContext(); 1.1779 + 1.1780 + mWorkerPrivate->RemoveFeature(cx, this); 1.1781 + 1.1782 + mRooted = false; 1.1783 + 1.1784 + NS_RELEASE_THIS(); 1.1785 +} 1.1786 + 1.1787 +void 1.1788 +XMLHttpRequest::SendInternal(const nsAString& aStringBody, 1.1789 + JSAutoStructuredCloneBuffer&& aBody, 1.1790 + nsTArray<nsCOMPtr<nsISupports> >& aClonedObjects, 1.1791 + ErrorResult& aRv) 1.1792 +{ 1.1793 + mWorkerPrivate->AssertIsOnWorkerThread(); 1.1794 + 1.1795 + bool hasUploadListeners = mUpload ? mUpload->HasListeners() : false; 1.1796 + 1.1797 + MaybePin(aRv); 1.1798 + if (aRv.Failed()) { 1.1799 + return; 1.1800 + } 1.1801 + 1.1802 + AutoUnpinXHR autoUnpin(this); 1.1803 + Maybe<AutoSyncLoopHolder> autoSyncLoop; 1.1804 + 1.1805 + nsCOMPtr<nsIEventTarget> syncLoopTarget; 1.1806 + bool isSyncXHR = mProxy->mIsSyncXHR; 1.1807 + if (isSyncXHR) { 1.1808 + autoSyncLoop.construct(mWorkerPrivate); 1.1809 + syncLoopTarget = autoSyncLoop.ref().EventTarget(); 1.1810 + } 1.1811 + 1.1812 + mProxy->mOuterChannelId++; 1.1813 + 1.1814 + JSContext* cx = mWorkerPrivate->GetJSContext(); 1.1815 + 1.1816 + nsRefPtr<SendRunnable> runnable = 1.1817 + new SendRunnable(mWorkerPrivate, mProxy, aStringBody, Move(aBody), 1.1818 + aClonedObjects, syncLoopTarget, hasUploadListeners); 1.1819 + if (!runnable->Dispatch(cx)) { 1.1820 + aRv.Throw(NS_ERROR_FAILURE); 1.1821 + return; 1.1822 + } 1.1823 + 1.1824 + if (!isSyncXHR) { 1.1825 + autoUnpin.Clear(); 1.1826 + MOZ_ASSERT(autoSyncLoop.empty()); 1.1827 + return; 1.1828 + } 1.1829 + 1.1830 + autoUnpin.Clear(); 1.1831 + 1.1832 + if (!autoSyncLoop.ref().Run()) { 1.1833 + aRv.Throw(NS_ERROR_FAILURE); 1.1834 + } 1.1835 +} 1.1836 + 1.1837 +bool 1.1838 +XMLHttpRequest::Notify(JSContext* aCx, Status aStatus) 1.1839 +{ 1.1840 + mWorkerPrivate->AssertIsOnWorkerThread(); 1.1841 + MOZ_ASSERT(mWorkerPrivate->GetJSContext() == aCx); 1.1842 + 1.1843 + if (aStatus >= Canceling && !mCanceled) { 1.1844 + mCanceled = true; 1.1845 + ReleaseProxy(WorkerIsGoingAway); 1.1846 + } 1.1847 + 1.1848 + return true; 1.1849 +} 1.1850 + 1.1851 +void 1.1852 +XMLHttpRequest::Open(const nsACString& aMethod, const nsAString& aUrl, 1.1853 + bool aAsync, const Optional<nsAString>& aUser, 1.1854 + const Optional<nsAString>& aPassword, ErrorResult& aRv) 1.1855 +{ 1.1856 + mWorkerPrivate->AssertIsOnWorkerThread(); 1.1857 + 1.1858 + if (mCanceled) { 1.1859 + aRv.Throw(UNCATCHABLE_EXCEPTION); 1.1860 + return; 1.1861 + } 1.1862 + 1.1863 + if (mProxy) { 1.1864 + MaybeDispatchPrematureAbortEvents(aRv); 1.1865 + if (aRv.Failed()) { 1.1866 + return; 1.1867 + } 1.1868 + } 1.1869 + else { 1.1870 + mProxy = new Proxy(this, mMozAnon, mMozSystem); 1.1871 + } 1.1872 + 1.1873 + mProxy->mOuterEventStreamId++; 1.1874 + 1.1875 + nsRefPtr<OpenRunnable> runnable = 1.1876 + new OpenRunnable(mWorkerPrivate, mProxy, aMethod, aUrl, aUser, aPassword, 1.1877 + mBackgroundRequest, mWithCredentials, 1.1878 + mTimeout); 1.1879 + 1.1880 + if (!runnable->Dispatch(mWorkerPrivate->GetJSContext())) { 1.1881 + ReleaseProxy(); 1.1882 + aRv.Throw(NS_ERROR_FAILURE); 1.1883 + return; 1.1884 + } 1.1885 + 1.1886 + mProxy->mIsSyncXHR = !aAsync; 1.1887 +} 1.1888 + 1.1889 +void 1.1890 +XMLHttpRequest::SetRequestHeader(const nsACString& aHeader, 1.1891 + const nsACString& aValue, ErrorResult& aRv) 1.1892 +{ 1.1893 + mWorkerPrivate->AssertIsOnWorkerThread(); 1.1894 + 1.1895 + if (mCanceled) { 1.1896 + aRv.Throw(UNCATCHABLE_EXCEPTION); 1.1897 + return; 1.1898 + } 1.1899 + 1.1900 + if (!mProxy) { 1.1901 + aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR); 1.1902 + return; 1.1903 + } 1.1904 + 1.1905 + nsRefPtr<SetRequestHeaderRunnable> runnable = 1.1906 + new SetRequestHeaderRunnable(mWorkerPrivate, mProxy, aHeader, aValue); 1.1907 + if (!runnable->Dispatch(mWorkerPrivate->GetJSContext())) { 1.1908 + aRv.Throw(NS_ERROR_FAILURE); 1.1909 + return; 1.1910 + } 1.1911 +} 1.1912 + 1.1913 +void 1.1914 +XMLHttpRequest::SetTimeout(uint32_t aTimeout, ErrorResult& aRv) 1.1915 +{ 1.1916 + mWorkerPrivate->AssertIsOnWorkerThread(); 1.1917 + 1.1918 + if (mCanceled) { 1.1919 + aRv.Throw(UNCATCHABLE_EXCEPTION); 1.1920 + return; 1.1921 + } 1.1922 + 1.1923 + mTimeout = aTimeout; 1.1924 + 1.1925 + if (!mProxy) { 1.1926 + // Open may not have been called yet, in which case we'll handle the 1.1927 + // timeout in OpenRunnable. 1.1928 + return; 1.1929 + } 1.1930 + 1.1931 + nsRefPtr<SetTimeoutRunnable> runnable = 1.1932 + new SetTimeoutRunnable(mWorkerPrivate, mProxy, aTimeout); 1.1933 + if (!runnable->Dispatch(mWorkerPrivate->GetJSContext())) { 1.1934 + aRv.Throw(NS_ERROR_FAILURE); 1.1935 + return; 1.1936 + } 1.1937 +} 1.1938 + 1.1939 +void 1.1940 +XMLHttpRequest::SetWithCredentials(bool aWithCredentials, ErrorResult& aRv) 1.1941 +{ 1.1942 + mWorkerPrivate->AssertIsOnWorkerThread(); 1.1943 + 1.1944 + if (mCanceled) { 1.1945 + aRv.Throw(UNCATCHABLE_EXCEPTION); 1.1946 + return; 1.1947 + } 1.1948 + 1.1949 + mWithCredentials = aWithCredentials; 1.1950 + 1.1951 + if (!mProxy) { 1.1952 + // Open may not have been called yet, in which case we'll handle the 1.1953 + // credentials in OpenRunnable. 1.1954 + return; 1.1955 + } 1.1956 + 1.1957 + nsRefPtr<SetWithCredentialsRunnable> runnable = 1.1958 + new SetWithCredentialsRunnable(mWorkerPrivate, mProxy, aWithCredentials); 1.1959 + if (!runnable->Dispatch(mWorkerPrivate->GetJSContext())) { 1.1960 + aRv.Throw(NS_ERROR_FAILURE); 1.1961 + return; 1.1962 + } 1.1963 +} 1.1964 + 1.1965 +void 1.1966 +XMLHttpRequest::SetMozBackgroundRequest(bool aBackgroundRequest, 1.1967 + ErrorResult& aRv) 1.1968 +{ 1.1969 + mWorkerPrivate->AssertIsOnWorkerThread(); 1.1970 + 1.1971 + if (mCanceled) { 1.1972 + aRv.Throw(UNCATCHABLE_EXCEPTION); 1.1973 + return; 1.1974 + } 1.1975 + 1.1976 + mBackgroundRequest = aBackgroundRequest; 1.1977 + 1.1978 + if (!mProxy) { 1.1979 + // Open may not have been called yet, in which case we'll handle the 1.1980 + // background request in OpenRunnable. 1.1981 + return; 1.1982 + } 1.1983 + 1.1984 + nsRefPtr<SetBackgroundRequestRunnable> runnable = 1.1985 + new SetBackgroundRequestRunnable(mWorkerPrivate, mProxy, 1.1986 + aBackgroundRequest); 1.1987 + if (!runnable->Dispatch(mWorkerPrivate->GetJSContext())) { 1.1988 + aRv.Throw(NS_ERROR_FAILURE); 1.1989 + return; 1.1990 + } 1.1991 +} 1.1992 + 1.1993 +XMLHttpRequestUpload* 1.1994 +XMLHttpRequest::GetUpload(ErrorResult& aRv) 1.1995 +{ 1.1996 + mWorkerPrivate->AssertIsOnWorkerThread(); 1.1997 + 1.1998 + if (mCanceled) { 1.1999 + aRv.Throw(UNCATCHABLE_EXCEPTION); 1.2000 + return nullptr; 1.2001 + } 1.2002 + 1.2003 + if (!mUpload) { 1.2004 + mUpload = XMLHttpRequestUpload::Create(this); 1.2005 + 1.2006 + if (!mUpload) { 1.2007 + aRv.Throw(NS_ERROR_FAILURE); 1.2008 + return nullptr; 1.2009 + } 1.2010 + } 1.2011 + 1.2012 + return mUpload; 1.2013 +} 1.2014 + 1.2015 +void 1.2016 +XMLHttpRequest::Send(ErrorResult& aRv) 1.2017 +{ 1.2018 + mWorkerPrivate->AssertIsOnWorkerThread(); 1.2019 + 1.2020 + if (mCanceled) { 1.2021 + aRv.Throw(UNCATCHABLE_EXCEPTION); 1.2022 + return; 1.2023 + } 1.2024 + 1.2025 + if (!mProxy) { 1.2026 + aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR); 1.2027 + return; 1.2028 + } 1.2029 + 1.2030 + // Nothing to clone. 1.2031 + JSAutoStructuredCloneBuffer buffer; 1.2032 + nsTArray<nsCOMPtr<nsISupports> > clonedObjects; 1.2033 + 1.2034 + SendInternal(NullString(), Move(buffer), clonedObjects, aRv); 1.2035 +} 1.2036 + 1.2037 +void 1.2038 +XMLHttpRequest::Send(const nsAString& aBody, ErrorResult& aRv) 1.2039 +{ 1.2040 + mWorkerPrivate->AssertIsOnWorkerThread(); 1.2041 + 1.2042 + if (mCanceled) { 1.2043 + aRv.Throw(UNCATCHABLE_EXCEPTION); 1.2044 + return; 1.2045 + } 1.2046 + 1.2047 + if (!mProxy) { 1.2048 + aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR); 1.2049 + return; 1.2050 + } 1.2051 + 1.2052 + // Nothing to clone. 1.2053 + JSAutoStructuredCloneBuffer buffer; 1.2054 + nsTArray<nsCOMPtr<nsISupports> > clonedObjects; 1.2055 + 1.2056 + SendInternal(aBody, Move(buffer), clonedObjects, aRv); 1.2057 +} 1.2058 + 1.2059 +void 1.2060 +XMLHttpRequest::Send(JS::Handle<JSObject*> aBody, ErrorResult& aRv) 1.2061 +{ 1.2062 + JSContext* cx = mWorkerPrivate->GetJSContext(); 1.2063 + 1.2064 + MOZ_ASSERT(aBody); 1.2065 + 1.2066 + mWorkerPrivate->AssertIsOnWorkerThread(); 1.2067 + 1.2068 + if (mCanceled) { 1.2069 + aRv.Throw(UNCATCHABLE_EXCEPTION); 1.2070 + return; 1.2071 + } 1.2072 + 1.2073 + if (!mProxy) { 1.2074 + aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR); 1.2075 + return; 1.2076 + } 1.2077 + 1.2078 + JS::Rooted<JS::Value> valToClone(cx); 1.2079 + if (JS_IsArrayBufferObject(aBody) || JS_IsArrayBufferViewObject(aBody) || 1.2080 + file::GetDOMBlobFromJSObject(aBody)) { 1.2081 + valToClone.setObject(*aBody); 1.2082 + } 1.2083 + else { 1.2084 + JS::Rooted<JS::Value> obj(cx, JS::ObjectValue(*aBody)); 1.2085 + JSString* bodyStr = JS::ToString(cx, obj); 1.2086 + if (!bodyStr) { 1.2087 + aRv.Throw(NS_ERROR_OUT_OF_MEMORY); 1.2088 + return; 1.2089 + } 1.2090 + valToClone.setString(bodyStr); 1.2091 + } 1.2092 + 1.2093 + JSStructuredCloneCallbacks* callbacks = 1.2094 + mWorkerPrivate->IsChromeWorker() ? 1.2095 + ChromeWorkerStructuredCloneCallbacks(false) : 1.2096 + WorkerStructuredCloneCallbacks(false); 1.2097 + 1.2098 + nsTArray<nsCOMPtr<nsISupports> > clonedObjects; 1.2099 + 1.2100 + JSAutoStructuredCloneBuffer buffer; 1.2101 + if (!buffer.write(cx, valToClone, callbacks, &clonedObjects)) { 1.2102 + aRv.Throw(NS_ERROR_DOM_DATA_CLONE_ERR); 1.2103 + return; 1.2104 + } 1.2105 + 1.2106 + SendInternal(EmptyString(), Move(buffer), clonedObjects, aRv); 1.2107 +} 1.2108 + 1.2109 +void 1.2110 +XMLHttpRequest::Send(const ArrayBuffer& aBody, ErrorResult& aRv) 1.2111 +{ 1.2112 + JS::Rooted<JSObject*> obj(mWorkerPrivate->GetJSContext(), aBody.Obj()); 1.2113 + return Send(obj, aRv); 1.2114 +} 1.2115 + 1.2116 +void 1.2117 +XMLHttpRequest::Send(const ArrayBufferView& aBody, ErrorResult& aRv) 1.2118 +{ 1.2119 + JS::Rooted<JSObject*> obj(mWorkerPrivate->GetJSContext(), aBody.Obj()); 1.2120 + return Send(obj, aRv); 1.2121 +} 1.2122 + 1.2123 +void 1.2124 +XMLHttpRequest::SendAsBinary(const nsAString& aBody, ErrorResult& aRv) 1.2125 +{ 1.2126 + NS_NOTYETIMPLEMENTED("Implement me!"); 1.2127 + aRv.Throw(NS_ERROR_NOT_IMPLEMENTED); 1.2128 + return; 1.2129 +} 1.2130 + 1.2131 +void 1.2132 +XMLHttpRequest::Abort(ErrorResult& aRv) 1.2133 +{ 1.2134 + mWorkerPrivate->AssertIsOnWorkerThread(); 1.2135 + 1.2136 + if (mCanceled) { 1.2137 + aRv.Throw(UNCATCHABLE_EXCEPTION); 1.2138 + } 1.2139 + 1.2140 + if (!mProxy) { 1.2141 + return; 1.2142 + } 1.2143 + 1.2144 + MaybeDispatchPrematureAbortEvents(aRv); 1.2145 + if (aRv.Failed()) { 1.2146 + return; 1.2147 + } 1.2148 + 1.2149 + mProxy->mOuterEventStreamId++; 1.2150 + 1.2151 + nsRefPtr<AbortRunnable> runnable = new AbortRunnable(mWorkerPrivate, mProxy); 1.2152 + if (!runnable->Dispatch(mWorkerPrivate->GetJSContext())) { 1.2153 + aRv.Throw(NS_ERROR_FAILURE); 1.2154 + return; 1.2155 + } 1.2156 +} 1.2157 + 1.2158 +void 1.2159 +XMLHttpRequest::GetResponseHeader(const nsACString& aHeader, 1.2160 + nsACString& aResponseHeader, ErrorResult& aRv) 1.2161 +{ 1.2162 + mWorkerPrivate->AssertIsOnWorkerThread(); 1.2163 + 1.2164 + if (mCanceled) { 1.2165 + aRv.Throw(UNCATCHABLE_EXCEPTION); 1.2166 + return; 1.2167 + } 1.2168 + 1.2169 + if (!mProxy) { 1.2170 + aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR); 1.2171 + return; 1.2172 + } 1.2173 + 1.2174 + nsCString responseHeader; 1.2175 + nsRefPtr<GetResponseHeaderRunnable> runnable = 1.2176 + new GetResponseHeaderRunnable(mWorkerPrivate, mProxy, aHeader, 1.2177 + responseHeader); 1.2178 + if (!runnable->Dispatch(mWorkerPrivate->GetJSContext())) { 1.2179 + aRv.Throw(NS_ERROR_FAILURE); 1.2180 + return; 1.2181 + } 1.2182 + aResponseHeader = responseHeader; 1.2183 +} 1.2184 + 1.2185 +void 1.2186 +XMLHttpRequest::GetAllResponseHeaders(nsACString& aResponseHeaders, 1.2187 + ErrorResult& aRv) 1.2188 +{ 1.2189 + mWorkerPrivate->AssertIsOnWorkerThread(); 1.2190 + 1.2191 + if (mCanceled) { 1.2192 + aRv.Throw(UNCATCHABLE_EXCEPTION); 1.2193 + return; 1.2194 + } 1.2195 + 1.2196 + if (!mProxy) { 1.2197 + aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR); 1.2198 + return; 1.2199 + } 1.2200 + 1.2201 + nsCString responseHeaders; 1.2202 + nsRefPtr<GetAllResponseHeadersRunnable> runnable = 1.2203 + new GetAllResponseHeadersRunnable(mWorkerPrivate, mProxy, responseHeaders); 1.2204 + if (!runnable->Dispatch(mWorkerPrivate->GetJSContext())) { 1.2205 + aRv.Throw(NS_ERROR_FAILURE); 1.2206 + return; 1.2207 + } 1.2208 + 1.2209 + aResponseHeaders = responseHeaders; 1.2210 +} 1.2211 + 1.2212 +void 1.2213 +XMLHttpRequest::OverrideMimeType(const nsAString& aMimeType, ErrorResult& aRv) 1.2214 +{ 1.2215 + mWorkerPrivate->AssertIsOnWorkerThread(); 1.2216 + 1.2217 + if (mCanceled) { 1.2218 + aRv.Throw(UNCATCHABLE_EXCEPTION); 1.2219 + return; 1.2220 + } 1.2221 + 1.2222 + // We're supposed to throw if the state is not OPENED or HEADERS_RECEIVED. We 1.2223 + // can detect OPENED really easily but we can't detect HEADERS_RECEIVED in a 1.2224 + // non-racy way until the XHR state machine actually runs on this thread 1.2225 + // (bug 671047). For now we're going to let this work only if the Send() 1.2226 + // method has not been called. 1.2227 + if (!mProxy || SendInProgress()) { 1.2228 + aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR); 1.2229 + return; 1.2230 + } 1.2231 + 1.2232 + nsRefPtr<OverrideMimeTypeRunnable> runnable = 1.2233 + new OverrideMimeTypeRunnable(mWorkerPrivate, mProxy, aMimeType); 1.2234 + if (!runnable->Dispatch(mWorkerPrivate->GetJSContext())) { 1.2235 + aRv.Throw(NS_ERROR_FAILURE); 1.2236 + return; 1.2237 + } 1.2238 +} 1.2239 + 1.2240 +void 1.2241 +XMLHttpRequest::SetResponseType(XMLHttpRequestResponseType aResponseType, 1.2242 + ErrorResult& aRv) 1.2243 +{ 1.2244 + mWorkerPrivate->AssertIsOnWorkerThread(); 1.2245 + 1.2246 + if (mCanceled) { 1.2247 + aRv.Throw(UNCATCHABLE_EXCEPTION); 1.2248 + return; 1.2249 + } 1.2250 + 1.2251 + if (!mProxy || SendInProgress()) { 1.2252 + aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR); 1.2253 + return; 1.2254 + } 1.2255 + 1.2256 + // "document" is fine for the main thread but not for a worker. Short-circuit 1.2257 + // that here. 1.2258 + if (aResponseType == XMLHttpRequestResponseType::Document) { 1.2259 + return; 1.2260 + } 1.2261 + 1.2262 + nsString responseType; 1.2263 + ConvertResponseTypeToString(aResponseType, responseType); 1.2264 + 1.2265 + nsRefPtr<SetResponseTypeRunnable> runnable = 1.2266 + new SetResponseTypeRunnable(mWorkerPrivate, mProxy, responseType); 1.2267 + if (!runnable->Dispatch(mWorkerPrivate->GetJSContext())) { 1.2268 + aRv.Throw(NS_ERROR_FAILURE); 1.2269 + return; 1.2270 + } 1.2271 + 1.2272 + nsString acceptedResponseTypeString; 1.2273 + runnable->GetResponseType(acceptedResponseTypeString); 1.2274 + 1.2275 + mResponseType = ConvertStringToResponseType(acceptedResponseTypeString); 1.2276 +} 1.2277 + 1.2278 +void 1.2279 +XMLHttpRequest::GetResponse(JSContext* /* unused */, 1.2280 + JS::MutableHandle<JS::Value> aResponse, 1.2281 + ErrorResult& aRv) 1.2282 +{ 1.2283 + if (NS_SUCCEEDED(mStateData.mResponseTextResult) && 1.2284 + JSVAL_IS_VOID(mStateData.mResponse)) { 1.2285 + MOZ_ASSERT(mStateData.mResponseText.Length()); 1.2286 + MOZ_ASSERT(NS_SUCCEEDED(mStateData.mResponseResult)); 1.2287 + 1.2288 + JSString* str = 1.2289 + JS_NewUCStringCopyN(mWorkerPrivate->GetJSContext(), 1.2290 + mStateData.mResponseText.get(), 1.2291 + mStateData.mResponseText.Length()); 1.2292 + if (!str) { 1.2293 + aRv.Throw(NS_ERROR_OUT_OF_MEMORY); 1.2294 + return; 1.2295 + } 1.2296 + 1.2297 + mStateData.mResponse = STRING_TO_JSVAL(str); 1.2298 + } 1.2299 + 1.2300 + JS::ExposeValueToActiveJS(mStateData.mResponse); 1.2301 + aRv = mStateData.mResponseResult; 1.2302 + aResponse.set(mStateData.mResponse); 1.2303 +} 1.2304 + 1.2305 +void 1.2306 +XMLHttpRequest::GetResponseText(nsAString& aResponseText, ErrorResult& aRv) 1.2307 +{ 1.2308 + aRv = mStateData.mResponseTextResult; 1.2309 + aResponseText = mStateData.mResponseText; 1.2310 +} 1.2311 + 1.2312 +void 1.2313 +XMLHttpRequest::UpdateState(const StateData& aStateData) 1.2314 +{ 1.2315 + mStateData = aStateData; 1.2316 +}