michael@0: /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* vim: set sw=2 ts=8 et tw=80 : */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "WebSocketLog.h" michael@0: #include "WebSocketChannelParent.h" michael@0: #include "nsIAuthPromptProvider.h" michael@0: #include "mozilla/ipc/InputStreamUtils.h" michael@0: #include "mozilla/ipc/URIUtils.h" michael@0: #include "SerializedLoadContext.h" michael@0: michael@0: using namespace mozilla::ipc; michael@0: michael@0: namespace mozilla { michael@0: namespace net { michael@0: michael@0: NS_IMPL_ISUPPORTS(WebSocketChannelParent, michael@0: nsIWebSocketListener, michael@0: nsIInterfaceRequestor) michael@0: michael@0: WebSocketChannelParent::WebSocketChannelParent(nsIAuthPromptProvider* aAuthProvider, michael@0: nsILoadContext* aLoadContext, michael@0: PBOverrideStatus aOverrideStatus) michael@0: : mAuthProvider(aAuthProvider) michael@0: , mLoadContext(aLoadContext) michael@0: , mIPCOpen(true) michael@0: { michael@0: // Websocket channels can't have a private browsing override michael@0: MOZ_ASSERT_IF(!aLoadContext, aOverrideStatus == kPBOverride_Unset); michael@0: #if defined(PR_LOGGING) michael@0: if (!webSocketLog) michael@0: webSocketLog = PR_NewLogModule("nsWebSocket"); michael@0: #endif michael@0: } michael@0: michael@0: //----------------------------------------------------------------------------- michael@0: // WebSocketChannelParent::PWebSocketChannelParent michael@0: //----------------------------------------------------------------------------- michael@0: michael@0: bool michael@0: WebSocketChannelParent::RecvDeleteSelf() michael@0: { michael@0: LOG(("WebSocketChannelParent::RecvDeleteSelf() %p\n", this)); michael@0: mChannel = nullptr; michael@0: mAuthProvider = nullptr; michael@0: return mIPCOpen ? Send__delete__(this) : true; michael@0: } michael@0: michael@0: bool michael@0: WebSocketChannelParent::RecvAsyncOpen(const URIParams& aURI, michael@0: const nsCString& aOrigin, michael@0: const nsCString& aProtocol, michael@0: const bool& aSecure, michael@0: const uint32_t& aPingInterval, michael@0: const bool& aClientSetPingInterval, michael@0: const uint32_t& aPingTimeout, michael@0: const bool& aClientSetPingTimeout) michael@0: { michael@0: LOG(("WebSocketChannelParent::RecvAsyncOpen() %p\n", this)); michael@0: michael@0: nsresult rv; michael@0: nsCOMPtr uri; michael@0: michael@0: if (aSecure) { michael@0: mChannel = michael@0: do_CreateInstance("@mozilla.org/network/protocol;1?name=wss", &rv); michael@0: } else { michael@0: mChannel = michael@0: do_CreateInstance("@mozilla.org/network/protocol;1?name=ws", &rv); michael@0: } michael@0: if (NS_FAILED(rv)) michael@0: goto fail; michael@0: michael@0: rv = mChannel->SetNotificationCallbacks(this); michael@0: if (NS_FAILED(rv)) michael@0: goto fail; michael@0: michael@0: rv = mChannel->SetProtocol(aProtocol); michael@0: if (NS_FAILED(rv)) michael@0: goto fail; michael@0: michael@0: uri = DeserializeURI(aURI); michael@0: if (!uri) { michael@0: rv = NS_ERROR_FAILURE; michael@0: goto fail; michael@0: } michael@0: michael@0: // only use ping values from child if they were overridden by client code. michael@0: if (aClientSetPingInterval) { michael@0: // IDL allows setting in seconds, so must be multiple of 1000 ms michael@0: MOZ_ASSERT(aPingInterval >= 1000 && !(aPingInterval % 1000)); michael@0: mChannel->SetPingInterval(aPingInterval / 1000); michael@0: } michael@0: if (aClientSetPingTimeout) { michael@0: MOZ_ASSERT(aPingTimeout >= 1000 && !(aPingTimeout % 1000)); michael@0: mChannel->SetPingTimeout(aPingTimeout / 1000); michael@0: } michael@0: michael@0: rv = mChannel->AsyncOpen(uri, aOrigin, this, nullptr); michael@0: if (NS_FAILED(rv)) michael@0: goto fail; michael@0: michael@0: return true; michael@0: michael@0: fail: michael@0: mChannel = nullptr; michael@0: return SendOnStop(rv); michael@0: } michael@0: michael@0: bool michael@0: WebSocketChannelParent::RecvClose(const uint16_t& code, const nsCString& reason) michael@0: { michael@0: LOG(("WebSocketChannelParent::RecvClose() %p\n", this)); michael@0: if (mChannel) { michael@0: nsresult rv = mChannel->Close(code, reason); michael@0: NS_ENSURE_SUCCESS(rv, true); michael@0: } michael@0: return true; michael@0: } michael@0: michael@0: bool michael@0: WebSocketChannelParent::RecvSendMsg(const nsCString& aMsg) michael@0: { michael@0: LOG(("WebSocketChannelParent::RecvSendMsg() %p\n", this)); michael@0: if (mChannel) { michael@0: nsresult rv = mChannel->SendMsg(aMsg); michael@0: NS_ENSURE_SUCCESS(rv, true); michael@0: } michael@0: return true; michael@0: } michael@0: michael@0: bool michael@0: WebSocketChannelParent::RecvSendBinaryMsg(const nsCString& aMsg) michael@0: { michael@0: LOG(("WebSocketChannelParent::RecvSendBinaryMsg() %p\n", this)); michael@0: if (mChannel) { michael@0: nsresult rv = mChannel->SendBinaryMsg(aMsg); michael@0: NS_ENSURE_SUCCESS(rv, true); michael@0: } michael@0: return true; michael@0: } michael@0: michael@0: bool michael@0: WebSocketChannelParent::RecvSendBinaryStream(const InputStreamParams& aStream, michael@0: const uint32_t& aLength) michael@0: { michael@0: LOG(("WebSocketChannelParent::RecvSendBinaryStream() %p\n", this)); michael@0: if (mChannel) { michael@0: nsTArray fds; michael@0: nsCOMPtr stream = DeserializeInputStream(aStream, fds); michael@0: if (!stream) { michael@0: return false; michael@0: } michael@0: nsresult rv = mChannel->SendBinaryStream(stream, aLength); michael@0: NS_ENSURE_SUCCESS(rv, true); michael@0: } michael@0: return true; michael@0: } michael@0: michael@0: //----------------------------------------------------------------------------- michael@0: // WebSocketChannelParent::nsIRequestObserver michael@0: //----------------------------------------------------------------------------- michael@0: michael@0: NS_IMETHODIMP michael@0: WebSocketChannelParent::OnStart(nsISupports *aContext) michael@0: { michael@0: LOG(("WebSocketChannelParent::OnStart() %p\n", this)); michael@0: nsAutoCString protocol, extensions; michael@0: if (mChannel) { michael@0: mChannel->GetProtocol(protocol); michael@0: mChannel->GetExtensions(extensions); michael@0: } michael@0: if (!mIPCOpen || !SendOnStart(protocol, extensions)) { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: WebSocketChannelParent::OnStop(nsISupports *aContext, nsresult aStatusCode) michael@0: { michael@0: LOG(("WebSocketChannelParent::OnStop() %p\n", this)); michael@0: if (!mIPCOpen || !SendOnStop(aStatusCode)) { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: WebSocketChannelParent::OnMessageAvailable(nsISupports *aContext, const nsACString& aMsg) michael@0: { michael@0: LOG(("WebSocketChannelParent::OnMessageAvailable() %p\n", this)); michael@0: if (!mIPCOpen || !SendOnMessageAvailable(nsCString(aMsg))) { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: WebSocketChannelParent::OnBinaryMessageAvailable(nsISupports *aContext, const nsACString& aMsg) michael@0: { michael@0: LOG(("WebSocketChannelParent::OnBinaryMessageAvailable() %p\n", this)); michael@0: if (!mIPCOpen || !SendOnBinaryMessageAvailable(nsCString(aMsg))) { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: WebSocketChannelParent::OnAcknowledge(nsISupports *aContext, uint32_t aSize) michael@0: { michael@0: LOG(("WebSocketChannelParent::OnAcknowledge() %p\n", this)); michael@0: if (!mIPCOpen || !SendOnAcknowledge(aSize)) { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: WebSocketChannelParent::OnServerClose(nsISupports *aContext, michael@0: uint16_t code, const nsACString & reason) michael@0: { michael@0: LOG(("WebSocketChannelParent::OnServerClose() %p\n", this)); michael@0: if (!mIPCOpen || !SendOnServerClose(code, nsCString(reason))) { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: return NS_OK; michael@0: } michael@0: michael@0: void michael@0: WebSocketChannelParent::ActorDestroy(ActorDestroyReason why) michael@0: { michael@0: LOG(("WebSocketChannelParent::ActorDestroy() %p\n", this)); michael@0: mIPCOpen = false; michael@0: } michael@0: michael@0: //----------------------------------------------------------------------------- michael@0: // WebSocketChannelParent::nsIInterfaceRequestor michael@0: //----------------------------------------------------------------------------- michael@0: michael@0: NS_IMETHODIMP michael@0: WebSocketChannelParent::GetInterface(const nsIID & iid, void **result) michael@0: { michael@0: LOG(("WebSocketChannelParent::GetInterface() %p\n", this)); michael@0: if (mAuthProvider && iid.Equals(NS_GET_IID(nsIAuthPromptProvider))) michael@0: return mAuthProvider->GetAuthPrompt(nsIAuthPromptProvider::PROMPT_NORMAL, michael@0: iid, result); michael@0: michael@0: // Only support nsILoadContext if child channel's callbacks did too michael@0: if (iid.Equals(NS_GET_IID(nsILoadContext)) && mLoadContext) { michael@0: NS_ADDREF(mLoadContext); michael@0: *result = static_cast(mLoadContext); michael@0: return NS_OK; michael@0: } michael@0: michael@0: return QueryInterface(iid, result); michael@0: } michael@0: michael@0: michael@0: } // namespace net michael@0: } // namespace mozilla