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 "nsWyciwyg.h" michael@0: michael@0: #include "mozilla/net/WyciwygChannelParent.h" michael@0: #include "nsWyciwygChannel.h" michael@0: #include "nsNetUtil.h" michael@0: #include "nsCharsetSource.h" michael@0: #include "nsISerializable.h" michael@0: #include "nsSerializationHelper.h" michael@0: #include "mozilla/ipc/URIUtils.h" michael@0: #include "mozilla/net/NeckoParent.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: WyciwygChannelParent::WyciwygChannelParent() michael@0: : mIPCClosed(false) michael@0: , mReceivedAppData(false) michael@0: { michael@0: #if defined(PR_LOGGING) michael@0: if (!gWyciwygLog) michael@0: gWyciwygLog = PR_NewLogModule("nsWyciwygChannel"); michael@0: #endif michael@0: } michael@0: michael@0: WyciwygChannelParent::~WyciwygChannelParent() michael@0: { michael@0: } michael@0: michael@0: void michael@0: WyciwygChannelParent::ActorDestroy(ActorDestroyReason why) michael@0: { michael@0: // We may still have refcount>0 if the channel hasn't called OnStopRequest michael@0: // yet, but we must not send any more msgs to child. michael@0: mIPCClosed = true; michael@0: michael@0: // We need to force the cycle to break here michael@0: mChannel->SetNotificationCallbacks(nullptr); michael@0: } michael@0: michael@0: //----------------------------------------------------------------------------- michael@0: // WyciwygChannelParent::nsISupports michael@0: //----------------------------------------------------------------------------- michael@0: michael@0: NS_IMPL_ISUPPORTS(WyciwygChannelParent, michael@0: nsIStreamListener, michael@0: nsIInterfaceRequestor, michael@0: nsIRequestObserver) michael@0: michael@0: //----------------------------------------------------------------------------- michael@0: // WyciwygChannelParent::PWyciwygChannelParent michael@0: //----------------------------------------------------------------------------- michael@0: michael@0: bool michael@0: WyciwygChannelParent::RecvInit(const URIParams& aURI) michael@0: { michael@0: nsresult rv; michael@0: michael@0: nsCOMPtr uri = DeserializeURI(aURI); michael@0: if (!uri) michael@0: return false; michael@0: michael@0: nsCString uriSpec; michael@0: uri->GetSpec(uriSpec); michael@0: LOG(("WyciwygChannelParent RecvInit [this=%p uri=%s]\n", michael@0: this, uriSpec.get())); michael@0: michael@0: nsCOMPtr ios(do_GetIOService(&rv)); michael@0: if (NS_FAILED(rv)) michael@0: return SendCancelEarly(rv); michael@0: michael@0: nsCOMPtr chan; michael@0: rv = NS_NewChannel(getter_AddRefs(chan), uri, ios); michael@0: if (NS_FAILED(rv)) michael@0: return SendCancelEarly(rv); michael@0: michael@0: mChannel = do_QueryInterface(chan, &rv); michael@0: if (NS_FAILED(rv)) michael@0: return SendCancelEarly(rv); michael@0: michael@0: return true; michael@0: } michael@0: michael@0: bool michael@0: WyciwygChannelParent::RecvAppData(const IPC::SerializedLoadContext& loadContext, michael@0: PBrowserParent* parent) michael@0: { michael@0: LOG(("WyciwygChannelParent RecvAppData [this=%p]\n", this)); michael@0: michael@0: if (!SetupAppData(loadContext, parent)) michael@0: return false; michael@0: michael@0: mChannel->SetNotificationCallbacks(this); michael@0: return true; michael@0: } michael@0: michael@0: bool michael@0: WyciwygChannelParent::SetupAppData(const IPC::SerializedLoadContext& loadContext, michael@0: PBrowserParent* aParent) michael@0: { michael@0: if (!mChannel) michael@0: return true; michael@0: michael@0: const char* error = NeckoParent::CreateChannelLoadContext(aParent, michael@0: Manager()->Manager(), michael@0: loadContext, michael@0: mLoadContext); michael@0: if (error) { michael@0: printf_stderr("WyciwygChannelParent::SetupAppData: FATAL ERROR: %s\n", michael@0: error); michael@0: return false; michael@0: } michael@0: michael@0: if (!mLoadContext && loadContext.IsPrivateBitValid()) { michael@0: nsCOMPtr pbChannel = do_QueryInterface(mChannel); michael@0: if (pbChannel) michael@0: pbChannel->SetPrivate(loadContext.mUsePrivateBrowsing); michael@0: } michael@0: michael@0: mReceivedAppData = true; michael@0: return true; michael@0: } michael@0: michael@0: bool michael@0: WyciwygChannelParent::RecvAsyncOpen(const URIParams& aOriginal, michael@0: const uint32_t& aLoadFlags, michael@0: const IPC::SerializedLoadContext& loadContext, michael@0: PBrowserParent* aParent) michael@0: { michael@0: nsCOMPtr original = DeserializeURI(aOriginal); michael@0: if (!original) michael@0: return false; michael@0: michael@0: LOG(("WyciwygChannelParent RecvAsyncOpen [this=%p]\n", this)); michael@0: michael@0: if (!mChannel) michael@0: return true; michael@0: michael@0: nsresult rv; michael@0: michael@0: rv = mChannel->SetOriginalURI(original); michael@0: if (NS_FAILED(rv)) michael@0: return SendCancelEarly(rv); michael@0: michael@0: rv = mChannel->SetLoadFlags(aLoadFlags); michael@0: if (NS_FAILED(rv)) michael@0: return SendCancelEarly(rv); michael@0: michael@0: if (!mReceivedAppData && !SetupAppData(loadContext, aParent)) { michael@0: return false; michael@0: } michael@0: michael@0: rv = mChannel->SetNotificationCallbacks(this); michael@0: if (NS_FAILED(rv)) michael@0: return SendCancelEarly(rv); michael@0: michael@0: rv = mChannel->AsyncOpen(this, nullptr); michael@0: if (NS_FAILED(rv)) michael@0: return SendCancelEarly(rv); michael@0: michael@0: return true; michael@0: } michael@0: michael@0: bool michael@0: WyciwygChannelParent::RecvWriteToCacheEntry(const nsString& data) michael@0: { michael@0: if (!mReceivedAppData) { michael@0: printf_stderr("WyciwygChannelParent::RecvWriteToCacheEntry: FATAL ERROR: didn't receive app data\n"); michael@0: return false; michael@0: } michael@0: michael@0: if (mChannel) michael@0: mChannel->WriteToCacheEntry(data); michael@0: michael@0: return true; michael@0: } michael@0: michael@0: bool michael@0: WyciwygChannelParent::RecvCloseCacheEntry(const nsresult& reason) michael@0: { michael@0: if (mChannel) { michael@0: mChannel->CloseCacheEntry(reason); michael@0: } michael@0: michael@0: return true; michael@0: } michael@0: michael@0: bool michael@0: WyciwygChannelParent::RecvSetCharsetAndSource(const int32_t& aCharsetSource, michael@0: const nsCString& aCharset) michael@0: { michael@0: if (mChannel) michael@0: mChannel->SetCharsetAndSource(aCharsetSource, aCharset); michael@0: michael@0: return true; michael@0: } michael@0: michael@0: bool michael@0: WyciwygChannelParent::RecvSetSecurityInfo(const nsCString& aSecurityInfo) michael@0: { michael@0: if (mChannel) { michael@0: nsCOMPtr securityInfo; michael@0: NS_DeserializeObject(aSecurityInfo, getter_AddRefs(securityInfo)); michael@0: mChannel->SetSecurityInfo(securityInfo); michael@0: } michael@0: michael@0: return true; michael@0: } michael@0: michael@0: bool michael@0: WyciwygChannelParent::RecvCancel(const nsresult& aStatusCode) michael@0: { michael@0: if (mChannel) michael@0: mChannel->Cancel(aStatusCode); michael@0: return true; michael@0: } michael@0: michael@0: //----------------------------------------------------------------------------- michael@0: // WyciwygChannelParent::nsIRequestObserver michael@0: //----------------------------------------------------------------------------- michael@0: michael@0: NS_IMETHODIMP michael@0: WyciwygChannelParent::OnStartRequest(nsIRequest *aRequest, nsISupports *aContext) michael@0: { michael@0: LOG(("WyciwygChannelParent::OnStartRequest [this=%p]\n", this)); michael@0: michael@0: nsresult rv; michael@0: michael@0: nsCOMPtr chan = do_QueryInterface(aRequest, &rv); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: nsresult status; michael@0: chan->GetStatus(&status); michael@0: michael@0: int64_t contentLength = -1; michael@0: chan->GetContentLength(&contentLength); michael@0: michael@0: int32_t charsetSource = kCharsetUninitialized; michael@0: nsAutoCString charset; michael@0: chan->GetCharsetAndSource(&charsetSource, charset); michael@0: michael@0: nsCOMPtr securityInfo; michael@0: chan->GetSecurityInfo(getter_AddRefs(securityInfo)); michael@0: nsCString secInfoStr; michael@0: if (securityInfo) { michael@0: nsCOMPtr serializable = do_QueryInterface(securityInfo); michael@0: if (serializable) michael@0: NS_SerializeToString(serializable, secInfoStr); michael@0: else { michael@0: NS_ERROR("Can't serialize security info"); michael@0: return NS_ERROR_UNEXPECTED; michael@0: } michael@0: } michael@0: michael@0: if (mIPCClosed || michael@0: !SendOnStartRequest(status, contentLength, charsetSource, charset, secInfoStr)) { michael@0: return NS_ERROR_UNEXPECTED; michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: WyciwygChannelParent::OnStopRequest(nsIRequest *aRequest, michael@0: nsISupports *aContext, michael@0: nsresult aStatusCode) michael@0: { michael@0: LOG(("WyciwygChannelParent::OnStopRequest: [this=%p status=%ul]\n", michael@0: this, aStatusCode)); michael@0: michael@0: if (mIPCClosed || !SendOnStopRequest(aStatusCode)) { michael@0: return NS_ERROR_UNEXPECTED; michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: //----------------------------------------------------------------------------- michael@0: // WyciwygChannelParent::nsIStreamListener michael@0: //----------------------------------------------------------------------------- michael@0: michael@0: NS_IMETHODIMP michael@0: WyciwygChannelParent::OnDataAvailable(nsIRequest *aRequest, michael@0: nsISupports *aContext, michael@0: nsIInputStream *aInputStream, michael@0: uint64_t aOffset, michael@0: uint32_t aCount) michael@0: { michael@0: LOG(("WyciwygChannelParent::OnDataAvailable [this=%p]\n", this)); michael@0: michael@0: nsCString data; michael@0: nsresult rv = NS_ReadInputStreamToString(aInputStream, data, aCount); michael@0: if (NS_FAILED(rv)) michael@0: return rv; michael@0: michael@0: if (mIPCClosed || !SendOnDataAvailable(data, aOffset)) { michael@0: return NS_ERROR_UNEXPECTED; michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: //----------------------------------------------------------------------------- michael@0: // WyciwygChannelParent::nsIInterfaceRequestor michael@0: //----------------------------------------------------------------------------- michael@0: michael@0: NS_IMETHODIMP michael@0: WyciwygChannelParent::GetInterface(const nsIID& uuid, void** result) michael@0: { michael@0: // Only support nsILoadContext if child channel's callbacks did too michael@0: if (uuid.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(uuid, result); michael@0: } michael@0: michael@0: michael@0: }} // mozilla::net