diff options
Diffstat (limited to '')
-rw-r--r-- | netwerk/protocol/gio/GIOChannelParent.cpp | 324 |
1 files changed, 324 insertions, 0 deletions
diff --git a/netwerk/protocol/gio/GIOChannelParent.cpp b/netwerk/protocol/gio/GIOChannelParent.cpp new file mode 100644 index 0000000000..a19829a81d --- /dev/null +++ b/netwerk/protocol/gio/GIOChannelParent.cpp @@ -0,0 +1,324 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=4 sw=2 sts=2 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 "GIOChannelParent.h" +#include "nsGIOProtocolHandler.h" +#include "mozilla/Assertions.h" +#include "mozilla/dom/ContentParent.h" +#include "mozilla/dom/BrowserParent.h" +#include "mozilla/net/NeckoParent.h" +#include "nsNetUtil.h" +#include "nsIChannel.h" +#include "mozilla/net/NeckoChannelParams.h" +#include "nsIAuthPrompt.h" +#include "nsIAuthPromptProvider.h" +#include "nsISecureBrowserUI.h" +#include "nsQueryObject.h" +#include "mozilla/Logging.h" +#include "mozilla/net/ChannelEventQueue.h" +#include "mozilla/ipc/URIUtils.h" + +using namespace mozilla::dom; +using namespace mozilla::ipc; + +namespace mozilla { +#undef LOG +#define LOG(args) MOZ_LOG(gGIOLog, mozilla::LogLevel::Debug, args) +namespace net { + +GIOChannelParent::GIOChannelParent(dom::BrowserParent* aIframeEmbedding, + nsILoadContext* aLoadContext, + PBOverrideStatus aOverrideStatus) + : mLoadContext(aLoadContext), + mPBOverride(aOverrideStatus), + mBrowserParent(aIframeEmbedding) { + mEventQ = new ChannelEventQueue(static_cast<nsIParentChannel*>(this)); +} + +void GIOChannelParent::ActorDestroy(ActorDestroyReason why) { + // We may still have refcount>0 if the channel hasn't called OnStopRequest + // yet, but we must not send any more msgs to child. + mIPCClosed = true; +} + +//----------------------------------------------------------------------------- +// GIOChannelParent::nsISupports +//----------------------------------------------------------------------------- +NS_IMPL_ISUPPORTS(GIOChannelParent, nsIStreamListener, nsIParentChannel, + nsIInterfaceRequestor, nsIRequestObserver) + +//----------------------------------------------------------------------------- +// GIOChannelParent methods +//----------------------------------------------------------------------------- + +bool GIOChannelParent::Init(const GIOChannelCreationArgs& aOpenArgs) { + switch (aOpenArgs.type()) { + case GIOChannelCreationArgs::TGIOChannelOpenArgs: { + const GIOChannelOpenArgs& a = aOpenArgs.get_GIOChannelOpenArgs(); + return DoAsyncOpen(a.uri(), a.startPos(), a.entityID(), a.uploadStream(), + a.loadInfo(), a.loadFlags()); + } + case GIOChannelCreationArgs::TGIOChannelConnectArgs: { + const GIOChannelConnectArgs& cArgs = + aOpenArgs.get_GIOChannelConnectArgs(); + return ConnectChannel(cArgs.channelId()); + } + default: + MOZ_ASSERT_UNREACHABLE("unknown open type"); + return false; + } +} + +bool GIOChannelParent::DoAsyncOpen(const URIParams& aURI, + const uint64_t& aStartPos, + const nsCString& aEntityID, + const Maybe<IPCStream>& aUploadStream, + const LoadInfoArgs& aLoadInfoArgs, + const uint32_t& aLoadFlags) { + nsresult rv; + + nsCOMPtr<nsIURI> uri = DeserializeURI(aURI); + if (!uri) { + return false; + } + +#ifdef DEBUG + LOG(("GIOChannelParent DoAsyncOpen [this=%p uri=%s]\n", this, + uri->GetSpecOrDefault().get())); +#endif + + nsCOMPtr<nsIIOService> ios(do_GetIOService(&rv)); + if (NS_FAILED(rv)) { + return SendFailedAsyncOpen(rv); + } + + nsAutoCString remoteType; + rv = GetRemoteType(remoteType); + if (NS_FAILED(rv)) { + return SendFailedAsyncOpen(rv); + } + + nsCOMPtr<nsILoadInfo> loadInfo; + rv = mozilla::ipc::LoadInfoArgsToLoadInfo(aLoadInfoArgs, remoteType, + getter_AddRefs(loadInfo)); + if (NS_FAILED(rv)) { + return SendFailedAsyncOpen(rv); + } + + OriginAttributes attrs; + rv = loadInfo->GetOriginAttributes(&attrs); + if (NS_FAILED(rv)) { + return SendFailedAsyncOpen(rv); + } + + nsCOMPtr<nsIChannel> chan; + rv = NS_NewChannelInternal(getter_AddRefs(chan), uri, loadInfo, nullptr, + nullptr, nullptr, aLoadFlags, ios); + + if (NS_FAILED(rv)) { + return SendFailedAsyncOpen(rv); + } + + mChannel = chan; + + nsIChannel* gioChan = static_cast<nsIChannel*>(mChannel.get()); + + rv = gioChan->AsyncOpen(this); + if (NS_FAILED(rv)) { + return SendFailedAsyncOpen(rv); + } + + return true; +} + +bool GIOChannelParent::ConnectChannel(const uint64_t& channelId) { + nsresult rv; + + LOG(("Looking for a registered channel [this=%p, id=%" PRIx64 "]", this, + channelId)); + + nsCOMPtr<nsIChannel> channel; + rv = NS_LinkRedirectChannels(channelId, this, getter_AddRefs(channel)); + if (NS_SUCCEEDED(rv)) { + mChannel = channel; + } + + LOG((" found channel %p, rv=%08" PRIx32, mChannel.get(), + static_cast<uint32_t>(rv))); + + return true; +} + +mozilla::ipc::IPCResult GIOChannelParent::RecvCancel(const nsresult& status) { + if (mChannel) { + mChannel->Cancel(status); + } + + return IPC_OK(); +} + +mozilla::ipc::IPCResult GIOChannelParent::RecvSuspend() { + if (mChannel) { + mChannel->Suspend(); + } + return IPC_OK(); +} + +mozilla::ipc::IPCResult GIOChannelParent::RecvResume() { + if (mChannel) { + mChannel->Resume(); + } + return IPC_OK(); +} + +//----------------------------------------------------------------------------- +// GIOChannelParent::nsIRequestObserver +//----------------------------------------------------------------------------- + +NS_IMETHODIMP +GIOChannelParent::OnStartRequest(nsIRequest* aRequest) { + LOG(("GIOChannelParent::OnStartRequest [this=%p]\n", this)); + nsCOMPtr<nsIChannel> chan = do_QueryInterface(aRequest); + MOZ_ASSERT(chan); + NS_ENSURE_TRUE(chan, NS_ERROR_UNEXPECTED); + + int64_t contentLength; + chan->GetContentLength(&contentLength); + nsCString contentType; + chan->GetContentType(contentType); + nsresult channelStatus = NS_OK; + chan->GetStatus(&channelStatus); + + nsCString entityID; + URIParams uriparam; + nsCOMPtr<nsIURI> uri; + chan->GetURI(getter_AddRefs(uri)); + SerializeURI(uri, uriparam); + + if (mIPCClosed || !SendOnStartRequest(channelStatus, contentLength, + contentType, entityID, uriparam)) { + return NS_ERROR_UNEXPECTED; + } + + return NS_OK; +} + +NS_IMETHODIMP +GIOChannelParent::OnStopRequest(nsIRequest* aRequest, nsresult aStatusCode) { + LOG(("GIOChannelParent::OnStopRequest: [this=%p status=%" PRIu32 "]\n", this, + static_cast<uint32_t>(aStatusCode))); + + if (mIPCClosed || !SendOnStopRequest(aStatusCode)) { + return NS_ERROR_UNEXPECTED; + } + + return NS_OK; +} + +//----------------------------------------------------------------------------- +// GIOChannelParent::nsIStreamListener +//----------------------------------------------------------------------------- + +NS_IMETHODIMP +GIOChannelParent::OnDataAvailable(nsIRequest* aRequest, + nsIInputStream* aInputStream, + uint64_t aOffset, uint32_t aCount) { + LOG(("GIOChannelParent::OnDataAvailable [this=%p]\n", this)); + + nsCString data; + nsresult rv = NS_ReadInputStreamToString(aInputStream, data, aCount); + if (NS_FAILED(rv)) { + return rv; + } + + nsresult channelStatus = NS_OK; + mChannel->GetStatus(&channelStatus); + + if (mIPCClosed || + !SendOnDataAvailable(channelStatus, data, aOffset, aCount)) { + return NS_ERROR_UNEXPECTED; + } + return NS_OK; +} + +//----------------------------------------------------------------------------- +// GIOChannelParent::nsIParentChannel +//----------------------------------------------------------------------------- + +NS_IMETHODIMP +GIOChannelParent::SetParentListener(ParentChannelListener* aListener) { + // Do not need ptr to ParentChannelListener. + return NS_OK; +} + +NS_IMETHODIMP +GIOChannelParent::NotifyClassificationFlags(uint32_t aClassificationFlags, + bool aIsThirdParty) { + // Nothing to do. + return NS_OK; +} + +NS_IMETHODIMP +GIOChannelParent::SetClassifierMatchedInfo(const nsACString& aList, + const nsACString& aProvider, + const nsACString& aFullHash) { + // nothing to do + return NS_OK; +} + +NS_IMETHODIMP +GIOChannelParent::SetClassifierMatchedTrackingInfo( + const nsACString& aLists, const nsACString& aFullHashes) { + // nothing to do + return NS_OK; +} + +NS_IMETHODIMP +GIOChannelParent::Delete() { + if (mIPCClosed || !SendDeleteSelf()) { + return NS_ERROR_UNEXPECTED; + } + + return NS_OK; +} + +NS_IMETHODIMP +GIOChannelParent::GetRemoteType(nsACString& aRemoteType) { + if (!CanSend()) { + return NS_ERROR_UNEXPECTED; + } + + dom::PContentParent* pcp = Manager()->Manager(); + aRemoteType = static_cast<dom::ContentParent*>(pcp)->GetRemoteType(); + return NS_OK; +} + +//----------------------------------------------------------------------------- +// GIOChannelParent::nsIInterfaceRequestor +//----------------------------------------------------------------------------- + +NS_IMETHODIMP +GIOChannelParent::GetInterface(const nsIID& uuid, void** result) { + if (uuid.Equals(NS_GET_IID(nsIAuthPromptProvider)) || + uuid.Equals(NS_GET_IID(nsISecureBrowserUI))) { + if (mBrowserParent) { + return mBrowserParent->QueryInterface(uuid, result); + } + } + + // Only support nsILoadContext if child channel's callbacks did too + if (uuid.Equals(NS_GET_IID(nsILoadContext)) && mLoadContext) { + nsCOMPtr<nsILoadContext> copy = mLoadContext; + copy.forget(result); + return NS_OK; + } + + return QueryInterface(uuid, result); +} + +//--------------------- +} // namespace net +} // namespace mozilla |