LCOV - code coverage report
Current view: top level - dom/workers - ServiceWorkerEvents.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 610 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 100 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
       3             : /* This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       5             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : #include "ServiceWorkerEvents.h"
       8             : 
       9             : #include "nsAutoPtr.h"
      10             : #include "nsIConsoleReportCollector.h"
      11             : #include "nsIHttpChannelInternal.h"
      12             : #include "nsINetworkInterceptController.h"
      13             : #include "nsIOutputStream.h"
      14             : #include "nsIScriptError.h"
      15             : #include "nsITimedChannel.h"
      16             : #include "mozilla/Encoding.h"
      17             : #include "nsContentPolicyUtils.h"
      18             : #include "nsContentUtils.h"
      19             : #include "nsComponentManagerUtils.h"
      20             : #include "nsServiceManagerUtils.h"
      21             : #include "nsStreamUtils.h"
      22             : #include "nsNetCID.h"
      23             : #include "nsNetUtil.h"
      24             : #include "nsSerializationHelper.h"
      25             : #include "nsQueryObject.h"
      26             : #include "ServiceWorkerClient.h"
      27             : #include "ServiceWorkerManager.h"
      28             : 
      29             : #include "mozilla/ErrorResult.h"
      30             : #include "mozilla/LoadInfo.h"
      31             : #include "mozilla/Preferences.h"
      32             : #include "mozilla/dom/BodyUtil.h"
      33             : #include "mozilla/dom/DOMException.h"
      34             : #include "mozilla/dom/DOMExceptionBinding.h"
      35             : #include "mozilla/dom/FetchEventBinding.h"
      36             : #include "mozilla/dom/MessagePort.h"
      37             : #include "mozilla/dom/PromiseNativeHandler.h"
      38             : #include "mozilla/dom/PushEventBinding.h"
      39             : #include "mozilla/dom/PushMessageDataBinding.h"
      40             : #include "mozilla/dom/PushUtil.h"
      41             : #include "mozilla/dom/Request.h"
      42             : #include "mozilla/dom/TypedArray.h"
      43             : #include "mozilla/dom/Response.h"
      44             : #include "mozilla/dom/WorkerScope.h"
      45             : #include "mozilla/dom/workers/bindings/ServiceWorker.h"
      46             : 
      47             : #include "js/Conversions.h"
      48             : #include "js/TypeDecls.h"
      49             : #include "WorkerPrivate.h"
      50             : #include "xpcpublic.h"
      51             : 
      52             : using namespace mozilla::dom;
      53             : using namespace mozilla::dom::workers;
      54             : 
      55             : namespace {
      56             : 
      57             : void
      58           0 : AsyncLog(nsIInterceptedChannel *aInterceptedChannel,
      59             :          const nsACString& aRespondWithScriptSpec,
      60             :          uint32_t aRespondWithLineNumber, uint32_t aRespondWithColumnNumber,
      61             :          const nsACString& aMessageName, const nsTArray<nsString>& aParams)
      62             : {
      63           0 :   MOZ_ASSERT(aInterceptedChannel);
      64             :   nsCOMPtr<nsIConsoleReportCollector> reporter =
      65           0 :     aInterceptedChannel->GetConsoleReportCollector();
      66           0 :   if (reporter) {
      67           0 :     reporter->AddConsoleReport(nsIScriptError::errorFlag,
      68           0 :                                NS_LITERAL_CSTRING("Service Worker Interception"),
      69             :                                nsContentUtils::eDOM_PROPERTIES,
      70             :                                aRespondWithScriptSpec,
      71             :                                aRespondWithLineNumber,
      72             :                                aRespondWithColumnNumber,
      73           0 :                                aMessageName, aParams);
      74             :   }
      75           0 : }
      76             : 
      77             : template<typename... Params>
      78             : void
      79           0 : AsyncLog(nsIInterceptedChannel* aInterceptedChannel,
      80             :          const nsACString& aRespondWithScriptSpec,
      81             :          uint32_t aRespondWithLineNumber, uint32_t aRespondWithColumnNumber,
      82             :          // We have to list one explicit string so that calls with an
      83             :          // nsTArray of params won't end up in here.
      84             :          const nsACString& aMessageName, const nsAString& aFirstParam,
      85             :          Params&&... aParams)
      86             : {
      87           0 :   nsTArray<nsString> paramsList(sizeof...(Params) + 1);
      88           0 :   StringArrayAppender::Append(paramsList, sizeof...(Params) + 1,
      89             :                               aFirstParam, Forward<Params>(aParams)...);
      90           0 :   AsyncLog(aInterceptedChannel, aRespondWithScriptSpec, aRespondWithLineNumber,
      91             :            aRespondWithColumnNumber, aMessageName, paramsList);
      92           0 : }
      93             : 
      94             : } // anonymous namespace
      95             : 
      96             : BEGIN_WORKERS_NAMESPACE
      97             : 
      98           0 : CancelChannelRunnable::CancelChannelRunnable(
      99             :   nsMainThreadPtrHandle<nsIInterceptedChannel>& aChannel,
     100             :   nsMainThreadPtrHandle<ServiceWorkerRegistrationInfo>& aRegistration,
     101           0 :   nsresult aStatus)
     102             :   : Runnable("dom::workers::CancelChannelRunnable")
     103             :   , mChannel(aChannel)
     104             :   , mRegistration(aRegistration)
     105           0 :   , mStatus(aStatus)
     106             : {
     107           0 : }
     108             : 
     109             : NS_IMETHODIMP
     110           0 : CancelChannelRunnable::Run()
     111             : {
     112           0 :   MOZ_ASSERT(NS_IsMainThread());
     113             : 
     114             :   // TODO: When bug 1204254 is implemented, this time marker should be moved to
     115             :   // the point where the body of the network request is complete.
     116           0 :   mChannel->SetHandleFetchEventEnd(TimeStamp::Now());
     117           0 :   mChannel->SaveTimeStamps();
     118             : 
     119           0 :   mChannel->Cancel(mStatus);
     120           0 :   mRegistration->MaybeScheduleUpdate();
     121           0 :   return NS_OK;
     122             : }
     123             : 
     124           0 : FetchEvent::FetchEvent(EventTarget* aOwner)
     125             :   : ExtendableEvent(aOwner)
     126             :   , mPreventDefaultLineNumber(0)
     127             :   , mPreventDefaultColumnNumber(0)
     128             :   , mIsReload(false)
     129           0 :   , mWaitToRespond(false)
     130             : {
     131           0 : }
     132             : 
     133           0 : FetchEvent::~FetchEvent()
     134             : {
     135           0 : }
     136             : 
     137             : void
     138           0 : FetchEvent::PostInit(nsMainThreadPtrHandle<nsIInterceptedChannel>& aChannel,
     139             :                      nsMainThreadPtrHandle<ServiceWorkerRegistrationInfo>& aRegistration,
     140             :                      const nsACString& aScriptSpec)
     141             : {
     142           0 :   mChannel = aChannel;
     143           0 :   mRegistration = aRegistration;
     144           0 :   mScriptSpec.Assign(aScriptSpec);
     145           0 : }
     146             : 
     147             : /*static*/ already_AddRefed<FetchEvent>
     148           0 : FetchEvent::Constructor(const GlobalObject& aGlobal,
     149             :                         const nsAString& aType,
     150             :                         const FetchEventInit& aOptions,
     151             :                         ErrorResult& aRv)
     152             : {
     153           0 :   RefPtr<EventTarget> owner = do_QueryObject(aGlobal.GetAsSupports());
     154           0 :   MOZ_ASSERT(owner);
     155           0 :   RefPtr<FetchEvent> e = new FetchEvent(owner);
     156           0 :   bool trusted = e->Init(owner);
     157           0 :   e->InitEvent(aType, aOptions.mBubbles, aOptions.mCancelable);
     158           0 :   e->SetTrusted(trusted);
     159           0 :   e->SetComposed(aOptions.mComposed);
     160           0 :   e->mRequest = aOptions.mRequest;
     161           0 :   e->mClientId = aOptions.mClientId;
     162           0 :   e->mIsReload = aOptions.mIsReload;
     163           0 :   return e.forget();
     164             : }
     165             : 
     166             : namespace {
     167             : 
     168           0 : class FinishResponse final : public Runnable
     169             : {
     170             :   nsMainThreadPtrHandle<nsIInterceptedChannel> mChannel;
     171             :   RefPtr<InternalResponse> mInternalResponse;
     172             :   ChannelInfo mWorkerChannelInfo;
     173             :   const nsCString mScriptSpec;
     174             :   const nsCString mResponseURLSpec;
     175             : 
     176             : public:
     177           0 :   FinishResponse(nsMainThreadPtrHandle<nsIInterceptedChannel>& aChannel,
     178             :                  InternalResponse* aInternalResponse,
     179             :                  const ChannelInfo& aWorkerChannelInfo,
     180             :                  const nsACString& aScriptSpec,
     181             :                  const nsACString& aResponseURLSpec)
     182           0 :     : Runnable("dom::workers::FinishResponse")
     183             :     , mChannel(aChannel)
     184             :     , mInternalResponse(aInternalResponse)
     185             :     , mWorkerChannelInfo(aWorkerChannelInfo)
     186             :     , mScriptSpec(aScriptSpec)
     187           0 :     , mResponseURLSpec(aResponseURLSpec)
     188             :   {
     189           0 :   }
     190             : 
     191             :   NS_IMETHOD
     192           0 :   Run() override
     193             :   {
     194           0 :     AssertIsOnMainThread();
     195             : 
     196           0 :     nsCOMPtr<nsIChannel> underlyingChannel;
     197           0 :     nsresult rv = mChannel->GetChannel(getter_AddRefs(underlyingChannel));
     198           0 :     NS_ENSURE_SUCCESS(rv, rv);
     199           0 :     NS_ENSURE_TRUE(underlyingChannel, NS_ERROR_UNEXPECTED);
     200           0 :     nsCOMPtr<nsILoadInfo> loadInfo = underlyingChannel->GetLoadInfo();
     201             : 
     202           0 :     if (!loadInfo || !CSPPermitsResponse(loadInfo)) {
     203           0 :       mChannel->Cancel(NS_ERROR_CONTENT_BLOCKED);
     204           0 :       return NS_OK;
     205             :     }
     206             : 
     207           0 :     ChannelInfo channelInfo;
     208           0 :     if (mInternalResponse->GetChannelInfo().IsInitialized()) {
     209           0 :       channelInfo = mInternalResponse->GetChannelInfo();
     210             :     } else {
     211             :       // We are dealing with a synthesized response here, so fall back to the
     212             :       // channel info for the worker script.
     213           0 :       channelInfo = mWorkerChannelInfo;
     214             :     }
     215           0 :     rv = mChannel->SetChannelInfo(&channelInfo);
     216           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
     217           0 :       mChannel->Cancel(NS_ERROR_INTERCEPTION_FAILED);
     218           0 :       return NS_OK;
     219             :     }
     220             : 
     221           0 :     rv = mChannel->SynthesizeStatus(mInternalResponse->GetUnfilteredStatus(),
     222           0 :                                     mInternalResponse->GetUnfilteredStatusText());
     223           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
     224           0 :       mChannel->Cancel(NS_ERROR_INTERCEPTION_FAILED);
     225           0 :       return NS_OK;
     226             :     }
     227             : 
     228           0 :     AutoTArray<InternalHeaders::Entry, 5> entries;
     229           0 :     mInternalResponse->UnfilteredHeaders()->GetEntries(entries);
     230           0 :     for (uint32_t i = 0; i < entries.Length(); ++i) {
     231           0 :        mChannel->SynthesizeHeader(entries[i].mName, entries[i].mValue);
     232             :     }
     233             : 
     234           0 :     auto castLoadInfo = static_cast<LoadInfo*>(loadInfo.get());
     235           0 :     castLoadInfo->SynthesizeServiceWorkerTainting(mInternalResponse->GetTainting());
     236             : 
     237           0 :     rv = mChannel->FinishSynthesizedResponse(mResponseURLSpec);
     238           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
     239           0 :       mChannel->Cancel(NS_ERROR_INTERCEPTION_FAILED);
     240           0 :       return NS_OK;
     241             :     }
     242             : 
     243           0 :     TimeStamp timeStamp = TimeStamp::Now();
     244           0 :     mChannel->SetHandleFetchEventEnd(timeStamp);
     245           0 :     mChannel->SetFinishSynthesizedResponseEnd(timeStamp);
     246           0 :     mChannel->SaveTimeStamps();
     247             : 
     248           0 :     nsCOMPtr<nsIObserverService> obsService = services::GetObserverService();
     249           0 :     if (obsService) {
     250           0 :       obsService->NotifyObservers(underlyingChannel, "service-worker-synthesized-response", nullptr);
     251             :     }
     252             : 
     253           0 :     return rv;
     254             :   }
     255           0 :   bool CSPPermitsResponse(nsILoadInfo* aLoadInfo)
     256             :   {
     257           0 :     AssertIsOnMainThread();
     258           0 :     MOZ_ASSERT(aLoadInfo);
     259             :     nsresult rv;
     260           0 :     nsCOMPtr<nsIURI> uri;
     261           0 :     nsCString url = mInternalResponse->GetUnfilteredURL();
     262           0 :     if (url.IsEmpty()) {
     263             :       // Synthetic response. The buck stops at the worker script.
     264           0 :       url = mScriptSpec;
     265             :     }
     266           0 :     rv = NS_NewURI(getter_AddRefs(uri), url, nullptr, nullptr);
     267           0 :     NS_ENSURE_SUCCESS(rv, false);
     268           0 :     int16_t decision = nsIContentPolicy::ACCEPT;
     269           0 :     rv = NS_CheckContentLoadPolicy(aLoadInfo->InternalContentPolicyType(), uri,
     270           0 :                                    aLoadInfo->LoadingPrincipal(),
     271           0 :                                    aLoadInfo->LoadingNode(), EmptyCString(),
     272           0 :                                    nullptr, &decision);
     273           0 :     NS_ENSURE_SUCCESS(rv, false);
     274           0 :     return decision == nsIContentPolicy::ACCEPT;
     275             :   }
     276             : };
     277             : 
     278             : class RespondWithHandler final : public PromiseNativeHandler
     279             : {
     280             :   nsMainThreadPtrHandle<nsIInterceptedChannel> mInterceptedChannel;
     281             :   nsMainThreadPtrHandle<ServiceWorkerRegistrationInfo> mRegistration;
     282             :   const RequestMode mRequestMode;
     283             :   const RequestRedirect mRequestRedirectMode;
     284             : #ifdef DEBUG
     285             :   const bool mIsClientRequest;
     286             : #endif
     287             :   const nsCString mScriptSpec;
     288             :   const nsString mRequestURL;
     289             :   const nsCString mRespondWithScriptSpec;
     290             :   const uint32_t mRespondWithLineNumber;
     291             :   const uint32_t mRespondWithColumnNumber;
     292             :   bool mRequestWasHandled;
     293             : public:
     294             :   NS_DECL_ISUPPORTS
     295             : 
     296           0 :   RespondWithHandler(nsMainThreadPtrHandle<nsIInterceptedChannel>& aChannel,
     297             :                      nsMainThreadPtrHandle<ServiceWorkerRegistrationInfo>& aRegistration,
     298             :                      RequestMode aRequestMode, bool aIsClientRequest,
     299             :                      RequestRedirect aRedirectMode,
     300             :                      const nsACString& aScriptSpec,
     301             :                      const nsAString& aRequestURL,
     302             :                      const nsACString& aRespondWithScriptSpec,
     303             :                      uint32_t aRespondWithLineNumber,
     304             :                      uint32_t aRespondWithColumnNumber)
     305           0 :     : mInterceptedChannel(aChannel)
     306             :     , mRegistration(aRegistration)
     307             :     , mRequestMode(aRequestMode)
     308             :     , mRequestRedirectMode(aRedirectMode)
     309             : #ifdef DEBUG
     310             :     , mIsClientRequest(aIsClientRequest)
     311             : #endif
     312             :     , mScriptSpec(aScriptSpec)
     313             :     , mRequestURL(aRequestURL)
     314             :     , mRespondWithScriptSpec(aRespondWithScriptSpec)
     315             :     , mRespondWithLineNumber(aRespondWithLineNumber)
     316             :     , mRespondWithColumnNumber(aRespondWithColumnNumber)
     317           0 :     , mRequestWasHandled(false)
     318             :   {
     319           0 :   }
     320             : 
     321             :   void ResolvedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) override;
     322             : 
     323             :   void RejectedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) override;
     324             : 
     325             :   void CancelRequest(nsresult aStatus);
     326             : 
     327           0 :   void AsyncLog(const nsACString& aMessageName, const nsTArray<nsString>& aParams)
     328             :   {
     329           0 :     ::AsyncLog(mInterceptedChannel, mRespondWithScriptSpec, mRespondWithLineNumber,
     330           0 :                mRespondWithColumnNumber, aMessageName, aParams);
     331           0 :   }
     332             : 
     333           0 :   void AsyncLog(const nsACString& aSourceSpec, uint32_t aLine, uint32_t aColumn,
     334             :                 const nsACString& aMessageName, const nsTArray<nsString>& aParams)
     335             :   {
     336           0 :     ::AsyncLog(mInterceptedChannel, aSourceSpec, aLine, aColumn, aMessageName,
     337           0 :                aParams);
     338           0 :   }
     339             : 
     340             : private:
     341           0 :   ~RespondWithHandler()
     342           0 :   {
     343           0 :     if (!mRequestWasHandled) {
     344           0 :       ::AsyncLog(mInterceptedChannel, mRespondWithScriptSpec,
     345           0 :                  mRespondWithLineNumber, mRespondWithColumnNumber,
     346           0 :                  NS_LITERAL_CSTRING("InterceptionFailedWithURL"), mRequestURL);
     347           0 :       CancelRequest(NS_ERROR_INTERCEPTION_FAILED);
     348             :     }
     349           0 :   }
     350             : };
     351             : 
     352           0 : struct RespondWithClosure
     353             : {
     354             :   nsMainThreadPtrHandle<nsIInterceptedChannel> mInterceptedChannel;
     355             :   nsMainThreadPtrHandle<ServiceWorkerRegistrationInfo> mRegistration;
     356             :   RefPtr<InternalResponse> mInternalResponse;
     357             :   ChannelInfo mWorkerChannelInfo;
     358             :   const nsCString mScriptSpec;
     359             :   const nsCString mResponseURLSpec;
     360             :   const nsString mRequestURL;
     361             :   const nsCString mRespondWithScriptSpec;
     362             :   const uint32_t mRespondWithLineNumber;
     363             :   const uint32_t mRespondWithColumnNumber;
     364             : 
     365           0 :   RespondWithClosure(nsMainThreadPtrHandle<nsIInterceptedChannel>& aChannel,
     366             :                      nsMainThreadPtrHandle<ServiceWorkerRegistrationInfo>& aRegistration,
     367             :                      InternalResponse* aInternalResponse,
     368             :                      const ChannelInfo& aWorkerChannelInfo,
     369             :                      const nsCString& aScriptSpec,
     370             :                      const nsACString& aResponseURLSpec,
     371             :                      const nsAString& aRequestURL,
     372             :                      const nsACString& aRespondWithScriptSpec,
     373             :                      uint32_t aRespondWithLineNumber,
     374             :                      uint32_t aRespondWithColumnNumber)
     375           0 :     : mInterceptedChannel(aChannel)
     376             :     , mRegistration(aRegistration)
     377             :     , mInternalResponse(aInternalResponse)
     378             :     , mWorkerChannelInfo(aWorkerChannelInfo)
     379             :     , mScriptSpec(aScriptSpec)
     380             :     , mResponseURLSpec(aResponseURLSpec)
     381             :     , mRequestURL(aRequestURL)
     382             :     , mRespondWithScriptSpec(aRespondWithScriptSpec)
     383             :     , mRespondWithLineNumber(aRespondWithLineNumber)
     384           0 :     , mRespondWithColumnNumber(aRespondWithColumnNumber)
     385             :   {
     386           0 :   }
     387             : };
     388             : 
     389           0 : void RespondWithCopyComplete(void* aClosure, nsresult aStatus)
     390             : {
     391           0 :   nsAutoPtr<RespondWithClosure> data(static_cast<RespondWithClosure*>(aClosure));
     392           0 :   nsCOMPtr<nsIRunnable> event;
     393           0 :   if (NS_WARN_IF(NS_FAILED(aStatus))) {
     394           0 :     AsyncLog(data->mInterceptedChannel, data->mRespondWithScriptSpec,
     395           0 :              data->mRespondWithLineNumber, data->mRespondWithColumnNumber,
     396           0 :              NS_LITERAL_CSTRING("InterceptionFailedWithURL"),
     397           0 :              data->mRequestURL);
     398           0 :     event = new CancelChannelRunnable(data->mInterceptedChannel,
     399           0 :                                       data->mRegistration,
     400           0 :                                       NS_ERROR_INTERCEPTION_FAILED);
     401             :   } else {
     402           0 :     event = new FinishResponse(data->mInterceptedChannel,
     403           0 :                                data->mInternalResponse,
     404           0 :                                data->mWorkerChannelInfo,
     405           0 :                                data->mScriptSpec,
     406           0 :                                data->mResponseURLSpec);
     407             :   }
     408             :   // In theory this can happen after the worker thread is terminated.
     409           0 :   WorkerPrivate* worker = GetCurrentThreadWorkerPrivate();
     410           0 :   if (worker) {
     411           0 :     MOZ_ALWAYS_SUCCEEDS(worker->DispatchToMainThread(event.forget()));
     412             :   } else {
     413           0 :     MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(event.forget()));
     414             :   }
     415           0 : }
     416             : 
     417             : namespace {
     418             : 
     419             : void
     420           0 : ExtractErrorValues(JSContext* aCx, JS::Handle<JS::Value> aValue,
     421             :                   nsACString& aSourceSpecOut, uint32_t *aLineOut,
     422             :                   uint32_t *aColumnOut, nsString& aMessageOut)
     423             : {
     424           0 :   MOZ_ASSERT(aLineOut);
     425           0 :   MOZ_ASSERT(aColumnOut);
     426             : 
     427           0 :   if (aValue.isObject()) {
     428           0 :     JS::Rooted<JSObject*> obj(aCx, &aValue.toObject());
     429           0 :     RefPtr<DOMException> domException;
     430             : 
     431             :     // Try to process as an Error object.  Use the file/line/column values
     432             :     // from the Error as they will be more specific to the root cause of
     433             :     // the problem.
     434           0 :     JSErrorReport* err = obj ? JS_ErrorFromException(aCx, obj) : nullptr;
     435           0 :     if (err) {
     436             :       // Use xpc to extract the error message only.  We don't actually send
     437             :       // this report anywhere.
     438           0 :       RefPtr<xpc::ErrorReport> report = new xpc::ErrorReport();
     439           0 :       report->Init(err,
     440             :                    "<unknown>", // toString result
     441             :                    false,       // chrome
     442           0 :                    0);          // window ID
     443             : 
     444           0 :       if (!report->mFileName.IsEmpty()) {
     445           0 :         CopyUTF16toUTF8(report->mFileName, aSourceSpecOut);
     446           0 :         *aLineOut = report->mLineNumber;
     447           0 :         *aColumnOut = report->mColumn;
     448             :       }
     449           0 :       aMessageOut.Assign(report->mErrorMsg);
     450             :     }
     451             : 
     452             :     // Next, try to unwrap the rejection value as a DOMException.
     453           0 :     else if(NS_SUCCEEDED(UNWRAP_OBJECT(DOMException, obj, domException))) {
     454             : 
     455           0 :       nsAutoString filename;
     456           0 :       domException->GetFilename(aCx, filename);
     457           0 :       if (!filename.IsEmpty()) {
     458           0 :         CopyUTF16toUTF8(filename, aSourceSpecOut);
     459           0 :         *aLineOut = domException->LineNumber(aCx);
     460           0 :         *aColumnOut = domException->ColumnNumber();
     461             :       }
     462             : 
     463           0 :       domException->GetName(aMessageOut);
     464           0 :       aMessageOut.AppendLiteral(": ");
     465             : 
     466           0 :       nsAutoString message;
     467           0 :       domException->GetMessageMoz(message);
     468           0 :       aMessageOut.Append(message);
     469             :     }
     470             :   }
     471             : 
     472             :   // If we could not unwrap a specific error type, then perform default safe
     473             :   // string conversions on primitives.  Objects will result in "[Object]"
     474             :   // unfortunately.
     475           0 :   if (aMessageOut.IsEmpty()) {
     476           0 :     nsAutoJSString jsString;
     477           0 :     if (jsString.init(aCx, aValue)) {
     478           0 :       aMessageOut = jsString;
     479             :     } else {
     480           0 :       JS_ClearPendingException(aCx);
     481             :     }
     482             :   }
     483           0 : }
     484             : 
     485             : } // anonymous namespace
     486             : 
     487             : class MOZ_STACK_CLASS AutoCancel
     488             : {
     489             :   RefPtr<RespondWithHandler> mOwner;
     490             :   nsCString mSourceSpec;
     491             :   uint32_t mLine;
     492             :   uint32_t mColumn;
     493             :   nsCString mMessageName;
     494             :   nsTArray<nsString> mParams;
     495             : 
     496             : public:
     497           0 :   AutoCancel(RespondWithHandler* aOwner, const nsString& aRequestURL)
     498           0 :     : mOwner(aOwner)
     499             :     , mLine(0)
     500             :     , mColumn(0)
     501           0 :     , mMessageName(NS_LITERAL_CSTRING("InterceptionFailedWithURL"))
     502             :   {
     503           0 :     mParams.AppendElement(aRequestURL);
     504           0 :   }
     505             : 
     506           0 :   ~AutoCancel()
     507           0 :   {
     508           0 :     if (mOwner) {
     509           0 :       if (mSourceSpec.IsEmpty()) {
     510           0 :         mOwner->AsyncLog(mMessageName, mParams);
     511             :       } else {
     512           0 :         mOwner->AsyncLog(mSourceSpec, mLine, mColumn, mMessageName, mParams);
     513             :       }
     514           0 :       mOwner->CancelRequest(NS_ERROR_INTERCEPTION_FAILED);
     515             :     }
     516           0 :   }
     517             : 
     518             :   template<typename... Params>
     519           0 :   void SetCancelMessage(const nsACString& aMessageName, Params&&... aParams)
     520             :   {
     521           0 :     MOZ_ASSERT(mOwner);
     522           0 :     MOZ_ASSERT(mMessageName.EqualsLiteral("InterceptionFailedWithURL"));
     523           0 :     MOZ_ASSERT(mParams.Length() == 1);
     524           0 :     mMessageName = aMessageName;
     525           0 :     mParams.Clear();
     526           0 :     StringArrayAppender::Append(mParams, sizeof...(Params),
     527           0 :                                 Forward<Params>(aParams)...);
     528           0 :   }
     529             : 
     530             :   template<typename... Params>
     531           0 :   void SetCancelMessageAndLocation(const nsACString& aSourceSpec,
     532             :                                    uint32_t aLine, uint32_t aColumn,
     533             :                                    const nsACString& aMessageName,
     534             :                                    Params&&... aParams)
     535             :   {
     536           0 :     MOZ_ASSERT(mOwner);
     537           0 :     MOZ_ASSERT(mMessageName.EqualsLiteral("InterceptionFailedWithURL"));
     538           0 :     MOZ_ASSERT(mParams.Length() == 1);
     539             : 
     540           0 :     mSourceSpec = aSourceSpec;
     541           0 :     mLine = aLine;
     542           0 :     mColumn = aColumn;
     543             : 
     544           0 :     mMessageName = aMessageName;
     545           0 :     mParams.Clear();
     546           0 :     StringArrayAppender::Append(mParams, sizeof...(Params),
     547           0 :                                 Forward<Params>(aParams)...);
     548           0 :   }
     549             : 
     550           0 :   void Reset()
     551             :   {
     552           0 :     mOwner = nullptr;
     553           0 :   }
     554             : };
     555             : 
     556           0 : NS_IMPL_ISUPPORTS0(RespondWithHandler)
     557             : 
     558             : void
     559           0 : RespondWithHandler::ResolvedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue)
     560             : {
     561           0 :   AutoCancel autoCancel(this, mRequestURL);
     562           0 :   mInterceptedChannel->SetFinishResponseStart(TimeStamp::Now());
     563             : 
     564           0 :   if (!aValue.isObject()) {
     565           0 :     NS_WARNING("FetchEvent::RespondWith was passed a promise resolved to a non-Object value");
     566             : 
     567           0 :     nsCString sourceSpec;
     568           0 :     uint32_t line = 0;
     569           0 :     uint32_t column = 0;
     570           0 :     nsString valueString;
     571           0 :     ExtractErrorValues(aCx, aValue, sourceSpec, &line, &column, valueString);
     572             : 
     573           0 :     autoCancel.SetCancelMessageAndLocation(sourceSpec, line, column,
     574           0 :                                            NS_LITERAL_CSTRING("InterceptedNonResponseWithURL"),
     575           0 :                                            mRequestURL, valueString);
     576           0 :     return;
     577             :   }
     578             : 
     579           0 :   RefPtr<Response> response;
     580           0 :   nsresult rv = UNWRAP_OBJECT(Response, &aValue.toObject(), response);
     581           0 :   if (NS_FAILED(rv)) {
     582           0 :     nsCString sourceSpec;
     583           0 :     uint32_t line = 0;
     584           0 :     uint32_t column = 0;
     585           0 :     nsString valueString;
     586           0 :     ExtractErrorValues(aCx, aValue, sourceSpec, &line, &column, valueString);
     587             : 
     588           0 :     autoCancel.SetCancelMessageAndLocation(sourceSpec, line, column,
     589           0 :                                            NS_LITERAL_CSTRING("InterceptedNonResponseWithURL"),
     590           0 :                                            mRequestURL, valueString);
     591           0 :     return;
     592             :   }
     593             : 
     594           0 :   WorkerPrivate* worker = GetCurrentThreadWorkerPrivate();
     595           0 :   MOZ_ASSERT(worker);
     596           0 :   worker->AssertIsOnWorkerThread();
     597             : 
     598             :   // Section "HTTP Fetch", step 3.3:
     599             :   //  If one of the following conditions is true, return a network error:
     600             :   //    * response's type is "error".
     601             :   //    * request's mode is not "no-cors" and response's type is "opaque".
     602             :   //    * request's redirect mode is not "manual" and response's type is
     603             :   //      "opaqueredirect".
     604             :   //    * request's redirect mode is not "follow" and response's url list
     605             :   //      has more than one item.
     606             : 
     607           0 :   if (response->Type() == ResponseType::Error) {
     608           0 :     autoCancel.SetCancelMessage(
     609           0 :       NS_LITERAL_CSTRING("InterceptedErrorResponseWithURL"), mRequestURL);
     610           0 :     return;
     611             :   }
     612             : 
     613           0 :   MOZ_ASSERT_IF(mIsClientRequest, mRequestMode == RequestMode::Same_origin ||
     614             :                                   mRequestMode == RequestMode::Navigate);
     615             : 
     616           0 :   if (response->Type() == ResponseType::Opaque && mRequestMode != RequestMode::No_cors) {
     617           0 :     uint32_t mode = static_cast<uint32_t>(mRequestMode);
     618           0 :     NS_ConvertASCIItoUTF16 modeString(RequestModeValues::strings[mode].value,
     619           0 :                                       RequestModeValues::strings[mode].length);
     620             : 
     621           0 :     autoCancel.SetCancelMessage(
     622           0 :       NS_LITERAL_CSTRING("BadOpaqueInterceptionRequestModeWithURL"),
     623           0 :       mRequestURL, modeString);
     624           0 :     return;
     625             :   }
     626             : 
     627           0 :   if (mRequestRedirectMode != RequestRedirect::Manual &&
     628           0 :       response->Type() == ResponseType::Opaqueredirect) {
     629           0 :     autoCancel.SetCancelMessage(
     630           0 :       NS_LITERAL_CSTRING("BadOpaqueRedirectInterceptionWithURL"), mRequestURL);
     631           0 :     return;
     632             :   }
     633             : 
     634           0 :   if (mRequestRedirectMode != RequestRedirect::Follow && response->Redirected()) {
     635           0 :     autoCancel.SetCancelMessage(
     636           0 :       NS_LITERAL_CSTRING("BadRedirectModeInterceptionWithURL"), mRequestURL);
     637           0 :     return;
     638             :   }
     639             : 
     640           0 :   if (NS_WARN_IF(response->BodyUsed())) {
     641           0 :     autoCancel.SetCancelMessage(
     642           0 :       NS_LITERAL_CSTRING("InterceptedUsedResponseWithURL"), mRequestURL);
     643           0 :     return;
     644             :   }
     645             : 
     646           0 :   RefPtr<InternalResponse> ir = response->GetInternalResponse();
     647           0 :   if (NS_WARN_IF(!ir)) {
     648           0 :     return;
     649             :   }
     650             :   // When an opaque response is encountered, we need the original channel's principal
     651             :   // to reflect the final URL. Non-opaque responses are either same-origin or CORS-enabled
     652             :   // cross-origin responses, which are treated as same-origin by consumers.
     653           0 :   nsCString responseURL;
     654           0 :   if (response->Type() == ResponseType::Opaque) {
     655           0 :     responseURL = ir->GetUnfilteredURL();
     656           0 :     if (NS_WARN_IF(responseURL.IsEmpty())) {
     657           0 :       return;
     658             :     }
     659             :   }
     660             :   nsAutoPtr<RespondWithClosure> closure(new RespondWithClosure(mInterceptedChannel,
     661             :                                                                mRegistration, ir,
     662           0 :                                                                worker->GetChannelInfo(),
     663             :                                                                mScriptSpec,
     664             :                                                                responseURL,
     665             :                                                                mRequestURL,
     666             :                                                                mRespondWithScriptSpec,
     667           0 :                                                                mRespondWithLineNumber,
     668           0 :                                                                mRespondWithColumnNumber));
     669           0 :   nsCOMPtr<nsIInputStream> body;
     670           0 :   ir->GetUnfilteredBody(getter_AddRefs(body));
     671             :   // Errors and redirects may not have a body.
     672           0 :   if (body) {
     673           0 :     response->SetBodyUsed();
     674             : 
     675           0 :     nsCOMPtr<nsIOutputStream> responseBody;
     676           0 :     rv = mInterceptedChannel->GetResponseBody(getter_AddRefs(responseBody));
     677           0 :     if (NS_WARN_IF(NS_FAILED(rv)) || !responseBody) {
     678           0 :       return;
     679             :     }
     680             : 
     681           0 :     const uint32_t kCopySegmentSize = 4096;
     682             : 
     683             :     // Depending on how the Response passed to .respondWith() was created, we may
     684             :     // get a non-buffered input stream.  In addition, in some configurations the
     685             :     // destination channel's output stream can be unbuffered.  We wrap the output
     686             :     // stream side here so that NS_AsyncCopy() works.  Wrapping the output side
     687             :     // provides the most consistent operation since there are fewer stream types
     688             :     // we are writing to.  The input stream can be a wide variety of concrete
     689             :     // objects which may or many not play well with NS_InputStreamIsBuffered().
     690           0 :     if (!NS_OutputStreamIsBuffered(responseBody)) {
     691           0 :       nsCOMPtr<nsIOutputStream> buffered;
     692           0 :       rv = NS_NewBufferedOutputStream(getter_AddRefs(buffered), responseBody,
     693             :            kCopySegmentSize);
     694           0 :       if (NS_WARN_IF(NS_FAILED(rv))) {
     695           0 :         return;
     696             :       }
     697           0 :       responseBody = buffered;
     698             :     }
     699             : 
     700           0 :     nsCOMPtr<nsIEventTarget> stsThread = do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID, &rv);
     701           0 :     if (NS_WARN_IF(!stsThread)) {
     702           0 :       return;
     703             :     }
     704             : 
     705             :     // XXXnsm, Fix for Bug 1141332 means that if we decide to make this
     706             :     // streaming at some point, we'll need a different solution to that bug.
     707           0 :     rv = NS_AsyncCopy(body, responseBody, stsThread, NS_ASYNCCOPY_VIA_WRITESEGMENTS,
     708           0 :                       kCopySegmentSize, RespondWithCopyComplete, closure.forget());
     709           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
     710           0 :       return;
     711             :     }
     712             :   } else {
     713           0 :     RespondWithCopyComplete(closure.forget(), NS_OK);
     714             :   }
     715             : 
     716           0 :   MOZ_ASSERT(!closure);
     717           0 :   autoCancel.Reset();
     718           0 :   mRequestWasHandled = true;
     719             : }
     720             : 
     721             : void
     722           0 : RespondWithHandler::RejectedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue)
     723             : {
     724           0 :   nsCString sourceSpec = mRespondWithScriptSpec;
     725           0 :   uint32_t line = mRespondWithLineNumber;
     726           0 :   uint32_t column = mRespondWithColumnNumber;
     727           0 :   nsString valueString;
     728             : 
     729           0 :   mInterceptedChannel->SetFinishResponseStart(TimeStamp::Now());
     730             : 
     731           0 :   ExtractErrorValues(aCx, aValue, sourceSpec, &line, &column, valueString);
     732             : 
     733           0 :   ::AsyncLog(mInterceptedChannel, sourceSpec, line, column,
     734           0 :              NS_LITERAL_CSTRING("InterceptionRejectedResponseWithURL"),
     735           0 :              mRequestURL, valueString);
     736             : 
     737           0 :   CancelRequest(NS_ERROR_INTERCEPTION_FAILED);
     738           0 : }
     739             : 
     740             : void
     741           0 : RespondWithHandler::CancelRequest(nsresult aStatus)
     742             : {
     743             :   nsCOMPtr<nsIRunnable> runnable =
     744           0 :     new CancelChannelRunnable(mInterceptedChannel, mRegistration, aStatus);
     745             :   // Note, this may run off the worker thread during worker termination.
     746           0 :   WorkerPrivate* worker = GetCurrentThreadWorkerPrivate();
     747           0 :   if (worker) {
     748           0 :     MOZ_ALWAYS_SUCCEEDS(worker->DispatchToMainThread(runnable.forget()));
     749             :   } else {
     750           0 :     MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(runnable.forget()));
     751             :   }
     752           0 :   mRequestWasHandled = true;
     753           0 : }
     754             : 
     755             : } // namespace
     756             : 
     757             : void
     758           0 : FetchEvent::RespondWith(JSContext* aCx, Promise& aArg, ErrorResult& aRv)
     759             : {
     760           0 :   if (EventPhase() == nsIDOMEvent::NONE || mWaitToRespond) {
     761           0 :     aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
     762           0 :     return;
     763             :   }
     764             : 
     765             : 
     766             :   // Record where respondWith() was called in the script so we can include the
     767             :   // information in any error reporting.  We should be guaranteed not to get
     768             :   // a file:// string here because service workers require http/https.
     769           0 :   nsCString spec;
     770           0 :   uint32_t line = 0;
     771           0 :   uint32_t column = 0;
     772           0 :   nsJSUtils::GetCallingLocation(aCx, spec, &line, &column);
     773             : 
     774           0 :   RefPtr<InternalRequest> ir = mRequest->GetInternalRequest();
     775             : 
     776           0 :   nsAutoCString requestURL;
     777           0 :   ir->GetURL(requestURL);
     778             : 
     779           0 :   StopImmediatePropagation();
     780           0 :   mWaitToRespond = true;
     781             :   RefPtr<RespondWithHandler> handler =
     782           0 :     new RespondWithHandler(mChannel, mRegistration, mRequest->Mode(),
     783           0 :                            ir->IsClientRequest(), mRequest->Redirect(),
     784           0 :                            mScriptSpec, NS_ConvertUTF8toUTF16(requestURL),
     785           0 :                            spec, line, column);
     786           0 :   aArg.AppendNativeHandler(handler);
     787             : 
     788           0 :   if (!WaitOnPromise(aArg)) {
     789           0 :     aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
     790             :   }
     791             : }
     792             : 
     793             : void
     794           0 : FetchEvent::PreventDefault(JSContext* aCx, CallerType aCallerType)
     795             : {
     796           0 :   MOZ_ASSERT(aCx);
     797           0 :   MOZ_ASSERT(aCallerType != CallerType::System,
     798             :              "Since when do we support system-principal service workers?");
     799             : 
     800           0 :   if (mPreventDefaultScriptSpec.IsEmpty()) {
     801             :     // Note when the FetchEvent might have been canceled by script, but don't
     802             :     // actually log the location until we are sure it matters.  This is
     803             :     // determined in ServiceWorkerPrivate.cpp.  We only remember the first
     804             :     // call to preventDefault() as its the most likely to have actually canceled
     805             :     // the event.
     806           0 :     nsJSUtils::GetCallingLocation(aCx, mPreventDefaultScriptSpec,
     807             :                                   &mPreventDefaultLineNumber,
     808           0 :                                   &mPreventDefaultColumnNumber);
     809             :   }
     810             : 
     811           0 :   Event::PreventDefault(aCx, aCallerType);
     812           0 : }
     813             : 
     814             : void
     815           0 : FetchEvent::ReportCanceled()
     816             : {
     817           0 :   MOZ_ASSERT(!mPreventDefaultScriptSpec.IsEmpty());
     818             : 
     819           0 :   RefPtr<InternalRequest> ir = mRequest->GetInternalRequest();
     820           0 :   nsAutoCString url;
     821           0 :   ir->GetURL(url);
     822             : 
     823             :   // The variadic template provided by StringArrayAppender requires exactly
     824             :   // an nsString.
     825           0 :   NS_ConvertUTF8toUTF16 requestURL(url);
     826             :   //nsString requestURL;
     827             :   //CopyUTF8toUTF16(url, requestURL);
     828             : 
     829           0 :   ::AsyncLog(mChannel.get(), mPreventDefaultScriptSpec,
     830             :              mPreventDefaultLineNumber, mPreventDefaultColumnNumber,
     831           0 :              NS_LITERAL_CSTRING("InterceptionCanceledWithURL"), requestURL);
     832           0 : }
     833             : 
     834             : namespace {
     835             : 
     836             : class WaitUntilHandler final : public PromiseNativeHandler
     837             : {
     838             :   WorkerPrivate* mWorkerPrivate;
     839             :   const nsCString mScope;
     840             :   nsCString mSourceSpec;
     841             :   uint32_t mLine;
     842             :   uint32_t mColumn;
     843             :   nsString mRejectValue;
     844             : 
     845           0 :   ~WaitUntilHandler()
     846           0 :   {
     847           0 :   }
     848             : 
     849             : public:
     850             :   NS_DECL_THREADSAFE_ISUPPORTS
     851             : 
     852           0 :   WaitUntilHandler(WorkerPrivate* aWorkerPrivate, JSContext* aCx)
     853           0 :     : mWorkerPrivate(aWorkerPrivate)
     854           0 :     , mScope(mWorkerPrivate->ServiceWorkerScope())
     855             :     , mLine(0)
     856           0 :     , mColumn(0)
     857             :   {
     858           0 :     mWorkerPrivate->AssertIsOnWorkerThread();
     859             : 
     860             :     // Save the location of the waitUntil() call itself as a fallback
     861             :     // in case the rejection value does not contain any location info.
     862           0 :     nsJSUtils::GetCallingLocation(aCx, mSourceSpec, &mLine, &mColumn);
     863           0 :   }
     864             : 
     865           0 :   void ResolvedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) override
     866             :   {
     867             :     // do nothing, we are only here to report errors
     868           0 :   }
     869             : 
     870           0 :   void RejectedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) override
     871             :   {
     872           0 :     mWorkerPrivate->AssertIsOnWorkerThread();
     873             : 
     874           0 :     nsCString spec;
     875           0 :     uint32_t line = 0;
     876           0 :     uint32_t column = 0;
     877           0 :     ExtractErrorValues(aCx, aValue, spec, &line, &column, mRejectValue);
     878             : 
     879             :     // only use the extracted location if we found one
     880           0 :     if (!spec.IsEmpty()) {
     881           0 :       mSourceSpec = spec;
     882           0 :       mLine = line;
     883           0 :       mColumn = column;
     884             :     }
     885             : 
     886           0 :     MOZ_ALWAYS_SUCCEEDS(mWorkerPrivate->DispatchToMainThread(
     887             :                           NewRunnableMethod("WaitUntilHandler::ReportOnMainThread",
     888             :                                             this, &WaitUntilHandler::ReportOnMainThread)));
     889           0 :   }
     890             : 
     891             :   void
     892           0 :   ReportOnMainThread()
     893             :   {
     894           0 :     AssertIsOnMainThread();
     895           0 :     RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
     896           0 :     if (!swm) {
     897             :       // browser shutdown
     898           0 :       return;
     899             :     }
     900             : 
     901             :     // TODO: Make the error message a localized string. (bug 1222720)
     902           0 :     nsString message;
     903             :     message.AppendLiteral("Service worker event waitUntil() was passed a "
     904           0 :                           "promise that rejected with '");
     905           0 :     message.Append(mRejectValue);
     906           0 :     message.AppendLiteral("'.");
     907             : 
     908             :     // Note, there is a corner case where this won't report to the window
     909             :     // that triggered the error.  Consider a navigation fetch event that
     910             :     // rejects waitUntil() without holding respondWith() open.  In this case
     911             :     // there is no controlling document yet, the window did call .register()
     912             :     // because there is no documeny yet, and the navigation is no longer
     913             :     // being intercepted.
     914             : 
     915           0 :     swm->ReportToAllClients(mScope, message, NS_ConvertUTF8toUTF16(mSourceSpec),
     916             :                             EmptyString(), mLine, mColumn,
     917           0 :                             nsIScriptError::errorFlag);
     918             :   }
     919             : };
     920             : 
     921           0 : NS_IMPL_ISUPPORTS0(WaitUntilHandler)
     922             : 
     923             : } // anonymous namespace
     924             : 
     925           0 : NS_IMPL_ADDREF_INHERITED(FetchEvent, ExtendableEvent)
     926           0 : NS_IMPL_RELEASE_INHERITED(FetchEvent, ExtendableEvent)
     927             : 
     928           0 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(FetchEvent)
     929           0 : NS_INTERFACE_MAP_END_INHERITING(ExtendableEvent)
     930             : 
     931           0 : NS_IMPL_CYCLE_COLLECTION_INHERITED(FetchEvent, ExtendableEvent, mRequest)
     932             : 
     933           0 : ExtendableEvent::ExtendableEvent(EventTarget* aOwner)
     934           0 :   : Event(aOwner, nullptr, nullptr)
     935             : {
     936           0 : }
     937             : 
     938             : bool
     939           0 : ExtendableEvent::WaitOnPromise(Promise& aPromise)
     940             : {
     941           0 :   if (!mExtensionsHandler) {
     942           0 :     return false;
     943             :   }
     944           0 :   return mExtensionsHandler->WaitOnPromise(aPromise);
     945             : }
     946             : 
     947             : void
     948           0 : ExtendableEvent::SetKeepAliveHandler(ExtensionsHandler* aExtensionsHandler)
     949             : {
     950           0 :   MOZ_ASSERT(!mExtensionsHandler);
     951           0 :   WorkerPrivate* worker = GetCurrentThreadWorkerPrivate();
     952           0 :   MOZ_ASSERT(worker);
     953           0 :   worker->AssertIsOnWorkerThread();
     954           0 :   mExtensionsHandler = aExtensionsHandler;
     955           0 : }
     956             : 
     957             : void
     958           0 : ExtendableEvent::WaitUntil(JSContext* aCx, Promise& aPromise, ErrorResult& aRv)
     959             : {
     960           0 :   MOZ_ASSERT(!NS_IsMainThread());
     961             : 
     962           0 :   if (!WaitOnPromise(aPromise)) {
     963           0 :     aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
     964           0 :     return;
     965             :   }
     966             : 
     967             :   // Append our handler to each waitUntil promise separately so we
     968             :   // can record the location in script where waitUntil was called.
     969             :   RefPtr<WaitUntilHandler> handler =
     970           0 :     new WaitUntilHandler(GetCurrentThreadWorkerPrivate(), aCx);
     971           0 :   aPromise.AppendNativeHandler(handler);
     972             : }
     973             : 
     974           0 : NS_IMPL_ADDREF_INHERITED(ExtendableEvent, Event)
     975           0 : NS_IMPL_RELEASE_INHERITED(ExtendableEvent, Event)
     976             : 
     977           0 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(ExtendableEvent)
     978           0 : NS_INTERFACE_MAP_END_INHERITING(Event)
     979             : 
     980             : namespace {
     981             : nsresult
     982           0 : ExtractBytesFromUSVString(const nsAString& aStr, nsTArray<uint8_t>& aBytes)
     983             : {
     984           0 :   MOZ_ASSERT(aBytes.IsEmpty());
     985           0 :   auto encoder = UTF_8_ENCODING->NewEncoder();
     986             :   CheckedInt<size_t> needed =
     987           0 :     encoder->MaxBufferLengthFromUTF16WithoutReplacement(aStr.Length());
     988           0 :   if (NS_WARN_IF(!needed.isValid() ||
     989             :                  !aBytes.SetLength(needed.value(), fallible))) {
     990           0 :     return NS_ERROR_OUT_OF_MEMORY;
     991             :   }
     992             :   uint32_t result;
     993             :   size_t read;
     994             :   size_t written;
     995           0 :   Tie(result, read, written) =
     996           0 :     encoder->EncodeFromUTF16WithoutReplacement(aStr, aBytes, true);
     997           0 :   MOZ_ASSERT(result == kInputEmpty);
     998           0 :   MOZ_ASSERT(read == aStr.Length());
     999           0 :   aBytes.TruncateLength(written);
    1000           0 :   return NS_OK;
    1001             : }
    1002             : 
    1003             : nsresult
    1004           0 : ExtractBytesFromData(const OwningArrayBufferViewOrArrayBufferOrUSVString& aDataInit, nsTArray<uint8_t>& aBytes)
    1005             : {
    1006           0 :   if (aDataInit.IsArrayBufferView()) {
    1007           0 :     const ArrayBufferView& view = aDataInit.GetAsArrayBufferView();
    1008           0 :     if (NS_WARN_IF(!PushUtil::CopyArrayBufferViewToArray(view, aBytes))) {
    1009           0 :       return NS_ERROR_OUT_OF_MEMORY;
    1010             :     }
    1011           0 :     return NS_OK;
    1012             :   }
    1013           0 :   if (aDataInit.IsArrayBuffer()) {
    1014           0 :     const ArrayBuffer& buffer = aDataInit.GetAsArrayBuffer();
    1015           0 :     if (NS_WARN_IF(!PushUtil::CopyArrayBufferToArray(buffer, aBytes))) {
    1016           0 :       return NS_ERROR_OUT_OF_MEMORY;
    1017             :     }
    1018           0 :     return NS_OK;
    1019             :   }
    1020           0 :   if (aDataInit.IsUSVString()) {
    1021           0 :     return ExtractBytesFromUSVString(aDataInit.GetAsUSVString(), aBytes);
    1022             :   }
    1023           0 :   NS_NOTREACHED("Unexpected push message data");
    1024           0 :   return NS_ERROR_FAILURE;
    1025             : }
    1026             : }
    1027             : 
    1028           0 : PushMessageData::PushMessageData(nsISupports* aOwner,
    1029           0 :                                  nsTArray<uint8_t>&& aBytes)
    1030           0 :   : mOwner(aOwner), mBytes(Move(aBytes)) {}
    1031             : 
    1032           0 : PushMessageData::~PushMessageData()
    1033             : {
    1034           0 : }
    1035             : 
    1036           0 : NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(PushMessageData, mOwner)
    1037             : 
    1038           0 : NS_IMPL_CYCLE_COLLECTING_ADDREF(PushMessageData)
    1039           0 : NS_IMPL_CYCLE_COLLECTING_RELEASE(PushMessageData)
    1040             : 
    1041           0 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(PushMessageData)
    1042           0 :   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
    1043           0 :   NS_INTERFACE_MAP_ENTRY(nsISupports)
    1044           0 : NS_INTERFACE_MAP_END
    1045             : 
    1046             : JSObject*
    1047           0 : PushMessageData::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
    1048             : {
    1049           0 :   return mozilla::dom::PushMessageDataBinding::Wrap(aCx, this, aGivenProto);
    1050             : }
    1051             : 
    1052             : void
    1053           0 : PushMessageData::Json(JSContext* cx, JS::MutableHandle<JS::Value> aRetval,
    1054             :                       ErrorResult& aRv)
    1055             : {
    1056           0 :   if (NS_FAILED(EnsureDecodedText())) {
    1057           0 :     aRv.Throw(NS_ERROR_DOM_UNKNOWN_ERR);
    1058           0 :     return;
    1059             :   }
    1060           0 :   BodyUtil::ConsumeJson(cx, aRetval, mDecodedText, aRv);
    1061             : }
    1062             : 
    1063             : void
    1064           0 : PushMessageData::Text(nsAString& aData)
    1065             : {
    1066           0 :   if (NS_SUCCEEDED(EnsureDecodedText())) {
    1067           0 :     aData = mDecodedText;
    1068             :   }
    1069           0 : }
    1070             : 
    1071             : void
    1072           0 : PushMessageData::ArrayBuffer(JSContext* cx,
    1073             :                              JS::MutableHandle<JSObject*> aRetval,
    1074             :                              ErrorResult& aRv)
    1075             : {
    1076           0 :   uint8_t* data = GetContentsCopy();
    1077           0 :   if (data) {
    1078           0 :     BodyUtil::ConsumeArrayBuffer(cx, aRetval, mBytes.Length(), data, aRv);
    1079             :   }
    1080           0 : }
    1081             : 
    1082             : already_AddRefed<mozilla::dom::Blob>
    1083           0 : PushMessageData::Blob(ErrorResult& aRv)
    1084             : {
    1085           0 :   uint8_t* data = GetContentsCopy();
    1086           0 :   if (data) {
    1087           0 :     RefPtr<mozilla::dom::Blob> blob = BodyUtil::ConsumeBlob(
    1088           0 :       mOwner, EmptyString(), mBytes.Length(), data, aRv);
    1089           0 :     if (blob) {
    1090           0 :       return blob.forget();
    1091             :     }
    1092             :   }
    1093           0 :   return nullptr;
    1094             : }
    1095             : 
    1096             : nsresult
    1097           0 : PushMessageData::EnsureDecodedText()
    1098             : {
    1099           0 :   if (mBytes.IsEmpty() || !mDecodedText.IsEmpty()) {
    1100           0 :     return NS_OK;
    1101             :   }
    1102           0 :   nsresult rv = BodyUtil::ConsumeText(
    1103           0 :     mBytes.Length(),
    1104             :     reinterpret_cast<uint8_t*>(mBytes.Elements()),
    1105             :     mDecodedText
    1106           0 :   );
    1107           0 :   if (NS_WARN_IF(NS_FAILED(rv))) {
    1108           0 :     mDecodedText.Truncate();
    1109           0 :     return rv;
    1110             :   }
    1111           0 :   return NS_OK;
    1112             : }
    1113             : 
    1114             : uint8_t*
    1115           0 : PushMessageData::GetContentsCopy()
    1116             : {
    1117           0 :   uint32_t length = mBytes.Length();
    1118           0 :   void* data = malloc(length);
    1119           0 :   if (!data) {
    1120           0 :     return nullptr;
    1121             :   }
    1122           0 :   memcpy(data, mBytes.Elements(), length);
    1123           0 :   return reinterpret_cast<uint8_t*>(data);
    1124             : }
    1125             : 
    1126           0 : PushEvent::PushEvent(EventTarget* aOwner)
    1127           0 :   : ExtendableEvent(aOwner)
    1128             : {
    1129           0 : }
    1130             : 
    1131             : already_AddRefed<PushEvent>
    1132           0 : PushEvent::Constructor(mozilla::dom::EventTarget* aOwner,
    1133             :                        const nsAString& aType,
    1134             :                        const PushEventInit& aOptions,
    1135             :                        ErrorResult& aRv)
    1136             : {
    1137           0 :   RefPtr<PushEvent> e = new PushEvent(aOwner);
    1138           0 :   bool trusted = e->Init(aOwner);
    1139           0 :   e->InitEvent(aType, aOptions.mBubbles, aOptions.mCancelable);
    1140           0 :   e->SetTrusted(trusted);
    1141           0 :   e->SetComposed(aOptions.mComposed);
    1142           0 :   if(aOptions.mData.WasPassed()){
    1143           0 :     nsTArray<uint8_t> bytes;
    1144           0 :     nsresult rv = ExtractBytesFromData(aOptions.mData.Value(), bytes);
    1145           0 :     if (NS_FAILED(rv)) {
    1146           0 :       aRv.Throw(rv);
    1147           0 :       return nullptr;
    1148             :     }
    1149           0 :     e->mData = new PushMessageData(aOwner, Move(bytes));
    1150             :   }
    1151           0 :   return e.forget();
    1152             : }
    1153             : 
    1154           0 : NS_IMPL_ADDREF_INHERITED(PushEvent, ExtendableEvent)
    1155           0 : NS_IMPL_RELEASE_INHERITED(PushEvent, ExtendableEvent)
    1156             : 
    1157           0 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(PushEvent)
    1158           0 : NS_INTERFACE_MAP_END_INHERITING(ExtendableEvent)
    1159             : 
    1160           0 : NS_IMPL_CYCLE_COLLECTION_INHERITED(PushEvent, ExtendableEvent, mData)
    1161             : 
    1162             : JSObject*
    1163           0 : PushEvent::WrapObjectInternal(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
    1164             : {
    1165           0 :   return mozilla::dom::PushEventBinding::Wrap(aCx, this, aGivenProto);
    1166             : }
    1167             : 
    1168           0 : ExtendableMessageEvent::ExtendableMessageEvent(EventTarget* aOwner)
    1169             :   : ExtendableEvent(aOwner)
    1170           0 :   , mData(JS::UndefinedValue())
    1171             : {
    1172           0 :   mozilla::HoldJSObjects(this);
    1173           0 : }
    1174             : 
    1175           0 : ExtendableMessageEvent::~ExtendableMessageEvent()
    1176             : {
    1177           0 :   mData.setUndefined();
    1178           0 :   DropJSObjects(this);
    1179           0 : }
    1180             : 
    1181             : void
    1182           0 : ExtendableMessageEvent::GetData(JSContext* aCx,
    1183             :                                 JS::MutableHandle<JS::Value> aData,
    1184             :                                 ErrorResult& aRv)
    1185             : {
    1186           0 :   aData.set(mData);
    1187           0 :   if (!JS_WrapValue(aCx, aData)) {
    1188           0 :     aRv.Throw(NS_ERROR_FAILURE);
    1189             :   }
    1190           0 : }
    1191             : 
    1192             : void
    1193           0 : ExtendableMessageEvent::GetSource(Nullable<OwningClientOrServiceWorkerOrMessagePort>& aValue) const
    1194             : {
    1195           0 :   if (mClient) {
    1196           0 :     aValue.SetValue().SetAsClient() = mClient;
    1197           0 :   } else if (mServiceWorker) {
    1198           0 :     aValue.SetValue().SetAsServiceWorker() = mServiceWorker;
    1199           0 :   } else if (mMessagePort) {
    1200           0 :     aValue.SetValue().SetAsMessagePort() = mMessagePort;
    1201             :   } else {
    1202             :     // nullptr source is possible for manually constructed event
    1203           0 :     aValue.SetNull();
    1204             :   }
    1205           0 : }
    1206             : 
    1207             : /* static */ already_AddRefed<ExtendableMessageEvent>
    1208           0 : ExtendableMessageEvent::Constructor(const GlobalObject& aGlobal,
    1209             :                                     const nsAString& aType,
    1210             :                                     const ExtendableMessageEventInit& aOptions,
    1211             :                                     ErrorResult& aRv)
    1212             : {
    1213           0 :   nsCOMPtr<EventTarget> t = do_QueryInterface(aGlobal.GetAsSupports());
    1214           0 :   return Constructor(t, aType, aOptions, aRv);
    1215             : }
    1216             : 
    1217             : /* static */ already_AddRefed<ExtendableMessageEvent>
    1218           0 : ExtendableMessageEvent::Constructor(mozilla::dom::EventTarget* aEventTarget,
    1219             :                                     const nsAString& aType,
    1220             :                                     const ExtendableMessageEventInit& aOptions,
    1221             :                                     ErrorResult& aRv)
    1222             : {
    1223           0 :   RefPtr<ExtendableMessageEvent> event = new ExtendableMessageEvent(aEventTarget);
    1224             : 
    1225           0 :   event->InitEvent(aType, aOptions.mBubbles, aOptions.mCancelable);
    1226           0 :   bool trusted = event->Init(aEventTarget);
    1227           0 :   event->SetTrusted(trusted);
    1228             : 
    1229           0 :   event->mData = aOptions.mData;
    1230           0 :   event->mOrigin = aOptions.mOrigin;
    1231           0 :   event->mLastEventId = aOptions.mLastEventId;
    1232             : 
    1233           0 :   if (!aOptions.mSource.IsNull()) {
    1234           0 :     if (aOptions.mSource.Value().IsClient()) {
    1235           0 :       event->mClient = aOptions.mSource.Value().GetAsClient();
    1236           0 :     } else if (aOptions.mSource.Value().IsServiceWorker()){
    1237           0 :       event->mServiceWorker = aOptions.mSource.Value().GetAsServiceWorker();
    1238           0 :     } else if (aOptions.mSource.Value().IsMessagePort()){
    1239           0 :       event->mMessagePort = aOptions.mSource.Value().GetAsMessagePort();
    1240             :     }
    1241             :   }
    1242             : 
    1243           0 :   event->mPorts.AppendElements(aOptions.mPorts);
    1244           0 :   return event.forget();
    1245             : }
    1246             : 
    1247             : void
    1248           0 : ExtendableMessageEvent::GetPorts(nsTArray<RefPtr<MessagePort>>& aPorts)
    1249             : {
    1250           0 :   aPorts = mPorts;
    1251           0 : }
    1252             : 
    1253             : NS_IMPL_CYCLE_COLLECTION_CLASS(ExtendableMessageEvent)
    1254             : 
    1255           0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(ExtendableMessageEvent, Event)
    1256           0 :   tmp->mData.setUndefined();
    1257           0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK(mClient)
    1258           0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK(mServiceWorker)
    1259           0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK(mMessagePort)
    1260           0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK(mPorts)
    1261           0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_END
    1262             : 
    1263           0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(ExtendableMessageEvent, Event)
    1264           0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mClient)
    1265           0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mServiceWorker)
    1266           0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMessagePort)
    1267           0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPorts)
    1268           0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
    1269             : 
    1270           0 : NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(ExtendableMessageEvent, Event)
    1271           0 :   NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mData)
    1272           0 : NS_IMPL_CYCLE_COLLECTION_TRACE_END
    1273             : 
    1274           0 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(ExtendableMessageEvent)
    1275           0 : NS_INTERFACE_MAP_END_INHERITING(Event)
    1276             : 
    1277           0 : NS_IMPL_ADDREF_INHERITED(ExtendableMessageEvent, Event)
    1278           0 : NS_IMPL_RELEASE_INHERITED(ExtendableMessageEvent, Event)
    1279             : 
    1280             : END_WORKERS_NAMESPACE

Generated by: LCOV version 1.13