Files
tubestation/netwerk/protocol/websocket/WebSocketChannelParent.cpp
Ehsan Akhgari 8857726bbb Bug 1156084 - Disallow AddRef() and Release() calls on the return value of methods returning XPCOM objects; r=jrmuizel
When a method returns type D derived from RefCounted type B, there is an
ImplicitCastExpr (or an ExplicitCastExpr, if there is an explicit cast
to the base type in the code) in the AST between the CallExpr and
MemberExpr, which we didn't take into account before.  This caused the
analysis to not work on common patterns such as
nsCOMPtr<nsIXPCOMInterface>.
2015-05-15 08:39:55 -04:00

336 lines
9.6 KiB
C++

/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set sw=2 ts=8 et 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 "WebSocketLog.h"
#include "WebSocketChannelParent.h"
#include "nsIAuthPromptProvider.h"
#include "mozilla/ipc/InputStreamUtils.h"
#include "mozilla/ipc/URIUtils.h"
#include "mozilla/ipc/BackgroundUtils.h"
#include "SerializedLoadContext.h"
#include "nsIOService.h"
#include "mozilla/net/NeckoCommon.h"
#include "mozilla/net/WebSocketChannel.h"
using namespace mozilla::ipc;
namespace mozilla {
namespace net {
NS_IMPL_ISUPPORTS(WebSocketChannelParent,
nsIWebSocketListener,
nsIInterfaceRequestor)
WebSocketChannelParent::WebSocketChannelParent(nsIAuthPromptProvider* aAuthProvider,
nsILoadContext* aLoadContext,
PBOverrideStatus aOverrideStatus)
: mAuthProvider(aAuthProvider)
, mLoadContext(aLoadContext)
, mIPCOpen(true)
{
// Websocket channels can't have a private browsing override
MOZ_ASSERT_IF(!aLoadContext, aOverrideStatus == kPBOverride_Unset);
if (!webSocketLog)
webSocketLog = PR_NewLogModule("nsWebSocket");
mObserver = new OfflineObserver(this);
}
WebSocketChannelParent::~WebSocketChannelParent()
{
if (mObserver) {
mObserver->RemoveObserver();
}
}
//-----------------------------------------------------------------------------
// WebSocketChannelParent::PWebSocketChannelParent
//-----------------------------------------------------------------------------
bool
WebSocketChannelParent::RecvDeleteSelf()
{
LOG(("WebSocketChannelParent::RecvDeleteSelf() %p\n", this));
mChannel = nullptr;
mAuthProvider = nullptr;
return mIPCOpen ? Send__delete__(this) : true;
}
bool
WebSocketChannelParent::RecvAsyncOpen(const URIParams& aURI,
const nsCString& aOrigin,
const nsCString& aProtocol,
const bool& aSecure,
const uint32_t& aPingInterval,
const bool& aClientSetPingInterval,
const uint32_t& aPingTimeout,
const bool& aClientSetPingTimeout,
const WebSocketLoadInfoArgs& aLoadInfoArgs)
{
LOG(("WebSocketChannelParent::RecvAsyncOpen() %p\n", this));
nsresult rv;
nsCOMPtr<nsIURI> uri;
nsCOMPtr<nsIPrincipal> requestingPrincipal, triggeringPrincipal;
nsCOMPtr<nsILoadInfo> loadInfo;
bool appOffline = false;
uint32_t appId = GetAppId();
if (appId != NECKO_UNKNOWN_APP_ID &&
appId != NECKO_NO_APP_ID) {
gIOService->IsAppOffline(appId, &appOffline);
if (appOffline) {
goto fail;
}
}
if (aSecure) {
mChannel =
do_CreateInstance("@mozilla.org/network/protocol;1?name=wss", &rv);
} else {
mChannel =
do_CreateInstance("@mozilla.org/network/protocol;1?name=ws", &rv);
}
if (NS_FAILED(rv))
goto fail;
requestingPrincipal =
mozilla::ipc::PrincipalInfoToPrincipal(aLoadInfoArgs.requestingPrincipalInfo(), &rv);
if (NS_FAILED(rv)) {
goto fail;
}
triggeringPrincipal =
mozilla::ipc::PrincipalInfoToPrincipal(aLoadInfoArgs.triggeringPrincipalInfo(), &rv);
if (NS_FAILED(rv)) {
goto fail;
}
loadInfo = new LoadInfo(requestingPrincipal,
triggeringPrincipal,
aLoadInfoArgs.securityFlags(),
aLoadInfoArgs.contentPolicyType(),
aLoadInfoArgs.innerWindowID());
rv = mChannel->SetLoadInfo(loadInfo);
if (NS_FAILED(rv)) {
goto fail;
}
rv = mChannel->SetNotificationCallbacks(this);
if (NS_FAILED(rv))
goto fail;
rv = mChannel->SetProtocol(aProtocol);
if (NS_FAILED(rv))
goto fail;
uri = DeserializeURI(aURI);
if (!uri) {
rv = NS_ERROR_FAILURE;
goto fail;
}
// only use ping values from child if they were overridden by client code.
if (aClientSetPingInterval) {
// IDL allows setting in seconds, so must be multiple of 1000 ms
MOZ_ASSERT(aPingInterval >= 1000 && !(aPingInterval % 1000));
mChannel->SetPingInterval(aPingInterval / 1000);
}
if (aClientSetPingTimeout) {
MOZ_ASSERT(aPingTimeout >= 1000 && !(aPingTimeout % 1000));
mChannel->SetPingTimeout(aPingTimeout / 1000);
}
rv = mChannel->AsyncOpen(uri, aOrigin, this, nullptr);
if (NS_FAILED(rv))
goto fail;
return true;
fail:
mChannel = nullptr;
return SendOnStop(rv);
}
bool
WebSocketChannelParent::RecvClose(const uint16_t& code, const nsCString& reason)
{
LOG(("WebSocketChannelParent::RecvClose() %p\n", this));
if (mChannel) {
nsresult rv = mChannel->Close(code, reason);
NS_ENSURE_SUCCESS(rv, true);
}
return true;
}
bool
WebSocketChannelParent::RecvSendMsg(const nsCString& aMsg)
{
LOG(("WebSocketChannelParent::RecvSendMsg() %p\n", this));
if (mChannel) {
nsresult rv = mChannel->SendMsg(aMsg);
NS_ENSURE_SUCCESS(rv, true);
}
return true;
}
bool
WebSocketChannelParent::RecvSendBinaryMsg(const nsCString& aMsg)
{
LOG(("WebSocketChannelParent::RecvSendBinaryMsg() %p\n", this));
if (mChannel) {
nsresult rv = mChannel->SendBinaryMsg(aMsg);
NS_ENSURE_SUCCESS(rv, true);
}
return true;
}
bool
WebSocketChannelParent::RecvSendBinaryStream(const InputStreamParams& aStream,
const uint32_t& aLength)
{
LOG(("WebSocketChannelParent::RecvSendBinaryStream() %p\n", this));
if (mChannel) {
nsTArray<mozilla::ipc::FileDescriptor> fds;
nsCOMPtr<nsIInputStream> stream = DeserializeInputStream(aStream, fds);
if (!stream) {
return false;
}
nsresult rv = mChannel->SendBinaryStream(stream, aLength);
NS_ENSURE_SUCCESS(rv, true);
}
return true;
}
//-----------------------------------------------------------------------------
// WebSocketChannelParent::nsIRequestObserver
//-----------------------------------------------------------------------------
NS_IMETHODIMP
WebSocketChannelParent::OnStart(nsISupports *aContext)
{
LOG(("WebSocketChannelParent::OnStart() %p\n", this));
nsAutoCString protocol, extensions;
nsString effectiveURL;
bool encrypted = false;
if (mChannel) {
mChannel->GetProtocol(protocol);
mChannel->GetExtensions(extensions);
nsRefPtr<WebSocketChannel> channel;
channel = static_cast<WebSocketChannel*>(mChannel.get());
MOZ_ASSERT(channel);
channel->GetEffectiveURL(effectiveURL);
encrypted = channel->IsEncrypted();
}
if (!mIPCOpen || !SendOnStart(protocol, extensions, effectiveURL, encrypted)) {
return NS_ERROR_FAILURE;
}
return NS_OK;
}
NS_IMETHODIMP
WebSocketChannelParent::OnStop(nsISupports *aContext, nsresult aStatusCode)
{
LOG(("WebSocketChannelParent::OnStop() %p\n", this));
if (!mIPCOpen || !SendOnStop(aStatusCode)) {
return NS_ERROR_FAILURE;
}
return NS_OK;
}
NS_IMETHODIMP
WebSocketChannelParent::OnMessageAvailable(nsISupports *aContext, const nsACString& aMsg)
{
LOG(("WebSocketChannelParent::OnMessageAvailable() %p\n", this));
if (!mIPCOpen || !SendOnMessageAvailable(nsCString(aMsg))) {
return NS_ERROR_FAILURE;
}
return NS_OK;
}
NS_IMETHODIMP
WebSocketChannelParent::OnBinaryMessageAvailable(nsISupports *aContext, const nsACString& aMsg)
{
LOG(("WebSocketChannelParent::OnBinaryMessageAvailable() %p\n", this));
if (!mIPCOpen || !SendOnBinaryMessageAvailable(nsCString(aMsg))) {
return NS_ERROR_FAILURE;
}
return NS_OK;
}
NS_IMETHODIMP
WebSocketChannelParent::OnAcknowledge(nsISupports *aContext, uint32_t aSize)
{
LOG(("WebSocketChannelParent::OnAcknowledge() %p\n", this));
if (!mIPCOpen || !SendOnAcknowledge(aSize)) {
return NS_ERROR_FAILURE;
}
return NS_OK;
}
NS_IMETHODIMP
WebSocketChannelParent::OnServerClose(nsISupports *aContext,
uint16_t code, const nsACString & reason)
{
LOG(("WebSocketChannelParent::OnServerClose() %p\n", this));
if (!mIPCOpen || !SendOnServerClose(code, nsCString(reason))) {
return NS_ERROR_FAILURE;
}
return NS_OK;
}
void
WebSocketChannelParent::ActorDestroy(ActorDestroyReason why)
{
LOG(("WebSocketChannelParent::ActorDestroy() %p\n", this));
mIPCOpen = false;
}
//-----------------------------------------------------------------------------
// WebSocketChannelParent::nsIInterfaceRequestor
//-----------------------------------------------------------------------------
NS_IMETHODIMP
WebSocketChannelParent::GetInterface(const nsIID & iid, void **result)
{
LOG(("WebSocketChannelParent::GetInterface() %p\n", this));
if (mAuthProvider && iid.Equals(NS_GET_IID(nsIAuthPromptProvider)))
return mAuthProvider->GetAuthPrompt(nsIAuthPromptProvider::PROMPT_NORMAL,
iid, result);
// Only support nsILoadContext if child channel's callbacks did too
if (iid.Equals(NS_GET_IID(nsILoadContext)) && mLoadContext) {
nsCOMPtr<nsILoadContext> copy = mLoadContext;
copy.forget(result);
return NS_OK;
}
return QueryInterface(iid, result);
}
void
WebSocketChannelParent::OfflineDisconnect()
{
if (mChannel) {
mChannel->Close(nsIWebSocketChannel::CLOSE_GOING_AWAY,
nsCString("App is offline"));
}
}
uint32_t
WebSocketChannelParent::GetAppId()
{
uint32_t appId = NECKO_UNKNOWN_APP_ID;
if (mLoadContext) {
mLoadContext->GetAppId(&appId);
}
return appId;
}
} // namespace net
} // namespace mozilla