From 8acff5cdbeb2f92be5e9e926b72ba4a1f19d425d Mon Sep 17 00:00:00 2001 From: "Matt A. Tobin" Date: Thu, 6 Feb 2020 19:49:46 -0500 Subject: Issue #1395 - Part 2: Remove the rest of FlyWeb --- dom/flyweb/FlyWebDiscoveryManager.cpp | 125 --- dom/flyweb/FlyWebDiscoveryManager.h | 61 -- dom/flyweb/FlyWebPublishOptionsIPCSerializer.h | 33 - dom/flyweb/FlyWebPublishedServer.cpp | 675 ------------ dom/flyweb/FlyWebPublishedServer.h | 109 -- dom/flyweb/FlyWebPublishedServerIPC.h | 172 --- dom/flyweb/FlyWebServerEvents.cpp | 141 --- dom/flyweb/FlyWebServerEvents.h | 88 -- dom/flyweb/FlyWebService.cpp | 1310 ----------------------- dom/flyweb/FlyWebService.h | 113 -- dom/flyweb/HttpServer.cpp | 1319 ------------------------ dom/flyweb/HttpServer.h | 193 ---- dom/flyweb/PFlyWebPublishedServer.ipdl | 38 - dom/flyweb/moz.build | 42 - 14 files changed, 4419 deletions(-) delete mode 100644 dom/flyweb/FlyWebDiscoveryManager.cpp delete mode 100644 dom/flyweb/FlyWebDiscoveryManager.h delete mode 100644 dom/flyweb/FlyWebPublishOptionsIPCSerializer.h delete mode 100644 dom/flyweb/FlyWebPublishedServer.cpp delete mode 100644 dom/flyweb/FlyWebPublishedServer.h delete mode 100644 dom/flyweb/FlyWebPublishedServerIPC.h delete mode 100644 dom/flyweb/FlyWebServerEvents.cpp delete mode 100644 dom/flyweb/FlyWebServerEvents.h delete mode 100644 dom/flyweb/FlyWebService.cpp delete mode 100644 dom/flyweb/FlyWebService.h delete mode 100644 dom/flyweb/HttpServer.cpp delete mode 100644 dom/flyweb/HttpServer.h delete mode 100644 dom/flyweb/PFlyWebPublishedServer.ipdl delete mode 100644 dom/flyweb/moz.build (limited to 'dom') diff --git a/dom/flyweb/FlyWebDiscoveryManager.cpp b/dom/flyweb/FlyWebDiscoveryManager.cpp deleted file mode 100644 index 5a97eb6d8..000000000 --- a/dom/flyweb/FlyWebDiscoveryManager.cpp +++ /dev/null @@ -1,125 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: set ts=8 sts=2 et sw=2 tw=80: */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "nsString.h" -#include "nsTHashtable.h" -#include "nsClassHashtable.h" -#include "nsIUUIDGenerator.h" -#include "jsapi.h" -#include "mozilla/StaticPtr.h" -#include "mozilla/Logging.h" -#include "nsComponentManagerUtils.h" -#include "nsServiceManagerUtils.h" - -#include "mozilla/dom/FlyWebDiscoveryManager.h" -#include "mozilla/dom/FlyWebDiscoveryManagerBinding.h" - -namespace mozilla { -namespace dom { - -static LazyLogModule gFlyWebDiscoveryManagerLog("FlyWebDiscoveryManager"); -#undef LOG_I -#define LOG_I(...) MOZ_LOG(mozilla::dom::gFlyWebDiscoveryManagerLog, mozilla::LogLevel::Debug, (__VA_ARGS__)) -#undef LOG_E -#define LOG_E(...) MOZ_LOG(mozilla::dom::gFlyWebDiscoveryManagerLog, mozilla::LogLevel::Error, (__VA_ARGS__)) - - -NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(FlyWebDiscoveryManager) - -NS_IMPL_CYCLE_COLLECTING_ADDREF(FlyWebDiscoveryManager) -NS_IMPL_CYCLE_COLLECTING_RELEASE(FlyWebDiscoveryManager) -NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(FlyWebDiscoveryManager) - NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY - NS_INTERFACE_MAP_ENTRY(nsISupports) -NS_INTERFACE_MAP_END - -FlyWebDiscoveryManager::FlyWebDiscoveryManager(nsISupports* aParent, - FlyWebService* aService) - : mParent(aParent) - , mService(aService) - , mNextId(0) -{ -} - -FlyWebDiscoveryManager::~FlyWebDiscoveryManager() -{ - mService->UnregisterDiscoveryManager(this); -} - -JSObject* -FlyWebDiscoveryManager::WrapObject(JSContext* aCx, JS::Handle aGivenProto) -{ - return FlyWebDiscoveryManagerBinding::Wrap(aCx, this, aGivenProto); -} - -nsISupports* -FlyWebDiscoveryManager::GetParentObject() const -{ - return mParent; -} - -/* static */ already_AddRefed -FlyWebDiscoveryManager::Constructor(const GlobalObject& aGlobal, ErrorResult& rv) -{ - RefPtr service = FlyWebService::GetOrCreate(); - if (!service) { - return nullptr; - } - - RefPtr result = new FlyWebDiscoveryManager( - aGlobal.GetAsSupports(), service); - return result.forget(); -} - -void -FlyWebDiscoveryManager::ListServices(nsTArray& aServices) -{ - return mService->ListDiscoveredServices(aServices); -} - -uint32_t -FlyWebDiscoveryManager::StartDiscovery(FlyWebDiscoveryCallback& aCallback) -{ - uint32_t id = GenerateId(); - mCallbackMap.Put(id, &aCallback); - mService->RegisterDiscoveryManager(this); - return id; -} - -void -FlyWebDiscoveryManager::StopDiscovery(uint32_t aId) -{ - mCallbackMap.Remove(aId); - if (mCallbackMap.Count() == 0) { - mService->UnregisterDiscoveryManager(this); - } -} - -void -FlyWebDiscoveryManager::PairWithService(const nsAString& aServiceId, - FlyWebPairingCallback& aCallback) -{ - mService->PairWithService(aServiceId, aCallback); -} - -void -FlyWebDiscoveryManager::NotifyDiscoveredServicesChanged() -{ - nsTArray services; - ListServices(services); - Sequence servicesSeq; - servicesSeq.SwapElements(services); - for (auto iter = mCallbackMap.Iter(); !iter.Done(); iter.Next()) { - FlyWebDiscoveryCallback *callback = iter.UserData(); - ErrorResult err; - callback->OnDiscoveredServicesChanged(servicesSeq, err); - ENSURE_SUCCESS_VOID(err); - } -} - - -} // namespace dom -} // namespace mozilla diff --git a/dom/flyweb/FlyWebDiscoveryManager.h b/dom/flyweb/FlyWebDiscoveryManager.h deleted file mode 100644 index cb5f692f8..000000000 --- a/dom/flyweb/FlyWebDiscoveryManager.h +++ /dev/null @@ -1,61 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: set ts=8 sts=2 et sw=2 tw=80: */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef mozilla_dom_FlyWebDiscoveryManager_h -#define mozilla_dom_FlyWebDiscoveryManager_h - -#include "nsISupportsImpl.h" -#include "mozilla/ErrorResult.h" -#include "nsRefPtrHashtable.h" -#include "nsWrapperCache.h" -#include "FlyWebDiscoveryManagerBinding.h" -#include "FlyWebService.h" - -namespace mozilla { -namespace dom { - -class FlyWebDiscoveryManager final : public nsISupports - , public nsWrapperCache -{ -public: - NS_DECL_CYCLE_COLLECTING_ISUPPORTS - NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(FlyWebDiscoveryManager) - - virtual JSObject* WrapObject(JSContext* aCx, JS::Handle aGivenProto) override; - nsISupports* GetParentObject() const; - - static already_AddRefed Constructor(const GlobalObject& aGlobal, - ErrorResult& rv); - - void ListServices(nsTArray& aServices); - uint32_t StartDiscovery(FlyWebDiscoveryCallback& aCallback); - void StopDiscovery(uint32_t aId); - - void PairWithService(const nsAString& aServiceId, - FlyWebPairingCallback& callback); - - void NotifyDiscoveredServicesChanged(); - -private: - FlyWebDiscoveryManager(nsISupports* mParent, FlyWebService* aService); - ~FlyWebDiscoveryManager(); - - uint32_t GenerateId() { - return ++mNextId; - } - - nsCOMPtr mParent; - RefPtr mService; - - uint32_t mNextId; - - nsRefPtrHashtable mCallbackMap; -}; - -} // namespace dom -} // namespace mozilla - -#endif // mozilla_dom_FlyWebDiscoveryManager_h diff --git a/dom/flyweb/FlyWebPublishOptionsIPCSerializer.h b/dom/flyweb/FlyWebPublishOptionsIPCSerializer.h deleted file mode 100644 index fa1a44113..000000000 --- a/dom/flyweb/FlyWebPublishOptionsIPCSerializer.h +++ /dev/null @@ -1,33 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: set ts=8 sts=2 et sw=2 tw=80: */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef mozilla_dom_FlyWebPublishOptionsIPCSerialiser_h -#define mozilla_dom_FlyWebPublishOptionsIPCSerialiser_h - -#include "mozilla/dom/FlyWebPublishBinding.h" - -namespace IPC { - -template <> -struct ParamTraits -{ - typedef mozilla::dom::FlyWebPublishOptions paramType; - - // Function to serialize a FlyWebPublishOptions - static void Write(Message *aMsg, const paramType& aParam) - { - WriteParam(aMsg, aParam.mUiUrl); - } - // Function to de-serialize a FlyWebPublishOptions - static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult) - { - return ReadParam(aMsg, aIter, &(aResult->mUiUrl)); - } -}; - -} - -#endif // mozilla_dom_FlyWebPublishOptionsIPCSerialiser_h diff --git a/dom/flyweb/FlyWebPublishedServer.cpp b/dom/flyweb/FlyWebPublishedServer.cpp deleted file mode 100644 index 375df332f..000000000 --- a/dom/flyweb/FlyWebPublishedServer.cpp +++ /dev/null @@ -1,675 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: set ts=8 sts=2 et sw=2 tw=80: */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "mozilla/dom/FlyWebPublishedServerIPC.h" -#include "mozilla/dom/FlyWebPublishBinding.h" -#include "mozilla/dom/FlyWebService.h" -#include "mozilla/dom/Request.h" -#include "mozilla/dom/FlyWebServerEvents.h" -#include "mozilla/dom/ContentChild.h" -#include "mozilla/dom/ContentParent.h" -#include "mozilla/dom/InternalResponse.h" -#include "mozilla/ipc/IPCStreamUtils.h" -#include "mozilla/net/NeckoParent.h" -#include "mozilla/net/IPCTransportProvider.h" -#include "mozilla/ErrorResult.h" -#include "mozilla/Preferences.h" -#include "mozilla/Unused.h" -#include "nsCharSeparatedTokenizer.h" -#include "nsGlobalWindow.h" -#include "WebSocketChannel.h" - -namespace mozilla { -namespace dom { - -static LazyLogModule gFlyWebPublishedServerLog("FlyWebPublishedServer"); -#undef LOG_I -#define LOG_I(...) MOZ_LOG(mozilla::dom::gFlyWebPublishedServerLog, mozilla::LogLevel::Debug, (__VA_ARGS__)) -#undef LOG_E -#define LOG_E(...) MOZ_LOG(mozilla::dom::gFlyWebPublishedServerLog, mozilla::LogLevel::Error, (__VA_ARGS__)) - -/******** FlyWebPublishedServer ********/ - -FlyWebPublishedServer::FlyWebPublishedServer(nsPIDOMWindowInner* aOwner, - const nsAString& aName, - const FlyWebPublishOptions& aOptions) - : mozilla::DOMEventTargetHelper(aOwner) - , mOwnerWindowID(aOwner ? aOwner->WindowID() : 0) - , mName(aName) - , mUiUrl(aOptions.mUiUrl) - , mIsRegistered(true) // Registered by the FlyWebService -{ -} - -void -FlyWebPublishedServer::LastRelease() -{ - // Make sure to unregister to avoid dangling pointers. Use the LastRelease - // hook rather than dtor since calling virtual functions during dtor - // wouldn't do what we want. Also, LastRelease is called earlier than dtor - // for CC objects. - Close(); -} - -JSObject* -FlyWebPublishedServer::WrapObject(JSContext* aCx, JS::Handle aGivenProto) -{ - return FlyWebPublishedServerBinding::Wrap(aCx, this, aGivenProto); -} - -void -FlyWebPublishedServer::Close() -{ - LOG_I("FlyWebPublishedServer::Close(%p)", this); - - // Unregister from server. - if (mIsRegistered) { - MOZ_ASSERT(FlyWebService::GetExisting()); - FlyWebService::GetExisting()->UnregisterServer(this); - mIsRegistered = false; - - DispatchTrustedEvent(NS_LITERAL_STRING("close")); - } -} - -void -FlyWebPublishedServer::FireFetchEvent(InternalRequest* aRequest) -{ - nsCOMPtr global = do_QueryInterface(GetOwner()); - RefPtr e = new FlyWebFetchEvent(this, - new Request(global, aRequest), - aRequest); - e->Init(this); - e->InitEvent(NS_LITERAL_STRING("fetch"), false, false); - - DispatchTrustedEvent(e); -} - -void -FlyWebPublishedServer::FireWebsocketEvent(InternalRequest* aConnectRequest) -{ - nsCOMPtr global = do_QueryInterface(GetOwner()); - RefPtr e = new FlyWebWebSocketEvent(this, - new Request(global, aConnectRequest), - aConnectRequest); - e->Init(this); - e->InitEvent(NS_LITERAL_STRING("websocket"), false, false); - - DispatchTrustedEvent(e); -} - -void -FlyWebPublishedServer::PublishedServerStarted(nsresult aStatus) -{ - LOG_I("FlyWebPublishedServer::PublishedServerStarted(%p)", this); - - RefPtr promise = mPublishPromise.Ensure(__func__); - if (NS_SUCCEEDED(aStatus)) { - mPublishPromise.Resolve(this, __func__); - } else { - Close(); - mPublishPromise.Reject(aStatus, __func__); - } -} - -already_AddRefed -FlyWebPublishedServer::OnWebSocketAccept(InternalRequest* aConnectRequest, - const Optional& aProtocol, - ErrorResult& aRv) -{ - MOZ_ASSERT(aConnectRequest); - - LOG_I("FlyWebPublishedServer::OnWebSocketAccept(%p)", this); - - nsCOMPtr provider = - OnWebSocketAcceptInternal(aConnectRequest, - aProtocol, - aRv); - if (aRv.Failed()) { - return nullptr; - } - MOZ_ASSERT(provider); - - nsCOMPtr window = do_QueryInterface(GetOwner()); - AutoJSContext cx; - GlobalObject global(cx, nsGlobalWindow::Cast(window)->FastGetGlobalJSObject()); - - nsAutoCString extensions, negotiatedExtensions; - aConnectRequest->Headers()-> - GetFirst(NS_LITERAL_CSTRING("Sec-WebSocket-Extensions"), extensions, aRv); - mozilla::net::ProcessServerWebSocketExtensions(extensions, - negotiatedExtensions); - - nsCString url; - aConnectRequest->GetURL(url); - Sequence protocols; - if (aProtocol.WasPassed() && - !protocols.AppendElement(aProtocol.Value(), fallible)) { - aRv.Throw(NS_ERROR_OUT_OF_MEMORY); - return nullptr; - } - - return WebSocket::ConstructorCommon(global, - NS_ConvertUTF8toUTF16(url), - protocols, - provider, - negotiatedExtensions, - aRv); -} - -/******** FlyWebPublishedServerImpl ********/ - -NS_IMPL_ISUPPORTS_INHERITED0(FlyWebPublishedServerImpl, mozilla::DOMEventTargetHelper) - -FlyWebPublishedServerImpl::FlyWebPublishedServerImpl(nsPIDOMWindowInner* aOwner, - const nsAString& aName, - const FlyWebPublishOptions& aOptions) - : FlyWebPublishedServer(aOwner, aName, aOptions) - , mHttpServer(new HttpServer()) -{ - LOG_I("FlyWebPublishedServerImpl::FlyWebPublishedServerImpl(%p)", this); -} - -void -FlyWebPublishedServerImpl::PermissionGranted(bool aGranted) -{ - LOG_I("FlyWebPublishedServerImpl::PermissionGranted(%b)", aGranted); - if (!aGranted) { - PublishedServerStarted(NS_ERROR_FAILURE); - return; - } - - mHttpServer->Init(-1, Preferences::GetBool("flyweb.use-tls", false), this); -} - -void -FlyWebPublishedServerImpl::Close() -{ - FlyWebPublishedServer::Close(); - - if (mMDNSCancelRegister) { - mMDNSCancelRegister->Cancel(NS_BINDING_ABORTED); - mMDNSCancelRegister = nullptr; - } - - if (mHttpServer) { - RefPtr server = mHttpServer.forget(); - server->Close(); - } -} - -void -FlyWebPublishedServerImpl::OnServerStarted(nsresult aStatus) -{ - if (NS_SUCCEEDED(aStatus)) { - FlyWebService::GetOrCreate()->StartDiscoveryOf(this); - } else { - PublishedServerStarted(aStatus); - } -} - -void -FlyWebPublishedServerImpl::OnFetchResponse(InternalRequest* aRequest, - InternalResponse* aResponse) -{ - MOZ_ASSERT(aRequest); - MOZ_ASSERT(aResponse); - - LOG_I("FlyWebPublishedServerImpl::OnFetchResponse(%p)", this); - - if (mHttpServer) { - mHttpServer->SendResponse(aRequest, aResponse); - } -} - -void -FlyWebPublishedServerImpl::OnWebSocketResponse(InternalRequest* aConnectRequest, - InternalResponse* aResponse) -{ - MOZ_ASSERT(aConnectRequest); - MOZ_ASSERT(aResponse); - - LOG_I("FlyWebPublishedMDNSServer::OnWebSocketResponse(%p)", this); - - if (mHttpServer) { - mHttpServer->SendWebSocketResponse(aConnectRequest, aResponse); - } -} - -already_AddRefed -FlyWebPublishedServerImpl::OnWebSocketAcceptInternal(InternalRequest* aConnectRequest, - const Optional& aProtocol, - ErrorResult& aRv) -{ - LOG_I("FlyWebPublishedServerImpl::OnWebSocketAcceptInternal(%p)", this); - - if (!mHttpServer) { - aRv.Throw(NS_ERROR_UNEXPECTED); - return nullptr; - } - - return mHttpServer->AcceptWebSocket(aConnectRequest, - aProtocol, - aRv); -} - -/******** FlyWebPublishedServerChild ********/ - -FlyWebPublishedServerChild::FlyWebPublishedServerChild(nsPIDOMWindowInner* aOwner, - const nsAString& aName, - const FlyWebPublishOptions& aOptions) - : FlyWebPublishedServer(aOwner, aName, aOptions) - , mActorExists(false) -{ - LOG_I("FlyWebPublishedServerChild::FlyWebPublishedServerChild(%p)", this); - - // The matching release happens when the actor is destroyed, in - // ContentChild::DeallocPFlyWebPublishedServerChild - NS_ADDREF_THIS(); -} - -void -FlyWebPublishedServerChild::PermissionGranted(bool aGranted) -{ - if (!aGranted) { - PublishedServerStarted(NS_ERROR_FAILURE); - return; - } - - mActorExists = true; - FlyWebPublishOptions options; - options.mUiUrl = mUiUrl; - - // Proceed with initialization. - ContentChild::GetSingleton()-> - SendPFlyWebPublishedServerConstructor(this, mName, options); -} - -bool -FlyWebPublishedServerChild::RecvServerReady(const nsresult& aStatus) -{ - LOG_I("FlyWebPublishedServerChild::RecvServerReady(%p)", this); - MOZ_ASSERT(mActorExists); - - PublishedServerStarted(aStatus); - return true; -} - -bool -FlyWebPublishedServerChild::RecvServerClose() -{ - LOG_I("FlyWebPublishedServerChild::RecvServerClose(%p)", this); - MOZ_ASSERT(mActorExists); - - Close(); - - return true; -} - -bool -FlyWebPublishedServerChild::RecvFetchRequest(const IPCInternalRequest& aRequest, - const uint64_t& aRequestId) -{ - LOG_I("FlyWebPublishedServerChild::RecvFetchRequest(%p)", this); - MOZ_ASSERT(mActorExists); - - RefPtr request = new InternalRequest(aRequest); - mPendingRequests.Put(request, aRequestId); - FireFetchEvent(request); - - return true; -} - -bool -FlyWebPublishedServerChild::RecvWebSocketRequest(const IPCInternalRequest& aRequest, - const uint64_t& aRequestId, - PTransportProviderChild* aProvider) -{ - LOG_I("FlyWebPublishedServerChild::RecvWebSocketRequest(%p)", this); - MOZ_ASSERT(mActorExists); - - RefPtr request = new InternalRequest(aRequest); - mPendingRequests.Put(request, aRequestId); - - // Not addreffing here. The addref was already done when the - // PTransportProvider child constructor original ran. - mPendingTransportProviders.Put(aRequestId, - dont_AddRef(static_cast(aProvider))); - - FireWebsocketEvent(request); - - return true; -} - -void -FlyWebPublishedServerChild::ActorDestroy(ActorDestroyReason aWhy) -{ - LOG_I("FlyWebPublishedServerChild::ActorDestroy(%p)", this); - - mActorExists = false; -} - -void -FlyWebPublishedServerChild::OnFetchResponse(InternalRequest* aRequest, - InternalResponse* aResponse) -{ - LOG_I("FlyWebPublishedServerChild::OnFetchResponse(%p)", this); - - if (!mActorExists) { - LOG_I("FlyWebPublishedServerChild::OnFetchResponse(%p) - No actor!", this); - return; - } - - uint64_t id = mPendingRequests.Get(aRequest); - MOZ_ASSERT(id); - mPendingRequests.Remove(aRequest); - - IPCInternalResponse ipcResp; - UniquePtr autoStream; - nsIContentChild* cc = static_cast(Manager()); - aResponse->ToIPC(&ipcResp, cc, autoStream); - Unused << SendFetchResponse(ipcResp, id); - if (autoStream) { - autoStream->TakeOptionalValue(); - } -} - -already_AddRefed -FlyWebPublishedServerChild::OnWebSocketAcceptInternal(InternalRequest* aRequest, - const Optional& aProtocol, - ErrorResult& aRv) -{ - LOG_I("FlyWebPublishedServerChild::OnWebSocketAcceptInternal(%p)", this); - - if (!mActorExists) { - LOG_I("FlyWebPublishedServerChild::OnWebSocketAcceptInternal(%p) - No actor!", this); - return nullptr; - } - - uint64_t id = mPendingRequests.Get(aRequest); - MOZ_ASSERT(id); - mPendingRequests.Remove(aRequest); - - RefPtr provider; - mPendingTransportProviders.Remove(id, getter_AddRefs(provider)); - - nsString protocol; - if (aProtocol.WasPassed()) { - protocol = aProtocol.Value(); - - nsAutoCString reqProtocols; - aRequest->Headers()-> - GetFirst(NS_LITERAL_CSTRING("Sec-WebSocket-Protocol"), reqProtocols, aRv); - if (!ContainsToken(reqProtocols, NS_ConvertUTF16toUTF8(protocol))) { - // Should throw a better error here - aRv.Throw(NS_ERROR_FAILURE); - return nullptr; - } - } else { - protocol.SetIsVoid(true); - } - - Unused << SendWebSocketAccept(protocol, id); - - return provider.forget(); -} - -void -FlyWebPublishedServerChild::OnWebSocketResponse(InternalRequest* aRequest, - InternalResponse* aResponse) -{ - LOG_I("FlyWebPublishedServerChild::OnFetchResponse(%p)", this); - - if (!mActorExists) { - LOG_I("FlyWebPublishedServerChild::OnFetchResponse(%p) - No actor!", this); - return; - } - - uint64_t id = mPendingRequests.Get(aRequest); - MOZ_ASSERT(id); - mPendingRequests.Remove(aRequest); - - mPendingTransportProviders.Remove(id); - - IPCInternalResponse ipcResp; - UniquePtr autoStream; - nsIContentChild* cc = static_cast(Manager()); - aResponse->ToIPC(&ipcResp, cc, autoStream); - - Unused << SendWebSocketResponse(ipcResp, id); - if (autoStream) { - autoStream->TakeOptionalValue(); - } -} - -void -FlyWebPublishedServerChild::Close() -{ - LOG_I("FlyWebPublishedServerChild::Close(%p)", this); - - FlyWebPublishedServer::Close(); - - if (mActorExists) { - LOG_I("FlyWebPublishedServerChild::Close - sending __delete__ (%p)", this); - - Send__delete__(this); - } -} - -/******** FlyWebPublishedServerParent ********/ - -NS_IMPL_ISUPPORTS(FlyWebPublishedServerParent, nsIDOMEventListener) - -FlyWebPublishedServerParent::FlyWebPublishedServerParent(const nsAString& aName, - const FlyWebPublishOptions& aOptions) - : mActorDestroyed(false) - , mNextRequestId(1) -{ - LOG_I("FlyWebPublishedServerParent::FlyWebPublishedServerParent(%p)", this); - - RefPtr service = FlyWebService::GetOrCreate(); - if (!service) { - Unused << SendServerReady(NS_ERROR_FAILURE); - return; - } - - RefPtr mozPromise = - service->PublishServer(aName, aOptions, nullptr); - if (!mozPromise) { - Unused << SendServerReady(NS_ERROR_FAILURE); - return; - } - - RefPtr self = this; - - mozPromise->Then( - AbstractThread::MainThread(), - __func__, - [this, self] (FlyWebPublishedServer* aServer) { - mPublishedServer = static_cast(aServer); - if (mActorDestroyed) { - mPublishedServer->Close(); - return; - } - - mPublishedServer->AddEventListener(NS_LITERAL_STRING("fetch"), - this, false, false, 2); - mPublishedServer->AddEventListener(NS_LITERAL_STRING("websocket"), - this, false, false, 2); - mPublishedServer->AddEventListener(NS_LITERAL_STRING("close"), - this, false, false, 2); - Unused << SendServerReady(NS_OK); - }, - [this, self] (nsresult aStatus) { - MOZ_ASSERT(NS_FAILED(aStatus)); - if (!mActorDestroyed) { - Unused << SendServerReady(aStatus); - } - }); -} - -NS_IMETHODIMP -FlyWebPublishedServerParent::HandleEvent(nsIDOMEvent* aEvent) -{ - if (mActorDestroyed) { - return NS_OK; - } - - nsAutoString type; - aEvent->GetType(type); - if (type.EqualsLiteral("close")) { - Unused << SendServerClose(); - return NS_OK; - } - - if (type.EqualsLiteral("fetch")) { - RefPtr request = - static_cast(aEvent)->Request()->GetInternalRequest(); - uint64_t id = mNextRequestId++; - mPendingRequests.Put(id, request); - - IPCInternalRequest ipcReq; - request->ToIPC(&ipcReq); - Unused << SendFetchRequest(ipcReq, id); - return NS_OK; - } - - if (type.EqualsLiteral("websocket")) { - RefPtr request = - static_cast(aEvent)->Request()->GetInternalRequest(); - uint64_t id = mNextRequestId++; - mPendingRequests.Put(id, request); - - nsTArray neckoParents; - Manager()->ManagedPNeckoParent(neckoParents); - if (neckoParents.Length() != 1) { - MOZ_CRASH("Expected exactly 1 PNeckoParent instance per PNeckoChild"); - } - - RefPtr provider = - static_cast( - neckoParents[0]->SendPTransportProviderConstructor()); - - IPCInternalRequest ipcReq; - request->ToIPC(&ipcReq); - Unused << SendWebSocketRequest(ipcReq, id, provider); - - mPendingTransportProviders.Put(id, provider.forget()); - return NS_OK; - } - - MOZ_CRASH("Unknown event type"); - - return NS_OK; -} - -bool -FlyWebPublishedServerParent::RecvFetchResponse(const IPCInternalResponse& aResponse, - const uint64_t& aRequestId) -{ - MOZ_ASSERT(!mActorDestroyed); - - RefPtr request; - mPendingRequests.Remove(aRequestId, getter_AddRefs(request)); - if (!request) { - static_cast(Manager())->KillHard("unknown request id"); - return false; - } - - RefPtr response = InternalResponse::FromIPC(aResponse); - - mPublishedServer->OnFetchResponse(request, response); - - return true; -} - -bool -FlyWebPublishedServerParent::RecvWebSocketResponse(const IPCInternalResponse& aResponse, - const uint64_t& aRequestId) -{ - MOZ_ASSERT(!mActorDestroyed); - - mPendingTransportProviders.Remove(aRequestId); - - RefPtr request; - mPendingRequests.Remove(aRequestId, getter_AddRefs(request)); - if (!request) { - static_cast(Manager())->KillHard("unknown websocket request id"); - return false; - } - - RefPtr response = InternalResponse::FromIPC(aResponse); - - mPublishedServer->OnWebSocketResponse(request, response); - - return true; -} - -bool -FlyWebPublishedServerParent::RecvWebSocketAccept(const nsString& aProtocol, - const uint64_t& aRequestId) -{ - MOZ_ASSERT(!mActorDestroyed); - - RefPtr providerIPC; - mPendingTransportProviders.Remove(aRequestId, getter_AddRefs(providerIPC)); - - RefPtr request; - mPendingRequests.Remove(aRequestId, getter_AddRefs(request)); - - if (!request || !providerIPC) { - static_cast(Manager())->KillHard("unknown websocket request id"); - return false; - } - - Optional protocol; - if (!aProtocol.IsVoid()) { - protocol = &aProtocol; - } - - ErrorResult result; - nsCOMPtr providerServer = - mPublishedServer->OnWebSocketAcceptInternal(request, protocol, result); - if (result.Failed()) { - return false; - } - - providerServer->SetListener(providerIPC); - - return true; -} - -void -FlyWebPublishedServerParent::ActorDestroy(ActorDestroyReason aWhy) -{ - LOG_I("FlyWebPublishedServerParent::ActorDestroy(%p)", this); - - mActorDestroyed = true; -} - -bool -FlyWebPublishedServerParent::Recv__delete__() -{ - LOG_I("FlyWebPublishedServerParent::Recv__delete__(%p)", this); - MOZ_ASSERT(!mActorDestroyed); - - if (mPublishedServer) { - mPublishedServer->RemoveEventListener(NS_LITERAL_STRING("fetch"), - this, false); - mPublishedServer->RemoveEventListener(NS_LITERAL_STRING("websocket"), - this, false); - mPublishedServer->RemoveEventListener(NS_LITERAL_STRING("close"), - this, false); - mPublishedServer->Close(); - mPublishedServer = nullptr; - } - return true; -} - -} // namespace dom -} // namespace mozilla - - diff --git a/dom/flyweb/FlyWebPublishedServer.h b/dom/flyweb/FlyWebPublishedServer.h deleted file mode 100644 index ec3a685ec..000000000 --- a/dom/flyweb/FlyWebPublishedServer.h +++ /dev/null @@ -1,109 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: set ts=8 sts=2 et sw=2 tw=80: */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef mozilla_dom_FlyWebPublishedServer_h -#define mozilla_dom_FlyWebPublishedServer_h - -#include "mozilla/DOMEventTargetHelper.h" -#include "mozilla/MozPromise.h" - -class nsPIDOMWindowInner; -class nsITransportProvider; - -namespace mozilla { - -class ErrorResult; - -namespace dom { - -class InternalResponse; -class InternalRequest; -class WebSocket; -struct FlyWebPublishOptions; -class FlyWebPublishedServer; - -typedef MozPromise, nsresult, false> - FlyWebPublishPromise; - -class FlyWebPublishedServer : public mozilla::DOMEventTargetHelper -{ -public: - FlyWebPublishedServer(nsPIDOMWindowInner* aOwner, - const nsAString& aName, - const FlyWebPublishOptions& aOptions); - - virtual void LastRelease() override; - - virtual JSObject* WrapObject(JSContext *cx, JS::Handle aGivenProto) override; - - uint64_t OwnerWindowID() const { - return mOwnerWindowID; - } - - void GetName(nsAString& aName) - { - aName = mName; - } - nsAString& Name() - { - return mName; - } - - void GetUiUrl(nsAString& aUiUrl) - { - aUiUrl = mUiUrl; - } - - virtual void PermissionGranted(bool aGranted) = 0; - - virtual void OnFetchResponse(InternalRequest* aRequest, - InternalResponse* aResponse) = 0; - already_AddRefed - OnWebSocketAccept(InternalRequest* aConnectRequest, - const Optional& aProtocol, - ErrorResult& aRv); - virtual void OnWebSocketResponse(InternalRequest* aConnectRequest, - InternalResponse* aResponse) = 0; - virtual already_AddRefed - OnWebSocketAcceptInternal(InternalRequest* aConnectRequest, - const Optional& aProtocol, - ErrorResult& aRv) = 0; - - virtual void Close(); - - void FireFetchEvent(InternalRequest* aRequest); - void FireWebsocketEvent(InternalRequest* aConnectRequest); - void PublishedServerStarted(nsresult aStatus); - - IMPL_EVENT_HANDLER(fetch) - IMPL_EVENT_HANDLER(websocket) - IMPL_EVENT_HANDLER(close) - - already_AddRefed - GetPublishPromise() - { - return mPublishPromise.Ensure(__func__); - } - -protected: - virtual ~FlyWebPublishedServer() - { - MOZ_ASSERT(!mIsRegistered, "Subclass dtor forgot to call Close()"); - } - - uint64_t mOwnerWindowID; - MozPromiseHolder mPublishPromise; - - nsString mName; - nsString mUiUrl; - - bool mIsRegistered; -}; - -} // namespace dom -} // namespace mozilla - -#endif // mozilla_dom_FlyWebPublishedServer_h diff --git a/dom/flyweb/FlyWebPublishedServerIPC.h b/dom/flyweb/FlyWebPublishedServerIPC.h deleted file mode 100644 index 942c7847e..000000000 --- a/dom/flyweb/FlyWebPublishedServerIPC.h +++ /dev/null @@ -1,172 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: set ts=8 sts=2 et sw=2 tw=80: */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef mozilla_dom_FlyWebPublishedServerIPC_h -#define mozilla_dom_FlyWebPublishedServerIPC_h - -#include "HttpServer.h" -#include "mozilla/dom/FlyWebPublishedServer.h" -#include "mozilla/dom/PFlyWebPublishedServerParent.h" -#include "mozilla/dom/PFlyWebPublishedServerChild.h" -#include "mozilla/MozPromise.h" -#include "nsICancelable.h" -#include "nsIDOMEventListener.h" -#include "nsISupportsImpl.h" - -class nsPIDOMWindowInner; - -namespace mozilla { -namespace net { -class TransportProviderParent; -class TransportProviderChild; -} - -namespace dom { - -class FlyWebPublishedServerParent; - -class FlyWebPublishedServerImpl final : public FlyWebPublishedServer - , public HttpServerListener -{ -public: - FlyWebPublishedServerImpl(nsPIDOMWindowInner* aOwner, - const nsAString& aName, - const FlyWebPublishOptions& aOptions); - - NS_DECL_ISUPPORTS_INHERITED - - int32_t Port() - { - return mHttpServer ? mHttpServer->GetPort() : 0; - } - void GetCertKey(nsACString& aKey) { - if (mHttpServer) { - mHttpServer->GetCertKey(aKey); - } else { - aKey.Truncate(); - } - } - - virtual void PermissionGranted(bool aGranted) override; - virtual void OnFetchResponse(InternalRequest* aRequest, - InternalResponse* aResponse) override; - virtual void OnWebSocketResponse(InternalRequest* aConnectRequest, - InternalResponse* aResponse) override; - virtual already_AddRefed - OnWebSocketAcceptInternal(InternalRequest* aConnectRequest, - const Optional& aProtocol, - ErrorResult& aRv) override; - - void SetCancelRegister(nsICancelable* aCancelRegister) - { - mMDNSCancelRegister = aCancelRegister; - } - - virtual void Close() override; - - // HttpServerListener - virtual void OnServerStarted(nsresult aStatus) override; - virtual void OnRequest(InternalRequest* aRequest) override - { - FireFetchEvent(aRequest); - } - virtual void OnWebSocket(InternalRequest* aConnectRequest) override - { - FireWebsocketEvent(aConnectRequest); - } - virtual void OnServerClose() override - { - mHttpServer = nullptr; - Close(); - } - -private: - ~FlyWebPublishedServerImpl() {} - - RefPtr mHttpServer; - nsCOMPtr mMDNSCancelRegister; - RefPtr mServerParent; -}; - -class FlyWebPublishedServerChild final : public FlyWebPublishedServer - , public PFlyWebPublishedServerChild -{ -public: - FlyWebPublishedServerChild(nsPIDOMWindowInner* aOwner, - const nsAString& aName, - const FlyWebPublishOptions& aOptions); - - virtual void PermissionGranted(bool aGranted) override; - virtual bool RecvServerReady(const nsresult& aStatus) override; - virtual bool RecvServerClose() override; - virtual bool RecvFetchRequest(const IPCInternalRequest& aRequest, - const uint64_t& aRequestId) override; - virtual bool RecvWebSocketRequest(const IPCInternalRequest& aRequest, - const uint64_t& aRequestId, - PTransportProviderChild* aProvider) override; - - virtual void OnFetchResponse(InternalRequest* aRequest, - InternalResponse* aResponse) override; - virtual void OnWebSocketResponse(InternalRequest* aConnectRequest, - InternalResponse* aResponse) override; - virtual already_AddRefed - OnWebSocketAcceptInternal(InternalRequest* aConnectRequest, - const Optional& aProtocol, - ErrorResult& aRv) override; - - virtual void Close() override; - - virtual void ActorDestroy(ActorDestroyReason aWhy) override; - -private: - ~FlyWebPublishedServerChild() {} - - nsDataHashtable, uint64_t> mPendingRequests; - nsRefPtrHashtable - mPendingTransportProviders; - bool mActorExists; -}; - -class FlyWebPublishedServerParent final : public PFlyWebPublishedServerParent - , public nsIDOMEventListener -{ -public: - FlyWebPublishedServerParent(const nsAString& aName, - const FlyWebPublishOptions& aOptions); - - NS_DECL_ISUPPORTS - NS_DECL_NSIDOMEVENTLISTENER - -private: - virtual void - ActorDestroy(ActorDestroyReason aWhy) override; - - virtual bool - Recv__delete__() override; - virtual bool - RecvFetchResponse(const IPCInternalResponse& aResponse, - const uint64_t& aRequestId) override; - virtual bool - RecvWebSocketResponse(const IPCInternalResponse& aResponse, - const uint64_t& aRequestId) override; - virtual bool - RecvWebSocketAccept(const nsString& aProtocol, - const uint64_t& aRequestId) override; - - ~FlyWebPublishedServerParent() {} - - bool mActorDestroyed; - uint64_t mNextRequestId; - nsRefPtrHashtable mPendingRequests; - nsRefPtrHashtable - mPendingTransportProviders; - RefPtr mPublishedServer; -}; - -} // namespace dom -} // namespace mozilla - -#endif // mozilla_dom_FlyWebPublishedServerIPC_h diff --git a/dom/flyweb/FlyWebServerEvents.cpp b/dom/flyweb/FlyWebServerEvents.cpp deleted file mode 100644 index fe774ffb0..000000000 --- a/dom/flyweb/FlyWebServerEvents.cpp +++ /dev/null @@ -1,141 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim:set ts=2 sw=2 sts=2 et cindent: */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "mozilla/dom/EventBinding.h" -#include "mozilla/dom/FlyWebFetchEventBinding.h" -#include "mozilla/dom/FlyWebPublishedServer.h" -#include "mozilla/dom/FlyWebServerEvents.h" -#include "mozilla/dom/FlyWebWebSocketEventBinding.h" -#include "mozilla/dom/Nullable.h" -#include "mozilla/dom/Promise.h" -#include "mozilla/dom/Response.h" - -#include "js/GCAPI.h" - -namespace mozilla { -namespace dom { - - -NS_IMPL_CYCLE_COLLECTION_CLASS(FlyWebFetchEvent) - -NS_IMPL_ADDREF_INHERITED(FlyWebFetchEvent, Event) -NS_IMPL_RELEASE_INHERITED(FlyWebFetchEvent, Event) - -NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(FlyWebFetchEvent, Event) - NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mRequest) -NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END - -NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(FlyWebFetchEvent, Event) -NS_IMPL_CYCLE_COLLECTION_TRACE_END - -NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(FlyWebFetchEvent, Event) - NS_IMPL_CYCLE_COLLECTION_UNLINK(mRequest) -NS_IMPL_CYCLE_COLLECTION_UNLINK_END - -NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(FlyWebFetchEvent) -NS_INTERFACE_MAP_END_INHERITING(Event) - -FlyWebFetchEvent::FlyWebFetchEvent(FlyWebPublishedServer* aServer, - class Request* aRequest, - InternalRequest* aInternalRequest) - : Event(aServer, nullptr, nullptr) - , mRequest(aRequest) - , mInternalRequest(aInternalRequest) - , mServer(aServer) - , mResponded(false) -{ - MOZ_ASSERT(aServer); - MOZ_ASSERT(aRequest); - MOZ_ASSERT(aInternalRequest); -} - -FlyWebFetchEvent::~FlyWebFetchEvent() -{ -} - -JSObject* -FlyWebFetchEvent::WrapObjectInternal(JSContext* aCx, JS::Handle aGivenProto) -{ - return FlyWebFetchEventBinding::Wrap(aCx, this, aGivenProto); -} - -void -FlyWebFetchEvent::RespondWith(Promise& aArg, ErrorResult& aRv) -{ - if (mResponded) { - aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR); - return; - } - - mResponded = true; - - aArg.AppendNativeHandler(this); -} - -void -FlyWebFetchEvent::ResolvedCallback(JSContext* aCx, JS::Handle aValue) -{ - RefPtr response; - if (aValue.isObject()) { - UNWRAP_OBJECT(Response, &aValue.toObject(), response); - } - - RefPtr intResponse; - if (response && response->Type() != ResponseType::Opaque) { - intResponse = response->GetInternalResponse(); - } - - if (!intResponse) { - intResponse = InternalResponse::NetworkError(); - } - - NotifyServer(intResponse); -} - -void -FlyWebFetchEvent::NotifyServer(InternalResponse* aResponse) -{ - mServer->OnFetchResponse(mInternalRequest, aResponse); -} - -void -FlyWebFetchEvent::RejectedCallback(JSContext* aCx, JS::Handle aValue) -{ - RefPtr err = InternalResponse::NetworkError(); - - NotifyServer(err); -} - -JSObject* -FlyWebWebSocketEvent::WrapObjectInternal(JSContext* aCx, JS::Handle aGivenProto) -{ - return FlyWebWebSocketEventBinding::Wrap(aCx, this, aGivenProto); -} - -already_AddRefed -FlyWebWebSocketEvent::Accept(const Optional& aProtocol, - ErrorResult& aRv) -{ - if (mResponded) { - aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR); - return nullptr; - } - - mResponded = true; - - return mServer->OnWebSocketAccept(mInternalRequest, aProtocol, aRv); -} - - -void -FlyWebWebSocketEvent::NotifyServer(InternalResponse* aResponse) -{ - mServer->OnWebSocketResponse(mInternalRequest, aResponse); -} - - -} // namespace dom -} // namespace mozilla diff --git a/dom/flyweb/FlyWebServerEvents.h b/dom/flyweb/FlyWebServerEvents.h deleted file mode 100644 index f00e86018..000000000 --- a/dom/flyweb/FlyWebServerEvents.h +++ /dev/null @@ -1,88 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim:set ts=2 sw=2 sts=2 et cindent: */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef mozilla_dom_FlyWebFetchEvent_h -#define mozilla_dom_FlyWebFetchEvent_h - -#include "mozilla/Attributes.h" -#include "mozilla/ErrorResult.h" -#include "mozilla/dom/BindingUtils.h" -#include "mozilla/dom/Event.h" -#include "mozilla/dom/FlyWebFetchEventBinding.h" -#include "mozilla/dom/PromiseNativeHandler.h" -#include "mozilla/dom/WebSocket.h" - -struct JSContext; -namespace mozilla { -namespace dom { - -class Request; -class Response; -class FlyWebPublishedServer; -class InternalRequest; -class InternalResponse; - -class FlyWebFetchEvent : public Event - , public PromiseNativeHandler -{ -public: - NS_DECL_ISUPPORTS_INHERITED - NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(FlyWebFetchEvent, Event) - - virtual JSObject* WrapObjectInternal(JSContext* aCx, JS::Handle aGivenProto) override; - - virtual void - ResolvedCallback(JSContext* aCx, JS::Handle aValue) override; - virtual void - RejectedCallback(JSContext* aCx, JS::Handle aValue) override; - - class Request* Request() const - { - return mRequest; - } - - void RespondWith(Promise& aArg, ErrorResult& aRv); - - FlyWebFetchEvent(FlyWebPublishedServer* aServer, - class Request* aRequest, - InternalRequest* aInternalRequest); - -protected: - virtual ~FlyWebFetchEvent(); - - virtual void NotifyServer(InternalResponse* aResponse); - - RefPtr mRequest; - RefPtr mInternalRequest; - RefPtr mServer; - - bool mResponded; -}; - -class FlyWebWebSocketEvent final : public FlyWebFetchEvent -{ -public: - FlyWebWebSocketEvent(FlyWebPublishedServer* aServer, - class Request* aRequest, - InternalRequest* aInternalRequest) - : FlyWebFetchEvent(aServer, aRequest, aInternalRequest) - {} - - virtual JSObject* WrapObjectInternal(JSContext* aCx, JS::Handle aGivenProto) override; - - already_AddRefed Accept(const Optional& aProtocol, - ErrorResult& aRv); - -private: - ~FlyWebWebSocketEvent() {}; - - virtual void NotifyServer(InternalResponse* aResponse) override; -}; - -} // namespace dom -} // namespace mozilla - -#endif // mozilla_dom_FlyWebFetchEvent_h diff --git a/dom/flyweb/FlyWebService.cpp b/dom/flyweb/FlyWebService.cpp deleted file mode 100644 index 5f3b0d66f..000000000 --- a/dom/flyweb/FlyWebService.cpp +++ /dev/null @@ -1,1310 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: set ts=8 sts=2 et sw=2 tw=80: */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "mozilla/dom/FlyWebService.h" -#include "mozilla/ClearOnShutdown.h" -#include "mozilla/StaticPtr.h" -#include "mozilla/ScopeExit.h" -#include "mozilla/dom/Promise.h" -#include "mozilla/dom/FlyWebPublishedServerIPC.h" -#include "mozilla/AddonPathService.h" -#include "nsISocketTransportService.h" -#include "mdns/libmdns/nsDNSServiceInfo.h" -#include "nsIUUIDGenerator.h" -#include "nsStandardURL.h" -#include "mozilla/Services.h" -#include "nsISupportsPrimitives.h" -#include "mozilla/dom/FlyWebDiscoveryManagerBinding.h" -#include "prnetdb.h" -#include "DNS.h" -#include "nsContentPermissionHelper.h" -#include "nsSocketTransportService2.h" -#include "nsSocketTransport2.h" -#include "nsHashPropertyBag.h" -#include "nsNetUtil.h" -#include "nsISimpleEnumerator.h" -#include "nsIProperty.h" -#include "nsICertOverrideService.h" - -namespace mozilla { -namespace dom { - -struct FlyWebPublishOptions; - -static LazyLogModule gFlyWebServiceLog("FlyWebService"); -#undef LOG_I -#define LOG_I(...) MOZ_LOG(mozilla::dom::gFlyWebServiceLog, mozilla::LogLevel::Debug, (__VA_ARGS__)) - -#undef LOG_E -#define LOG_E(...) MOZ_LOG(mozilla::dom::gFlyWebServiceLog, mozilla::LogLevel::Error, (__VA_ARGS__)) - -#undef LOG_TEST_I -#define LOG_TEST_I(...) MOZ_LOG_TEST(mozilla::dom::gFlyWebServiceLog, mozilla::LogLevel::Debug) - -class FlyWebPublishServerPermissionCheck final - : public nsIContentPermissionRequest - , public nsIRunnable -{ -public: - NS_DECL_ISUPPORTS - - FlyWebPublishServerPermissionCheck(const nsCString& aServiceName, uint64_t aWindowID, - FlyWebPublishedServer* aServer) - : mServiceName(aServiceName) - , mWindowID(aWindowID) - , mServer(aServer) - {} - - uint64_t WindowID() const - { - return mWindowID; - } - - NS_IMETHOD Run() override - { - MOZ_ASSERT(NS_IsMainThread()); - - nsGlobalWindow* globalWindow = nsGlobalWindow::GetInnerWindowWithId(mWindowID); - if (!globalWindow) { - return Cancel(); - } - mWindow = globalWindow->AsInner(); - if (NS_WARN_IF(!mWindow)) { - return Cancel(); - } - - nsCOMPtr doc = mWindow->GetDoc(); - if (NS_WARN_IF(!doc)) { - return Cancel(); - } - - mPrincipal = doc->NodePrincipal(); - MOZ_ASSERT(mPrincipal); - - mRequester = new nsContentPermissionRequester(mWindow); - return nsContentPermissionUtils::AskPermission(this, mWindow); - } - - NS_IMETHOD Cancel() override - { - Resolve(false); - return NS_OK; - } - - NS_IMETHOD Allow(JS::HandleValue aChoices) override - { - MOZ_ASSERT(aChoices.isUndefined()); - Resolve(true); - return NS_OK; - } - - NS_IMETHOD GetTypes(nsIArray** aTypes) override - { - nsTArray emptyOptions; - return nsContentPermissionUtils::CreatePermissionArray(NS_LITERAL_CSTRING("flyweb-publish-server"), - NS_LITERAL_CSTRING("unused"), emptyOptions, aTypes); - } - - NS_IMETHOD GetRequester(nsIContentPermissionRequester** aRequester) override - { - NS_ENSURE_ARG_POINTER(aRequester); - nsCOMPtr requester = mRequester; - requester.forget(aRequester); - return NS_OK; - } - - NS_IMETHOD GetPrincipal(nsIPrincipal** aRequestingPrincipal) override - { - NS_IF_ADDREF(*aRequestingPrincipal = mPrincipal); - return NS_OK; - } - - NS_IMETHOD GetWindow(mozIDOMWindow** aRequestingWindow) override - { - NS_IF_ADDREF(*aRequestingWindow = mWindow); - return NS_OK; - } - - NS_IMETHOD GetElement(nsIDOMElement** aRequestingElement) override - { - *aRequestingElement = nullptr; - return NS_OK; - } - -private: - void Resolve(bool aResolve) - { - mServer->PermissionGranted(aResolve); - } - - virtual ~FlyWebPublishServerPermissionCheck() = default; - - nsCString mServiceName; - uint64_t mWindowID; - RefPtr mServer; - nsCOMPtr mWindow; - nsCOMPtr mPrincipal; - nsCOMPtr mRequester; -}; - -NS_IMPL_ISUPPORTS(FlyWebPublishServerPermissionCheck, - nsIContentPermissionRequest, - nsIRunnable) - -class FlyWebMDNSService final - : public nsIDNSServiceDiscoveryListener - , public nsIDNSServiceResolveListener - , public nsIDNSRegistrationListener - , public nsITimerCallback -{ - friend class FlyWebService; - -private: - enum DiscoveryState { - DISCOVERY_IDLE, - DISCOVERY_STARTING, - DISCOVERY_RUNNING, - DISCOVERY_STOPPING - }; - -public: - NS_DECL_ISUPPORTS - NS_DECL_NSIDNSSERVICEDISCOVERYLISTENER - NS_DECL_NSIDNSSERVICERESOLVELISTENER - NS_DECL_NSIDNSREGISTRATIONLISTENER - NS_DECL_NSITIMERCALLBACK - - explicit FlyWebMDNSService(FlyWebService* aService, - const nsACString& aServiceType); - -private: - virtual ~FlyWebMDNSService() = default; - - nsresult Init(); - nsresult StartDiscovery(); - nsresult StopDiscovery(); - - void ListDiscoveredServices(nsTArray& aServices); - bool HasService(const nsAString& aServiceId); - nsresult PairWithService(const nsAString& aServiceId, - UniquePtr& aInfo); - - nsresult StartDiscoveryOf(FlyWebPublishedServerImpl* aServer); - - void EnsureDiscoveryStarted(); - void EnsureDiscoveryStopped(); - - // Cycle-breaking link to manager. - FlyWebService* mService; - nsCString mServiceType; - - // Indicates the desired state of the system. If mDiscoveryActive is true, - // it indicates that backend discovery "should be happening", and discovery - // events should be forwarded to listeners. - // If false, the backend discovery "should be idle", and any discovery events - // that show up should not be forwarded to listeners. - bool mDiscoveryActive; - - uint32_t mNumConsecutiveStartDiscoveryFailures; - - // Represents the internal discovery state as it relates to nsDNSServiceDiscovery. - // When mDiscoveryActive is true, this state will periodically loop from - // (IDLE => STARTING => RUNNING => STOPPING => IDLE). - DiscoveryState mDiscoveryState; - - nsCOMPtr mDiscoveryStartTimer; - nsCOMPtr mDiscoveryStopTimer; - nsCOMPtr mDNSServiceDiscovery; - nsCOMPtr mCancelDiscovery; - nsTHashtable mNewServiceSet; - - struct DiscoveredInfo - { - explicit DiscoveredInfo(nsIDNSServiceInfo* aDNSServiceInfo); - FlyWebDiscoveredService mService; - nsCOMPtr mDNSServiceInfo; - }; - nsClassHashtable mServiceMap; -}; - -void -LogDNSInfo(nsIDNSServiceInfo* aServiceInfo, const char* aFunc) -{ - if (!LOG_TEST_I()) { - return; - } - - nsCString tmp; - aServiceInfo->GetServiceName(tmp); - LOG_I("%s: serviceName=%s", aFunc, tmp.get()); - - aServiceInfo->GetHost(tmp); - LOG_I("%s: host=%s", aFunc, tmp.get()); - - aServiceInfo->GetAddress(tmp); - LOG_I("%s: address=%s", aFunc, tmp.get()); - - uint16_t port = -2; - aServiceInfo->GetPort(&port); - LOG_I("%s: port=%d", aFunc, (int)port); - - nsCOMPtr attributes; - aServiceInfo->GetAttributes(getter_AddRefs(attributes)); - if (!attributes) { - LOG_I("%s: no attributes", aFunc); - } else { - nsCOMPtr enumerator; - attributes->GetEnumerator(getter_AddRefs(enumerator)); - MOZ_ASSERT(enumerator); - - LOG_I("%s: attributes start", aFunc); - - bool hasMoreElements; - while (NS_SUCCEEDED(enumerator->HasMoreElements(&hasMoreElements)) && - hasMoreElements) { - nsCOMPtr element; - MOZ_ALWAYS_SUCCEEDS(enumerator->GetNext(getter_AddRefs(element))); - nsCOMPtr property = do_QueryInterface(element); - MOZ_ASSERT(property); - - nsAutoString name; - nsCOMPtr value; - MOZ_ALWAYS_SUCCEEDS(property->GetName(name)); - MOZ_ALWAYS_SUCCEEDS(property->GetValue(getter_AddRefs(value))); - - nsAutoCString str; - nsresult rv = value->GetAsACString(str); - if (NS_SUCCEEDED(rv)) { - LOG_I("%s: attribute name=%s value=%s", aFunc, - NS_ConvertUTF16toUTF8(name).get(), str.get()); - } else { - uint16_t type; - MOZ_ALWAYS_SUCCEEDS(value->GetDataType(&type)); - LOG_I("%s: attribute *unstringifiable* name=%s type=%d", aFunc, - NS_ConvertUTF16toUTF8(name).get(), (int)type); - } - } - - LOG_I("%s: attributes end", aFunc); - } -} - -NS_IMPL_ISUPPORTS(FlyWebMDNSService, - nsIDNSServiceDiscoveryListener, - nsIDNSServiceResolveListener, - nsIDNSRegistrationListener, - nsITimerCallback) - -FlyWebMDNSService::FlyWebMDNSService( - FlyWebService* aService, - const nsACString& aServiceType) - : mService(aService) - , mServiceType(aServiceType) - , mDiscoveryActive(false) - , mNumConsecutiveStartDiscoveryFailures(0) - , mDiscoveryState(DISCOVERY_IDLE) -{} - -nsresult -FlyWebMDNSService::OnDiscoveryStarted(const nsACString& aServiceType) -{ - MOZ_ASSERT(mDiscoveryState == DISCOVERY_STARTING); - mDiscoveryState = DISCOVERY_RUNNING; - // Reset consecutive start discovery failures. - mNumConsecutiveStartDiscoveryFailures = 0; - LOG_I("==========================================="); - LOG_I("MDNSService::OnDiscoveryStarted(%s)", PromiseFlatCString(aServiceType).get()); - LOG_I("==========================================="); - - // Clear the new service array. - mNewServiceSet.Clear(); - - // If service discovery is inactive, then stop network discovery immediately. - if (!mDiscoveryActive) { - // Set the stop timer to fire immediately. - Unused << NS_WARN_IF(NS_FAILED(mDiscoveryStopTimer->InitWithCallback(this, 0, nsITimer::TYPE_ONE_SHOT))); - return NS_OK; - } - - // Otherwise, set the stop timer to fire in 5 seconds. - Unused << NS_WARN_IF(NS_FAILED(mDiscoveryStopTimer->InitWithCallback(this, 5 * 1000, nsITimer::TYPE_ONE_SHOT))); - - return NS_OK; -} - -nsresult -FlyWebMDNSService::OnDiscoveryStopped(const nsACString& aServiceType) -{ - LOG_I("///////////////////////////////////////////"); - LOG_I("MDNSService::OnDiscoveryStopped(%s)", PromiseFlatCString(aServiceType).get()); - LOG_I("///////////////////////////////////////////"); - MOZ_ASSERT(mDiscoveryState == DISCOVERY_STOPPING); - mDiscoveryState = DISCOVERY_IDLE; - - // If service discovery is inactive, then discard all results and do not proceed. - if (!mDiscoveryActive) { - mServiceMap.Clear(); - mNewServiceSet.Clear(); - return NS_OK; - } - - // Process the service map, add to the pair map. - for (auto iter = mServiceMap.Iter(); !iter.Done(); iter.Next()) { - DiscoveredInfo* service = iter.UserData(); - - if (!mNewServiceSet.Contains(service->mService.mServiceId)) { - iter.Remove(); - } - } - - // Notify FlyWebService of changed service list. - mService->NotifyDiscoveredServicesChanged(); - - // Start discovery again immediately. - Unused << NS_WARN_IF(NS_FAILED(mDiscoveryStartTimer->InitWithCallback(this, 0, nsITimer::TYPE_ONE_SHOT))); - - return NS_OK; -} - -nsresult -FlyWebMDNSService::OnServiceFound(nsIDNSServiceInfo* aServiceInfo) -{ - LogDNSInfo(aServiceInfo, "FlyWebMDNSService::OnServiceFound"); - - // If discovery is not active, don't do anything with the result. - // If there is no discovery underway, ignore this. - if (!mDiscoveryActive || mDiscoveryState != DISCOVERY_RUNNING) { - return NS_OK; - } - - // Discovery is underway - resolve the service. - nsresult rv = mDNSServiceDiscovery->ResolveService(aServiceInfo, this); - NS_ENSURE_SUCCESS(rv, rv); - - return NS_OK; -} - -nsresult -FlyWebMDNSService::OnServiceLost(nsIDNSServiceInfo* aServiceInfo) -{ - LogDNSInfo(aServiceInfo, "FlyWebMDNSService::OnServiceLost"); - - return NS_OK; -} - -nsresult -FlyWebMDNSService::OnStartDiscoveryFailed(const nsACString& aServiceType, int32_t aErrorCode) -{ - LOG_E("MDNSService::OnStartDiscoveryFailed(%s): %d", PromiseFlatCString(aServiceType).get(), (int) aErrorCode); - - MOZ_ASSERT(mDiscoveryState == DISCOVERY_STARTING); - mDiscoveryState = DISCOVERY_IDLE; - mNumConsecutiveStartDiscoveryFailures++; - - // If discovery is active, and the number of consecutive failures is < 3, try starting again. - if (mDiscoveryActive && mNumConsecutiveStartDiscoveryFailures < 3) { - Unused << NS_WARN_IF(NS_FAILED(mDiscoveryStartTimer->InitWithCallback(this, 0, nsITimer::TYPE_ONE_SHOT))); - } - - return NS_OK; -} - -nsresult -FlyWebMDNSService::OnStopDiscoveryFailed(const nsACString& aServiceType, int32_t aErrorCode) -{ - LOG_E("MDNSService::OnStopDiscoveryFailed(%s)", PromiseFlatCString(aServiceType).get()); - MOZ_ASSERT(mDiscoveryState == DISCOVERY_STOPPING); - mDiscoveryState = DISCOVERY_IDLE; - - // If discovery is active, start discovery again immediately. - if (mDiscoveryActive) { - Unused << NS_WARN_IF(NS_FAILED(mDiscoveryStartTimer->InitWithCallback(this, 0, nsITimer::TYPE_ONE_SHOT))); - } - - return NS_OK; -} - -static bool -IsAcceptableServiceAddress(const nsCString& addr) -{ - PRNetAddr prNetAddr; - PRStatus status = PR_StringToNetAddr(addr.get(), &prNetAddr); - if (status == PR_FAILURE) { - return false; - } - // Only allow ipv4 addreses for now. - return prNetAddr.raw.family == PR_AF_INET; -} - -nsresult -FlyWebMDNSService::OnServiceResolved(nsIDNSServiceInfo* aServiceInfo) -{ - LogDNSInfo(aServiceInfo, "FlyWebMDNSService::OnServiceResolved"); - - // If discovery is not active, don't do anything with the result. - // If there is no discovery underway, ignore this resolve. - if (!mDiscoveryActive || mDiscoveryState != DISCOVERY_RUNNING) { - return NS_OK; - } - - nsresult rv; - - nsCString address; - rv = aServiceInfo->GetAddress(address); - if (NS_WARN_IF(NS_FAILED(rv))) { - return rv; - } - - if (!IsAcceptableServiceAddress(address)) { - return NS_OK; - } - - // Create a new serviceInfo and stuff it in the new service array. - UniquePtr svc(new DiscoveredInfo(aServiceInfo)); - mNewServiceSet.PutEntry(svc->mService.mServiceId); - - DiscoveredInfo* existingSvc = - mServiceMap.Get(svc->mService.mServiceId); - if (existingSvc) { - // Update the underlying DNS service info, but leave the old object in place. - existingSvc->mDNSServiceInfo = aServiceInfo; - } else { - DiscoveredInfo* info = svc.release(); - mServiceMap.Put(info->mService.mServiceId, info); - } - - // Notify FlyWebService of changed service list. - mService->NotifyDiscoveredServicesChanged(); - - return NS_OK; -} - -FlyWebMDNSService::DiscoveredInfo::DiscoveredInfo(nsIDNSServiceInfo* aDNSServiceInfo) - : mDNSServiceInfo(aDNSServiceInfo) -{ - nsCString tmp; - DebugOnly drv = aDNSServiceInfo->GetServiceName(tmp); - MOZ_ASSERT(NS_SUCCEEDED(drv)); - CopyUTF8toUTF16(tmp, mService.mDisplayName); - - mService.mTransport = NS_LITERAL_STRING("mdns"); - - drv = aDNSServiceInfo->GetServiceType(tmp); - MOZ_ASSERT(NS_SUCCEEDED(drv)); - CopyUTF8toUTF16(tmp, mService.mServiceType); - - nsCOMPtr attrs; - drv = aDNSServiceInfo->GetAttributes(getter_AddRefs(attrs)); - MOZ_ASSERT(NS_SUCCEEDED(drv)); - if (attrs) { - attrs->GetPropertyAsAString(NS_LITERAL_STRING("cert"), mService.mCert); - attrs->GetPropertyAsAString(NS_LITERAL_STRING("path"), mService.mPath); - } - - // Construct a service id from the name, host, address, and port. - nsCString cHost; - drv = aDNSServiceInfo->GetHost(cHost); - MOZ_ASSERT(NS_SUCCEEDED(drv)); - - nsCString cAddress; - drv = aDNSServiceInfo->GetAddress(cAddress); - MOZ_ASSERT(NS_SUCCEEDED(drv)); - - uint16_t port; - drv = aDNSServiceInfo->GetPort(&port); - MOZ_ASSERT(NS_SUCCEEDED(drv)); - nsAutoString portStr; - portStr.AppendInt(port, 10); - - mService.mServiceId = - NS_ConvertUTF8toUTF16(cAddress) + - NS_LITERAL_STRING(":") + - portStr + - NS_LITERAL_STRING("|") + - mService.mServiceType + - NS_LITERAL_STRING("|") + - NS_ConvertUTF8toUTF16(cHost) + - NS_LITERAL_STRING("|") + - mService.mDisplayName; -} - - -nsresult -FlyWebMDNSService::OnResolveFailed(nsIDNSServiceInfo* aServiceInfo, int32_t aErrorCode) -{ - LogDNSInfo(aServiceInfo, "FlyWebMDNSService::OnResolveFailed"); - - return NS_OK; -} - -nsresult -FlyWebMDNSService::OnServiceRegistered(nsIDNSServiceInfo* aServiceInfo) -{ - LogDNSInfo(aServiceInfo, "FlyWebMDNSService::OnServiceRegistered"); - - nsCString cName; - if (NS_WARN_IF(NS_FAILED(aServiceInfo->GetServiceName(cName)))) { - return NS_ERROR_FAILURE; - } - - nsString name = NS_ConvertUTF8toUTF16(cName); - RefPtr existingServer = - FlyWebService::GetOrCreate()->FindPublishedServerByName(name); - if (!existingServer) { - return NS_ERROR_FAILURE; - } - - existingServer->PublishedServerStarted(NS_OK); - - return NS_OK; -} - -nsresult -FlyWebMDNSService::OnServiceUnregistered(nsIDNSServiceInfo* aServiceInfo) -{ - LogDNSInfo(aServiceInfo, "FlyWebMDNSService::OnServiceUnregistered"); - - nsCString cName; - if (NS_WARN_IF(NS_FAILED(aServiceInfo->GetServiceName(cName)))) { - return NS_ERROR_FAILURE; - } - - nsString name = NS_ConvertUTF8toUTF16(cName); - RefPtr existingServer = - FlyWebService::GetOrCreate()->FindPublishedServerByName(name); - if (!existingServer) { - return NS_ERROR_FAILURE; - } - - LOG_I("OnServiceRegistered(MDNS): De-advertised server with name %s.", cName.get()); - - return NS_OK; -} - -nsresult -FlyWebMDNSService::OnRegistrationFailed(nsIDNSServiceInfo* aServiceInfo, int32_t errorCode) -{ - LogDNSInfo(aServiceInfo, "FlyWebMDNSService::OnRegistrationFailed"); - - nsCString cName; - if (NS_WARN_IF(NS_FAILED(aServiceInfo->GetServiceName(cName)))) { - return NS_ERROR_FAILURE; - } - - nsString name = NS_ConvertUTF8toUTF16(cName); - RefPtr existingServer = - FlyWebService::GetOrCreate()->FindPublishedServerByName(name); - if (!existingServer) { - return NS_ERROR_FAILURE; - } - - LOG_I("OnServiceRegistered(MDNS): Registration of server with name %s failed.", cName.get()); - - // Remove the nsICancelable from the published server. - existingServer->PublishedServerStarted(NS_ERROR_FAILURE); - return NS_OK; -} - -nsresult -FlyWebMDNSService::OnUnregistrationFailed(nsIDNSServiceInfo* aServiceInfo, int32_t errorCode) -{ - LogDNSInfo(aServiceInfo, "FlyWebMDNSService::OnUnregistrationFailed"); - - nsCString cName; - if (NS_WARN_IF(NS_FAILED(aServiceInfo->GetServiceName(cName)))) { - return NS_ERROR_FAILURE; - } - - nsString name = NS_ConvertUTF8toUTF16(cName); - RefPtr existingServer = - FlyWebService::GetOrCreate()->FindPublishedServerByName(name); - if (!existingServer) { - return NS_ERROR_FAILURE; - } - - LOG_I("OnServiceRegistered(MDNS): Un-Advertisement of server with name %s failed.", cName.get()); - return NS_OK; -} - -nsresult -FlyWebMDNSService::Notify(nsITimer* timer) -{ - if (timer == mDiscoveryStopTimer.get()) { - LOG_I("MDNSService::Notify() got discovery stop timeout"); - // Internet discovery stop timer has fired. - nsresult rv = StopDiscovery(); - if (NS_WARN_IF(NS_FAILED(rv))) { - return rv; - } - return NS_OK; - } - - if (timer == mDiscoveryStartTimer.get()) { - LOG_I("MDNSService::Notify() got discovery start timeout"); - // Internet discovery start timer has fired. - nsresult rv = StartDiscovery(); - if (NS_WARN_IF(NS_FAILED(rv))) { - return rv; - } - return NS_OK; - } - - LOG_E("MDNSService::Notify got unknown timeout."); - return NS_OK; -} - -nsresult -FlyWebMDNSService::Init() -{ - MOZ_ASSERT(mDiscoveryState == DISCOVERY_IDLE); - - mDiscoveryStartTimer = do_CreateInstance("@mozilla.org/timer;1"); - if (!mDiscoveryStartTimer) { - return NS_ERROR_FAILURE; - } - - mDiscoveryStopTimer = do_CreateInstance("@mozilla.org/timer;1"); - if (!mDiscoveryStopTimer) { - return NS_ERROR_FAILURE; - } - - nsresult rv; - mDNSServiceDiscovery = do_GetService(DNSSERVICEDISCOVERY_CONTRACT_ID, &rv); - if (NS_WARN_IF(NS_FAILED(rv))) { - return rv; - } - - return NS_OK; -} - -nsresult -FlyWebMDNSService::StartDiscovery() -{ - nsresult rv; - - // Always cancel the timer. - rv = mDiscoveryStartTimer->Cancel(); - if (NS_WARN_IF(NS_FAILED(rv))) { - LOG_E("FlyWeb failed to cancel DNS service discovery start timer."); - } - - // If discovery is not idle, don't start it. - if (mDiscoveryState != DISCOVERY_IDLE) { - return NS_OK; - } - - LOG_I("FlyWeb starting dicovery."); - mDiscoveryState = DISCOVERY_STARTING; - - // start the discovery. - rv = mDNSServiceDiscovery->StartDiscovery(mServiceType, this, - getter_AddRefs(mCancelDiscovery)); - if (NS_WARN_IF(NS_FAILED(rv))) { - LOG_E("FlyWeb failed to start DNS service discovery."); - return rv; - } - - return NS_OK; -} - -nsresult -FlyWebMDNSService::StopDiscovery() -{ - nsresult rv; - - // Always cancel the timer. - rv = mDiscoveryStopTimer->Cancel(); - if (NS_WARN_IF(NS_FAILED(rv))) { - LOG_E("FlyWeb failed to cancel DNS service discovery stop timer."); - } - - // If discovery is not running, do nothing. - if (mDiscoveryState != DISCOVERY_RUNNING) { - return NS_OK; - } - - LOG_I("FlyWeb stopping dicovery."); - - // Mark service discovery as stopping. - mDiscoveryState = DISCOVERY_STOPPING; - - if (mCancelDiscovery) { - LOG_I("MDNSService::StopDiscovery() - mCancelDiscovery exists!"); - nsCOMPtr cancelDiscovery = mCancelDiscovery.forget(); - rv = cancelDiscovery->Cancel(NS_ERROR_ABORT); - if (NS_WARN_IF(NS_FAILED(rv))) { - LOG_E("FlyWeb failed to cancel DNS stop service discovery."); - } - } else { - LOG_I("MDNSService::StopDiscovery() - mCancelDiscovery does not exist!"); - mDiscoveryState = DISCOVERY_IDLE; - } - - return NS_OK; -} - -void -FlyWebMDNSService::ListDiscoveredServices(nsTArray& aServices) -{ - for (auto iter = mServiceMap.Iter(); !iter.Done(); iter.Next()) { - aServices.AppendElement(iter.UserData()->mService); - } -} - -bool -FlyWebMDNSService::HasService(const nsAString& aServiceId) -{ - return mServiceMap.Contains(aServiceId); -} - -nsresult -FlyWebMDNSService::PairWithService(const nsAString& aServiceId, - UniquePtr& aInfo) -{ - MOZ_ASSERT(HasService(aServiceId)); - - nsresult rv; - nsCOMPtr uuidgen = - do_GetService("@mozilla.org/uuid-generator;1", &rv); - NS_ENSURE_SUCCESS(rv, rv); - - nsID id; - rv = uuidgen->GenerateUUIDInPlace(&id); - NS_ENSURE_SUCCESS(rv, rv); - - aInfo.reset(new FlyWebService::PairedInfo()); - - char uuidChars[NSID_LENGTH]; - id.ToProvidedString(uuidChars); - CopyUTF8toUTF16(Substring(uuidChars + 1, uuidChars + NSID_LENGTH - 2), - aInfo->mService.mHostname); - - DiscoveredInfo* discInfo = mServiceMap.Get(aServiceId); - - nsAutoString url; - if (discInfo->mService.mCert.IsEmpty()) { - url.AssignLiteral("http://"); - } else { - url.AssignLiteral("https://"); - } - url.Append(aInfo->mService.mHostname + NS_LITERAL_STRING("/")); - nsCOMPtr uiURL; - NS_NewURI(getter_AddRefs(uiURL), url); - MOZ_ASSERT(uiURL); - if (!discInfo->mService.mPath.IsEmpty()) { - nsCOMPtr tmp = uiURL.forget(); - NS_NewURI(getter_AddRefs(uiURL), discInfo->mService.mPath, nullptr, tmp); - } - if (uiURL) { - nsAutoCString spec; - uiURL->GetSpec(spec); - CopyUTF8toUTF16(spec, aInfo->mService.mUiUrl); - } - - aInfo->mService.mDiscoveredService = discInfo->mService; - aInfo->mDNSServiceInfo = discInfo->mDNSServiceInfo; - - return NS_OK; -} - -nsresult -FlyWebMDNSService::StartDiscoveryOf(FlyWebPublishedServerImpl* aServer) -{ - - RefPtr existingServer = - FlyWebService::GetOrCreate()->FindPublishedServerByName(aServer->Name()); - MOZ_ASSERT(existingServer); - - // Advertise the service via mdns. - RefPtr serviceInfo(new net::nsDNSServiceInfo()); - - serviceInfo->SetPort(aServer->Port()); - serviceInfo->SetServiceType(mServiceType); - - nsCString certKey; - aServer->GetCertKey(certKey); - nsString uiURL; - aServer->GetUiUrl(uiURL); - - if (!uiURL.IsEmpty() || !certKey.IsEmpty()) { - RefPtr attrs = new nsHashPropertyBag(); - if (!uiURL.IsEmpty()) { - attrs->SetPropertyAsAString(NS_LITERAL_STRING("path"), uiURL); - } - if (!certKey.IsEmpty()) { - attrs->SetPropertyAsACString(NS_LITERAL_STRING("cert"), certKey); - } - serviceInfo->SetAttributes(attrs); - } - - nsCString cstrName = NS_ConvertUTF16toUTF8(aServer->Name()); - LOG_I("MDNSService::StartDiscoveryOf() advertising service %s", cstrName.get()); - serviceInfo->SetServiceName(cstrName); - - LogDNSInfo(serviceInfo, "FlyWebMDNSService::StartDiscoveryOf"); - - // Advertise the service. - nsCOMPtr cancelRegister; - nsresult rv = mDNSServiceDiscovery-> - RegisterService(serviceInfo, this, getter_AddRefs(cancelRegister)); - NS_ENSURE_SUCCESS(rv, rv); - - // All done. - aServer->SetCancelRegister(cancelRegister); - - return NS_OK; -} - -void -FlyWebMDNSService::EnsureDiscoveryStarted() -{ - mDiscoveryActive = true; - // If state is idle, start discovery immediately. - if (mDiscoveryState == DISCOVERY_IDLE) { - StartDiscovery(); - } -} - -void -FlyWebMDNSService::EnsureDiscoveryStopped() -{ - // All we need to do is set the flag to false. - // If current state is IDLE, it's already the correct state. - // Otherwise, the handlers for the internal state - // transitions will check this flag and drive the state - // towards IDLE. - mDiscoveryActive = false; -} - -static StaticRefPtr gFlyWebService; - -NS_IMPL_ISUPPORTS(FlyWebService, nsIObserver) - -FlyWebService::FlyWebService() - : mMonitor("FlyWebService::mMonitor") -{ - MOZ_ASSERT(NS_IsMainThread()); - nsCOMPtr obs = mozilla::services::GetObserverService(); - if (obs) { - obs->AddObserver(this, "inner-window-destroyed", false); - } -} - -FlyWebService::~FlyWebService() -{ -} - -FlyWebService* -FlyWebService::GetExisting() -{ - return gFlyWebService; -} - -FlyWebService* -FlyWebService::GetOrCreate() -{ - if (!gFlyWebService) { - gFlyWebService = new FlyWebService(); - ClearOnShutdown(&gFlyWebService); - ErrorResult rv = gFlyWebService->Init(); - if (rv.Failed()) { - gFlyWebService = nullptr; - return nullptr; - } - } - return gFlyWebService; -} - -ErrorResult -FlyWebService::Init() -{ - // Most functions of FlyWebService should not be started in the child. - // Instead FlyWebService in the child is mainly responsible for tracking - // publishedServer lifetimes. Other functions are handled by the - // FlyWebService running in the parent. - if (XRE_GetProcessType() == GeckoProcessType_Content) { - return ErrorResult(NS_OK); - } - - MOZ_ASSERT(NS_IsMainThread()); - if (!mMDNSHttpService) { - mMDNSHttpService = new FlyWebMDNSService(this, NS_LITERAL_CSTRING("_http._tcp.")); - ErrorResult rv; - - rv = mMDNSHttpService->Init(); - if (rv.Failed()) { - LOG_E("FlyWebService failed to initialize MDNS _http._tcp."); - mMDNSHttpService = nullptr; - rv.SuppressException(); - } - } - - if (!mMDNSFlywebService) { - mMDNSFlywebService = new FlyWebMDNSService(this, NS_LITERAL_CSTRING("_flyweb._tcp.")); - ErrorResult rv; - - rv = mMDNSFlywebService->Init(); - if (rv.Failed()) { - LOG_E("FlyWebService failed to initialize MDNS _flyweb._tcp."); - mMDNSFlywebService = nullptr; - rv.SuppressException(); - } - } - - return ErrorResult(NS_OK); -} - -static already_AddRefed -MakeRejectionPromise(const char* name) -{ - MozPromiseHolder holder; - RefPtr promise = holder.Ensure(name); - holder.Reject(NS_ERROR_FAILURE, name); - return promise.forget(); -} - -static bool -CheckForFlyWebAddon(const nsACString& uriString) -{ - // Before proceeding, ensure that the FlyWeb system addon exists. - nsresult rv; - nsCOMPtr uri; - rv = NS_NewURI(getter_AddRefs(uri), uriString); - if (NS_FAILED(rv)) { - return false; - } - - JSAddonId *addonId = MapURIToAddonID(uri); - if (!addonId) { - return false; - } - - JSFlatString* flat = JS_ASSERT_STRING_IS_FLAT(JS::StringOfAddonId(addonId)); - nsAutoString addonIdString; - AssignJSFlatString(addonIdString, flat); - if (!addonIdString.EqualsLiteral("flyweb@mozilla.org")) { - nsCString addonIdCString = NS_ConvertUTF16toUTF8(addonIdString); - return false; - } - - return true; -} - -already_AddRefed -FlyWebService::PublishServer(const nsAString& aName, - const FlyWebPublishOptions& aOptions, - nsPIDOMWindowInner* aWindow) -{ - // Scan uiUrl for illegal characters - - RefPtr existingServer = - FlyWebService::GetOrCreate()->FindPublishedServerByName(aName); - if (existingServer) { - LOG_I("PublishServer: Trying to publish server with already-existing name %s.", - NS_ConvertUTF16toUTF8(aName).get()); - return MakeRejectionPromise(__func__); - } - - RefPtr server; - if (XRE_GetProcessType() == GeckoProcessType_Content) { - server = new FlyWebPublishedServerChild(aWindow, aName, aOptions); - } else { - server = new FlyWebPublishedServerImpl(aWindow, aName, aOptions); - - // Before proceeding, ensure that the FlyWeb system addon exists. - if (!CheckForFlyWebAddon(NS_LITERAL_CSTRING("chrome://flyweb/skin/icon-64.png")) && - !CheckForFlyWebAddon(NS_LITERAL_CSTRING("chrome://flyweb/content/icon-64.png"))) - { - LOG_E("PublishServer: Failed to find FlyWeb system addon."); - return MakeRejectionPromise(__func__); - } - } - - if (aWindow) { - nsresult rv; - - MOZ_ASSERT(NS_IsMainThread()); - rv = NS_DispatchToCurrentThread( - MakeAndAddRef( - NS_ConvertUTF16toUTF8(aName), aWindow->WindowID(), server)); - if (NS_WARN_IF(NS_FAILED(rv))) { - LOG_E("PublishServer: Failed to dispatch permission check runnable for %s", - NS_ConvertUTF16toUTF8(aName).get()); - return MakeRejectionPromise(__func__); - } - } else { - // If aWindow is null, we're definitely in the e10s parent process. - // In this case, we know that permission has already been granted - // by the user because of content-process prompt. - MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default); - server->PermissionGranted(true); - } - - mServers.AppendElement(server); - - return server->GetPublishPromise(); -} - -already_AddRefed -FlyWebService::FindPublishedServerByName( - const nsAString& aName) -{ - MOZ_ASSERT(NS_IsMainThread()); - for (FlyWebPublishedServer* publishedServer : mServers) { - if (publishedServer->Name().Equals(aName)) { - RefPtr server = publishedServer; - return server.forget(); - } - } - return nullptr; -} - -void -FlyWebService::RegisterDiscoveryManager(FlyWebDiscoveryManager* aDiscoveryManager) -{ - MOZ_ASSERT(NS_IsMainThread()); - mDiscoveryManagerTable.PutEntry(aDiscoveryManager); - if (mMDNSHttpService) { - mMDNSHttpService->EnsureDiscoveryStarted(); - } - if (mMDNSFlywebService) { - mMDNSFlywebService->EnsureDiscoveryStarted(); - } -} - -void -FlyWebService::UnregisterDiscoveryManager(FlyWebDiscoveryManager* aDiscoveryManager) -{ - MOZ_ASSERT(NS_IsMainThread()); - mDiscoveryManagerTable.RemoveEntry(aDiscoveryManager); - if (mDiscoveryManagerTable.IsEmpty()) { - if (mMDNSHttpService) { - mMDNSHttpService->EnsureDiscoveryStopped(); - } - if (mMDNSFlywebService) { - mMDNSFlywebService->EnsureDiscoveryStopped(); - } - } -} - -NS_IMETHODIMP -FlyWebService::Observe(nsISupports* aSubject, const char* aTopic, - const char16_t* aData) -{ - MOZ_ASSERT(NS_IsMainThread()); - if (strcmp(aTopic, "inner-window-destroyed")) { - return NS_OK; - } - - nsCOMPtr wrapper = do_QueryInterface(aSubject); - NS_ENSURE_TRUE(wrapper, NS_ERROR_FAILURE); - - uint64_t innerID; - nsresult rv = wrapper->GetData(&innerID); - NS_ENSURE_SUCCESS(rv, rv); - - for (FlyWebPublishedServer* server : mServers) { - if (server->OwnerWindowID() == innerID) { - server->Close(); - } - } - - return NS_OK; -} - -void -FlyWebService::UnregisterServer(FlyWebPublishedServer* aServer) -{ - MOZ_ASSERT(NS_IsMainThread()); - DebugOnly removed = mServers.RemoveElement(aServer); - MOZ_ASSERT(removed); -} - -bool -FlyWebService::HasConnectionOrServer(uint64_t aWindowID) -{ - MOZ_ASSERT(NS_IsMainThread()); - for (FlyWebPublishedServer* server : mServers) { - nsPIDOMWindowInner* win = server->GetOwner(); - if (win && win->WindowID() == aWindowID) { - return true; - } - } - - return false; -} - -void -FlyWebService::NotifyDiscoveredServicesChanged() -{ - // Process the service map, add to the pair map. - for (auto iter = mDiscoveryManagerTable.Iter(); !iter.Done(); iter.Next()) { - iter.Get()->GetKey()->NotifyDiscoveredServicesChanged(); - } -} - -void -FlyWebService::ListDiscoveredServices(nsTArray& aServices) -{ - MOZ_ASSERT(NS_IsMainThread()); - if (mMDNSHttpService) { - mMDNSHttpService->ListDiscoveredServices(aServices); - } - if (mMDNSFlywebService) { - mMDNSFlywebService->ListDiscoveredServices(aServices); - } -} - -void -FlyWebService::PairWithService(const nsAString& aServiceId, - FlyWebPairingCallback& aCallback) -{ - MOZ_ASSERT(NS_IsMainThread()); - // See if we have already paired with this service. If so, re-use the - // FlyWebPairedService for that. - { - ReentrantMonitorAutoEnter pairedMapLock(mMonitor); - for (auto iter = mPairedServiceTable.Iter(); !iter.Done(); iter.Next()) { - PairedInfo* pairInfo = iter.UserData(); - if (pairInfo->mService.mDiscoveredService.mServiceId.Equals(aServiceId)) { - ErrorResult er; - ReentrantMonitorAutoExit pairedMapRelease(mMonitor); - aCallback.PairingSucceeded(pairInfo->mService, er); - ENSURE_SUCCESS_VOID(er); - return; - } - } - } - - UniquePtr pairInfo; - - nsresult rv = NS_OK; - bool notFound = false; - if (mMDNSHttpService && mMDNSHttpService->HasService(aServiceId)) { - rv = mMDNSHttpService->PairWithService(aServiceId, pairInfo); - } else if (mMDNSFlywebService && mMDNSFlywebService->HasService(aServiceId)) { - rv = mMDNSFlywebService->PairWithService(aServiceId, pairInfo); - } else { - notFound = true; - } - - if (NS_FAILED(rv)) { - ErrorResult result; - result.Throw(rv); - const nsAString& reason = NS_LITERAL_STRING("Error pairing."); - aCallback.PairingFailed(reason, result); - ENSURE_SUCCESS_VOID(result); - return; - } - - if (!pairInfo) { - ErrorResult res; - const nsAString& reason = notFound ? - NS_LITERAL_STRING("No such service.") : - NS_LITERAL_STRING("Error pairing."); - aCallback.PairingFailed(reason, res); - ENSURE_SUCCESS_VOID(res); - return; - } - - // Add fingerprint to certificate override database. - if (!pairInfo->mService.mDiscoveredService.mCert.IsEmpty()) { - nsCOMPtr override = - do_GetService("@mozilla.org/security/certoverride;1"); - if (!override || - NS_FAILED(override->RememberTemporaryValidityOverrideUsingFingerprint( - NS_ConvertUTF16toUTF8(pairInfo->mService.mHostname), - -1, - NS_ConvertUTF16toUTF8(pairInfo->mService.mDiscoveredService.mCert), - nsICertOverrideService::ERROR_UNTRUSTED | - nsICertOverrideService::ERROR_MISMATCH))) { - ErrorResult res; - aCallback.PairingFailed(NS_LITERAL_STRING("Error adding certificate override."), res); - ENSURE_SUCCESS_VOID(res); - return; - } - } - - // Grab a weak reference to the PairedInfo so that we can - // use it even after ownership has been transferred to mPairedServiceTable - PairedInfo* pairInfoWeak = pairInfo.release(); - - { - ReentrantMonitorAutoEnter pairedMapLock(mMonitor); - mPairedServiceTable.Put( - NS_ConvertUTF16toUTF8(pairInfoWeak->mService.mHostname), pairInfoWeak); - } - - ErrorResult er; - aCallback.PairingSucceeded(pairInfoWeak->mService, er); - ENSURE_SUCCESS_VOID(er); -} - -nsresult -FlyWebService::CreateTransportForHost(const char **types, - uint32_t typeCount, - const nsACString &host, - int32_t port, - const nsACString &hostRoute, - int32_t portRoute, - nsIProxyInfo *proxyInfo, - nsISocketTransport **result) -{ - // This might be called on background threads - - *result = nullptr; - - nsCString ipAddrString; - uint16_t discPort; - - { - ReentrantMonitorAutoEnter pairedMapLock(mMonitor); - - PairedInfo* info = mPairedServiceTable.Get(host); - - if (!info) { - return NS_OK; - } - - // Get the ip address of the underlying service. - info->mDNSServiceInfo->GetAddress(ipAddrString); - info->mDNSServiceInfo->GetPort(&discPort); - } - - // Parse it into an NetAddr. - PRNetAddr prNetAddr; - PRStatus status = PR_StringToNetAddr(ipAddrString.get(), &prNetAddr); - NS_ENSURE_FALSE(status == PR_FAILURE, NS_ERROR_FAILURE); - - // Convert PRNetAddr to NetAddr. - mozilla::net::NetAddr netAddr; - PRNetAddrToNetAddr(&prNetAddr, &netAddr); - netAddr.inet.port = htons(discPort); - - RefPtr trans = new mozilla::net::nsSocketTransport(); - nsresult rv = trans->InitPreResolved( - types, typeCount, host, port, hostRoute, portRoute, proxyInfo, &netAddr); - NS_ENSURE_SUCCESS(rv, rv); - - trans.forget(result); - return NS_OK; -} - -void -FlyWebService::StartDiscoveryOf(FlyWebPublishedServerImpl* aServer) -{ - MOZ_ASSERT(NS_IsMainThread()); - nsresult rv = mMDNSFlywebService ? - mMDNSFlywebService->StartDiscoveryOf(aServer) : - NS_ERROR_FAILURE; - - if (NS_FAILED(rv)) { - aServer->PublishedServerStarted(rv); - } -} - -} // namespace dom -} // namespace mozilla diff --git a/dom/flyweb/FlyWebService.h b/dom/flyweb/FlyWebService.h deleted file mode 100644 index f7b983440..000000000 --- a/dom/flyweb/FlyWebService.h +++ /dev/null @@ -1,113 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: set ts=8 sts=2 et sw=2 tw=80: */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef mozilla_dom_FlyWebService_h -#define mozilla_dom_FlyWebService_h - -#include "nsISupportsImpl.h" -#include "mozilla/ErrorResult.h" -#include "nsIProtocolHandler.h" -#include "nsDataHashtable.h" -#include "nsClassHashtable.h" -#include "nsIObserver.h" -#include "mozilla/MozPromise.h" -#include "mozilla/ReentrantMonitor.h" -#include "mozilla/dom/FlyWebDiscoveryManagerBinding.h" -#include "nsITimer.h" -#include "nsICancelable.h" -#include "nsIDNSServiceDiscovery.h" - -class nsPIDOMWindowInner; -class nsIProxyInfo; -class nsISocketTransport; - -namespace mozilla { -namespace dom { - -struct FlyWebPublishOptions; -struct FlyWebFilter; -class FlyWebPublishedServer; -class FlyWebPublishedServerImpl; -class FlyWebPairingCallback; -class FlyWebDiscoveryManager; -class FlyWebMDNSService; - -typedef MozPromise, nsresult, false> - FlyWebPublishPromise; - -class FlyWebService final : public nsIObserver -{ - friend class FlyWebMDNSService; -public: - NS_DECL_THREADSAFE_ISUPPORTS - NS_DECL_NSIOBSERVER - - static FlyWebService* GetExisting(); - static FlyWebService* GetOrCreate(); - static already_AddRefed GetOrCreateAddRefed() - { - return do_AddRef(GetOrCreate()); - } - - already_AddRefed - PublishServer(const nsAString& aName, - const FlyWebPublishOptions& aOptions, - nsPIDOMWindowInner* aWindow); - - void UnregisterServer(FlyWebPublishedServer* aServer); - - bool HasConnectionOrServer(uint64_t aWindowID); - - void ListDiscoveredServices(nsTArray& aServices); - void PairWithService(const nsAString& aServiceId, FlyWebPairingCallback& aCallback); - nsresult CreateTransportForHost(const char **types, - uint32_t typeCount, - const nsACString &host, - int32_t port, - const nsACString &hostRoute, - int32_t portRoute, - nsIProxyInfo *proxyInfo, - nsISocketTransport **result); - - already_AddRefed FindPublishedServerByName( - const nsAString& aName); - - void RegisterDiscoveryManager(FlyWebDiscoveryManager* aDiscoveryManager); - void UnregisterDiscoveryManager(FlyWebDiscoveryManager* aDiscoveryManager); - - // Should only be called by FlyWebPublishedServerImpl - void StartDiscoveryOf(FlyWebPublishedServerImpl* aServer); - -private: - FlyWebService(); - ~FlyWebService(); - - ErrorResult Init(); - - void NotifyDiscoveredServicesChanged(); - - // Might want to make these hashes for perf - nsTArray mServers; - - RefPtr mMDNSHttpService; - RefPtr mMDNSFlywebService; - - struct PairedInfo - { - FlyWebPairedService mService; - nsCOMPtr mDNSServiceInfo; - }; - nsClassHashtable - mPairedServiceTable; - ReentrantMonitor mMonitor; // Protecting mPairedServiceTable - - nsTHashtable> mDiscoveryManagerTable; -}; - -} // namespace dom -} // namespace mozilla - -#endif // mozilla_dom_FlyWebService_h diff --git a/dom/flyweb/HttpServer.cpp b/dom/flyweb/HttpServer.cpp deleted file mode 100644 index 26e15d9d5..000000000 --- a/dom/flyweb/HttpServer.cpp +++ /dev/null @@ -1,1319 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: set ts=8 sts=2 et sw=2 tw=80: */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "mozilla/dom/HttpServer.h" -#include "nsISocketTransport.h" -#include "nsWhitespaceTokenizer.h" -#include "nsNetUtil.h" -#include "nsIStreamTransportService.h" -#include "nsIAsyncStreamCopier2.h" -#include "nsIPipe.h" -#include "nsIOService.h" -#include "nsIHttpChannelInternal.h" -#include "Base64.h" -#include "WebSocketChannel.h" -#include "nsCharSeparatedTokenizer.h" -#include "nsIX509Cert.h" - -static NS_DEFINE_CID(kStreamTransportServiceCID, NS_STREAMTRANSPORTSERVICE_CID); - -namespace mozilla { -namespace dom { - -static LazyLogModule gHttpServerLog("HttpServer"); -#undef LOG_I -#define LOG_I(...) MOZ_LOG(gHttpServerLog, mozilla::LogLevel::Debug, (__VA_ARGS__)) -#undef LOG_V -#define LOG_V(...) MOZ_LOG(gHttpServerLog, mozilla::LogLevel::Verbose, (__VA_ARGS__)) -#undef LOG_E -#define LOG_E(...) MOZ_LOG(gHttpServerLog, mozilla::LogLevel::Error, (__VA_ARGS__)) - - -NS_IMPL_ISUPPORTS(HttpServer, - nsIServerSocketListener, - nsILocalCertGetCallback) - -HttpServer::HttpServer() - : mPort() - , mHttps() -{ -} - -HttpServer::~HttpServer() -{ -} - -void -HttpServer::Init(int32_t aPort, bool aHttps, HttpServerListener* aListener) -{ - mPort = aPort; - mHttps = aHttps; - mListener = aListener; - - if (mHttps) { - nsCOMPtr lcs = - do_CreateInstance("@mozilla.org/security/local-cert-service;1"); - nsresult rv = lcs->GetOrCreateCert(NS_LITERAL_CSTRING("flyweb"), this); - if (NS_FAILED(rv)) { - NotifyStarted(rv); - } - } else { - // Make sure to always have an async step before notifying callbacks - HandleCert(nullptr, NS_OK); - } -} - -NS_IMETHODIMP -HttpServer::HandleCert(nsIX509Cert* aCert, nsresult aResult) -{ - nsresult rv = aResult; - if (NS_SUCCEEDED(rv)) { - rv = StartServerSocket(aCert); - } - - if (NS_FAILED(rv) && mServerSocket) { - mServerSocket->Close(); - mServerSocket = nullptr; - } - - NotifyStarted(rv); - - return NS_OK; -} - -void -HttpServer::NotifyStarted(nsresult aStatus) -{ - RefPtr listener = mListener; - nsCOMPtr event = NS_NewRunnableFunction([listener, aStatus] () - { - listener->OnServerStarted(aStatus); - }); - NS_DispatchToCurrentThread(event); -} - -nsresult -HttpServer::StartServerSocket(nsIX509Cert* aCert) -{ - nsresult rv; - mServerSocket = - do_CreateInstance(aCert ? "@mozilla.org/network/tls-server-socket;1" - : "@mozilla.org/network/server-socket;1", &rv); - NS_ENSURE_SUCCESS(rv, rv); - - rv = mServerSocket->Init(mPort, false, -1); - NS_ENSURE_SUCCESS(rv, rv); - - if (aCert) { - nsCOMPtr tls = do_QueryInterface(mServerSocket); - rv = tls->SetServerCert(aCert); - NS_ENSURE_SUCCESS(rv, rv); - - rv = tls->SetSessionTickets(false); - NS_ENSURE_SUCCESS(rv, rv); - - mCert = aCert; - } - - rv = mServerSocket->AsyncListen(this); - NS_ENSURE_SUCCESS(rv, rv); - - rv = mServerSocket->GetPort(&mPort); - NS_ENSURE_SUCCESS(rv, rv); - - LOG_I("HttpServer::StartServerSocket(%p)", this); - - return NS_OK; -} - -NS_IMETHODIMP -HttpServer::OnSocketAccepted(nsIServerSocket* aServ, - nsISocketTransport* aTransport) -{ - MOZ_ASSERT(SameCOMIdentity(aServ, mServerSocket)); - - nsresult rv; - RefPtr conn = new Connection(aTransport, this, rv); - NS_ENSURE_SUCCESS(rv, rv); - - LOG_I("HttpServer::OnSocketAccepted(%p) - Socket %p", this, conn.get()); - - mConnections.AppendElement(conn.forget()); - - return NS_OK; -} - -NS_IMETHODIMP -HttpServer::OnStopListening(nsIServerSocket* aServ, - nsresult aStatus) -{ - MOZ_ASSERT(aServ == mServerSocket || !mServerSocket); - - LOG_I("HttpServer::OnStopListening(%p) - status 0x%lx", this, aStatus); - - Close(); - - return NS_OK; -} - -void -HttpServer::SendResponse(InternalRequest* aRequest, InternalResponse* aResponse) -{ - for (Connection* conn : mConnections) { - if (conn->TryHandleResponse(aRequest, aResponse)) { - return; - } - } - - MOZ_ASSERT(false, "Unknown request"); -} - -already_AddRefed -HttpServer::AcceptWebSocket(InternalRequest* aConnectRequest, - const Optional& aProtocol, - ErrorResult& aRv) -{ - for (Connection* conn : mConnections) { - if (!conn->HasPendingWebSocketRequest(aConnectRequest)) { - continue; - } - nsCOMPtr provider = - conn->HandleAcceptWebSocket(aProtocol, aRv); - if (aRv.Failed()) { - conn->Close(); - } - // This connection is now owned by the websocket, or we just closed it - mConnections.RemoveElement(conn); - return provider.forget(); - } - - aRv.Throw(NS_ERROR_UNEXPECTED); - MOZ_ASSERT(false, "Unknown request"); - - return nullptr; -} - -void -HttpServer::SendWebSocketResponse(InternalRequest* aConnectRequest, - InternalResponse* aResponse) -{ - for (Connection* conn : mConnections) { - if (conn->HasPendingWebSocketRequest(aConnectRequest)) { - conn->HandleWebSocketResponse(aResponse); - return; - } - } - - MOZ_ASSERT(false, "Unknown request"); -} - -void -HttpServer::Close() -{ - if (mServerSocket) { - mServerSocket->Close(); - mServerSocket = nullptr; - } - - if (mListener) { - RefPtr listener = mListener.forget(); - listener->OnServerClose(); - } - - for (Connection* conn : mConnections) { - conn->Close(); - } - mConnections.Clear(); -} - -void -HttpServer::GetCertKey(nsACString& aKey) -{ - nsAutoString tmp; - if (mCert) { - mCert->GetSha256Fingerprint(tmp); - } - LossyCopyUTF16toASCII(tmp, aKey); -} - -NS_IMPL_ISUPPORTS(HttpServer::TransportProvider, - nsITransportProvider) - -HttpServer::TransportProvider::~TransportProvider() -{ -} - -NS_IMETHODIMP -HttpServer::TransportProvider::SetListener(nsIHttpUpgradeListener* aListener) -{ - MOZ_ASSERT(!mListener); - MOZ_ASSERT(aListener); - - mListener = aListener; - - MaybeNotify(); - - return NS_OK; -} - -NS_IMETHODIMP -HttpServer::TransportProvider::GetIPCChild(PTransportProviderChild** aChild) -{ - MOZ_CRASH("Don't call this in parent process"); - *aChild = nullptr; - return NS_OK; -} - -void -HttpServer::TransportProvider::SetTransport(nsISocketTransport* aTransport, - nsIAsyncInputStream* aInput, - nsIAsyncOutputStream* aOutput) -{ - MOZ_ASSERT(!mTransport); - MOZ_ASSERT(aTransport && aInput && aOutput); - - mTransport = aTransport; - mInput = aInput; - mOutput = aOutput; - - MaybeNotify(); -} - -void -HttpServer::TransportProvider::MaybeNotify() -{ - if (mTransport && mListener) { - RefPtr self = this; - nsCOMPtr event = NS_NewRunnableFunction([self, this] () - { - mListener->OnTransportAvailable(mTransport, mInput, mOutput); - }); - NS_DispatchToCurrentThread(event); - } -} - -NS_IMPL_ISUPPORTS(HttpServer::Connection, - nsIInputStreamCallback, - nsIOutputStreamCallback) - -HttpServer::Connection::Connection(nsISocketTransport* aTransport, - HttpServer* aServer, - nsresult& rv) - : mServer(aServer) - , mTransport(aTransport) - , mState(eRequestLine) - , mPendingReqVersion() - , mRemainingBodySize() - , mCloseAfterRequest(false) -{ - nsCOMPtr input; - rv = mTransport->OpenInputStream(0, 0, 0, getter_AddRefs(input)); - NS_ENSURE_SUCCESS_VOID(rv); - - mInput = do_QueryInterface(input); - - nsCOMPtr output; - rv = mTransport->OpenOutputStream(0, 0, 0, getter_AddRefs(output)); - NS_ENSURE_SUCCESS_VOID(rv); - - mOutput = do_QueryInterface(output); - - if (mServer->mHttps) { - SetSecurityObserver(true); - } else { - mInput->AsyncWait(this, 0, 0, NS_GetCurrentThread()); - } -} - -NS_IMETHODIMP -HttpServer::Connection::OnHandshakeDone(nsITLSServerSocket* aServer, - nsITLSClientStatus* aStatus) -{ - LOG_I("HttpServer::Connection::OnHandshakeDone(%p)", this); - - // XXX Verify connection security - - SetSecurityObserver(false); - mInput->AsyncWait(this, 0, 0, NS_GetCurrentThread()); - - return NS_OK; -} - -void -HttpServer::Connection::SetSecurityObserver(bool aListen) -{ - LOG_I("HttpServer::Connection::SetSecurityObserver(%p) - %s", this, - aListen ? "On" : "Off"); - - nsCOMPtr secInfo; - mTransport->GetSecurityInfo(getter_AddRefs(secInfo)); - nsCOMPtr tlsConnInfo = - do_QueryInterface(secInfo); - MOZ_ASSERT(tlsConnInfo); - tlsConnInfo->SetSecurityObserver(aListen ? this : nullptr); -} - -HttpServer::Connection::~Connection() -{ -} - -NS_IMETHODIMP -HttpServer::Connection::OnInputStreamReady(nsIAsyncInputStream* aStream) -{ - MOZ_ASSERT(!mInput || aStream == mInput); - - LOG_I("HttpServer::Connection::OnInputStreamReady(%p)", this); - - if (!mInput || mState == ePause) { - return NS_OK; - } - - uint64_t avail; - nsresult rv = mInput->Available(&avail); - if (NS_FAILED(rv)) { - LOG_I("HttpServer::Connection::OnInputStreamReady(%p) - Connection closed", this); - - mServer->mConnections.RemoveElement(this); - // Connection closed. Handle errors here. - return NS_OK; - } - - uint32_t numRead; - rv = mInput->ReadSegments(ReadSegmentsFunc, - this, - UINT32_MAX, - &numRead); - NS_ENSURE_SUCCESS(rv, rv); - - rv = mInput->AsyncWait(this, 0, 0, NS_GetCurrentThread()); - NS_ENSURE_SUCCESS(rv, rv); - - return NS_OK; -} - -nsresult -HttpServer::Connection::ReadSegmentsFunc(nsIInputStream* aIn, - void* aClosure, - const char* aBuffer, - uint32_t aToOffset, - uint32_t aCount, - uint32_t* aWriteCount) -{ - const char* buffer = aBuffer; - nsresult rv = static_cast(aClosure)-> - ConsumeInput(buffer, buffer + aCount); - - *aWriteCount = buffer - aBuffer; - MOZ_ASSERT(*aWriteCount <= aCount); - - return rv; -} - -static const char* -findCRLF(const char* aBuffer, const char* aEnd) -{ - if (aBuffer + 1 >= aEnd) { - return nullptr; - } - - const char* pos; - while ((pos = static_cast(memchr(aBuffer, - '\r', - aEnd - aBuffer - 1)))) { - if (*(pos + 1) == '\n') { - return pos; - } - aBuffer = pos + 1; - } - return nullptr; -} - -nsresult -HttpServer::Connection::ConsumeInput(const char*& aBuffer, - const char* aEnd) -{ - nsresult rv; - while (mState == eRequestLine || - mState == eHeaders) { - // Consume line-by-line - - // Check if buffer boundry ended up right between the CR and LF - if (!mInputBuffer.IsEmpty() && mInputBuffer.Last() == '\r' && - *aBuffer == '\n') { - aBuffer++; - rv = ConsumeLine(mInputBuffer.BeginReading(), mInputBuffer.Length() - 1); - NS_ENSURE_SUCCESS(rv, rv); - - mInputBuffer.Truncate(); - } - - // Look for a CRLF - const char* pos = findCRLF(aBuffer, aEnd); - if (!pos) { - mInputBuffer.Append(aBuffer, aEnd - aBuffer); - aBuffer = aEnd; - return NS_OK; - } - - if (!mInputBuffer.IsEmpty()) { - mInputBuffer.Append(aBuffer, pos - aBuffer); - aBuffer = pos + 2; - rv = ConsumeLine(mInputBuffer.BeginReading(), mInputBuffer.Length() - 1); - NS_ENSURE_SUCCESS(rv, rv); - - mInputBuffer.Truncate(); - } else { - rv = ConsumeLine(aBuffer, pos - aBuffer); - NS_ENSURE_SUCCESS(rv, rv); - - aBuffer = pos + 2; - } - } - - if (mState == eBody) { - uint32_t size = std::min(mRemainingBodySize, - static_cast(aEnd - aBuffer)); - uint32_t written = size; - - if (mCurrentRequestBody) { - rv = mCurrentRequestBody->Write(aBuffer, size, &written); - // Since we've given the pipe unlimited size, we should never - // end up needing to block. - MOZ_ASSERT(rv != NS_BASE_STREAM_WOULD_BLOCK); - if (NS_FAILED(rv)) { - written = size; - mCurrentRequestBody = nullptr; - } - } - - aBuffer += written; - mRemainingBodySize -= written; - if (!mRemainingBodySize) { - mCurrentRequestBody->Close(); - mCurrentRequestBody = nullptr; - mState = eRequestLine; - } - } - - return NS_OK; -} - -bool -ContainsToken(const nsCString& aList, const nsCString& aToken) -{ - nsCCharSeparatedTokenizer tokens(aList, ','); - bool found = false; - while (!found && tokens.hasMoreTokens()) { - found = tokens.nextToken().Equals(aToken); - } - return found; -} - -static bool -IsWebSocketRequest(InternalRequest* aRequest, uint32_t aHttpVersion) -{ - if (aHttpVersion < 1) { - return false; - } - - nsAutoCString str; - aRequest->GetMethod(str); - if (!str.EqualsLiteral("GET")) { - return false; - } - - InternalHeaders* headers = aRequest->Headers(); - ErrorResult res; - - headers->GetFirst(NS_LITERAL_CSTRING("upgrade"), str, res); - MOZ_ASSERT(!res.Failed()); - if (!str.EqualsLiteral("websocket")) { - return false; - } - - headers->GetFirst(NS_LITERAL_CSTRING("connection"), str, res); - MOZ_ASSERT(!res.Failed()); - if (!ContainsToken(str, NS_LITERAL_CSTRING("Upgrade"))) { - return false; - } - - headers->GetFirst(NS_LITERAL_CSTRING("sec-websocket-key"), str, res); - MOZ_ASSERT(!res.Failed()); - nsAutoCString binary; - if (NS_FAILED(Base64Decode(str, binary)) || binary.Length() != 16) { - return false; - } - - nsresult rv; - headers->GetFirst(NS_LITERAL_CSTRING("sec-websocket-version"), str, res); - MOZ_ASSERT(!res.Failed()); - if (str.ToInteger(&rv) != 13 || NS_FAILED(rv)) { - return false; - } - - return true; -} - -nsresult -HttpServer::Connection::ConsumeLine(const char* aBuffer, - size_t aLength) -{ - MOZ_ASSERT(mState == eRequestLine || - mState == eHeaders); - - if (MOZ_LOG_TEST(gHttpServerLog, mozilla::LogLevel::Verbose)) { - nsCString line(aBuffer, aLength); - LOG_V("HttpServer::Connection::ConsumeLine(%p) - \"%s\"", this, line.get()); - } - - if (mState == eRequestLine) { - LOG_V("HttpServer::Connection::ConsumeLine(%p) - Parsing request line", this); - NS_ENSURE_FALSE(mCloseAfterRequest, NS_ERROR_UNEXPECTED); - - if (aLength == 0) { - // Ignore empty lines before the request line - return NS_OK; - } - MOZ_ASSERT(!mPendingReq); - - // Process request line - nsCWhitespaceTokenizer tokens(Substring(aBuffer, aLength)); - - NS_ENSURE_TRUE(tokens.hasMoreTokens(), NS_ERROR_UNEXPECTED); - nsDependentCSubstring method = tokens.nextToken(); - NS_ENSURE_TRUE(NS_IsValidHTTPToken(method), NS_ERROR_UNEXPECTED); - NS_ENSURE_TRUE(tokens.hasMoreTokens(), NS_ERROR_UNEXPECTED); - nsDependentCSubstring url = tokens.nextToken(); - // Seems like it's also allowed to pass full urls with scheme+host+port. - // May need to support that. - NS_ENSURE_TRUE(url.First() == '/', NS_ERROR_UNEXPECTED); - mPendingReq = new InternalRequest(url, /* aURLFragment */ EmptyCString()); - mPendingReq->SetMethod(method); - NS_ENSURE_TRUE(tokens.hasMoreTokens(), NS_ERROR_UNEXPECTED); - nsDependentCSubstring version = tokens.nextToken(); - NS_ENSURE_TRUE(StringBeginsWith(version, NS_LITERAL_CSTRING("HTTP/1.")), - NS_ERROR_UNEXPECTED); - nsresult rv; - // This integer parsing is likely not strict enough. - nsCString reqVersion; - reqVersion = Substring(version, MOZ_ARRAY_LENGTH("HTTP/1.") - 1); - mPendingReqVersion = reqVersion.ToInteger(&rv); - NS_ENSURE_SUCCESS(rv, NS_ERROR_UNEXPECTED); - - NS_ENSURE_FALSE(tokens.hasMoreTokens(), NS_ERROR_UNEXPECTED); - - LOG_V("HttpServer::Connection::ConsumeLine(%p) - Parsed request line", this); - - mState = eHeaders; - - return NS_OK; - } - - if (aLength == 0) { - LOG_V("HttpServer::Connection::ConsumeLine(%p) - Found end of headers", this); - - MaybeAddPendingHeader(); - - ErrorResult res; - mPendingReq->Headers()->SetGuard(HeadersGuardEnum::Immutable, res); - - // Check for WebSocket - if (IsWebSocketRequest(mPendingReq, mPendingReqVersion)) { - LOG_V("HttpServer::Connection::ConsumeLine(%p) - Fire OnWebSocket", this); - - mState = ePause; - mPendingWebSocketRequest = mPendingReq.forget(); - mPendingReqVersion = 0; - - RefPtr listener = mServer->mListener; - RefPtr request = mPendingWebSocketRequest; - nsCOMPtr event = - NS_NewRunnableFunction([listener, request] () - { - listener->OnWebSocket(request); - }); - NS_DispatchToCurrentThread(event); - - return NS_OK; - } - - nsAutoCString header; - mPendingReq->Headers()->GetFirst(NS_LITERAL_CSTRING("connection"), - header, - res); - MOZ_ASSERT(!res.Failed()); - // 1.0 defaults to closing connections. - // 1.1 and higher defaults to keep-alive. - if (ContainsToken(header, NS_LITERAL_CSTRING("close")) || - (mPendingReqVersion == 0 && - !ContainsToken(header, NS_LITERAL_CSTRING("keep-alive")))) { - mCloseAfterRequest = true; - } - - mPendingReq->Headers()->GetFirst(NS_LITERAL_CSTRING("content-length"), - header, - res); - MOZ_ASSERT(!res.Failed()); - - LOG_V("HttpServer::Connection::ConsumeLine(%p) - content-length is \"%s\"", - this, header.get()); - - if (!header.IsEmpty()) { - nsresult rv; - mRemainingBodySize = header.ToInteger(&rv); - NS_ENSURE_SUCCESS(rv, rv); - } else { - mRemainingBodySize = 0; - } - - if (mRemainingBodySize) { - LOG_V("HttpServer::Connection::ConsumeLine(%p) - Starting consume body", this); - mState = eBody; - - // We use an unlimited buffer size here to ensure - // that we get to the next request even if the webpage hangs on - // to the request indefinitely without consuming the body. - nsCOMPtr input; - nsCOMPtr output; - nsresult rv = NS_NewPipe(getter_AddRefs(input), - getter_AddRefs(output), - 0, // Segment size - UINT32_MAX, // Unlimited buffer size - false, // not nonBlockingInput - true); // nonBlockingOutput - NS_ENSURE_SUCCESS(rv, rv); - - mCurrentRequestBody = do_QueryInterface(output); - mPendingReq->SetBody(input); - } else { - LOG_V("HttpServer::Connection::ConsumeLine(%p) - No body", this); - mState = eRequestLine; - } - - mPendingRequests.AppendElement(PendingRequest(mPendingReq, nullptr)); - - LOG_V("HttpServer::Connection::ConsumeLine(%p) - Fire OnRequest", this); - - RefPtr listener = mServer->mListener; - RefPtr request = mPendingReq.forget(); - nsCOMPtr event = - NS_NewRunnableFunction([listener, request] () - { - listener->OnRequest(request); - }); - NS_DispatchToCurrentThread(event); - - mPendingReqVersion = 0; - - return NS_OK; - } - - // Parse header line - if (aBuffer[0] == ' ' || aBuffer[0] == '\t') { - LOG_V("HttpServer::Connection::ConsumeLine(%p) - Add to header %s", - this, - mPendingHeaderName.get()); - - NS_ENSURE_FALSE(mPendingHeaderName.IsEmpty(), - NS_ERROR_UNEXPECTED); - - // We might need to do whitespace trimming/compression here. - mPendingHeaderValue.Append(aBuffer, aLength); - return NS_OK; - } - - MaybeAddPendingHeader(); - - const char* colon = static_cast(memchr(aBuffer, ':', aLength)); - NS_ENSURE_TRUE(colon, NS_ERROR_UNEXPECTED); - - ToLowerCase(Substring(aBuffer, colon - aBuffer), mPendingHeaderName); - mPendingHeaderValue.Assign(colon + 1, aLength - (colon - aBuffer) - 1); - - NS_ENSURE_TRUE(NS_IsValidHTTPToken(mPendingHeaderName), - NS_ERROR_UNEXPECTED); - - LOG_V("HttpServer::Connection::ConsumeLine(%p) - Parsed header %s", - this, - mPendingHeaderName.get()); - - return NS_OK; -} - -void -HttpServer::Connection::MaybeAddPendingHeader() -{ - if (mPendingHeaderName.IsEmpty()) { - return; - } - - // We might need to do more whitespace trimming/compression here. - mPendingHeaderValue.Trim(" \t"); - - ErrorResult rv; - mPendingReq->Headers()->Append(mPendingHeaderName, mPendingHeaderValue, rv); - mPendingHeaderName.Truncate(); -} - -bool -HttpServer::Connection::TryHandleResponse(InternalRequest* aRequest, - InternalResponse* aResponse) -{ - bool handledResponse = false; - for (uint32_t i = 0; i < mPendingRequests.Length(); ++i) { - PendingRequest& pending = mPendingRequests[i]; - if (pending.first() == aRequest) { - MOZ_ASSERT(!handledResponse); - MOZ_ASSERT(!pending.second()); - - pending.second() = aResponse; - if (i != 0) { - return true; - } - handledResponse = true; - } - - if (handledResponse && !pending.second()) { - // Shortcut if we've handled the response, and - // we don't have more responses to send - return true; - } - - if (i == 0 && pending.second()) { - RefPtr resp = pending.second().forget(); - mPendingRequests.RemoveElementAt(0); - QueueResponse(resp); - --i; - } - } - - return handledResponse; -} - -already_AddRefed -HttpServer::Connection::HandleAcceptWebSocket(const Optional& aProtocol, - ErrorResult& aRv) -{ - MOZ_ASSERT(mPendingWebSocketRequest); - - RefPtr response = - new InternalResponse(101, NS_LITERAL_CSTRING("Switching Protocols")); - - InternalHeaders* headers = response->Headers(); - headers->Set(NS_LITERAL_CSTRING("Upgrade"), - NS_LITERAL_CSTRING("websocket"), - aRv); - headers->Set(NS_LITERAL_CSTRING("Connection"), - NS_LITERAL_CSTRING("Upgrade"), - aRv); - if (aProtocol.WasPassed()) { - NS_ConvertUTF16toUTF8 protocol(aProtocol.Value()); - nsAutoCString reqProtocols; - mPendingWebSocketRequest->Headers()-> - GetFirst(NS_LITERAL_CSTRING("Sec-WebSocket-Protocol"), reqProtocols, aRv); - if (!ContainsToken(reqProtocols, protocol)) { - // Should throw a better error here - aRv.Throw(NS_ERROR_FAILURE); - return nullptr; - } - - headers->Set(NS_LITERAL_CSTRING("Sec-WebSocket-Protocol"), - protocol, aRv); - } - - nsAutoCString key, hash; - mPendingWebSocketRequest->Headers()-> - GetFirst(NS_LITERAL_CSTRING("Sec-WebSocket-Key"), key, aRv); - nsresult rv = mozilla::net::CalculateWebSocketHashedSecret(key, hash); - if (NS_FAILED(rv)) { - aRv.Throw(rv); - return nullptr; - } - headers->Set(NS_LITERAL_CSTRING("Sec-WebSocket-Accept"), hash, aRv); - - nsAutoCString extensions, negotiatedExtensions; - mPendingWebSocketRequest->Headers()-> - GetFirst(NS_LITERAL_CSTRING("Sec-WebSocket-Extensions"), extensions, aRv); - mozilla::net::ProcessServerWebSocketExtensions(extensions, - negotiatedExtensions); - if (!negotiatedExtensions.IsEmpty()) { - headers->Set(NS_LITERAL_CSTRING("Sec-WebSocket-Extensions"), - negotiatedExtensions, aRv); - } - - RefPtr result = new TransportProvider(); - mWebSocketTransportProvider = result; - - QueueResponse(response); - - return result.forget(); -} - -void -HttpServer::Connection::HandleWebSocketResponse(InternalResponse* aResponse) -{ - MOZ_ASSERT(mPendingWebSocketRequest); - - mState = eRequestLine; - mPendingWebSocketRequest = nullptr; - mInput->AsyncWait(this, 0, 0, NS_GetCurrentThread()); - - QueueResponse(aResponse); -} - -void -HttpServer::Connection::QueueResponse(InternalResponse* aResponse) -{ - bool chunked = false; - - RefPtr headers = new InternalHeaders(*aResponse->Headers()); - { - ErrorResult res; - headers->SetGuard(HeadersGuardEnum::None, res); - } - nsCOMPtr body; - int64_t bodySize; - aResponse->GetBody(getter_AddRefs(body), &bodySize); - - if (body && bodySize >= 0) { - nsCString sizeStr; - sizeStr.AppendInt(bodySize); - - LOG_V("HttpServer::Connection::QueueResponse(%p) - " - "Setting content-length to %s", - this, sizeStr.get()); - - ErrorResult res; - headers->Set(NS_LITERAL_CSTRING("content-length"), sizeStr, res); - } else if (body) { - // Use chunked transfer encoding - LOG_V("HttpServer::Connection::QueueResponse(%p) - Chunked transfer-encoding", - this); - - ErrorResult res; - headers->Set(NS_LITERAL_CSTRING("transfer-encoding"), - NS_LITERAL_CSTRING("chunked"), - res); - headers->Delete(NS_LITERAL_CSTRING("content-length"), res); - chunked = true; - - } else { - LOG_V("HttpServer::Connection::QueueResponse(%p) - " - "No body - setting content-length to 0", this); - - ErrorResult res; - headers->Set(NS_LITERAL_CSTRING("content-length"), - NS_LITERAL_CSTRING("0"), res); - } - - nsCString head(NS_LITERAL_CSTRING("HTTP/1.1 ")); - head.AppendInt(aResponse->GetStatus()); - // XXX is the statustext security checked? - head.Append(NS_LITERAL_CSTRING(" ") + - aResponse->GetStatusText() + - NS_LITERAL_CSTRING("\r\n")); - - AutoTArray entries; - headers->GetEntries(entries); - - for (auto header : entries) { - head.Append(header.mName + - NS_LITERAL_CSTRING(": ") + - header.mValue + - NS_LITERAL_CSTRING("\r\n")); - } - - head.Append(NS_LITERAL_CSTRING("\r\n")); - - mOutputBuffers.AppendElement()->mString = head; - if (body) { - OutputBuffer* bodyBuffer = mOutputBuffers.AppendElement(); - bodyBuffer->mStream = body; - bodyBuffer->mChunked = chunked; - } - - OnOutputStreamReady(mOutput); -} - -namespace { - -typedef MozPromise StreamCopyPromise; - -class StreamCopier final : public nsIOutputStreamCallback - , public nsIInputStreamCallback - , public nsIRunnable -{ -public: - static RefPtr - Copy(nsIInputStream* aSource, nsIAsyncOutputStream* aSink, - bool aChunked) - { - RefPtr copier = new StreamCopier(aSource, aSink, aChunked); - - RefPtr p = copier->mPromise.Ensure(__func__); - - nsresult rv = copier->mTarget->Dispatch(copier, NS_DISPATCH_NORMAL); - if (NS_FAILED(rv)) { - copier->mPromise.Resolve(rv, __func__); - } - - return p; - } - - NS_DECL_THREADSAFE_ISUPPORTS - NS_DECL_NSIINPUTSTREAMCALLBACK - NS_DECL_NSIOUTPUTSTREAMCALLBACK - NS_DECL_NSIRUNNABLE - -private: - StreamCopier(nsIInputStream* aSource, nsIAsyncOutputStream* aSink, - bool aChunked) - : mSource(aSource) - , mAsyncSource(do_QueryInterface(aSource)) - , mSink(aSink) - , mTarget(do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID)) - , mChunkRemaining(0) - , mChunked(aChunked) - , mAddedFinalSeparator(false) - , mFirstChunk(aChunked) - { - } - ~StreamCopier() {} - - static nsresult FillOutputBufferHelper(nsIOutputStream* aOutStr, - void* aClosure, - char* aBuffer, - uint32_t aOffset, - uint32_t aCount, - uint32_t* aCountRead); - nsresult FillOutputBuffer(char* aBuffer, - uint32_t aCount, - uint32_t* aCountRead); - - nsCOMPtr mSource; - nsCOMPtr mAsyncSource; - nsCOMPtr mSink; - MozPromiseHolder mPromise; - nsCOMPtr mTarget; // XXX we should cache this somewhere - uint32_t mChunkRemaining; - nsCString mSeparator; - bool mChunked; - bool mAddedFinalSeparator; - bool mFirstChunk; -}; - -NS_IMPL_ISUPPORTS(StreamCopier, - nsIOutputStreamCallback, - nsIInputStreamCallback, - nsIRunnable) - -struct WriteState -{ - StreamCopier* copier; - nsresult sourceRv; -}; - -// This function only exists to enable FillOutputBuffer to be a non-static -// function where we can use member variables more easily. -nsresult -StreamCopier::FillOutputBufferHelper(nsIOutputStream* aOutStr, - void* aClosure, - char* aBuffer, - uint32_t aOffset, - uint32_t aCount, - uint32_t* aCountRead) -{ - WriteState* ws = static_cast(aClosure); - ws->sourceRv = ws->copier->FillOutputBuffer(aBuffer, aCount, aCountRead); - return ws->sourceRv; -} - -nsresult -CheckForEOF(nsIInputStream* aIn, - void* aClosure, - const char* aBuffer, - uint32_t aToOffset, - uint32_t aCount, - uint32_t* aWriteCount) -{ - *static_cast(aClosure) = true; - *aWriteCount = 0; - return NS_BINDING_ABORTED; -} - -nsresult -StreamCopier::FillOutputBuffer(char* aBuffer, - uint32_t aCount, - uint32_t* aCountRead) -{ - nsresult rv = NS_OK; - while (mChunked && mSeparator.IsEmpty() && !mChunkRemaining && - !mAddedFinalSeparator) { - uint64_t avail; - rv = mSource->Available(&avail); - if (rv == NS_BASE_STREAM_CLOSED) { - avail = 0; - rv = NS_OK; - } - NS_ENSURE_SUCCESS(rv, rv); - - mChunkRemaining = avail > UINT32_MAX ? UINT32_MAX : - static_cast(avail); - - if (!mChunkRemaining) { - // Either it's an non-blocking stream without any data - // currently available, or we're at EOF. Sadly there's no way - // to tell other than to read from the stream. - bool hadData = false; - uint32_t numRead; - rv = mSource->ReadSegments(CheckForEOF, &hadData, 1, &numRead); - if (rv == NS_BASE_STREAM_CLOSED) { - avail = 0; - rv = NS_OK; - } - NS_ENSURE_SUCCESS(rv, rv); - MOZ_ASSERT(numRead == 0); - - if (hadData) { - // The source received data between the call to Available and the - // call to ReadSegments. Restart with a new call to Available - continue; - } - - // We're at EOF, write a separator with 0 - mAddedFinalSeparator = true; - } - - if (mFirstChunk) { - mFirstChunk = false; - MOZ_ASSERT(mSeparator.IsEmpty()); - } else { - // For all chunks except the first, add the newline at the end - // of the previous chunk of data - mSeparator.AssignLiteral("\r\n"); - } - mSeparator.AppendInt(mChunkRemaining, 16); - mSeparator.AppendLiteral("\r\n"); - - if (mAddedFinalSeparator) { - mSeparator.AppendLiteral("\r\n"); - } - - break; - } - - // If we're doing chunked encoding, we should either have a chunk size, - // or we should have reached the end of the input stream. - MOZ_ASSERT_IF(mChunked, mChunkRemaining || mAddedFinalSeparator); - // We should only have a separator if we're doing chunked encoding - MOZ_ASSERT_IF(!mSeparator.IsEmpty(), mChunked); - - if (!mSeparator.IsEmpty()) { - *aCountRead = std::min(mSeparator.Length(), aCount); - memcpy(aBuffer, mSeparator.BeginReading(), *aCountRead); - mSeparator.Cut(0, *aCountRead); - rv = NS_OK; - } else if (mChunked) { - *aCountRead = 0; - if (mChunkRemaining) { - rv = mSource->Read(aBuffer, - std::min(aCount, mChunkRemaining), - aCountRead); - mChunkRemaining -= *aCountRead; - } - } else { - rv = mSource->Read(aBuffer, aCount, aCountRead); - } - - if (NS_SUCCEEDED(rv) && *aCountRead == 0) { - rv = NS_BASE_STREAM_CLOSED; - } - - return rv; -} - -NS_IMETHODIMP -StreamCopier::Run() -{ - nsresult rv; - while (1) { - WriteState state = { this, NS_OK }; - uint32_t written; - rv = mSink->WriteSegments(FillOutputBufferHelper, &state, - mozilla::net::nsIOService::gDefaultSegmentSize, - &written); - MOZ_ASSERT(NS_SUCCEEDED(rv) || NS_SUCCEEDED(state.sourceRv)); - if (rv == NS_BASE_STREAM_WOULD_BLOCK) { - mSink->AsyncWait(this, 0, 0, mTarget); - return NS_OK; - } - if (NS_FAILED(rv)) { - mPromise.Resolve(rv, __func__); - return NS_OK; - } - - if (state.sourceRv == NS_BASE_STREAM_WOULD_BLOCK) { - MOZ_ASSERT(mAsyncSource); - mAsyncSource->AsyncWait(this, 0, 0, mTarget); - mSink->AsyncWait(this, nsIAsyncInputStream::WAIT_CLOSURE_ONLY, - 0, mTarget); - - return NS_OK; - } - if (state.sourceRv == NS_BASE_STREAM_CLOSED) { - // We're done! - // No longer interested in callbacks about either stream closing - mSink->AsyncWait(nullptr, 0, 0, nullptr); - if (mAsyncSource) { - mAsyncSource->AsyncWait(nullptr, 0, 0, nullptr); - } - - mSource->Close(); - mSource = nullptr; - mAsyncSource = nullptr; - mSink = nullptr; - - mPromise.Resolve(NS_OK, __func__); - - return NS_OK; - } - - if (NS_FAILED(state.sourceRv)) { - mPromise.Resolve(state.sourceRv, __func__); - return NS_OK; - } - } - - MOZ_ASSUME_UNREACHABLE_MARKER(); -} - -NS_IMETHODIMP -StreamCopier::OnInputStreamReady(nsIAsyncInputStream* aStream) -{ - MOZ_ASSERT(aStream == mAsyncSource || - (!mSource && !mAsyncSource && !mSink)); - return mSource ? Run() : NS_OK; -} - -NS_IMETHODIMP -StreamCopier::OnOutputStreamReady(nsIAsyncOutputStream* aStream) -{ - MOZ_ASSERT(aStream == mSink || - (!mSource && !mAsyncSource && !mSink)); - return mSource ? Run() : NS_OK; -} - -} // namespace - -NS_IMETHODIMP -HttpServer::Connection::OnOutputStreamReady(nsIAsyncOutputStream* aStream) -{ - MOZ_ASSERT(aStream == mOutput || !mOutput); - if (!mOutput) { - return NS_OK; - } - - nsresult rv; - - while (!mOutputBuffers.IsEmpty()) { - if (!mOutputBuffers[0].mStream) { - nsCString& buffer = mOutputBuffers[0].mString; - while (!buffer.IsEmpty()) { - uint32_t written = 0; - rv = mOutput->Write(buffer.BeginReading(), - buffer.Length(), - &written); - - buffer.Cut(0, written); - - if (rv == NS_BASE_STREAM_WOULD_BLOCK) { - return mOutput->AsyncWait(this, 0, 0, NS_GetCurrentThread()); - } - - if (NS_FAILED(rv)) { - Close(); - return NS_OK; - } - } - mOutputBuffers.RemoveElementAt(0); - } else { - if (mOutputCopy) { - // we're already copying the stream - return NS_OK; - } - - mOutputCopy = - StreamCopier::Copy(mOutputBuffers[0].mStream, - mOutput, - mOutputBuffers[0].mChunked); - - RefPtr self = this; - - mOutputCopy-> - Then(AbstractThread::MainThread(), - __func__, - [self, this] (nsresult aStatus) { - MOZ_ASSERT(mOutputBuffers[0].mStream); - LOG_V("HttpServer::Connection::OnOutputStreamReady(%p) - " - "Sent body. Status 0x%lx", - this, aStatus); - - mOutputBuffers.RemoveElementAt(0); - mOutputCopy = nullptr; - OnOutputStreamReady(mOutput); - }, - [] (bool) { MOZ_ASSERT_UNREACHABLE("Reject unexpected"); }); - } - } - - if (mPendingRequests.IsEmpty()) { - if (mCloseAfterRequest) { - LOG_V("HttpServer::Connection::OnOutputStreamReady(%p) - Closing channel", - this); - Close(); - } else if (mWebSocketTransportProvider) { - mInput->AsyncWait(nullptr, 0, 0, nullptr); - mOutput->AsyncWait(nullptr, 0, 0, nullptr); - - mWebSocketTransportProvider->SetTransport(mTransport, mInput, mOutput); - mTransport = nullptr; - mInput = nullptr; - mOutput = nullptr; - mWebSocketTransportProvider = nullptr; - } - } - - return NS_OK; -} - -void -HttpServer::Connection::Close() -{ - if (!mTransport) { - MOZ_ASSERT(!mOutput && !mInput); - return; - } - - mTransport->Close(NS_BINDING_ABORTED); - if (mInput) { - mInput->Close(); - mInput = nullptr; - } - if (mOutput) { - mOutput->Close(); - mOutput = nullptr; - } - - mTransport = nullptr; - - mInputBuffer.Truncate(); - mOutputBuffers.Clear(); - mPendingRequests.Clear(); -} - - -} // namespace net -} // namespace mozilla diff --git a/dom/flyweb/HttpServer.h b/dom/flyweb/HttpServer.h deleted file mode 100644 index dab601c24..000000000 --- a/dom/flyweb/HttpServer.h +++ /dev/null @@ -1,193 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: set ts=8 sts=2 et sw=2 tw=80: */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef mozilla_dom_HttpServer_h -#define mozilla_dom_HttpServer_h - -#include "nsISupportsImpl.h" -#include "mozilla/DOMEventTargetHelper.h" -#include "nsITLSServerSocket.h" -#include "nsIAsyncInputStream.h" -#include "nsIAsyncOutputStream.h" -#include "mozilla/Variant.h" -#include "nsIRequestObserver.h" -#include "mozilla/MozPromise.h" -#include "nsITransportProvider.h" -#include "nsILocalCertService.h" - -class nsIX509Cert; - -namespace mozilla { -namespace dom { - -extern bool -ContainsToken(const nsCString& aList, const nsCString& aToken); - -class InternalRequest; -class InternalResponse; - -class HttpServerListener -{ -public: - // switch to NS_INLINE_DECL_PURE_VIRTUAL_REFCOUNTING when that lands - NS_IMETHOD_(MozExternalRefCountType) AddRef(void) = 0; - NS_IMETHOD_(MozExternalRefCountType) Release(void) = 0; - - virtual void OnServerStarted(nsresult aStatus) = 0; - virtual void OnRequest(InternalRequest* aRequest) = 0; - virtual void OnWebSocket(InternalRequest* aConnectRequest) = 0; - virtual void OnServerClose() = 0; -}; - -class HttpServer final : public nsIServerSocketListener, - public nsILocalCertGetCallback -{ -public: - HttpServer(); - - NS_DECL_ISUPPORTS - NS_DECL_NSISERVERSOCKETLISTENER - NS_DECL_NSILOCALCERTGETCALLBACK - - void Init(int32_t aPort, bool aHttps, HttpServerListener* aListener); - - void SendResponse(InternalRequest* aRequest, InternalResponse* aResponse); - already_AddRefed - AcceptWebSocket(InternalRequest* aConnectRequest, - const Optional& aProtocol, - ErrorResult& aRv); - void SendWebSocketResponse(InternalRequest* aConnectRequest, - InternalResponse* aResponse); - - void Close(); - - void GetCertKey(nsACString& aKey); - - int32_t GetPort() - { - return mPort; - } - -private: - ~HttpServer(); - - nsresult StartServerSocket(nsIX509Cert* aCert); - void NotifyStarted(nsresult aStatus); - - class TransportProvider final : public nsITransportProvider - { - public: - NS_DECL_ISUPPORTS - NS_DECL_NSITRANSPORTPROVIDER - - void SetTransport(nsISocketTransport* aTransport, - nsIAsyncInputStream* aInput, - nsIAsyncOutputStream* aOutput); - - private: - virtual ~TransportProvider(); - void MaybeNotify(); - - nsCOMPtr mListener; - nsCOMPtr mTransport; - nsCOMPtr mInput; - nsCOMPtr mOutput; - }; - - class Connection final : public nsIInputStreamCallback - , public nsIOutputStreamCallback - , public nsITLSServerSecurityObserver - { - public: - Connection(nsISocketTransport* aTransport, - HttpServer* aServer, - nsresult& rv); - - NS_DECL_ISUPPORTS - NS_DECL_NSIINPUTSTREAMCALLBACK - NS_DECL_NSIOUTPUTSTREAMCALLBACK - NS_DECL_NSITLSSERVERSECURITYOBSERVER - - bool TryHandleResponse(InternalRequest* aRequest, - InternalResponse* aResponse); - already_AddRefed - HandleAcceptWebSocket(const Optional& aProtocol, - ErrorResult& aRv); - void HandleWebSocketResponse(InternalResponse* aResponse); - bool HasPendingWebSocketRequest(InternalRequest* aRequest) - { - return aRequest == mPendingWebSocketRequest; - } - - void Close(); - - private: - ~Connection(); - - void SetSecurityObserver(bool aListen); - - static nsresult ReadSegmentsFunc(nsIInputStream* aIn, - void* aClosure, - const char* aBuffer, - uint32_t aToOffset, - uint32_t aCount, - uint32_t* aWriteCount); - nsresult ConsumeInput(const char*& aBuffer, - const char* aEnd); - nsresult ConsumeLine(const char* aBuffer, - size_t aLength); - void MaybeAddPendingHeader(); - - void QueueResponse(InternalResponse* aResponse); - - RefPtr mServer; - nsCOMPtr mTransport; - nsCOMPtr mInput; - nsCOMPtr mOutput; - - enum { eRequestLine, eHeaders, eBody, ePause } mState; - RefPtr mPendingReq; - uint32_t mPendingReqVersion; - nsCString mInputBuffer; - nsCString mPendingHeaderName; - nsCString mPendingHeaderValue; - uint32_t mRemainingBodySize; - nsCOMPtr mCurrentRequestBody; - bool mCloseAfterRequest; - - typedef Pair, - RefPtr> PendingRequest; - nsTArray mPendingRequests; - RefPtr> mOutputCopy; - - RefPtr mPendingWebSocketRequest; - RefPtr mWebSocketTransportProvider; - - struct OutputBuffer { - nsCString mString; - nsCOMPtr mStream; - bool mChunked; - }; - - nsTArray mOutputBuffers; - }; - - friend class Connection; - - RefPtr mListener; - nsCOMPtr mServerSocket; - nsCOMPtr mCert; - - nsTArray> mConnections; - - int32_t mPort; - bool mHttps; -}; - -} // namespace dom -} // namespace mozilla - -#endif // mozilla_dom_HttpServer_h diff --git a/dom/flyweb/PFlyWebPublishedServer.ipdl b/dom/flyweb/PFlyWebPublishedServer.ipdl deleted file mode 100644 index 4d08a47fc..000000000 --- a/dom/flyweb/PFlyWebPublishedServer.ipdl +++ /dev/null @@ -1,38 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: set sw=2 ts=8 et ft=cpp : */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -include protocol PContent; -include protocol PSendStream; -include protocol PFileDescriptorSet; -include protocol PTransportProvider; -include FetchTypes; -include ChannelInfo; -include PBackgroundSharedTypes; - -namespace mozilla { -namespace dom { - -async protocol PFlyWebPublishedServer -{ - manager PContent; - -child: - async ServerReady(nsresult aStatus); - async FetchRequest(IPCInternalRequest aRequest, uint64_t aRequestId); - async WebSocketRequest(IPCInternalRequest aRequest, uint64_t aRequestId, - PTransportProvider aProvider); - async ServerClose(); - -parent: - async __delete__(); - - async FetchResponse(IPCInternalResponse aResponse, uint64_t aRequestId); - async WebSocketResponse(IPCInternalResponse aResponse, uint64_t aRequestId); - async WebSocketAccept(nsString aProtocol, uint64_t aRequestId); -}; - -} // namespace dom -} // namespace mozilla diff --git a/dom/flyweb/moz.build b/dom/flyweb/moz.build deleted file mode 100644 index aa8c034b7..000000000 --- a/dom/flyweb/moz.build +++ /dev/null @@ -1,42 +0,0 @@ -# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- -# vim: set filetype=python: -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -EXPORTS.mozilla.dom += [ - 'FlyWebDiscoveryManager.h', - 'FlyWebPublishedServer.h', - 'FlyWebPublishedServerIPC.h', - 'FlyWebPublishOptionsIPCSerializer.h', - 'FlyWebServerEvents.h', - 'FlyWebService.h', - 'HttpServer.h', -] - -UNIFIED_SOURCES += [ - 'FlyWebDiscoveryManager.cpp', - 'FlyWebPublishedServer.cpp', - 'FlyWebServerEvents.cpp', - 'FlyWebService.cpp', - 'HttpServer.cpp' -] - -IPDL_SOURCES += [ - 'PFlyWebPublishedServer.ipdl', -] - -FINAL_LIBRARY = 'xul' - -LOCAL_INCLUDES += [ - '/dom/base', - '/netwerk/base', - '/netwerk/dns', - '/netwerk/protocol/websocket', - '/xpcom/io' -] - -include('/ipc/chromium/chromium-config.mozbuild') - -if CONFIG['GNU_CXX']: - CXXFLAGS += ['-Wshadow'] -- cgit v1.2.3