diff --git a/netwerk/ipc/NeckoChild.cpp b/netwerk/ipc/NeckoChild.cpp index 3809d637703..3ceb8bea589 100644 --- a/netwerk/ipc/NeckoChild.cpp +++ b/netwerk/ipc/NeckoChild.cpp @@ -145,7 +145,8 @@ NeckoChild::DeallocPWyciwygChannelChild(PWyciwygChannelChild* channel) PWebSocketChild* NeckoChild::AllocPWebSocketChild(const PBrowserOrId& browser, - const SerializedLoadContext& aSerialized) + const SerializedLoadContext& aSerialized, + const uint32_t& aSerial) { NS_NOTREACHED("AllocPWebSocketChild should not be called"); return nullptr; diff --git a/netwerk/ipc/NeckoChild.h b/netwerk/ipc/NeckoChild.h index 37f03550269..19f481dfe1f 100644 --- a/netwerk/ipc/NeckoChild.h +++ b/netwerk/ipc/NeckoChild.h @@ -40,7 +40,8 @@ protected: virtual bool DeallocPFTPChannelChild(PFTPChannelChild*) override; virtual PWebSocketChild* AllocPWebSocketChild(const PBrowserOrId&, - const SerializedLoadContext&) override; + const SerializedLoadContext&, + const uint32_t&) override; virtual bool DeallocPWebSocketChild(PWebSocketChild*) override; virtual PTCPSocketChild* AllocPTCPSocketChild(const nsString& host, const uint16_t& port) override; diff --git a/netwerk/ipc/NeckoParent.cpp b/netwerk/ipc/NeckoParent.cpp index 1bf8c4a2677..85d3eba66a0 100644 --- a/netwerk/ipc/NeckoParent.cpp +++ b/netwerk/ipc/NeckoParent.cpp @@ -320,7 +320,8 @@ NeckoParent::DeallocPWyciwygChannelParent(PWyciwygChannelParent* channel) PWebSocketParent* NeckoParent::AllocPWebSocketParent(const PBrowserOrId& browser, - const SerializedLoadContext& serialized) + const SerializedLoadContext& serialized, + const uint32_t& aSerial) { nsCOMPtr loadContext; const char *error = CreateChannelLoadContext(browser, Manager(), @@ -335,7 +336,8 @@ NeckoParent::AllocPWebSocketParent(const PBrowserOrId& browser, RefPtr tabParent = TabParent::GetFrom(browser.get_PBrowserParent()); PBOverrideStatus overrideStatus = PBOverrideStatusFromLoadContext(serialized); WebSocketChannelParent* p = new WebSocketChannelParent(tabParent, loadContext, - overrideStatus); + overrideStatus, + aSerial); p->AddRef(); return p; } diff --git a/netwerk/ipc/NeckoParent.h b/netwerk/ipc/NeckoParent.h index dbbc525cfd4..c548b1b6e04 100644 --- a/netwerk/ipc/NeckoParent.h +++ b/netwerk/ipc/NeckoParent.h @@ -124,7 +124,8 @@ protected: virtual bool DeallocPFTPChannelParent(PFTPChannelParent*) override; virtual PWebSocketParent* AllocPWebSocketParent(const PBrowserOrId& browser, - const SerializedLoadContext& aSerialized) override; + const SerializedLoadContext& aSerialized, + const uint32_t& aSerial) override; virtual bool DeallocPWebSocketParent(PWebSocketParent*) override; virtual PTCPSocketParent* AllocPTCPSocketParent(const nsString& host, const uint16_t& port) override; diff --git a/netwerk/ipc/PNecko.ipdl b/netwerk/ipc/PNecko.ipdl index 5ea25d72c5d..2e1f2f51829 100644 --- a/netwerk/ipc/PNecko.ipdl +++ b/netwerk/ipc/PNecko.ipdl @@ -68,7 +68,8 @@ parent: PFTPChannel(PBrowserOrId browser, SerializedLoadContext loadContext, FTPChannelCreationArgs args); - PWebSocket(PBrowserOrId browser, SerializedLoadContext loadContext); + PWebSocket(PBrowserOrId browser, SerializedLoadContext loadContext, + uint32_t aSerialID); PTCPServerSocket(uint16_t localPort, uint16_t backlog, bool useArrayBuffers); PUDPSocket(Principal principal, nsCString filter); diff --git a/netwerk/protocol/websocket/BaseWebSocketChannel.cpp b/netwerk/protocol/websocket/BaseWebSocketChannel.cpp index 91eb34f2cbc..dd9136b93aa 100644 --- a/netwerk/protocol/websocket/BaseWebSocketChannel.cpp +++ b/netwerk/protocol/websocket/BaseWebSocketChannel.cpp @@ -14,12 +14,25 @@ #include "nsStandardURL.h" #include "LoadInfo.h" #include "nsIDOMNode.h" +#include "mozilla/dom/ContentChild.h" + +using mozilla::dom::ContentChild; PRLogModuleInfo *webSocketLog = nullptr; namespace mozilla { namespace net { +static uint64_t gNextWebSocketID = 0; + +// We use only 53 bits for the WebSocket serial ID so that it can be converted +// to and from a JS value without loss of precision. The upper bits of the +// WebSocket serial ID hold the process ID. The lower bits identify the +// WebSocket. +static const uint64_t kWebSocketIDTotalBits = 53; +static const uint64_t kWebSocketIDProcessBits = 22; +static const uint64_t kWebSocketIDWebSocketBits = kWebSocketIDTotalBits - kWebSocketIDProcessBits; + BaseWebSocketChannel::BaseWebSocketChannel() : mWasOpened(0) , mClientSetPingInterval(0) @@ -31,6 +44,24 @@ BaseWebSocketChannel::BaseWebSocketChannel() { if (!webSocketLog) webSocketLog = PR_NewLogModule("nsWebSocket"); + + // Generation of a unique serial ID. + uint64_t processID = 0; + if (XRE_IsContentProcess()) { + ContentChild* cc = ContentChild::GetSingleton(); + processID = cc->GetID(); + } + + uint64_t processBits = processID & ((uint64_t(1) << kWebSocketIDProcessBits) - 1); + + // Make sure no actual webSocket ends up with mWebSocketID == 0 but less then + // what the kWebSocketIDProcessBits allows. + if (++gNextWebSocketID >= (uint64_t(1) << kWebSocketIDWebSocketBits)) { + gNextWebSocketID = 1; + } + + uint64_t webSocketBits = gNextWebSocketID & ((uint64_t(1) << kWebSocketIDWebSocketBits) - 1); + mSerial = (processBits << kWebSocketIDWebSocketBits) | webSocketBits; } //----------------------------------------------------------------------------- @@ -197,6 +228,24 @@ BaseWebSocketChannel::InitLoadInfo(nsIDOMNode* aLoadingNode, return NS_OK; } +NS_IMETHODIMP +BaseWebSocketChannel::GetSerial(uint32_t* aSerial) +{ + if (!aSerial) { + return NS_ERROR_FAILURE; + } + + *aSerial = mSerial; + return NS_OK; +} + +NS_IMETHODIMP +BaseWebSocketChannel::SetSerial(uint32_t aSerial) +{ + mSerial = aSerial; + return NS_OK; +} + //----------------------------------------------------------------------------- // BaseWebSocketChannel::nsIProtocolHandler //----------------------------------------------------------------------------- diff --git a/netwerk/protocol/websocket/BaseWebSocketChannel.h b/netwerk/protocol/websocket/BaseWebSocketChannel.h index d9f52864e64..34757d85bbe 100644 --- a/netwerk/protocol/websocket/BaseWebSocketChannel.h +++ b/netwerk/protocol/websocket/BaseWebSocketChannel.h @@ -55,6 +55,8 @@ class BaseWebSocketChannel : public nsIWebSocketChannel, NS_IMETHOD InitLoadInfo(nsIDOMNode* aLoadingNode, nsIPrincipal* aLoadingPrincipal, nsIPrincipal* aTriggeringPrincipal, uint32_t aSecurityFlags, uint32_t aContentPolicyType) override; + NS_IMETHOD GetSerial(uint32_t* aSerial) override; + NS_IMETHOD SetSerial(uint32_t aSerial) override; // Off main thread URI access. virtual void GetEffectiveURL(nsAString& aEffectiveURL) const = 0; @@ -98,6 +100,8 @@ class BaseWebSocketChannel : public nsIWebSocketChannel, uint32_t mPingInterval; /* milliseconds */ uint32_t mPingResponseTimeout; /* milliseconds */ + + uint32_t mSerial; }; } // namespace net diff --git a/netwerk/protocol/websocket/WebSocketChannel.cpp b/netwerk/protocol/websocket/WebSocketChannel.cpp index 0158be5328e..ca850695d8a 100644 --- a/netwerk/protocol/websocket/WebSocketChannel.cpp +++ b/netwerk/protocol/websocket/WebSocketChannel.cpp @@ -1138,8 +1138,6 @@ NS_IMPL_ISUPPORTS(OutboundEnqueuer, nsIRunnable) // WebSocketChannel //----------------------------------------------------------------------------- -uint32_t WebSocketChannel::sSerialSeed = 0; - WebSocketChannel::WebSocketChannel() : mPort(0), mCloseTimeout(20000), @@ -1194,8 +1192,6 @@ WebSocketChannel::WebSocketChannel() : if (NS_FAILED(rv)) LOG(("Failed to initiate dashboard service.")); - mSerial = sSerialSeed++; - mService = WebSocketEventService::GetOrCreate(); } diff --git a/netwerk/protocol/websocket/WebSocketChannel.h b/netwerk/protocol/websocket/WebSocketChannel.h index 3fdb1ca0ecd..de9fed7064c 100644 --- a/netwerk/protocol/websocket/WebSocketChannel.h +++ b/netwerk/protocol/websocket/WebSocketChannel.h @@ -294,8 +294,6 @@ private: bool mPrivateBrowsing; nsCOMPtr mConnectionLogService; - uint32_t mSerial; - static uint32_t sSerialSeed; // These members are used for network per-app metering (bug 855949) // Currently, they are only available on gonk. diff --git a/netwerk/protocol/websocket/WebSocketChannelChild.cpp b/netwerk/protocol/websocket/WebSocketChannelChild.cpp index fafbcc23fae..34f87a9868a 100644 --- a/netwerk/protocol/websocket/WebSocketChannelChild.cpp +++ b/netwerk/protocol/websocket/WebSocketChannelChild.cpp @@ -489,7 +489,8 @@ WebSocketChannelChild::AsyncOpen(nsIURI *aURI, NS_ENSURE_SUCCESS(rv, rv); gNeckoChild->SendPWebSocketConstructor(this, tabChild, - IPC::SerializedLoadContext(this)); + IPC::SerializedLoadContext(this), + mSerial); if (!SendAsyncOpen(uri, nsCString(aOrigin), aInnerWindowID, mProtocol, mEncrypted, mPingInterval, mClientSetPingInterval, mPingResponseTimeout, mClientSetPingTimeout, loadInfoArgs)) { diff --git a/netwerk/protocol/websocket/WebSocketChannelParent.cpp b/netwerk/protocol/websocket/WebSocketChannelParent.cpp index d04b0c7509c..2354703b0fd 100644 --- a/netwerk/protocol/websocket/WebSocketChannelParent.cpp +++ b/netwerk/protocol/websocket/WebSocketChannelParent.cpp @@ -26,10 +26,12 @@ NS_IMPL_ISUPPORTS(WebSocketChannelParent, WebSocketChannelParent::WebSocketChannelParent(nsIAuthPromptProvider* aAuthProvider, nsILoadContext* aLoadContext, - PBOverrideStatus aOverrideStatus) + PBOverrideStatus aOverrideStatus, + uint32_t aSerial) : mAuthProvider(aAuthProvider) , mLoadContext(aLoadContext) , mIPCOpen(true) + , mSerial(aSerial) { // Websocket channels can't have a private browsing override MOZ_ASSERT_IF(!aLoadContext, aOverrideStatus == kPBOverride_Unset); @@ -95,6 +97,11 @@ WebSocketChannelParent::RecvAsyncOpen(const URIParams& aURI, if (NS_FAILED(rv)) goto fail; + rv = mChannel->SetSerial(mSerial); + if (NS_WARN_IF(NS_FAILED(rv))) { + goto fail; + } + rv = LoadInfoArgsToLoadInfo(aLoadInfoArgs, getter_AddRefs(loadInfo)); if (NS_FAILED(rv)) goto fail; diff --git a/netwerk/protocol/websocket/WebSocketChannelParent.h b/netwerk/protocol/websocket/WebSocketChannelParent.h index 239e99d74c5..293223f8a67 100644 --- a/netwerk/protocol/websocket/WebSocketChannelParent.h +++ b/netwerk/protocol/websocket/WebSocketChannelParent.h @@ -35,7 +35,8 @@ class WebSocketChannelParent : public PWebSocketParent, WebSocketChannelParent(nsIAuthPromptProvider* aAuthProvider, nsILoadContext* aLoadContext, - PBOverrideStatus aOverrideStatus); + PBOverrideStatus aOverrideStatus, + uint32_t aSerial); private: bool RecvAsyncOpen(const URIParams& aURI, @@ -66,6 +67,7 @@ class WebSocketChannelParent : public PWebSocketParent, nsCOMPtr mLoadContext; bool mIPCOpen; + uint32_t mSerial; }; } // namespace net diff --git a/netwerk/protocol/websocket/nsIWebSocketChannel.idl b/netwerk/protocol/websocket/nsIWebSocketChannel.idl index 0adae64404a..10d446bd4d5 100644 --- a/netwerk/protocol/websocket/nsIWebSocketChannel.idl +++ b/netwerk/protocol/websocket/nsIWebSocketChannel.idl @@ -22,7 +22,7 @@ interface nsIPrincipal; * We are also making it scriptable for now, but this may change once we have * WebSockets for Workers. */ -[scriptable, uuid(352e0c08-f14c-40c8-ad06-2f8bb5d9d9e0)] +[scriptable, uuid(1bfc252b-ad46-413c-860b-2079bf1399c7)] interface nsIWebSocketChannel : nsISupports { /** @@ -223,4 +223,9 @@ interface nsIWebSocketChannel : nsISupports */ attribute unsigned long pingTimeout; + /** + * Unique ID for this channel. It's not readonly because when the channel is + * created via IPC, the serial number is received from the child process. + */ + attribute unsigned long serial; };