dom/workers/XMLHttpRequest.cpp
author Carsten "Tomcat" Book <cbook@mozilla.com>
Fri, 09 May 2014 14:13:29 +0200
changeset 182330 420f4c65a67f
parent 182301 db13bb9473cc
child 183841 7ce943352e8e
permissions -rw-r--r--
merge b2g-inbound to mozilla-central
bent@72705
     1
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
peterv@90770
     2
/* This Source Code Form is subject to the terms of the Mozilla Public
peterv@90770
     3
 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
peterv@90770
     4
 * You can obtain one at http://mozilla.org/MPL/2.0/. */
bent@72705
     5
bent@72705
     6
#include "XMLHttpRequest.h"
bent@72705
     7
peterv@90770
     8
#include "nsIDOMEvent.h"
peterv@90770
     9
#include "nsIDOMEventListener.h"
peterv@90770
    10
#include "nsIDOMProgressEvent.h"
peterv@90770
    11
#include "nsIRunnable.h"
peterv@90770
    12
#include "nsIVariant.h"
peterv@90770
    13
#include "nsIXMLHttpRequest.h"
peterv@90770
    14
#include "nsIXPConnect.h"
bent@72705
    15
evilpies>@92092
    16
#include "jsfriendapi.h"
bent@160748
    17
#include "mozilla/ArrayUtils.h"
bent@160748
    18
#include "mozilla/dom/Exceptions.h"
bent@160748
    19
#include "nsComponentManagerUtils.h"
peterv@90770
    20
#include "nsContentUtils.h"
bobbyholley@132658
    21
#include "nsCxPusher.h"
peterv@90770
    22
#include "nsJSUtils.h"
peterv@90770
    23
#include "nsThreadUtils.h"
peterv@90770
    24
peterv@90770
    25
#include "File.h"
peterv@90770
    26
#include "RuntimeService.h"
bent@72705
    27
#include "WorkerPrivate.h"
bent@160748
    28
#include "WorkerRunnable.h"
peterv@90770
    29
#include "XMLHttpRequestUpload.h"
bent@72705
    30
ms2ger@107474
    31
using namespace mozilla;
ms2ger@107474
    32
mjoras@113318
    33
using namespace mozilla::dom;
bent@72705
    34
USING_WORKERS_NAMESPACE
bent@72705
    35
peterv@90770
    36
// XXX Need to figure this out...
peterv@90770
    37
#define UNCATCHABLE_EXCEPTION NS_ERROR_OUT_OF_MEMORY
peterv@90770
    38
peterv@90770
    39
/**
peterv@90770
    40
 *  XMLHttpRequest in workers
peterv@90770
    41
 *
peterv@90770
    42
 *  XHR in workers is implemented by proxying calls/events/etc between the
peterv@90770
    43
 *  worker thread and an nsXMLHttpRequest on the main thread.  The glue
peterv@90770
    44
 *  object here is the Proxy, which lives on both threads.  All other objects
peterv@90770
    45
 *  live on either the main thread (the nsXMLHttpRequest) or the worker thread
peterv@90770
    46
 *  (the worker and XHR private objects).
peterv@90770
    47
 *
peterv@90770
    48
 *  The main thread XHR is always operated in async mode, even for sync XHR
peterv@90770
    49
 *  in workers.  Calls made on the worker thread are proxied to the main thread
peterv@90770
    50
 *  synchronously (meaning the worker thread is blocked until the call
peterv@90770
    51
 *  returns).  Each proxied call spins up a sync queue, which captures any
peterv@90770
    52
 *  synchronously dispatched events and ensures that they run synchronously
peterv@90770
    53
 *  on the worker as well.  Asynchronously dispatched events are posted to the
peterv@90770
    54
 *  worker thread to run asynchronously.  Some of the XHR state is mirrored on
peterv@90770
    55
 *  the worker thread to avoid needing a cross-thread call on every property
peterv@90770
    56
 *  access.
peterv@90770
    57
 *
peterv@90770
    58
 *  The XHR private is stored in the private slot of the XHR JSObject on the
peterv@90770
    59
 *  worker thread.  It is destroyed when that JSObject is GCd.  The private
peterv@90770
    60
 *  roots its JSObject while network activity is in progress.  It also
peterv@90770
    61
 *  adds itself as a feature to the worker to give itself a chance to clean up
peterv@90770
    62
 *  if the worker goes away during an XHR call.  It is important that the
peterv@90770
    63
 *  rooting and feature registration (collectively called pinning) happens at
peterv@90770
    64
 *  the proper times.  If we pin for too long we can cause memory leaks or even
peterv@90770
    65
 *  shutdown hangs.  If we don't pin for long enough we introduce a GC hazard.
peterv@90770
    66
 *
peterv@90770
    67
 *  The XHR is pinned from the time Send is called to roughly the time loadend
peterv@90770
    68
 *  is received.  There are some complications involved with Abort and XHR
peterv@90770
    69
 *  reuse.  We maintain a counter on the main thread of how many times Send was
peterv@90770
    70
 *  called on this XHR, and we decrement the counter every time we receive a
peterv@90770
    71
 *  loadend event.  When the counter reaches zero we dispatch a runnable to the
peterv@90770
    72
 *  worker thread to unpin the XHR.  We only decrement the counter if the 
peterv@90770
    73
 *  dispatch was successful, because the worker may no longer be accepting
peterv@90770
    74
 *  regular runnables.  In the event that we reach Proxy::Teardown and there
peterv@90770
    75
 *  the outstanding Send count is still non-zero, we dispatch a control
peterv@90770
    76
 *  runnable which is guaranteed to run.
peterv@90770
    77
 *
peterv@90770
    78
 *  NB: Some of this could probably be simplified now that we have the
peterv@90770
    79
 *  inner/outer channel ids.
peterv@90770
    80
 */
peterv@90770
    81
peterv@90770
    82
BEGIN_WORKERS_NAMESPACE
peterv@90770
    83
ehsan@96936
    84
class Proxy MOZ_FINAL : public nsIDOMEventListener
bent@72705
    85
{
peterv@90770
    86
public:
peterv@90770
    87
  // Read on multiple threads.
peterv@90770
    88
  WorkerPrivate* mWorkerPrivate;
peterv@90770
    89
  XMLHttpRequest* mXMLHttpRequestPrivate;
bent@72705
    90
amarchesini@107196
    91
  // XHR Params:
amarchesini@107196
    92
  bool mMozAnon;
amarchesini@107196
    93
  bool mMozSystem;
amarchesini@107196
    94
peterv@90770
    95
  // Only touched on the main thread.
peterv@90770
    96
  nsRefPtr<nsXMLHttpRequest> mXHR;
peterv@90770
    97
  nsCOMPtr<nsIXMLHttpRequestUpload> mXHRUpload;
bent@160748
    98
  nsCOMPtr<nsIEventTarget> mSyncLoopTarget;
bent@160748
    99
  nsCOMPtr<nsIEventTarget> mSyncEventResponseTarget;
ehsan@102997
   100
  uint32_t mInnerEventStreamId;
ehsan@102997
   101
  uint32_t mInnerChannelId;
ehsan@102997
   102
  uint32_t mOutstandingSendCount;
bent@72705
   103
peterv@90770
   104
  // Only touched on the worker thread.
ehsan@102997
   105
  uint32_t mOuterEventStreamId;
ehsan@102997
   106
  uint32_t mOuterChannelId;
ehsan@102997
   107
  uint64_t mLastLoaded;
ehsan@102997
   108
  uint64_t mLastTotal;
ehsan@102997
   109
  uint64_t mLastUploadLoaded;
ehsan@102997
   110
  uint64_t mLastUploadTotal;
peterv@90770
   111
  bool mIsSyncXHR;
peterv@90770
   112
  bool mLastLengthComputable;
peterv@90770
   113
  bool mLastUploadLengthComputable;
peterv@90770
   114
  bool mSeenLoadStart;
peterv@90770
   115
  bool mSeenUploadLoadStart;
bent@72705
   116
peterv@90770
   117
  // Only touched on the main thread.
peterv@90770
   118
  bool mUploadEventListenersAttached;
peterv@90770
   119
  bool mMainThreadSeenLoadStart;
peterv@90770
   120
  bool mInOpen;
bent@79735
   121
bent@72705
   122
public:
amarchesini@107196
   123
  Proxy(XMLHttpRequest* aXHRPrivate, bool aMozAnon, bool aMozSystem)
ayg@100844
   124
  : mWorkerPrivate(nullptr), mXMLHttpRequestPrivate(aXHRPrivate),
amarchesini@107196
   125
    mMozAnon(aMozAnon), mMozSystem(aMozSystem),
peterv@90770
   126
    mInnerEventStreamId(0), mInnerChannelId(0), mOutstandingSendCount(0),
peterv@90770
   127
    mOuterEventStreamId(0), mOuterChannelId(0), mLastLoaded(0), mLastTotal(0),
peterv@90770
   128
    mLastUploadLoaded(0), mLastUploadTotal(0), mIsSyncXHR(false),
peterv@90770
   129
    mLastLengthComputable(false), mLastUploadLengthComputable(false),
peterv@90770
   130
    mSeenLoadStart(false), mSeenUploadLoadStart(false),
peterv@90770
   131
    mUploadEventListenersAttached(false), mMainThreadSeenLoadStart(false),
peterv@90770
   132
    mInOpen(false)
peterv@90770
   133
  { }
peterv@90770
   134
bent@160748
   135
  NS_DECL_THREADSAFE_ISUPPORTS
bent@160748
   136
  NS_DECL_NSIDOMEVENTLISTENER
bent@72705
   137
peterv@90770
   138
  bool
bent@160748
   139
  Init();
bent@72705
   140
peterv@90770
   141
  void
peterv@90770
   142
  Teardown();
bent@72705
   143
peterv@90770
   144
  bool
peterv@90770
   145
  AddRemoveEventListeners(bool aUpload, bool aAdd);
peterv@90770
   146
peterv@90770
   147
  void
peterv@90770
   148
  Reset()
bent@72705
   149
  {
peterv@90770
   150
    AssertIsOnMainThread();
peterv@90770
   151
peterv@90770
   152
    if (mUploadEventListenersAttached) {
peterv@90770
   153
      AddRemoveEventListeners(true, false);
bent@72705
   154
    }
bent@72705
   155
  }
bent@72705
   156
bent@160748
   157
  already_AddRefed<nsIEventTarget>
bent@160748
   158
  GetEventTarget()
peterv@90770
   159
  {
peterv@90770
   160
    AssertIsOnMainThread();
peterv@90770
   161
bent@160748
   162
    nsCOMPtr<nsIEventTarget> target = mSyncEventResponseTarget ?
bent@160748
   163
                                      mSyncEventResponseTarget :
bent@160748
   164
                                      mSyncLoopTarget;
bent@160748
   165
    return target.forget();
bent@160748
   166
  }
bent@160748
   167
bent@160748
   168
private:
bent@160748
   169
  ~Proxy()
bent@160748
   170
  {
bent@160748
   171
    MOZ_ASSERT(!mXHR);
bent@160748
   172
    MOZ_ASSERT(!mXHRUpload);
bent@160748
   173
    MOZ_ASSERT(!mOutstandingSendCount);
peterv@90770
   174
  }
peterv@90770
   175
};
peterv@90770
   176
peterv@90770
   177
END_WORKERS_NAMESPACE
peterv@90770
   178
peterv@90770
   179
namespace {
peterv@90770
   180
peterv@90770
   181
inline void
bzbarsky@92914
   182
ConvertResponseTypeToString(XMLHttpRequestResponseType aType,
bzbarsky@92914
   183
                            nsString& aString)
peterv@90770
   184
{
peterv@90770
   185
  using namespace
bzbarsky@92914
   186
    mozilla::dom::XMLHttpRequestResponseTypeValues;
peterv@90770
   187
peterv@90770
   188
  size_t index = static_cast<size_t>(aType);
peterv@90770
   189
  MOZ_ASSERT(index < ArrayLength(strings), "Codegen gave us a bad value!");
peterv@90770
   190
peterv@90770
   191
  aString.AssignASCII(strings[index].value, strings[index].length);
peterv@90770
   192
}
peterv@90770
   193
peterv@90770
   194
inline XMLHttpRequestResponseType
peterv@90770
   195
ConvertStringToResponseType(const nsAString& aString)
peterv@90770
   196
{
peterv@90770
   197
  using namespace
bzbarsky@92914
   198
    mozilla::dom::XMLHttpRequestResponseTypeValues;
peterv@90770
   199
peterv@90770
   200
  for (size_t index = 0; index < ArrayLength(strings) - 1; index++) {
peterv@90770
   201
    if (aString.EqualsASCII(strings[index].value, strings[index].length)) {
peterv@90770
   202
      return static_cast<XMLHttpRequestResponseType>(index);
peterv@90770
   203
    }
peterv@90770
   204
  }
peterv@90770
   205
cpeterson@182301
   206
  MOZ_CRASH("Don't know anything about this response type!");
peterv@90770
   207
}
peterv@90770
   208
peterv@90770
   209
enum
peterv@90770
   210
{
peterv@90770
   211
  STRING_abort = 0,
peterv@90770
   212
  STRING_error,
peterv@90770
   213
  STRING_load,
peterv@90770
   214
  STRING_loadstart,
peterv@90770
   215
  STRING_progress,
peterv@90770
   216
  STRING_timeout,
peterv@90770
   217
  STRING_readystatechange,
peterv@90770
   218
  STRING_loadend,
peterv@90770
   219
peterv@90770
   220
  STRING_COUNT,
peterv@90770
   221
peterv@90770
   222
  STRING_LAST_XHR = STRING_loadend,
peterv@90770
   223
  STRING_LAST_EVENTTARGET = STRING_timeout
peterv@90770
   224
};
peterv@90770
   225
bent@160748
   226
static_assert(STRING_LAST_XHR >= STRING_LAST_EVENTTARGET, "Bad string setup!");
bent@160748
   227
static_assert(STRING_LAST_XHR == STRING_COUNT - 1, "Bad string setup!");
peterv@90770
   228
peterv@90770
   229
const char* const sEventStrings[] = {
peterv@90770
   230
  // nsIXMLHttpRequestEventTarget event types, supported by both XHR and Upload.
peterv@90770
   231
  "abort",
peterv@90770
   232
  "error",
peterv@90770
   233
  "load",
peterv@90770
   234
  "loadstart",
peterv@90770
   235
  "progress",
peterv@90770
   236
  "timeout",
peterv@90770
   237
peterv@90770
   238
  // nsIXMLHttpRequest event types, supported only by XHR.
peterv@90770
   239
  "readystatechange",
peterv@90770
   240
  "loadend",
peterv@90770
   241
};
peterv@90770
   242
bent@160748
   243
static_assert(MOZ_ARRAY_LENGTH(sEventStrings) == STRING_COUNT,
bent@160748
   244
              "Bad string count!");
peterv@90770
   245
bent@160748
   246
class MainThreadProxyRunnable : public MainThreadWorkerSyncRunnable
peterv@90770
   247
{
peterv@90770
   248
protected:
peterv@90770
   249
  nsRefPtr<Proxy> mProxy;
peterv@90770
   250
bent@160748
   251
  MainThreadProxyRunnable(WorkerPrivate* aWorkerPrivate, Proxy* aProxy)
bent@160748
   252
  : MainThreadWorkerSyncRunnable(aWorkerPrivate, aProxy->GetEventTarget()),
peterv@90770
   253
    mProxy(aProxy)
bent@160748
   254
  {
bent@160748
   255
    MOZ_ASSERT(aProxy);
bent@160748
   256
  }
bent@160748
   257
bent@160748
   258
  virtual ~MainThreadProxyRunnable()
peterv@90770
   259
  { }
peterv@90770
   260
};
peterv@90770
   261
bent@160748
   262
class XHRUnpinRunnable MOZ_FINAL : public MainThreadWorkerControlRunnable
peterv@90770
   263
{
peterv@90770
   264
  XMLHttpRequest* mXMLHttpRequestPrivate;
peterv@90770
   265
peterv@90770
   266
public:
peterv@90770
   267
  XHRUnpinRunnable(WorkerPrivate* aWorkerPrivate,
peterv@90770
   268
                   XMLHttpRequest* aXHRPrivate)
bent@160748
   269
  : MainThreadWorkerControlRunnable(aWorkerPrivate),
peterv@90770
   270
    mXMLHttpRequestPrivate(aXHRPrivate)
peterv@90770
   271
  {
bent@160748
   272
    MOZ_ASSERT(aXHRPrivate);
peterv@90770
   273
  }
peterv@90770
   274
bent@160748
   275
private:
bent@160748
   276
  ~XHRUnpinRunnable()
bent@160748
   277
  { }
peterv@90770
   278
peterv@90770
   279
  bool
peterv@90770
   280
  WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
peterv@90770
   281
  {
peterv@90770
   282
    mXMLHttpRequestPrivate->Unpin();
peterv@90770
   283
peterv@90770
   284
    return true;
peterv@90770
   285
  }
peterv@90770
   286
};
peterv@90770
   287
bent@160748
   288
class AsyncTeardownRunnable MOZ_FINAL : public nsRunnable
peterv@90770
   289
{
peterv@90770
   290
  nsRefPtr<Proxy> mProxy;
peterv@90770
   291
peterv@90770
   292
public:
peterv@90770
   293
  AsyncTeardownRunnable(Proxy* aProxy)
bent@160748
   294
  : mProxy(aProxy)
peterv@90770
   295
  {
bent@160748
   296
    MOZ_ASSERT(aProxy);
peterv@90770
   297
  }
peterv@90770
   298
bent@160748
   299
  NS_DECL_ISUPPORTS_INHERITED
bent@160748
   300
bent@160748
   301
private:
bent@160748
   302
  ~AsyncTeardownRunnable()
bent@160748
   303
  { }
bent@160748
   304
bent@160748
   305
  NS_IMETHOD
bent@160748
   306
  Run() MOZ_OVERRIDE
peterv@90770
   307
  {
peterv@90770
   308
    AssertIsOnMainThread();
peterv@90770
   309
peterv@90770
   310
    mProxy->Teardown();
ayg@100844
   311
    mProxy = nullptr;
peterv@90770
   312
peterv@90770
   313
    return NS_OK;
peterv@90770
   314
  }
peterv@90770
   315
};
peterv@90770
   316
bent@160748
   317
class LoadStartDetectionRunnable MOZ_FINAL : public nsRunnable,
ehsan@96936
   318
                                             public nsIDOMEventListener
peterv@90770
   319
{
peterv@90770
   320
  WorkerPrivate* mWorkerPrivate;
peterv@90770
   321
  nsRefPtr<Proxy> mProxy;
peterv@90770
   322
  nsRefPtr<nsXMLHttpRequest> mXHR;
peterv@90770
   323
  XMLHttpRequest* mXMLHttpRequestPrivate;
peterv@90770
   324
  nsString mEventType;
bent@160748
   325
  uint32_t mChannelId;
peterv@90770
   326
  bool mReceivedLoadStart;
peterv@90770
   327
bent@160748
   328
  class ProxyCompleteRunnable MOZ_FINAL : public MainThreadProxyRunnable
peterv@90770
   329
  {
peterv@90770
   330
    XMLHttpRequest* mXMLHttpRequestPrivate;
ehsan@102997
   331
    uint32_t mChannelId;
peterv@90770
   332
peterv@90770
   333
  public:
peterv@90770
   334
    ProxyCompleteRunnable(WorkerPrivate* aWorkerPrivate, Proxy* aProxy,
ehsan@102997
   335
                          XMLHttpRequest* aXHRPrivate, uint32_t aChannelId)
bent@160748
   336
    : MainThreadProxyRunnable(aWorkerPrivate, aProxy),
peterv@90770
   337
      mXMLHttpRequestPrivate(aXHRPrivate), mChannelId(aChannelId)
peterv@90770
   338
    { }
peterv@90770
   339
bent@160748
   340
  private:
bent@160748
   341
    ~ProxyCompleteRunnable()
bent@160748
   342
    { }
bent@72705
   343
bent@160748
   344
    virtual bool
bent@160748
   345
    WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) MOZ_OVERRIDE
peterv@90770
   346
    {
peterv@90770
   347
      if (mChannelId != mProxy->mOuterChannelId) {
peterv@90770
   348
        // Threads raced, this event is now obsolete.
peterv@90770
   349
        return true;
peterv@90770
   350
      }
peterv@90770
   351
bent@160748
   352
      if (mSyncLoopTarget) {
bent@160748
   353
        aWorkerPrivate->StopSyncLoop(mSyncLoopTarget, true);
peterv@90770
   354
      }
peterv@90770
   355
peterv@90770
   356
      mXMLHttpRequestPrivate->Unpin();
peterv@90770
   357
peterv@90770
   358
      return true;
peterv@90770
   359
    }
bent@160748
   360
bent@160748
   361
    NS_IMETHOD
bent@160748
   362
    Cancel() MOZ_OVERRIDE
bent@160748
   363
    {
bent@160748
   364
      // This must run!
bent@160748
   365
      nsresult rv = MainThreadProxyRunnable::Cancel();
bent@160748
   366
      nsresult rv2 = Run();
bent@160748
   367
      return NS_FAILED(rv) ? rv : rv2;
bent@160748
   368
    }
peterv@90770
   369
  };
peterv@90770
   370
peterv@90770
   371
public:
peterv@90770
   372
  LoadStartDetectionRunnable(Proxy* aProxy, XMLHttpRequest* aXHRPrivate)
peterv@90770
   373
  : mWorkerPrivate(aProxy->mWorkerPrivate), mProxy(aProxy), mXHR(aProxy->mXHR),
bent@160748
   374
    mXMLHttpRequestPrivate(aXHRPrivate), mChannelId(mProxy->mInnerChannelId),
bent@160748
   375
    mReceivedLoadStart(false)
peterv@90770
   376
  {
peterv@90770
   377
    AssertIsOnMainThread();
peterv@90770
   378
    mEventType.AssignWithConversion(sEventStrings[STRING_loadstart]);
bent@72705
   379
  }
bent@72705
   380
bent@160748
   381
  NS_DECL_ISUPPORTS_INHERITED
bent@160748
   382
  NS_DECL_NSIRUNNABLE
bent@160748
   383
  NS_DECL_NSIDOMEVENTLISTENER
peterv@90770
   384
peterv@90770
   385
  bool
peterv@90770
   386
  RegisterAndDispatch()
peterv@90770
   387
  {
peterv@90770
   388
    AssertIsOnMainThread();
peterv@90770
   389
peterv@90770
   390
    if (NS_FAILED(mXHR->AddEventListener(mEventType, this, false, false, 2))) {
peterv@90770
   391
      NS_WARNING("Failed to add event listener!");
bent@72705
   392
      return false;
bent@72705
   393
    }
bent@72705
   394
peterv@90770
   395
    return NS_SUCCEEDED(NS_DispatchToCurrentThread(this));
peterv@90770
   396
  }
peterv@90770
   397
bent@160748
   398
private:
bent@160748
   399
  ~LoadStartDetectionRunnable()
peterv@90770
   400
  {
peterv@90770
   401
    AssertIsOnMainThread();
peterv@90770
   402
    }
peterv@90770
   403
};
peterv@90770
   404
bent@160748
   405
class EventRunnable MOZ_FINAL : public MainThreadProxyRunnable
peterv@90770
   406
{
peterv@90770
   407
  nsString mType;
peterv@90770
   408
  nsString mResponseType;
peterv@90770
   409
  JSAutoStructuredCloneBuffer mResponseBuffer;
peterv@90770
   410
  nsTArray<nsCOMPtr<nsISupports> > mClonedObjects;
jcoppeard@139582
   411
  JS::Heap<JS::Value> mResponse;
peterv@90770
   412
  nsString mResponseText;
jkitch@134920
   413
  nsCString mStatusText;
ehsan@102997
   414
  uint64_t mLoaded;
ehsan@102997
   415
  uint64_t mTotal;
ehsan@102997
   416
  uint32_t mEventStreamId;
ehsan@102997
   417
  uint32_t mStatus;
ehsan@102997
   418
  uint16_t mReadyState;
peterv@90770
   419
  bool mUploadEvent;
peterv@90770
   420
  bool mProgressEvent;
peterv@90770
   421
  bool mLengthComputable;
peterv@90770
   422
  nsresult mResponseTextResult;
peterv@90770
   423
  nsresult mStatusResult;
peterv@90770
   424
  nsresult mResponseResult;
peterv@90770
   425
peterv@90770
   426
public:
jcoppeard@139582
   427
  class StateDataAutoRooter : private JS::CustomAutoRooter
jcoppeard@139582
   428
  {
bent@160748
   429
    XMLHttpRequest::StateData* mStateData;
bent@160748
   430
    MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
bent@160748
   431
jcoppeard@139582
   432
  public:
jcoppeard@139582
   433
    explicit StateDataAutoRooter(JSContext* aCx, XMLHttpRequest::StateData* aData
jcoppeard@139582
   434
                                 MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
terrence@175880
   435
    : CustomAutoRooter(aCx), mStateData(aData)
jcoppeard@139582
   436
    {
jcoppeard@139582
   437
      MOZ_GUARD_OBJECT_NOTIFIER_INIT;
jcoppeard@139582
   438
    }
jcoppeard@139582
   439
jcoppeard@139582
   440
  private:
jcoppeard@139582
   441
    virtual void trace(JSTracer* aTrc)
jcoppeard@139582
   442
    {
jcoppeard@139582
   443
      JS_CallHeapValueTracer(aTrc, &mStateData->mResponse,
jcoppeard@139582
   444
                             "XMLHttpRequest::StateData::mResponse");
jcoppeard@139582
   445
    }
jcoppeard@139582
   446
  };
jcoppeard@139582
   447
bent@160748
   448
  EventRunnable(Proxy* aProxy, bool aUploadEvent, const nsString& aType,
bent@160748
   449
                bool aLengthComputable, uint64_t aLoaded, uint64_t aTotal)
bent@160748
   450
  : MainThreadProxyRunnable(aProxy->mWorkerPrivate, aProxy), mType(aType),
bent@160748
   451
    mResponse(JSVAL_VOID), mLoaded(aLoaded), mTotal(aTotal),
bent@160748
   452
    mEventStreamId(aProxy->mInnerEventStreamId), mStatus(0), mReadyState(0),
bent@160748
   453
    mUploadEvent(aUploadEvent), mProgressEvent(true),
bent@160748
   454
    mLengthComputable(aLengthComputable), mResponseTextResult(NS_OK),
bent@160748
   455
    mStatusResult(NS_OK), mResponseResult(NS_OK)
bent@160748
   456
  { }
peterv@90770
   457
bent@160748
   458
  EventRunnable(Proxy* aProxy, bool aUploadEvent, const nsString& aType)
bent@160748
   459
  : MainThreadProxyRunnable(aProxy->mWorkerPrivate, aProxy), mType(aType),
bent@160748
   460
    mResponse(JSVAL_VOID), mLoaded(0), mTotal(0),
bent@160748
   461
    mEventStreamId(aProxy->mInnerEventStreamId), mStatus(0), mReadyState(0),
bent@160748
   462
    mUploadEvent(aUploadEvent), mProgressEvent(false), mLengthComputable(0),
bent@160748
   463
    mResponseTextResult(NS_OK), mStatusResult(NS_OK), mResponseResult(NS_OK)
bent@160748
   464
  { }
peterv@90770
   465
bent@160748
   466
private:
bent@160748
   467
  ~EventRunnable()
bent@160748
   468
  { }
peterv@90770
   469
bent@160748
   470
  virtual bool
bent@160748
   471
  PreDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate) MOZ_OVERRIDE;
peterv@90770
   472
bent@160748
   473
  virtual bool
bent@160748
   474
  WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) MOZ_OVERRIDE;
peterv@90770
   475
};
peterv@90770
   476
peterv@90770
   477
class WorkerThreadProxySyncRunnable : public nsRunnable
peterv@90770
   478
{
peterv@90770
   479
protected:
peterv@90770
   480
  WorkerPrivate* mWorkerPrivate;
peterv@90770
   481
  nsRefPtr<Proxy> mProxy;
bent@160748
   482
  nsCOMPtr<nsIEventTarget> mSyncLoopTarget;
peterv@90770
   483
peterv@90770
   484
private:
bent@160748
   485
  class ResponseRunnable MOZ_FINAL: public MainThreadStopSyncLoopRunnable
peterv@90770
   486
  {
bent@160748
   487
    nsRefPtr<Proxy> mProxy;
VYV03354@92429
   488
    nsresult mErrorCode;
peterv@90770
   489
peterv@90770
   490
  public:
peterv@90770
   491
    ResponseRunnable(WorkerPrivate* aWorkerPrivate, Proxy* aProxy,
bent@160748
   492
                     nsresult aErrorCode)
bent@160748
   493
    : MainThreadStopSyncLoopRunnable(aWorkerPrivate, aProxy->GetEventTarget(),
bent@160748
   494
                                     NS_SUCCEEDED(aErrorCode)),
bent@160748
   495
      mProxy(aProxy), mErrorCode(aErrorCode)
peterv@90770
   496
    {
bent@160748
   497
      MOZ_ASSERT(aProxy);
peterv@90770
   498
    }
peterv@90770
   499
bent@160748
   500
  private:
bent@160748
   501
    ~ResponseRunnable()
bent@160748
   502
    { }
bent@160748
   503
bent@160748
   504
    virtual void
bent@160748
   505
    MaybeSetException(JSContext* aCx) MOZ_OVERRIDE
peterv@90770
   506
    {
bent@160748
   507
      MOZ_ASSERT(NS_FAILED(mErrorCode));
bent@160748
   508
khuey@163019
   509
      Throw(aCx, mErrorCode);
khuey@163019
   510
    }
peterv@90770
   511
  };
peterv@90770
   512
peterv@90770
   513
public:
peterv@90770
   514
  WorkerThreadProxySyncRunnable(WorkerPrivate* aWorkerPrivate, Proxy* aProxy)
bent@160748
   515
  : mWorkerPrivate(aWorkerPrivate), mProxy(aProxy)
peterv@90770
   516
  {
bent@160748
   517
    MOZ_ASSERT(aWorkerPrivate);
bent@160748
   518
    MOZ_ASSERT(aProxy);
bent@160748
   519
    aWorkerPrivate->AssertIsOnWorkerThread();
peterv@90770
   520
  }
peterv@90770
   521
bent@160748
   522
  NS_DECL_ISUPPORTS_INHERITED
bent@160748
   523
peterv@90770
   524
  bool
peterv@90770
   525
  Dispatch(JSContext* aCx)
peterv@90770
   526
  {
peterv@90770
   527
    mWorkerPrivate->AssertIsOnWorkerThread();
peterv@90770
   528
khuey@116826
   529
    AutoSyncLoopHolder syncLoop(mWorkerPrivate);
bent@160748
   530
    mSyncLoopTarget = syncLoop.EventTarget();
peterv@90770
   531
peterv@90770
   532
    if (NS_FAILED(NS_DispatchToMainThread(this, NS_DISPATCH_NORMAL))) {
peterv@90770
   533
      JS_ReportError(aCx, "Failed to dispatch to main thread!");
peterv@90770
   534
      return false;
peterv@90770
   535
    }
peterv@90770
   536
bent@160748
   537
    return syncLoop.Run();
bent@72705
   538
  }
bent@72705
   539
bent@160748
   540
protected:
bent@160748
   541
  virtual ~WorkerThreadProxySyncRunnable()
bent@160748
   542
  { }
bent@160748
   543
VYV03354@92429
   544
  virtual nsresult
peterv@90770
   545
  MainThreadRun() = 0;
peterv@90770
   546
bent@160748
   547
private:
bent@160748
   548
  NS_DECL_NSIRUNNABLE
bent@160748
   549
};
bent@160748
   550
bent@160748
   551
class SyncTeardownRunnable MOZ_FINAL : public WorkerThreadProxySyncRunnable
bent@160748
   552
{
bent@160748
   553
public:
bent@160748
   554
  SyncTeardownRunnable(WorkerPrivate* aWorkerPrivate, Proxy* aProxy)
bent@160748
   555
  : WorkerThreadProxySyncRunnable(aWorkerPrivate, aProxy)
bent@160748
   556
  { }
bent@160748
   557
bent@160748
   558
private:
bent@160748
   559
  ~SyncTeardownRunnable()
bent@160748
   560
  { }
bent@160748
   561
bent@160748
   562
  virtual nsresult
bent@160748
   563
  MainThreadRun() MOZ_OVERRIDE
bent@72705
   564
  {
bent@160748
   565
    mProxy->Teardown();
peterv@90770
   566
    return NS_OK;
peterv@90770
   567
  }
peterv@90770
   568
};
peterv@90770
   569
bent@160748
   570
class SetBackgroundRequestRunnable MOZ_FINAL :
bent@160748
   571
  public WorkerThreadProxySyncRunnable
peterv@90770
   572
{
peterv@90770
   573
  bool mValue;
peterv@90770
   574
peterv@90770
   575
public:
peterv@90770
   576
  SetBackgroundRequestRunnable(WorkerPrivate* aWorkerPrivate, Proxy* aProxy,
peterv@90770
   577
                               bool aValue)
peterv@90770
   578
  : WorkerThreadProxySyncRunnable(aWorkerPrivate, aProxy), mValue(aValue)
peterv@90770
   579
  { }
peterv@90770
   580
bent@160748
   581
private:
bent@160748
   582
  ~SetBackgroundRequestRunnable()
bent@160748
   583
  { }
bent@160748
   584
bent@160748
   585
  virtual nsresult
bent@160748
   586
  MainThreadRun() MOZ_OVERRIDE
peterv@90770
   587
  {
VYV03354@92429
   588
    return mProxy->mXHR->SetMozBackgroundRequest(mValue);
peterv@90770
   589
  }
peterv@90770
   590
};
peterv@90770
   591
bent@160748
   592
class SetWithCredentialsRunnable MOZ_FINAL :
bent@160748
   593
  public WorkerThreadProxySyncRunnable
peterv@90770
   594
{
peterv@90770
   595
  bool mValue;
peterv@90770
   596
peterv@90770
   597
public:
peterv@90770
   598
  SetWithCredentialsRunnable(WorkerPrivate* aWorkerPrivate, Proxy* aProxy,
peterv@90770
   599
                             bool aValue)
peterv@90770
   600
  : WorkerThreadProxySyncRunnable(aWorkerPrivate, aProxy), mValue(aValue)
peterv@90770
   601
  { }
peterv@90770
   602
bent@160748
   603
private:
bent@160748
   604
  ~SetWithCredentialsRunnable()
bent@160748
   605
  { }
bent@160748
   606
bent@160748
   607
  virtual nsresult
bent@160748
   608
  MainThreadRun() MOZ_OVERRIDE
peterv@90770
   609
  {
VYV03354@92429
   610
    return mProxy->mXHR->SetWithCredentials(mValue);
peterv@90770
   611
  }
peterv@90770
   612
};
peterv@90770
   613
bent@160748
   614
class SetResponseTypeRunnable MOZ_FINAL : public WorkerThreadProxySyncRunnable
peterv@90770
   615
{
peterv@90770
   616
  nsString mResponseType;
peterv@90770
   617
peterv@90770
   618
public:
peterv@90770
   619
  SetResponseTypeRunnable(WorkerPrivate* aWorkerPrivate, Proxy* aProxy,
peterv@90770
   620
                          const nsAString& aResponseType)
peterv@90770
   621
  : WorkerThreadProxySyncRunnable(aWorkerPrivate, aProxy),
peterv@90770
   622
    mResponseType(aResponseType)
peterv@90770
   623
  { }
peterv@90770
   624
bent@160748
   625
  void
bent@160748
   626
  GetResponseType(nsAString& aResponseType)
bent@160748
   627
  {
bent@160748
   628
    aResponseType.Assign(mResponseType);
bent@160748
   629
  }
bent@160748
   630
bent@160748
   631
private:
bent@160748
   632
  ~SetResponseTypeRunnable()
bent@160748
   633
  { }
bent@160748
   634
bent@160748
   635
  virtual nsresult
bent@160748
   636
  MainThreadRun() MOZ_OVERRIDE
peterv@90770
   637
  {
peterv@90770
   638
    nsresult rv = mProxy->mXHR->SetResponseType(mResponseType);
peterv@90770
   639
    mResponseType.Truncate();
peterv@90770
   640
    if (NS_SUCCEEDED(rv)) {
peterv@90770
   641
      rv = mProxy->mXHR->GetResponseType(mResponseType);
peterv@90770
   642
    }
VYV03354@92429
   643
    return rv;
peterv@90770
   644
  }
peterv@90770
   645
};
peterv@90770
   646
bent@160748
   647
class SetTimeoutRunnable MOZ_FINAL : public WorkerThreadProxySyncRunnable
peterv@90770
   648
{
ehsan@102997
   649
  uint32_t mTimeout;
peterv@90770
   650
peterv@90770
   651
public:
peterv@90770
   652
  SetTimeoutRunnable(WorkerPrivate* aWorkerPrivate, Proxy* aProxy,
ehsan@102997
   653
                     uint32_t aTimeout)
bent@160748
   654
  : WorkerThreadProxySyncRunnable(aWorkerPrivate, aProxy), mTimeout(aTimeout)
peterv@90770
   655
  { }
peterv@90770
   656
bent@160748
   657
private:
bent@160748
   658
  ~SetTimeoutRunnable()
bent@160748
   659
  { }
bent@160748
   660
bent@160748
   661
  virtual nsresult
bent@160748
   662
  MainThreadRun() MOZ_OVERRIDE
peterv@90770
   663
  {
VYV03354@92429
   664
    return mProxy->mXHR->SetTimeout(mTimeout);
peterv@90770
   665
  }
peterv@90770
   666
};
peterv@90770
   667
bent@160748
   668
class AbortRunnable MOZ_FINAL : public WorkerThreadProxySyncRunnable
peterv@90770
   669
{
peterv@90770
   670
public:
peterv@90770
   671
  AbortRunnable(WorkerPrivate* aWorkerPrivate, Proxy* aProxy)
peterv@90770
   672
  : WorkerThreadProxySyncRunnable(aWorkerPrivate, aProxy)
peterv@90770
   673
  { }
peterv@90770
   674
bent@160748
   675
private:
bent@160748
   676
  ~AbortRunnable()
bent@160748
   677
  { }
peterv@90770
   678
bent@160748
   679
  virtual nsresult
bent@160748
   680
  MainThreadRun() MOZ_OVERRIDE;
peterv@90770
   681
};
peterv@90770
   682
bent@160748
   683
class GetAllResponseHeadersRunnable MOZ_FINAL :
bent@160748
   684
  public WorkerThreadProxySyncRunnable
peterv@90770
   685
{
jkitch@134920
   686
  nsCString& mResponseHeaders;
peterv@90770
   687
peterv@90770
   688
public:
peterv@90770
   689
  GetAllResponseHeadersRunnable(WorkerPrivate* aWorkerPrivate, Proxy* aProxy,
jkitch@134920
   690
                                nsCString& aResponseHeaders)
peterv@90770
   691
  : WorkerThreadProxySyncRunnable(aWorkerPrivate, aProxy),
peterv@90770
   692
    mResponseHeaders(aResponseHeaders)
peterv@90770
   693
  { }
peterv@90770
   694
bent@160748
   695
private:
bent@160748
   696
  ~GetAllResponseHeadersRunnable()
bent@160748
   697
  { }
bent@160748
   698
bent@160748
   699
  virtual nsresult
bent@160748
   700
  MainThreadRun() MOZ_OVERRIDE
peterv@90770
   701
  {
peterv@90770
   702
    mProxy->mXHR->GetAllResponseHeaders(mResponseHeaders);
VYV03354@92429
   703
    return NS_OK;
peterv@90770
   704
  }
peterv@90770
   705
};
peterv@90770
   706
bent@160748
   707
class GetResponseHeaderRunnable MOZ_FINAL : public WorkerThreadProxySyncRunnable
peterv@90770
   708
{
peterv@90770
   709
  const nsCString mHeader;
peterv@90770
   710
  nsCString& mValue;
peterv@90770
   711
peterv@90770
   712
public:
peterv@90770
   713
  GetResponseHeaderRunnable(WorkerPrivate* aWorkerPrivate, Proxy* aProxy,
jkitch@134920
   714
                            const nsACString& aHeader, nsCString& aValue)
peterv@90770
   715
  : WorkerThreadProxySyncRunnable(aWorkerPrivate, aProxy), mHeader(aHeader),
peterv@90770
   716
    mValue(aValue)
peterv@90770
   717
  { }
peterv@90770
   718
bent@160748
   719
private:
bent@160748
   720
  ~GetResponseHeaderRunnable()
bent@160748
   721
  { }
bent@160748
   722
bent@160748
   723
  virtual nsresult
bent@160748
   724
  MainThreadRun() MOZ_OVERRIDE
peterv@90770
   725
  {
VYV03354@92429
   726
    return mProxy->mXHR->GetResponseHeader(mHeader, mValue);
peterv@90770
   727
  }
peterv@90770
   728
};
peterv@90770
   729
bent@160748
   730
class OpenRunnable MOZ_FINAL : public WorkerThreadProxySyncRunnable
peterv@90770
   731
{
jkitch@134920
   732
  nsCString mMethod;
bzbarsky@95230
   733
  nsString mURL;
bzbarsky@95230
   734
  Optional<nsAString> mUser;
bzbarsky@95230
   735
  nsString mUserStr;
bzbarsky@95230
   736
  Optional<nsAString> mPassword;
bzbarsky@95230
   737
  nsString mPasswordStr;
peterv@90770
   738
  bool mBackgroundRequest;
peterv@90770
   739
  bool mWithCredentials;
ehsan@102997
   740
  uint32_t mTimeout;
peterv@90770
   741
peterv@90770
   742
public:
peterv@90770
   743
  OpenRunnable(WorkerPrivate* aWorkerPrivate, Proxy* aProxy,
jkitch@134920
   744
               const nsACString& aMethod, const nsAString& aURL,
bzbarsky@95230
   745
               const Optional<nsAString>& aUser,
bzbarsky@95230
   746
               const Optional<nsAString>& aPassword,
hsivonen@123655
   747
               bool aBackgroundRequest, bool aWithCredentials,
ehsan@102997
   748
               uint32_t aTimeout)
peterv@90770
   749
  : WorkerThreadProxySyncRunnable(aWorkerPrivate, aProxy), mMethod(aMethod),
bent@160748
   750
    mURL(aURL), mBackgroundRequest(aBackgroundRequest),
bent@160748
   751
    mWithCredentials(aWithCredentials), mTimeout(aTimeout)
bzbarsky@95230
   752
  {
bzbarsky@95230
   753
    if (aUser.WasPassed()) {
bzbarsky@95230
   754
      mUserStr = aUser.Value();
bzbarsky@95230
   755
      mUser = &mUserStr;
bzbarsky@95230
   756
    }
bzbarsky@95230
   757
    if (aPassword.WasPassed()) {
bzbarsky@95230
   758
      mPasswordStr = aPassword.Value();
bzbarsky@95230
   759
      mPassword = &mPasswordStr;
bzbarsky@95230
   760
    }
bzbarsky@95230
   761
  }
peterv@90770
   762
bent@160748
   763
private:
bent@160748
   764
  ~OpenRunnable()
bent@160748
   765
  { }
bent@160748
   766
bent@160748
   767
  virtual nsresult
bent@160748
   768
  MainThreadRun() MOZ_OVERRIDE
peterv@90770
   769
  {
peterv@90770
   770
    WorkerPrivate* oldWorker = mProxy->mWorkerPrivate;
peterv@90770
   771
    mProxy->mWorkerPrivate = mWorkerPrivate;
peterv@90770
   772
VYV03354@92429
   773
    nsresult rv = MainThreadRunInternal();
peterv@90770
   774
peterv@90770
   775
    mProxy->mWorkerPrivate = oldWorker;
VYV03354@92429
   776
    return rv;
peterv@90770
   777
  }
peterv@90770
   778
VYV03354@92429
   779
  nsresult
bent@160748
   780
  MainThreadRunInternal();
peterv@90770
   781
};
peterv@90770
   782
bent@160748
   783
class SendRunnable MOZ_FINAL : public WorkerThreadProxySyncRunnable
peterv@90770
   784
{
peterv@90770
   785
  nsString mStringBody;
peterv@90770
   786
  JSAutoStructuredCloneBuffer mBody;
peterv@90770
   787
  nsTArray<nsCOMPtr<nsISupports> > mClonedObjects;
bent@160748
   788
  nsCOMPtr<nsIEventTarget> mSyncLoopTarget;
peterv@90770
   789
  bool mHasUploadListeners;
peterv@90770
   790
peterv@90770
   791
public:
peterv@90770
   792
  SendRunnable(WorkerPrivate* aWorkerPrivate, Proxy* aProxy,
khuey@166499
   793
               const nsAString& aStringBody, JSAutoStructuredCloneBuffer&& aBody,
khuey@166499
   794
               nsTArray<nsCOMPtr<nsISupports>>& aClonedObjects,
bent@160748
   795
               nsIEventTarget* aSyncLoopTarget, bool aHasUploadListeners)
khuey@166499
   796
  : WorkerThreadProxySyncRunnable(aWorkerPrivate, aProxy)
khuey@166499
   797
  , mStringBody(aStringBody)
khuey@166499
   798
  , mBody(Move(aBody))
khuey@166499
   799
  , mSyncLoopTarget(aSyncLoopTarget)
khuey@166499
   800
  , mHasUploadListeners(aHasUploadListeners)
peterv@90770
   801
  {
peterv@90770
   802
    mClonedObjects.SwapElements(aClonedObjects);
peterv@90770
   803
  }
peterv@90770
   804
bent@160748
   805
private:
bent@160748
   806
  ~SendRunnable()
bent@160748
   807
  { }
evilpies>@92092
   808
bent@160748
   809
  virtual nsresult
bent@160748
   810
  MainThreadRun() MOZ_OVERRIDE;
peterv@90770
   811
};
peterv@90770
   812
bent@160748
   813
class SetRequestHeaderRunnable MOZ_FINAL : public WorkerThreadProxySyncRunnable
peterv@90770
   814
{
peterv@90770
   815
  nsCString mHeader;
peterv@90770
   816
  nsCString mValue;
peterv@90770
   817
peterv@90770
   818
public:
peterv@90770
   819
  SetRequestHeaderRunnable(WorkerPrivate* aWorkerPrivate, Proxy* aProxy,
jkitch@134920
   820
                           const nsACString& aHeader, const nsACString& aValue)
peterv@90770
   821
  : WorkerThreadProxySyncRunnable(aWorkerPrivate, aProxy), mHeader(aHeader),
peterv@90770
   822
    mValue(aValue)
peterv@90770
   823
  { }
peterv@90770
   824
bent@160748
   825
private:
bent@160748
   826
  ~SetRequestHeaderRunnable()
bent@160748
   827
  { }
bent@160748
   828
bent@160748
   829
  virtual nsresult
bent@160748
   830
  MainThreadRun() MOZ_OVERRIDE
peterv@90770
   831
  {
VYV03354@92429
   832
    return mProxy->mXHR->SetRequestHeader(mHeader, mValue);
peterv@90770
   833
  }
peterv@90770
   834
};
peterv@90770
   835
bent@160748
   836
class OverrideMimeTypeRunnable MOZ_FINAL : public WorkerThreadProxySyncRunnable
peterv@90770
   837
{
peterv@90770
   838
  nsString mMimeType;
peterv@90770
   839
peterv@90770
   840
public:
peterv@90770
   841
  OverrideMimeTypeRunnable(WorkerPrivate* aWorkerPrivate, Proxy* aProxy,
peterv@90770
   842
                           const nsAString& aMimeType)
peterv@90770
   843
  : WorkerThreadProxySyncRunnable(aWorkerPrivate, aProxy), mMimeType(aMimeType)
peterv@90770
   844
  { }
peterv@90770
   845
bent@160748
   846
private:
bent@160748
   847
  ~OverrideMimeTypeRunnable()
bent@160748
   848
  { }
bent@160748
   849
bent@160748
   850
  virtual nsresult
bent@160748
   851
  MainThreadRun() MOZ_OVERRIDE
peterv@90770
   852
  {
peterv@90770
   853
    mProxy->mXHR->OverrideMimeType(mMimeType);
VYV03354@92429
   854
    return NS_OK;
peterv@90770
   855
  }
peterv@90770
   856
};
peterv@90770
   857
peterv@90770
   858
class AutoUnpinXHR
peterv@90770
   859
{
bent@160748
   860
  XMLHttpRequest* mXMLHttpRequestPrivate;
bent@160748
   861
peterv@90770
   862
public:
peterv@90770
   863
  AutoUnpinXHR(XMLHttpRequest* aXMLHttpRequestPrivate)
peterv@90770
   864
  : mXMLHttpRequestPrivate(aXMLHttpRequestPrivate)
peterv@90770
   865
  {
peterv@90770
   866
    MOZ_ASSERT(aXMLHttpRequestPrivate);
peterv@90770
   867
  }
peterv@90770
   868
peterv@90770
   869
  ~AutoUnpinXHR()
peterv@90770
   870
  {
peterv@90770
   871
    if (mXMLHttpRequestPrivate) {
peterv@90770
   872
      mXMLHttpRequestPrivate->Unpin();
bent@72705
   873
    }
bent@72705
   874
  }
bent@72705
   875
peterv@90770
   876
  void Clear()
bent@72705
   877
  {
birunthan@152502
   878
    mXMLHttpRequestPrivate = nullptr;
peterv@90770
   879
  }
peterv@90770
   880
};
peterv@90770
   881
peterv@90770
   882
} // anonymous namespace
peterv@90770
   883
bent@160748
   884
bool
bent@160748
   885
Proxy::Init()
bent@160748
   886
{
bent@160748
   887
  AssertIsOnMainThread();
bent@160748
   888
  MOZ_ASSERT(mWorkerPrivate);
bent@160748
   889
bent@160748
   890
  if (mXHR) {
bent@160748
   891
    return true;
bent@160748
   892
  }
bent@160748
   893
bent@160748
   894
  nsPIDOMWindow* ownerWindow = mWorkerPrivate->GetWindow();
bent@160748
   895
  if (ownerWindow) {
bent@160748
   896
    ownerWindow = ownerWindow->GetOuterWindow();
bent@160748
   897
    if (!ownerWindow) {
bent@160748
   898
      NS_ERROR("No outer window?!");
bent@160748
   899
      return false;
bent@160748
   900
    }
bent@160748
   901
bent@160748
   902
    nsPIDOMWindow* innerWindow = ownerWindow->GetCurrentInnerWindow();
bent@160748
   903
    if (mWorkerPrivate->GetWindow() != innerWindow) {
bent@160748
   904
      NS_WARNING("Window has navigated, cannot create XHR here.");
bent@160748
   905
      return false;
bent@160748
   906
    }
bent@160748
   907
  }
bent@160748
   908
bent@160748
   909
  mXHR = new nsXMLHttpRequest();
bent@160748
   910
bent@160748
   911
  nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(ownerWindow);
bent@160748
   912
  if (NS_FAILED(mXHR->Init(mWorkerPrivate->GetPrincipal(),
bent@160748
   913
                           mWorkerPrivate->GetScriptContext(),
bent@160748
   914
                           global, mWorkerPrivate->GetBaseURI()))) {
bent@160748
   915
    mXHR = nullptr;
bent@160748
   916
    return false;
bent@160748
   917
  }
bent@160748
   918
bent@160748
   919
  mXHR->SetParameters(mMozAnon, mMozSystem);
bent@160748
   920
bent@160748
   921
  if (NS_FAILED(mXHR->GetUpload(getter_AddRefs(mXHRUpload)))) {
bent@160748
   922
    mXHR = nullptr;
bent@160748
   923
    return false;
bent@160748
   924
  }
bent@160748
   925
bent@160748
   926
  if (!AddRemoveEventListeners(false, true)) {
bent@160748
   927
    mXHRUpload = nullptr;
bent@160748
   928
    mXHR = nullptr;
bent@160748
   929
    return false;
bent@160748
   930
  }
bent@160748
   931
bent@160748
   932
  return true;
bent@160748
   933
}
bent@160748
   934
peterv@90770
   935
void
peterv@90770
   936
Proxy::Teardown()
peterv@90770
   937
{
peterv@90770
   938
  AssertIsOnMainThread();
peterv@90770
   939
peterv@90770
   940
  if (mXHR) {
peterv@90770
   941
    Reset();
peterv@90770
   942
peterv@90770
   943
    // NB: We are intentionally dropping events coming from xhr.abort on the
peterv@90770
   944
    // floor.
peterv@90770
   945
    AddRemoveEventListeners(false, false);
peterv@90770
   946
    mXHR->Abort();
peterv@90770
   947
peterv@90770
   948
    if (mOutstandingSendCount) {
peterv@90770
   949
      nsRefPtr<XHRUnpinRunnable> runnable =
peterv@90770
   950
        new XHRUnpinRunnable(mWorkerPrivate, mXMLHttpRequestPrivate);
ayg@100844
   951
      if (!runnable->Dispatch(nullptr)) {
peterv@90770
   952
        NS_RUNTIMEABORT("We're going to hang at shutdown anyways.");
peterv@90770
   953
      }
peterv@90770
   954
ayg@100844
   955
      mWorkerPrivate = nullptr;
peterv@90770
   956
      mOutstandingSendCount = 0;
peterv@90770
   957
    }
peterv@90770
   958
ayg@100844
   959
    mXHRUpload = nullptr;
ayg@100844
   960
    mXHR = nullptr;
peterv@90770
   961
  }
peterv@90770
   962
}
peterv@90770
   963
peterv@90770
   964
bool
peterv@90770
   965
Proxy::AddRemoveEventListeners(bool aUpload, bool aAdd)
peterv@90770
   966
{
peterv@90770
   967
  AssertIsOnMainThread();
peterv@90770
   968
peterv@90770
   969
  NS_ASSERTION(!aUpload ||
peterv@90770
   970
               (mUploadEventListenersAttached && !aAdd) ||
peterv@90770
   971
               (!mUploadEventListenersAttached && aAdd),
peterv@90770
   972
               "Messed up logic for upload listeners!");
peterv@90770
   973
peterv@90770
   974
  nsCOMPtr<nsIDOMEventTarget> target =
peterv@90770
   975
    aUpload ?
peterv@90770
   976
    do_QueryInterface(mXHRUpload) :
peterv@90770
   977
    do_QueryInterface(static_cast<nsIXMLHttpRequest*>(mXHR.get()));
peterv@90770
   978
  NS_ASSERTION(target, "This should never fail!");
peterv@90770
   979
ehsan@102997
   980
  uint32_t lastEventType = aUpload ? STRING_LAST_EVENTTARGET : STRING_LAST_XHR;
peterv@90770
   981
peterv@90770
   982
  nsAutoString eventType;
ehsan@102997
   983
  for (uint32_t index = 0; index <= lastEventType; index++) {
peterv@90770
   984
    eventType = NS_ConvertASCIItoUTF16(sEventStrings[index]);
peterv@90770
   985
    if (aAdd) {
peterv@90770
   986
      if (NS_FAILED(target->AddEventListener(eventType, this, false))) {
peterv@90770
   987
        return false;
peterv@90770
   988
      }
peterv@90770
   989
    }
peterv@90770
   990
    else if (NS_FAILED(target->RemoveEventListener(eventType, this, false))) {
peterv@90770
   991
      return false;
bent@72705
   992
    }
bent@72705
   993
  }
bent@72705
   994
peterv@90770
   995
  if (aUpload) {
peterv@90770
   996
    mUploadEventListenersAttached = aAdd;
bent@79735
   997
  }
bent@79735
   998
bent@79735
   999
  return true;
bent@79735
  1000
}
bent@79735
  1001
birunthan@180485
  1002
NS_IMPL_ISUPPORTS(Proxy, nsIDOMEventListener)
bent@72705
  1003
peterv@90770
  1004
NS_IMETHODIMP
peterv@90770
  1005
Proxy::HandleEvent(nsIDOMEvent* aEvent)
peterv@90770
  1006
{
peterv@90770
  1007
  AssertIsOnMainThread();
bent@72705
  1008
peterv@90770
  1009
  if (!mWorkerPrivate || !mXMLHttpRequestPrivate) {
peterv@90770
  1010
    NS_ERROR("Shouldn't get here!");
peterv@90770
  1011
    return NS_OK;
peterv@90770
  1012
  }
bent@72705
  1013
peterv@90770
  1014
  nsString type;
peterv@90770
  1015
  if (NS_FAILED(aEvent->GetType(type))) {
peterv@90770
  1016
    NS_WARNING("Failed to get event type!");
peterv@90770
  1017
    return NS_ERROR_FAILURE;
peterv@90770
  1018
  }
peterv@90770
  1019
peterv@90770
  1020
  nsCOMPtr<nsIDOMEventTarget> target;
peterv@90770
  1021
  if (NS_FAILED(aEvent->GetTarget(getter_AddRefs(target)))) {
peterv@90770
  1022
    NS_WARNING("Failed to get target!");
peterv@90770
  1023
    return NS_ERROR_FAILURE;
peterv@90770
  1024
  }
peterv@90770
  1025
peterv@90770
  1026
  nsCOMPtr<nsIXMLHttpRequestUpload> uploadTarget = do_QueryInterface(target);
peterv@90770
  1027
  nsCOMPtr<nsIDOMProgressEvent> progressEvent = do_QueryInterface(aEvent);
peterv@90770
  1028
peterv@90770
  1029
  nsRefPtr<EventRunnable> runnable;
peterv@90770
  1030
peterv@90770
  1031
  if (mInOpen && type.EqualsASCII(sEventStrings[STRING_readystatechange])) {
ehsan@102997
  1032
    uint16_t readyState = 0;
peterv@90770
  1033
    if (NS_SUCCEEDED(mXHR->GetReadyState(&readyState)) &&
peterv@90770
  1034
        readyState == nsIXMLHttpRequest::OPENED) {
peterv@90770
  1035
      mInnerEventStreamId++;
peterv@90770
  1036
    }
peterv@90770
  1037
  }
peterv@90770
  1038
peterv@90770
  1039
  if (progressEvent) {
peterv@90770
  1040
    bool lengthComputable;
ehsan@102997
  1041
    uint64_t loaded, total;
peterv@90770
  1042
    if (NS_FAILED(progressEvent->GetLengthComputable(&lengthComputable)) ||
peterv@90770
  1043
        NS_FAILED(progressEvent->GetLoaded(&loaded)) ||
peterv@90770
  1044
        NS_FAILED(progressEvent->GetTotal(&total))) {
peterv@90770
  1045
      NS_WARNING("Bad progress event!");
peterv@90770
  1046
      return NS_ERROR_FAILURE;
peterv@90770
  1047
    }
peterv@90770
  1048
    runnable = new EventRunnable(this, !!uploadTarget, type, lengthComputable,
peterv@90770
  1049
                                 loaded, total);
peterv@90770
  1050
  }
peterv@90770
  1051
  else {
peterv@90770
  1052
    runnable = new EventRunnable(this, !!uploadTarget, type);
peterv@90770
  1053
  }
peterv@90770
  1054
peterv@90770
  1055
  {
sankha93@130973
  1056
    AutoSafeJSContext cx;
bobbyholley@129213
  1057
    JSAutoRequest ar(cx);
peterv@90770
  1058
    runnable->Dispatch(cx);
peterv@90770
  1059
  }
peterv@90770
  1060
peterv@90770
  1061
  if (!uploadTarget) {
peterv@90770
  1062
    if (type.EqualsASCII(sEventStrings[STRING_loadstart])) {
peterv@90770
  1063
      NS_ASSERTION(!mMainThreadSeenLoadStart, "Huh?!");
peterv@90770
  1064
      mMainThreadSeenLoadStart = true;
peterv@90770
  1065
    }
peterv@90770
  1066
    else if (mMainThreadSeenLoadStart &&
peterv@90770
  1067
             type.EqualsASCII(sEventStrings[STRING_loadend])) {
peterv@90770
  1068
      mMainThreadSeenLoadStart = false;
peterv@90770
  1069
peterv@90770
  1070
      nsRefPtr<LoadStartDetectionRunnable> runnable =
peterv@90770
  1071
        new LoadStartDetectionRunnable(this, mXMLHttpRequestPrivate);
ttaubert@165925
  1072
      if (!runnable->RegisterAndDispatch()) {
peterv@90770
  1073
        NS_WARNING("Failed to dispatch LoadStartDetectionRunnable!");
peterv@90770
  1074
      }
peterv@90770
  1075
    }
peterv@90770
  1076
  }
peterv@90770
  1077
peterv@90770
  1078
  return NS_OK;
peterv@90770
  1079
}
peterv@90770
  1080
bent@160748
  1081
NS_IMPL_ISUPPORTS_INHERITED0(WorkerThreadProxySyncRunnable, nsRunnable)
bent@160748
  1082
bent@160748
  1083
NS_IMPL_ISUPPORTS_INHERITED0(AsyncTeardownRunnable, nsRunnable)
bent@160748
  1084
birunthan@180485
  1085
NS_IMPL_ISUPPORTS_INHERITED(LoadStartDetectionRunnable, nsRunnable,
birunthan@180485
  1086
                                                        nsIDOMEventListener)
bent@160748
  1087
bent@160748
  1088
NS_IMETHODIMP
bent@160748
  1089
LoadStartDetectionRunnable::Run()
bent@160748
  1090
{
bent@160748
  1091
  AssertIsOnMainThread();
bent@160748
  1092
bent@160748
  1093
  if (NS_FAILED(mXHR->RemoveEventListener(mEventType, this, false))) {
bent@160748
  1094
    NS_WARNING("Failed to remove event listener!");
bent@160748
  1095
  }
bent@160748
  1096
bent@160748
  1097
  if (!mReceivedLoadStart) {
bent@160748
  1098
    if (mProxy->mOutstandingSendCount > 1) {
bent@160748
  1099
      mProxy->mOutstandingSendCount--;
bent@160748
  1100
    } else if (mProxy->mOutstandingSendCount == 1) {
bent@160748
  1101
      mProxy->Reset();
bent@160748
  1102
bent@160748
  1103
      nsRefPtr<ProxyCompleteRunnable> runnable =
bent@160748
  1104
        new ProxyCompleteRunnable(mWorkerPrivate, mProxy,
bent@160748
  1105
                                  mXMLHttpRequestPrivate, mChannelId);
bent@160748
  1106
      if (runnable->Dispatch(nullptr)) {
bent@160748
  1107
        mProxy->mWorkerPrivate = nullptr;
bent@160748
  1108
        mProxy->mOutstandingSendCount--;
bent@160748
  1109
      }
bent@160748
  1110
    }
bent@160748
  1111
  }
bent@160748
  1112
bent@160748
  1113
  mProxy = nullptr;
bent@160748
  1114
  mXHR = nullptr;
bent@160748
  1115
  mXMLHttpRequestPrivate = nullptr;
bent@160748
  1116
  return NS_OK;
bent@160748
  1117
}
bent@160748
  1118
bent@160748
  1119
NS_IMETHODIMP
bent@160748
  1120
LoadStartDetectionRunnable::HandleEvent(nsIDOMEvent* aEvent)
bent@160748
  1121
{
bent@160748
  1122
  AssertIsOnMainThread();
bent@160748
  1123
bent@160748
  1124
#ifdef DEBUG
bent@160748
  1125
  {
bent@160748
  1126
    nsString type;
bent@160748
  1127
    if (NS_SUCCEEDED(aEvent->GetType(type))) {
bent@160748
  1128
      MOZ_ASSERT(type == mEventType);
bent@160748
  1129
    }
bent@160748
  1130
    else {
bent@160748
  1131
      NS_WARNING("Failed to get event type!");
bent@160748
  1132
    }
bent@160748
  1133
  }
bent@160748
  1134
#endif
bent@160748
  1135
bent@160748
  1136
  mReceivedLoadStart = true;
bent@160748
  1137
  return NS_OK;
bent@160748
  1138
}
bent@160748
  1139
bent@160748
  1140
bool
bent@160748
  1141
EventRunnable::PreDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
bent@160748
  1142
{
bent@160748
  1143
  AssertIsOnMainThread();
bent@160748
  1144
bent@160748
  1145
  nsRefPtr<nsXMLHttpRequest>& xhr = mProxy->mXHR;
bent@160748
  1146
  MOZ_ASSERT(xhr);
bent@160748
  1147
bent@160748
  1148
  if (NS_FAILED(xhr->GetResponseType(mResponseType))) {
bent@160748
  1149
    MOZ_ASSERT(false, "This should never fail!");
bent@160748
  1150
  }
bent@160748
  1151
bent@160748
  1152
  mResponseTextResult = xhr->GetResponseText(mResponseText);
bent@160748
  1153
  if (NS_SUCCEEDED(mResponseTextResult)) {
bent@160748
  1154
    mResponseResult = mResponseTextResult;
bent@160748
  1155
    if (mResponseText.IsVoid()) {
bent@160748
  1156
      mResponse = JSVAL_NULL;
bent@160748
  1157
    }
bent@160748
  1158
  }
bent@160748
  1159
  else {
bent@160748
  1160
    JS::Rooted<JS::Value> response(aCx);
evilpies@163761
  1161
    mResponseResult = xhr->GetResponse(aCx, &response);
bent@160748
  1162
    if (NS_SUCCEEDED(mResponseResult)) {
nnethercote@180926
  1163
      if (!response.isGCThing()) {
bent@160748
  1164
        mResponse = response;
bent@160748
  1165
      }
bent@160748
  1166
      else {
bent@160748
  1167
        // Anything subject to GC must be cloned.
bent@160748
  1168
        JSStructuredCloneCallbacks* callbacks =
bent@160748
  1169
          aWorkerPrivate->IsChromeWorker() ?
bent@160748
  1170
          ChromeWorkerStructuredCloneCallbacks(true) :
bent@160748
  1171
          WorkerStructuredCloneCallbacks(true);
bent@160748
  1172
bent@160748
  1173
        nsTArray<nsCOMPtr<nsISupports> > clonedObjects;
bent@160748
  1174
bent@160748
  1175
        if (mResponseBuffer.write(aCx, response, callbacks, &clonedObjects)) {
bent@160748
  1176
          mClonedObjects.SwapElements(clonedObjects);
bent@160748
  1177
        }
bent@160748
  1178
        else {
bent@160748
  1179
          NS_WARNING("Failed to clone response!");
bent@160748
  1180
          mResponseResult = NS_ERROR_DOM_DATA_CLONE_ERR;
bent@160748
  1181
        }
bent@160748
  1182
      }
bent@160748
  1183
    }
bent@160748
  1184
  }
bent@160748
  1185
bent@160748
  1186
  mStatusResult = xhr->GetStatus(&mStatus);
bent@160748
  1187
bent@160748
  1188
  xhr->GetStatusText(mStatusText);
bent@160748
  1189
bent@160748
  1190
  mReadyState = xhr->ReadyState();
bent@160748
  1191
bent@160748
  1192
  return true;
bent@160748
  1193
}
bent@160748
  1194
bent@160748
  1195
bool
bent@160748
  1196
EventRunnable::WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
bent@160748
  1197
{
bent@160748
  1198
  if (mEventStreamId != mProxy->mOuterEventStreamId) {
bent@160748
  1199
    // Threads raced, this event is now obsolete.
bent@160748
  1200
    return true;
bent@160748
  1201
  }
bent@160748
  1202
bent@160748
  1203
  if (!mProxy->mXMLHttpRequestPrivate) {
bent@160748
  1204
    // Object was finalized, bail.
bent@160748
  1205
    return true;
bent@160748
  1206
  }
bent@160748
  1207
bent@160748
  1208
  if (mType.EqualsASCII(sEventStrings[STRING_loadstart])) {
bent@160748
  1209
    if (mUploadEvent) {
bent@160748
  1210
      mProxy->mSeenUploadLoadStart = true;
bent@160748
  1211
    }
bent@160748
  1212
    else {
bent@160748
  1213
      mProxy->mSeenLoadStart = true;
bent@160748
  1214
    }
bent@160748
  1215
  }
bent@160748
  1216
  else if (mType.EqualsASCII(sEventStrings[STRING_loadend])) {
bent@160748
  1217
    if (mUploadEvent) {
bent@160748
  1218
      mProxy->mSeenUploadLoadStart = false;
bent@160748
  1219
    }
bent@160748
  1220
    else {
bent@160748
  1221
      mProxy->mSeenLoadStart = false;
bent@160748
  1222
    }
bent@160748
  1223
  }
bent@160748
  1224
  else if (mType.EqualsASCII(sEventStrings[STRING_abort])) {
bent@160748
  1225
    if ((mUploadEvent && !mProxy->mSeenUploadLoadStart) ||
bent@160748
  1226
        (!mUploadEvent && !mProxy->mSeenLoadStart)) {
bent@160748
  1227
      // We've already dispatched premature abort events.
bent@160748
  1228
      return true;
bent@160748
  1229
    }
bent@160748
  1230
  }
bent@160748
  1231
  else if (mType.EqualsASCII(sEventStrings[STRING_readystatechange])) {
bent@160748
  1232
    if (mReadyState == 4 && !mUploadEvent && !mProxy->mSeenLoadStart) {
bent@160748
  1233
      // We've already dispatched premature abort events.
bent@160748
  1234
      return true;
bent@160748
  1235
    }
bent@160748
  1236
  }
bent@160748
  1237
bent@160748
  1238
  if (mProgressEvent) {
bent@160748
  1239
    // Cache these for premature abort events.
bent@160748
  1240
    if (mUploadEvent) {
bent@160748
  1241
      mProxy->mLastUploadLengthComputable = mLengthComputable;
bent@160748
  1242
      mProxy->mLastUploadLoaded = mLoaded;
bent@160748
  1243
      mProxy->mLastUploadTotal = mTotal;
bent@160748
  1244
    }
bent@160748
  1245
    else {
bent@160748
  1246
      mProxy->mLastLengthComputable = mLengthComputable;
bent@160748
  1247
      mProxy->mLastLoaded = mLoaded;
bent@160748
  1248
      mProxy->mLastTotal = mTotal;
bent@160748
  1249
    }
bent@160748
  1250
  }
bent@160748
  1251
bent@160748
  1252
  nsAutoPtr<XMLHttpRequest::StateData> state(new XMLHttpRequest::StateData());
bent@160748
  1253
  StateDataAutoRooter rooter(aCx, state);
bent@160748
  1254
bent@160748
  1255
  state->mResponseTextResult = mResponseTextResult;
bent@160748
  1256
  state->mResponseText = mResponseText;
bent@160748
  1257
bent@160748
  1258
  if (NS_SUCCEEDED(mResponseTextResult)) {
rrodrigue96@180910
  1259
    MOZ_ASSERT(mResponse.isUndefined() || mResponse.isNull());
bent@160748
  1260
    state->mResponseResult = mResponseTextResult;
bent@160748
  1261
    state->mResponse = mResponse;
bent@160748
  1262
  }
bent@160748
  1263
  else {
bent@160748
  1264
    state->mResponseResult = mResponseResult;
bent@160748
  1265
bent@160748
  1266
    if (NS_SUCCEEDED(mResponseResult)) {
bent@160748
  1267
      if (mResponseBuffer.data()) {
rrodrigue96@180910
  1268
        MOZ_ASSERT(mResponse.isUndefined());
bent@160748
  1269
khuey@166499
  1270
        JSAutoStructuredCloneBuffer responseBuffer(Move(mResponseBuffer));
bent@160748
  1271
bent@160748
  1272
        JSStructuredCloneCallbacks* callbacks =
bent@160748
  1273
          aWorkerPrivate->IsChromeWorker() ?
bent@160748
  1274
          ChromeWorkerStructuredCloneCallbacks(false) :
bent@160748
  1275
          WorkerStructuredCloneCallbacks(false);
bent@160748
  1276
bent@160748
  1277
        nsTArray<nsCOMPtr<nsISupports> > clonedObjects;
bent@160748
  1278
        clonedObjects.SwapElements(mClonedObjects);
bent@160748
  1279
bent@160748
  1280
        JS::Rooted<JS::Value> response(aCx);
bent@160748
  1281
        if (!responseBuffer.read(aCx, &response, callbacks, &clonedObjects)) {
bent@160748
  1282
          return false;
bent@160748
  1283
        }
bent@160748
  1284
bent@160748
  1285
        state->mResponse = response;
bent@160748
  1286
      }
bent@160748
  1287
      else {
bent@160748
  1288
        state->mResponse = mResponse;
bent@160748
  1289
      }
bent@160748
  1290
    }
bent@160748
  1291
  }
bent@160748
  1292
bent@160748
  1293
  state->mStatusResult = mStatusResult;
bent@160748
  1294
  state->mStatus = mStatus;
bent@160748
  1295
bent@160748
  1296
  state->mStatusText = mStatusText;
bent@160748
  1297
bent@160748
  1298
  state->mReadyState = mReadyState;
bent@160748
  1299
bent@160748
  1300
  XMLHttpRequest* xhr = mProxy->mXMLHttpRequestPrivate;
bent@160748
  1301
  xhr->UpdateState(*state);
bent@160748
  1302
bent@160748
  1303
  if (mUploadEvent && !xhr->GetUploadObjectNoCreate()) {
bent@160748
  1304
    return true;
bent@160748
  1305
  }
bent@160748
  1306
bent@160748
  1307
  JS::Rooted<JSString*> type(aCx,
bent@160748
  1308
    JS_NewUCStringCopyN(aCx, mType.get(), mType.Length()));
bent@160748
  1309
  if (!type) {
bent@160748
  1310
    return false;
bent@160748
  1311
  }
bent@160748
  1312
bent@160748
  1313
  nsXHREventTarget* target;
bent@160748
  1314
  if (mUploadEvent) {
bent@160748
  1315
    target = xhr->GetUploadObjectNoCreate();
bent@160748
  1316
  }
bent@160748
  1317
  else {
bent@160748
  1318
    target = xhr;
bent@160748
  1319
  }
bent@160748
  1320
bent@160748
  1321
  MOZ_ASSERT(target);
bent@160748
  1322
bent@160748
  1323
  nsCOMPtr<nsIDOMEvent> event;
bent@160748
  1324
  if (mProgressEvent) {
bent@160748
  1325
    NS_NewDOMProgressEvent(getter_AddRefs(event), target, nullptr, nullptr);
bent@160748
  1326
    nsCOMPtr<nsIDOMProgressEvent> progress = do_QueryInterface(event);
bent@160748
  1327
bent@160748
  1328
    if (progress) {
bent@160748
  1329
      progress->InitProgressEvent(mType, false, false, mLengthComputable,
bent@160748
  1330
                                  mLoaded, mTotal);
bent@160748
  1331
    }
bent@160748
  1332
  }
bent@160748
  1333
  else {
bent@160748
  1334
    NS_NewDOMEvent(getter_AddRefs(event), target, nullptr, nullptr);
bent@160748
  1335
bent@160748
  1336
    if (event) {
bent@160748
  1337
      event->InitEvent(mType, false, false);
bent@160748
  1338
    }
bent@160748
  1339
  }
bent@160748
  1340
bent@160748
  1341
  if (!event) {
bent@160748
  1342
    return false;
bent@160748
  1343
  }
bent@160748
  1344
bent@160748
  1345
  event->SetTrusted(true);
bent@160748
  1346
bent@160748
  1347
  target->DispatchDOMEvent(nullptr, event, nullptr, nullptr);
bent@160748
  1348
bent@160748
  1349
  // After firing the event set mResponse to JSVAL_NULL for chunked response
bent@160748
  1350
  // types.
bent@160748
  1351
  if (StringBeginsWith(mResponseType, NS_LITERAL_STRING("moz-chunked-"))) {
bent@160748
  1352
    xhr->NullResponseText();
bent@160748
  1353
  }
bent@160748
  1354
bent@160748
  1355
  return true;
bent@160748
  1356
}
bent@160748
  1357
bent@160748
  1358
NS_IMETHODIMP
bent@160748
  1359
WorkerThreadProxySyncRunnable::Run()
bent@160748
  1360
{
bent@160748
  1361
  AssertIsOnMainThread();
bent@160748
  1362
bent@160748
  1363
  nsCOMPtr<nsIEventTarget> tempTarget;
bent@160748
  1364
  mSyncLoopTarget.swap(tempTarget);
bent@160748
  1365
bent@160748
  1366
  mProxy->mSyncEventResponseTarget.swap(tempTarget);
bent@160748
  1367
bent@160748
  1368
  nsresult rv = MainThreadRun();
bent@160748
  1369
bent@160748
  1370
  nsRefPtr<ResponseRunnable> response =
bent@160748
  1371
    new ResponseRunnable(mWorkerPrivate, mProxy, rv);
bent@160748
  1372
  if (!response->Dispatch(nullptr)) {
bent@160748
  1373
    MOZ_ASSERT(false, "Failed to dispatch response!");
bent@160748
  1374
  }
bent@160748
  1375
bent@160748
  1376
  mProxy->mSyncEventResponseTarget.swap(tempTarget);
bent@160748
  1377
bent@160748
  1378
  return NS_OK;
bent@160748
  1379
}
bent@160748
  1380
bent@160748
  1381
nsresult
bent@160748
  1382
AbortRunnable::MainThreadRun()
bent@160748
  1383
{
bent@160748
  1384
  mProxy->mInnerEventStreamId++;
bent@160748
  1385
bent@160748
  1386
  WorkerPrivate* oldWorker = mProxy->mWorkerPrivate;
bent@160748
  1387
  mProxy->mWorkerPrivate = mWorkerPrivate;
bent@160748
  1388
bent@160748
  1389
  mProxy->mXHR->Abort();
bent@160748
  1390
bent@160748
  1391
  mProxy->mWorkerPrivate = oldWorker;
bent@160748
  1392
bent@160748
  1393
  mProxy->Reset();
bent@160748
  1394
bent@160748
  1395
  return NS_OK;
bent@160748
  1396
}
bent@160748
  1397
bent@160748
  1398
nsresult
bent@160748
  1399
OpenRunnable::MainThreadRunInternal()
bent@160748
  1400
{
bent@160748
  1401
  if (!mProxy->Init()) {
bent@160748
  1402
    return NS_ERROR_DOM_INVALID_STATE_ERR;
bent@160748
  1403
  }
bent@160748
  1404
bent@160748
  1405
  nsresult rv;
bent@160748
  1406
bent@160748
  1407
  if (mBackgroundRequest) {
bent@160748
  1408
    rv = mProxy->mXHR->SetMozBackgroundRequest(mBackgroundRequest);
bent@160748
  1409
    NS_ENSURE_SUCCESS(rv, rv);
bent@160748
  1410
  }
bent@160748
  1411
bent@160748
  1412
  if (mWithCredentials) {
bent@160748
  1413
    rv = mProxy->mXHR->SetWithCredentials(mWithCredentials);
bent@160748
  1414
    NS_ENSURE_SUCCESS(rv, rv);
bent@160748
  1415
  }
bent@160748
  1416
bent@160748
  1417
  if (mTimeout) {
bent@160748
  1418
    rv = mProxy->mXHR->SetTimeout(mTimeout);
bent@160748
  1419
    NS_ENSURE_SUCCESS(rv, rv);
bent@160748
  1420
  }
bent@160748
  1421
bent@160748
  1422
  MOZ_ASSERT(!mProxy->mInOpen);
bent@160748
  1423
  mProxy->mInOpen = true;
bent@160748
  1424
bent@160748
  1425
  ErrorResult rv2;
bent@160748
  1426
  mProxy->mXHR->Open(mMethod, mURL, true, mUser, mPassword, rv2);
bent@160748
  1427
bent@160748
  1428
  MOZ_ASSERT(mProxy->mInOpen);
bent@160748
  1429
  mProxy->mInOpen = false;
bent@160748
  1430
bent@160748
  1431
  if (rv2.Failed()) {
bent@160748
  1432
    return rv2.ErrorCode();
bent@160748
  1433
  }
bent@160748
  1434
bent@160748
  1435
  return mProxy->mXHR->SetResponseType(NS_LITERAL_STRING("text"));
bent@160748
  1436
}
bent@160748
  1437
bent@160748
  1438
bent@160748
  1439
nsresult
bent@160748
  1440
SendRunnable::MainThreadRun()
bent@160748
  1441
{
bent@160748
  1442
  nsCOMPtr<nsIVariant> variant;
bent@160748
  1443
bent@160748
  1444
  if (mBody.data()) {
bent@160748
  1445
    AutoSafeJSContext cx;
bent@160748
  1446
    JSAutoRequest ar(cx);
bent@160748
  1447
bent@160748
  1448
    nsIXPConnect* xpc = nsContentUtils::XPConnect();
bent@160748
  1449
    MOZ_ASSERT(xpc);
bent@160748
  1450
bent@160748
  1451
    nsresult rv = NS_OK;
bent@160748
  1452
bent@160748
  1453
    JSStructuredCloneCallbacks* callbacks =
bent@160748
  1454
      mWorkerPrivate->IsChromeWorker() ?
bent@160748
  1455
      ChromeWorkerStructuredCloneCallbacks(true) :
bent@160748
  1456
      WorkerStructuredCloneCallbacks(true);
bent@160748
  1457
bent@160748
  1458
    JS::Rooted<JS::Value> body(cx);
bent@160748
  1459
    if (mBody.read(cx, &body, callbacks, &mClonedObjects)) {
evilpies@163761
  1460
      if (NS_FAILED(xpc->JSValToVariant(cx, body, getter_AddRefs(variant)))) {
bent@160748
  1461
        rv = NS_ERROR_DOM_INVALID_STATE_ERR;
bent@160748
  1462
      }
bent@160748
  1463
    }
bent@160748
  1464
    else {
bent@160748
  1465
      rv = NS_ERROR_DOM_DATA_CLONE_ERR;
bent@160748
  1466
    }
bent@160748
  1467
bent@160748
  1468
    mBody.clear();
bent@160748
  1469
    mClonedObjects.Clear();
bent@160748
  1470
bent@160748
  1471
    NS_ENSURE_SUCCESS(rv, rv);
bent@160748
  1472
  }
bent@160748
  1473
  else {
bent@160748
  1474
    nsCOMPtr<nsIWritableVariant> wvariant =
bent@160748
  1475
      do_CreateInstance(NS_VARIANT_CONTRACTID);
bent@160748
  1476
    NS_ENSURE_TRUE(wvariant, NS_ERROR_UNEXPECTED);
bent@160748
  1477
bent@160748
  1478
    if (NS_FAILED(wvariant->SetAsAString(mStringBody))) {
bent@160748
  1479
      MOZ_ASSERT(false, "This should never fail!");
bent@160748
  1480
    }
bent@160748
  1481
bent@160748
  1482
    variant = wvariant;
bent@160748
  1483
  }
bent@160748
  1484
bent@160748
  1485
  MOZ_ASSERT(!mProxy->mWorkerPrivate);
bent@160748
  1486
  mProxy->mWorkerPrivate = mWorkerPrivate;
bent@160748
  1487
bent@160748
  1488
  MOZ_ASSERT(!mProxy->mSyncLoopTarget);
bent@160748
  1489
  mProxy->mSyncLoopTarget.swap(mSyncLoopTarget);
bent@160748
  1490
bent@160748
  1491
  if (mHasUploadListeners) {
bent@160748
  1492
    NS_ASSERTION(!mProxy->mUploadEventListenersAttached, "Huh?!");
bent@160748
  1493
    if (!mProxy->AddRemoveEventListeners(true, true)) {
bent@160748
  1494
      MOZ_ASSERT(false, "This should never fail!");
bent@160748
  1495
    }
bent@160748
  1496
  }
bent@160748
  1497
bent@160748
  1498
  mProxy->mInnerChannelId++;
bent@160748
  1499
bent@160748
  1500
  nsresult rv = mProxy->mXHR->Send(variant);
bent@160748
  1501
bent@160748
  1502
  if (NS_SUCCEEDED(rv)) {
bent@160748
  1503
    mProxy->mOutstandingSendCount++;
bent@160748
  1504
bent@160748
  1505
    if (!mHasUploadListeners) {
bent@160748
  1506
      NS_ASSERTION(!mProxy->mUploadEventListenersAttached, "Huh?!");
bent@160748
  1507
      if (!mProxy->AddRemoveEventListeners(true, true)) {
bent@160748
  1508
        MOZ_ASSERT(false, "This should never fail!");
bent@160748
  1509
      }
bent@160748
  1510
    }
bent@160748
  1511
  }
bent@160748
  1512
bent@160748
  1513
  return rv;
bent@160748
  1514
}
bent@160748
  1515
khuey@153626
  1516
XMLHttpRequest::XMLHttpRequest(WorkerPrivate* aWorkerPrivate)
khuey@153626
  1517
: mWorkerPrivate(aWorkerPrivate),
froydnj@131123
  1518
  mResponseType(XMLHttpRequestResponseType::Text), mTimeout(0),
khuey@153626
  1519
  mRooted(false), mBackgroundRequest(false), mWithCredentials(false),
khuey@153626
  1520
  mCanceled(false), mMozAnon(false), mMozSystem(false)
bent@72705
  1521
{
peterv@90770
  1522
  mWorkerPrivate->AssertIsOnWorkerThread();
khuey@153626
  1523
khuey@153626
  1524
  SetIsDOMBinding();
peterv@90770
  1525
}
peterv@90770
  1526
peterv@90770
  1527
XMLHttpRequest::~XMLHttpRequest()
peterv@90770
  1528
{
peterv@90770
  1529
  mWorkerPrivate->AssertIsOnWorkerThread();
khuey@153626
  1530
khuey@153626
  1531
  ReleaseProxy(XHRIsGoingAway);
khuey@153626
  1532
khuey@153626
  1533
  MOZ_ASSERT(!mRooted);
khuey@153626
  1534
khuey@153626
  1535
  mozilla::DropJSObjects(this);
peterv@90770
  1536
}
peterv@90770
  1537
khuey@153626
  1538
NS_IMPL_ADDREF_INHERITED(XMLHttpRequest, nsXHREventTarget)
khuey@153626
  1539
NS_IMPL_RELEASE_INHERITED(XMLHttpRequest, nsXHREventTarget)
khuey@153626
  1540
khuey@153626
  1541
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(XMLHttpRequest)
khuey@153626
  1542
NS_INTERFACE_MAP_END_INHERITING(nsXHREventTarget)
khuey@153626
  1543
khuey@153626
  1544
NS_IMPL_CYCLE_COLLECTION_CLASS(XMLHttpRequest)
khuey@153626
  1545
khuey@153626
  1546
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(XMLHttpRequest,
khuey@153626
  1547
                                                  nsXHREventTarget)
khuey@153626
  1548
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mUpload)
khuey@153626
  1549
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
khuey@153626
  1550
khuey@153626
  1551
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(XMLHttpRequest,
khuey@153626
  1552
                                                nsXHREventTarget)
khuey@153626
  1553
  tmp->ReleaseProxy(XHRIsGoingAway);
khuey@153626
  1554
  NS_IMPL_CYCLE_COLLECTION_UNLINK(mUpload)
bent@169776
  1555
  tmp->mStateData.mResponse.setUndefined();
khuey@153626
  1556
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
khuey@153626
  1557
khuey@153626
  1558
NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(XMLHttpRequest,
khuey@153626
  1559
                                               nsXHREventTarget)
khuey@153626
  1560
  NS_IMPL_CYCLE_COLLECTION_TRACE_JSVAL_MEMBER_CALLBACK(mStateData.mResponse)
khuey@153626
  1561
NS_IMPL_CYCLE_COLLECTION_TRACE_END
khuey@153626
  1562
khuey@153626
  1563
JSObject*
bzbarsky@177628
  1564
XMLHttpRequest::WrapObject(JSContext* aCx)
peterv@90770
  1565
{
bzbarsky@177626
  1566
  return XMLHttpRequestBinding_workers::Wrap(aCx, this);
peterv@90770
  1567
}
peterv@90770
  1568
peterv@90770
  1569
// static
khuey@153626
  1570
already_AddRefed<XMLHttpRequest>
khuey@144016
  1571
XMLHttpRequest::Constructor(const GlobalObject& aGlobal,
khuey@144017
  1572
                            const MozXMLHttpRequestParameters& aParams,
ryanvm@96331
  1573
                            ErrorResult& aRv)
peterv@90770
  1574
{
peterv@120081
  1575
  JSContext* cx = aGlobal.GetContext();
peterv@120081
  1576
  WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(cx);
peterv@90770
  1577
  MOZ_ASSERT(workerPrivate);
peterv@90770
  1578
khuey@153626
  1579
  nsRefPtr<XMLHttpRequest> xhr = new XMLHttpRequest(workerPrivate);
peterv@90770
  1580
amarchesini@107196
  1581
  if (workerPrivate->XHRParamsAllowed()) {
mwargers@159007
  1582
    if (aParams.mMozSystem)
mwargers@159007
  1583
      xhr->mMozAnon = true;
mwargers@159007
  1584
    else
mwargers@159007
  1585
      xhr->mMozAnon = aParams.mMozAnon;
wchen@116330
  1586
    xhr->mMozSystem = aParams.mMozSystem;
amarchesini@107196
  1587
  }
ryanvm@96331
  1588
khuey@153626
  1589
  return xhr.forget();
peterv@90770
  1590
}
peterv@90770
  1591
peterv@90770
  1592
void
peterv@90770
  1593
XMLHttpRequest::ReleaseProxy(ReleaseType aType)
peterv@90770
  1594
{
peterv@90770
  1595
  // Can't assert that we're on the worker thread here because mWorkerPrivate
peterv@90770
  1596
  // may be gone.
peterv@90770
  1597
peterv@90770
  1598
  if (mProxy) {
peterv@90770
  1599
    if (aType == XHRIsGoingAway) {
peterv@90770
  1600
      // We're in a GC finalizer, so we can't do a sync call here (and we don't
peterv@90770
  1601
      // need to).
peterv@90770
  1602
      nsRefPtr<AsyncTeardownRunnable> runnable =
peterv@90770
  1603
        new AsyncTeardownRunnable(mProxy);
ayg@100844
  1604
      mProxy = nullptr;
peterv@90770
  1605
ayg@102538
  1606
      if (NS_FAILED(NS_DispatchToMainThread(runnable))) {
peterv@90770
  1607
        NS_ERROR("Failed to dispatch teardown runnable!");
peterv@90770
  1608
      }
peterv@90770
  1609
    } else {
peterv@90770
  1610
      // This isn't necessary if the worker is going away or the XHR is going
peterv@90770
  1611
      // away.
peterv@90770
  1612
      if (aType == Default) {
peterv@90770
  1613
        // Don't let any more events run.
peterv@90770
  1614
        mProxy->mOuterEventStreamId++;
peterv@90770
  1615
      }
peterv@90770
  1616
peterv@90770
  1617
      // We need to make a sync call here.
peterv@90770
  1618
      nsRefPtr<SyncTeardownRunnable> runnable =
peterv@90770
  1619
        new SyncTeardownRunnable(mWorkerPrivate, mProxy);
ayg@100844
  1620
      mProxy = nullptr;
peterv@90770
  1621
ayg@100844
  1622
      if (!runnable->Dispatch(nullptr)) {
peterv@90770
  1623
        NS_ERROR("Failed to dispatch teardown runnable!");
peterv@90770
  1624
      }
peterv@90770
  1625
    }
peterv@90770
  1626
  }
peterv@90770
  1627
}
peterv@90770
  1628
peterv@90770
  1629
void
bzbarsky@93311
  1630
XMLHttpRequest::MaybePin(ErrorResult& aRv)
peterv@90770
  1631
{
peterv@90770
  1632
  mWorkerPrivate->AssertIsOnWorkerThread();
peterv@90770
  1633
khuey@153626
  1634
  if (mRooted) {
peterv@90770
  1635
    return;
peterv@90770
  1636
  }
peterv@90770
  1637
khuey@153626
  1638
  JSContext* cx = GetCurrentThreadJSContext();
peterv@90770
  1639
khuey@153626
  1640
  if (!mWorkerPrivate->AddFeature(cx, this)) {
ttaubert@165665
  1641
    aRv.Throw(NS_ERROR_FAILURE);
peterv@90770
  1642
    return;
peterv@90770
  1643
  }
peterv@90770
  1644
khuey@153626
  1645
  NS_ADDREF_THIS();
peterv@90770
  1646
khuey@153626
  1647
  mRooted = true;
peterv@90770
  1648
}
peterv@90770
  1649
peterv@90770
  1650
void
bzbarsky@93311
  1651
XMLHttpRequest::MaybeDispatchPrematureAbortEvents(ErrorResult& aRv)
peterv@90770
  1652
{
peterv@90770
  1653
  mWorkerPrivate->AssertIsOnWorkerThread();
peterv@90770
  1654
  MOZ_ASSERT(mProxy);
peterv@90770
  1655
peterv@90770
  1656
  mStateData.mReadyState = 4;
peterv@90770
  1657
peterv@90770
  1658
  if (mProxy->mSeenUploadLoadStart) {
peterv@90770
  1659
    MOZ_ASSERT(mUpload);
peterv@90770
  1660
khuey@153626
  1661
    DispatchPrematureAbortEvent(mUpload, NS_LITERAL_STRING("abort"), true,
khuey@153626
  1662
                                aRv);
bzbarsky@93311
  1663
    if (aRv.Failed()) {
peterv@90770
  1664
      return;
peterv@90770
  1665
    }
peterv@90770
  1666
khuey@153626
  1667
    DispatchPrematureAbortEvent(mUpload, NS_LITERAL_STRING("loadend"), true,
khuey@153626
  1668
                                aRv);
bzbarsky@93311
  1669
    if (aRv.Failed()) {
peterv@90770
  1670
      return;
peterv@90770
  1671
    }
peterv@90770
  1672
peterv@90770
  1673
    mProxy->mSeenUploadLoadStart = false;
peterv@90770
  1674
  }
peterv@90770
  1675
peterv@90770
  1676
  if (mProxy->mSeenLoadStart) {
khuey@153626
  1677
    DispatchPrematureAbortEvent(this, NS_LITERAL_STRING("readystatechange"),
khuey@153626
  1678
                                false, aRv);
bzbarsky@93311
  1679
    if (aRv.Failed()) {
peterv@90770
  1680
      return;
peterv@90770
  1681
    }
peterv@90770
  1682
khuey@153626
  1683
    DispatchPrematureAbortEvent(this, NS_LITERAL_STRING("abort"), false, aRv);
bzbarsky@93311
  1684
    if (aRv.Failed()) {
peterv@90770
  1685
      return;
peterv@90770
  1686
    }
peterv@90770
  1687
khuey@153626
  1688
    DispatchPrematureAbortEvent(this, NS_LITERAL_STRING("loadend"), false,
khuey@153626
  1689
                                aRv);
bzbarsky@93311
  1690
    if (aRv.Failed()) {
peterv@90770
  1691
      return;
peterv@90770
  1692
    }
peterv@90770
  1693
peterv@90770
  1694
    mProxy->mSeenLoadStart = false;
peterv@90770
  1695
  }
peterv@90770
  1696
}
peterv@90770
  1697
peterv@90770
  1698
void
khuey@153626
  1699
XMLHttpRequest::DispatchPrematureAbortEvent(EventTarget* aTarget,
khuey@153626
  1700
                                            const nsAString& aEventType,
bzbarsky@93311
  1701
                                            bool aUploadTarget,
bzbarsky@93311
  1702
                                            ErrorResult& aRv)
peterv@90770
  1703
{
peterv@90770
  1704
  mWorkerPrivate->AssertIsOnWorkerThread();
peterv@90770
  1705
  MOZ_ASSERT(aTarget);
peterv@90770
  1706
ms2ger@100496
  1707
  if (!mProxy) {
ms2ger@100496
  1708
    aRv.Throw(NS_ERROR_FAILURE);
ms2ger@100496
  1709
    return;
ms2ger@100496
  1710
  }
ms2ger@100496
  1711
khuey@153626
  1712
  nsCOMPtr<nsIDOMEvent> event;
khuey@153626
  1713
  if (aEventType.EqualsLiteral("readystatechange")) {
khuey@153626
  1714
    NS_NewDOMEvent(getter_AddRefs(event), aTarget, nullptr, nullptr);
peterv@90770
  1715
khuey@153626
  1716
    if (event) {
khuey@153626
  1717
      event->InitEvent(aEventType, false, false);
khuey@153626
  1718
    }
peterv@90770
  1719
  }
peterv@90770
  1720
  else {
khuey@153626
  1721
    NS_NewDOMProgressEvent(getter_AddRefs(event), aTarget, nullptr, nullptr);
khuey@153626
  1722
khuey@153626
  1723
    nsCOMPtr<nsIDOMProgressEvent> progress = do_QueryInterface(event);
khuey@153626
  1724
    if (progress) {
khuey@153626
  1725
      if (aUploadTarget) {
khuey@153626
  1726
        progress->InitProgressEvent(aEventType, false, false,
khuey@153626
  1727
                                    mProxy->mLastUploadLengthComputable,
khuey@153626
  1728
                                    mProxy->mLastUploadLoaded,
khuey@153626
  1729
                                    mProxy->mLastUploadTotal);
khuey@153626
  1730
      }
khuey@153626
  1731
      else {
khuey@153626
  1732
        progress->InitProgressEvent(aEventType, false, false,
khuey@153626
  1733
                                    mProxy->mLastLengthComputable,
khuey@153626
  1734
                                    mProxy->mLastLoaded,
khuey@153626
  1735
                                    mProxy->mLastTotal);
khuey@153626
  1736
      }
khuey@153626
  1737
    }
peterv@90770
  1738
  }
peterv@90770
  1739
peterv@90770
  1740
  if (!event) {
bzbarsky@93311
  1741
    aRv.Throw(NS_ERROR_FAILURE);
peterv@90770
  1742
    return;
peterv@90770
  1743
  }
peterv@90770
  1744
khuey@153626
  1745
  event->SetTrusted(true);
khuey@153626
  1746
khuey@153626
  1747
  aTarget->DispatchDOMEvent(nullptr, event, nullptr, nullptr);
peterv@90770
  1748
}
peterv@90770
  1749
peterv@90770
  1750
void
peterv@90770
  1751
XMLHttpRequest::Unpin()
peterv@90770
  1752
{
peterv@90770
  1753
  mWorkerPrivate->AssertIsOnWorkerThread();
peterv@90770
  1754
khuey@153626
  1755
  MOZ_ASSERT(mRooted, "Mismatched calls to Unpin!");
peterv@90770
  1756
khuey@153626
  1757
  JSContext* cx = GetCurrentThreadJSContext();
peterv@90770
  1758
peterv@90770
  1759
  mWorkerPrivate->RemoveFeature(cx, this);
peterv@90770
  1760
khuey@153626
  1761
  mRooted = false;
khuey@153626
  1762
khuey@153626
  1763
  NS_RELEASE_THIS();
peterv@90770
  1764
}
peterv@90770
  1765
peterv@90770
  1766
void
peterv@90770
  1767
XMLHttpRequest::SendInternal(const nsAString& aStringBody,
khuey@166499
  1768
                             JSAutoStructuredCloneBuffer&& aBody,
peterv@90770
  1769
                             nsTArray<nsCOMPtr<nsISupports> >& aClonedObjects,
bzbarsky@93311
  1770
                             ErrorResult& aRv)
peterv@90770
  1771
{
peterv@90770
  1772
  mWorkerPrivate->AssertIsOnWorkerThread();
peterv@90770
  1773
peterv@90770
  1774
  bool hasUploadListeners = mUpload ? mUpload->HasListeners() : false;
peterv@90770
  1775
peterv@90770
  1776
  MaybePin(aRv);
bzbarsky@93311