ServiceWorkerEvents.cpp 41 KB

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