ServiceWorkerClient.cpp 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232
  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 file,
  4. * You can obtain one at http://mozilla.org/MPL/2.0/.
  5. */
  6. #include "ServiceWorkerClient.h"
  7. #include "ServiceWorkerContainer.h"
  8. #include "mozilla/dom/MessageEvent.h"
  9. #include "mozilla/dom/Navigator.h"
  10. #include "mozilla/dom/ServiceWorkerMessageEvent.h"
  11. #include "mozilla/dom/ServiceWorkerMessageEventBinding.h"
  12. #include "nsGlobalWindow.h"
  13. #include "nsIBrowserDOMWindow.h"
  14. #include "nsIDocument.h"
  15. #include "ServiceWorker.h"
  16. #include "ServiceWorkerPrivate.h"
  17. #include "WorkerPrivate.h"
  18. using namespace mozilla;
  19. using namespace mozilla::dom;
  20. using namespace mozilla::dom::workers;
  21. NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(ServiceWorkerClient, mOwner)
  22. NS_IMPL_CYCLE_COLLECTING_ADDREF(ServiceWorkerClient)
  23. NS_IMPL_CYCLE_COLLECTING_RELEASE(ServiceWorkerClient)
  24. NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ServiceWorkerClient)
  25. NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
  26. NS_INTERFACE_MAP_ENTRY(nsISupports)
  27. NS_INTERFACE_MAP_END
  28. ServiceWorkerClientInfo::ServiceWorkerClientInfo(nsIDocument* aDoc)
  29. : mWindowId(0)
  30. , mFrameType(FrameType::None)
  31. {
  32. MOZ_ASSERT(aDoc);
  33. nsresult rv = aDoc->GetOrCreateId(mClientId);
  34. if (NS_FAILED(rv)) {
  35. NS_WARNING("Failed to get the UUID of the document.");
  36. }
  37. RefPtr<nsGlobalWindow> innerWindow = nsGlobalWindow::Cast(aDoc->GetInnerWindow());
  38. if (innerWindow) {
  39. // XXXcatalinb: The inner window can be null if the document is navigating
  40. // and was detached.
  41. mWindowId = innerWindow->WindowID();
  42. }
  43. nsCOMPtr<nsIURI> originalURI = aDoc->GetOriginalURI();
  44. if (originalURI) {
  45. nsAutoCString spec;
  46. originalURI->GetSpec(spec);
  47. CopyUTF8toUTF16(spec, mUrl);
  48. }
  49. mVisibilityState = aDoc->VisibilityState();
  50. ErrorResult result;
  51. mFocused = aDoc->HasFocus(result);
  52. if (result.Failed()) {
  53. NS_WARNING("Failed to get focus information.");
  54. }
  55. RefPtr<nsGlobalWindow> outerWindow = nsGlobalWindow::Cast(aDoc->GetWindow());
  56. if (!outerWindow) {
  57. MOZ_ASSERT(mFrameType == FrameType::None);
  58. } else if (!outerWindow->IsTopLevelWindow()) {
  59. mFrameType = FrameType::Nested;
  60. } else if (outerWindow->HadOriginalOpener()) {
  61. mFrameType = FrameType::Auxiliary;
  62. } else {
  63. mFrameType = FrameType::Top_level;
  64. }
  65. }
  66. JSObject*
  67. ServiceWorkerClient::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
  68. {
  69. return ClientBinding::Wrap(aCx, this, aGivenProto);
  70. }
  71. namespace {
  72. class ServiceWorkerClientPostMessageRunnable final
  73. : public Runnable
  74. , public StructuredCloneHolder
  75. {
  76. uint64_t mWindowId;
  77. public:
  78. explicit ServiceWorkerClientPostMessageRunnable(uint64_t aWindowId)
  79. : StructuredCloneHolder(CloningSupported, TransferringSupported,
  80. StructuredCloneScope::SameProcessDifferentThread)
  81. , mWindowId(aWindowId)
  82. {}
  83. NS_IMETHOD
  84. Run() override
  85. {
  86. AssertIsOnMainThread();
  87. nsGlobalWindow* window = nsGlobalWindow::GetInnerWindowWithId(mWindowId);
  88. if (!window) {
  89. return NS_ERROR_FAILURE;
  90. }
  91. ErrorResult result;
  92. dom::Navigator* navigator = window->GetNavigator(result);
  93. if (NS_WARN_IF(result.Failed())) {
  94. return result.StealNSResult();
  95. }
  96. RefPtr<ServiceWorkerContainer> container = navigator->ServiceWorker();
  97. AutoJSAPI jsapi;
  98. if (NS_WARN_IF(!jsapi.Init(window))) {
  99. return NS_ERROR_FAILURE;
  100. }
  101. JSContext* cx = jsapi.cx();
  102. return DispatchDOMEvent(cx, container);
  103. }
  104. private:
  105. NS_IMETHOD
  106. DispatchDOMEvent(JSContext* aCx, ServiceWorkerContainer* aTargetContainer)
  107. {
  108. AssertIsOnMainThread();
  109. MOZ_ASSERT(aTargetContainer->GetParentObject(),
  110. "How come we don't have a window here?!");
  111. JS::Rooted<JS::Value> messageData(aCx);
  112. ErrorResult rv;
  113. Read(aTargetContainer->GetParentObject(), aCx, &messageData, rv);
  114. if (NS_WARN_IF(rv.Failed())) {
  115. xpc::Throw(aCx, rv.StealNSResult());
  116. return NS_ERROR_FAILURE;
  117. }
  118. RootedDictionary<ServiceWorkerMessageEventInit> init(aCx);
  119. nsCOMPtr<nsIPrincipal> principal = aTargetContainer->GetParentObject()->PrincipalOrNull();
  120. NS_WARNING_ASSERTION(principal, "Why is the principal null here?");
  121. bool isNullPrincipal = false;
  122. bool isSystemPrincipal = false;
  123. if (principal) {
  124. isNullPrincipal = principal->GetIsNullPrincipal();
  125. MOZ_ASSERT(!isNullPrincipal);
  126. isSystemPrincipal = principal->GetIsSystemPrincipal();
  127. MOZ_ASSERT(!isSystemPrincipal);
  128. }
  129. init.mData = messageData;
  130. nsAutoCString origin;
  131. if (principal && !isNullPrincipal && !isSystemPrincipal) {
  132. principal->GetOrigin(origin);
  133. }
  134. init.mOrigin = NS_ConvertUTF8toUTF16(origin);
  135. RefPtr<ServiceWorker> serviceWorker = aTargetContainer->GetController();
  136. if (serviceWorker) {
  137. init.mSource.SetValue().SetAsServiceWorker() = serviceWorker;
  138. }
  139. if (!TakeTransferredPortsAsSequence(init.mPorts)) {
  140. return NS_ERROR_OUT_OF_MEMORY;
  141. }
  142. RefPtr<ServiceWorkerMessageEvent> event =
  143. ServiceWorkerMessageEvent::Constructor(aTargetContainer,
  144. NS_LITERAL_STRING("message"),
  145. init);
  146. event->SetTrusted(true);
  147. bool status = false;
  148. aTargetContainer->DispatchEvent(static_cast<dom::Event*>(event.get()),
  149. &status);
  150. if (!status) {
  151. return NS_ERROR_FAILURE;
  152. }
  153. return NS_OK;
  154. }
  155. };
  156. } // namespace
  157. void
  158. ServiceWorkerClient::PostMessage(JSContext* aCx, JS::Handle<JS::Value> aMessage,
  159. const Optional<Sequence<JS::Value>>& aTransferable,
  160. ErrorResult& aRv)
  161. {
  162. WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
  163. MOZ_ASSERT(workerPrivate);
  164. workerPrivate->AssertIsOnWorkerThread();
  165. JS::Rooted<JS::Value> transferable(aCx, JS::UndefinedValue());
  166. if (aTransferable.WasPassed()) {
  167. const Sequence<JS::Value>& realTransferable = aTransferable.Value();
  168. JS::HandleValueArray elements =
  169. JS::HandleValueArray::fromMarkedLocation(realTransferable.Length(),
  170. realTransferable.Elements());
  171. JSObject* array = JS_NewArrayObject(aCx, elements);
  172. if (!array) {
  173. aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
  174. return;
  175. }
  176. transferable.setObject(*array);
  177. }
  178. RefPtr<ServiceWorkerClientPostMessageRunnable> runnable =
  179. new ServiceWorkerClientPostMessageRunnable(mWindowId);
  180. runnable->Write(aCx, aMessage, transferable, JS::CloneDataPolicy().denySharedArrayBuffer(),
  181. aRv);
  182. if (NS_WARN_IF(aRv.Failed())) {
  183. return;
  184. }
  185. aRv = NS_DispatchToMainThread(runnable);
  186. if (NS_WARN_IF(aRv.Failed())) {
  187. return;
  188. }
  189. }