summaryrefslogtreecommitdiffstats
path: root/netwerk/protocol/wyciwyg
diff options
context:
space:
mode:
Diffstat (limited to 'netwerk/protocol/wyciwyg')
-rw-r--r--netwerk/protocol/wyciwyg/PWyciwygChannel.ipdl62
-rw-r--r--netwerk/protocol/wyciwyg/WyciwygChannelChild.cpp764
-rw-r--r--netwerk/protocol/wyciwyg/WyciwygChannelChild.h124
-rw-r--r--netwerk/protocol/wyciwyg/WyciwygChannelParent.cpp373
-rw-r--r--netwerk/protocol/wyciwyg/WyciwygChannelParent.h71
-rw-r--r--netwerk/protocol/wyciwyg/moz.build36
-rw-r--r--netwerk/protocol/wyciwyg/nsIWyciwygChannel.idl45
-rw-r--r--netwerk/protocol/wyciwyg/nsWyciwyg.cpp10
-rw-r--r--netwerk/protocol/wyciwyg/nsWyciwyg.h43
-rw-r--r--netwerk/protocol/wyciwyg/nsWyciwygChannel.cpp808
-rw-r--r--netwerk/protocol/wyciwyg/nsWyciwygChannel.h115
-rw-r--r--netwerk/protocol/wyciwyg/nsWyciwygProtocolHandler.cpp158
-rw-r--r--netwerk/protocol/wyciwyg/nsWyciwygProtocolHandler.h23
13 files changed, 2632 insertions, 0 deletions
diff --git a/netwerk/protocol/wyciwyg/PWyciwygChannel.ipdl b/netwerk/protocol/wyciwyg/PWyciwygChannel.ipdl
new file mode 100644
index 000000000..16f5848fb
--- /dev/null
+++ b/netwerk/protocol/wyciwyg/PWyciwygChannel.ipdl
@@ -0,0 +1,62 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set sw=2 ts=8 et tw=80 ft=cpp : */
+/* 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 protocol PNecko;
+include protocol PBrowser;
+include URIParams;
+include PBackgroundSharedTypes;
+include PBrowserOrId;
+
+using class IPC::SerializedLoadContext from "SerializedLoadContext.h";
+
+namespace mozilla {
+namespace net {
+
+//-------------------------------------------------------------------
+protocol PWyciwygChannel
+{
+ manager PNecko;
+
+parent:
+ async __delete__();
+
+ async Init(URIParams uri,
+ PrincipalInfo requestingPrincipalInfo,
+ PrincipalInfo triggeringPrincipalInfo,
+ PrincipalInfo principalToInheritInfo,
+ uint32_t securityFlags,
+ uint32_t contentPolicyType);
+ async AsyncOpen(URIParams originalURI,
+ uint32_t loadFlags,
+ SerializedLoadContext loadContext,
+ PBrowserOrId browser);
+ async AppData(SerializedLoadContext loadContext, PBrowserOrId browser);
+
+ // methods corresponding to those of nsIWyciwygChannel
+ async WriteToCacheEntry(nsString data);
+ async CloseCacheEntry(nsresult reason);
+ async SetCharsetAndSource(int32_t source, nsCString charset);
+ async SetSecurityInfo(nsCString securityInfo);
+ async Cancel(nsresult status);
+
+child:
+ async OnStartRequest(nsresult statusCode,
+ int64_t contentLength,
+ int32_t source,
+ nsCString charset,
+ nsCString securityInfo);
+
+ async OnDataAvailable(nsCString data,
+ uint64_t offset);
+
+ async OnStopRequest(nsresult statusCode);
+
+ async CancelEarly(nsresult statusCode);
+};
+
+
+} // namespace net
+} // namespace mozilla
diff --git a/netwerk/protocol/wyciwyg/WyciwygChannelChild.cpp b/netwerk/protocol/wyciwyg/WyciwygChannelChild.cpp
new file mode 100644
index 000000000..2a794df3b
--- /dev/null
+++ b/netwerk/protocol/wyciwyg/WyciwygChannelChild.cpp
@@ -0,0 +1,764 @@
+/* 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 "nsWyciwyg.h"
+
+#include "base/compiler_specific.h"
+
+#include "mozilla/net/ChannelEventQueue.h"
+#include "WyciwygChannelChild.h"
+#include "mozilla/dom/TabChild.h"
+#include "mozilla/dom/ContentChild.h"
+
+#include "nsCharsetSource.h"
+#include "nsContentUtils.h"
+#include "nsStringStream.h"
+#include "nsNetUtil.h"
+#include "nsISerializable.h"
+#include "nsSerializationHelper.h"
+#include "nsIProgressEventSink.h"
+#include "mozilla/ipc/URIUtils.h"
+#include "SerializedLoadContext.h"
+#include "mozilla/ipc/BackgroundUtils.h"
+#include "nsProxyRelease.h"
+#include "nsContentSecurityManager.h"
+
+using namespace mozilla::ipc;
+using namespace mozilla::dom;
+
+namespace mozilla {
+namespace net {
+
+NS_IMPL_ISUPPORTS(WyciwygChannelChild,
+ nsIRequest,
+ nsIChannel,
+ nsIWyciwygChannel,
+ nsIPrivateBrowsingChannel)
+
+
+WyciwygChannelChild::WyciwygChannelChild()
+ : mStatus(NS_OK)
+ , mIsPending(false)
+ , mCanceled(false)
+ , mLoadFlags(LOAD_NORMAL)
+ , mContentLength(-1)
+ , mCharsetSource(kCharsetUninitialized)
+ , mState(WCC_NEW)
+ , mIPCOpen(false)
+ , mSentAppData(false)
+{
+ LOG(("Creating WyciwygChannelChild @%x\n", this));
+ mEventQ = new ChannelEventQueue(NS_ISUPPORTS_CAST(nsIWyciwygChannel*, this));
+}
+
+WyciwygChannelChild::~WyciwygChannelChild()
+{
+ LOG(("Destroying WyciwygChannelChild @%x\n", this));
+ if (mLoadInfo) {
+ NS_ReleaseOnMainThread(mLoadInfo.forget());
+ }
+}
+
+void
+WyciwygChannelChild::AddIPDLReference()
+{
+ MOZ_ASSERT(!mIPCOpen, "Attempt to retain more than one IPDL reference");
+ mIPCOpen = true;
+ AddRef();
+}
+
+void
+WyciwygChannelChild::ReleaseIPDLReference()
+{
+ MOZ_ASSERT(mIPCOpen, "Attempt to release nonexistent IPDL reference");
+ mIPCOpen = false;
+ Release();
+}
+
+nsresult
+WyciwygChannelChild::Init(nsIURI* uri)
+{
+ NS_ENSURE_ARG_POINTER(uri);
+
+ mState = WCC_INIT;
+
+ mURI = uri;
+ mOriginalURI = uri;
+
+ URIParams serializedUri;
+ SerializeURI(uri, serializedUri);
+
+ // propagate loadInfo
+ mozilla::ipc::PrincipalInfo requestingPrincipalInfo;
+ mozilla::ipc::PrincipalInfo triggeringPrincipalInfo;
+ mozilla::ipc::PrincipalInfo principalToInheritInfo;
+ uint32_t securityFlags;
+ uint32_t policyType;
+ if (mLoadInfo) {
+ mozilla::ipc::PrincipalToPrincipalInfo(mLoadInfo->LoadingPrincipal(),
+ &requestingPrincipalInfo);
+ mozilla::ipc::PrincipalToPrincipalInfo(mLoadInfo->TriggeringPrincipal(),
+ &triggeringPrincipalInfo);
+ mozilla::ipc::PrincipalToPrincipalInfo(mLoadInfo->PrincipalToInherit(),
+ &principalToInheritInfo);
+ securityFlags = mLoadInfo->GetSecurityFlags();
+ policyType = mLoadInfo->InternalContentPolicyType();
+ }
+ else {
+ // use default values if no loadInfo is provided
+ mozilla::ipc::PrincipalToPrincipalInfo(nsContentUtils::GetSystemPrincipal(),
+ &requestingPrincipalInfo);
+ mozilla::ipc::PrincipalToPrincipalInfo(nsContentUtils::GetSystemPrincipal(),
+ &triggeringPrincipalInfo);
+ mozilla::ipc::PrincipalToPrincipalInfo(nsContentUtils::GetSystemPrincipal(),
+ &principalToInheritInfo);
+ securityFlags = nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL;
+ policyType = nsIContentPolicy::TYPE_OTHER;
+ }
+
+ SendInit(serializedUri,
+ requestingPrincipalInfo,
+ triggeringPrincipalInfo,
+ principalToInheritInfo,
+ securityFlags,
+ policyType);
+ return NS_OK;
+}
+
+//-----------------------------------------------------------------------------
+// WyciwygChannelChild::PWyciwygChannelChild
+//-----------------------------------------------------------------------------
+
+class WyciwygStartRequestEvent : public ChannelEvent
+{
+public:
+ WyciwygStartRequestEvent(WyciwygChannelChild* child,
+ const nsresult& statusCode,
+ const int64_t& contentLength,
+ const int32_t& source,
+ const nsCString& charset,
+ const nsCString& securityInfo)
+ : mChild(child), mStatusCode(statusCode), mContentLength(contentLength),
+ mSource(source), mCharset(charset), mSecurityInfo(securityInfo) {}
+ void Run() { mChild->OnStartRequest(mStatusCode, mContentLength, mSource,
+ mCharset, mSecurityInfo); }
+private:
+ WyciwygChannelChild* mChild;
+ nsresult mStatusCode;
+ int64_t mContentLength;
+ int32_t mSource;
+ nsCString mCharset;
+ nsCString mSecurityInfo;
+};
+
+bool
+WyciwygChannelChild::RecvOnStartRequest(const nsresult& statusCode,
+ const int64_t& contentLength,
+ const int32_t& source,
+ const nsCString& charset,
+ const nsCString& securityInfo)
+{
+ mEventQ->RunOrEnqueue(new WyciwygStartRequestEvent(this, statusCode,
+ contentLength, source,
+ charset, securityInfo));
+ return true;
+}
+
+void
+WyciwygChannelChild::OnStartRequest(const nsresult& statusCode,
+ const int64_t& contentLength,
+ const int32_t& source,
+ const nsCString& charset,
+ const nsCString& securityInfo)
+{
+ LOG(("WyciwygChannelChild::RecvOnStartRequest [this=%p]\n", this));
+
+ mState = WCC_ONSTART;
+
+ mStatus = statusCode;
+ mContentLength = contentLength;
+ mCharsetSource = source;
+ mCharset = charset;
+
+ if (!securityInfo.IsEmpty()) {
+ NS_DeserializeObject(securityInfo, getter_AddRefs(mSecurityInfo));
+ }
+
+ AutoEventEnqueuer ensureSerialDispatch(mEventQ);
+
+ nsresult rv = mListener->OnStartRequest(this, mListenerContext);
+ if (NS_FAILED(rv))
+ Cancel(rv);
+}
+
+class WyciwygDataAvailableEvent : public ChannelEvent
+{
+public:
+ WyciwygDataAvailableEvent(WyciwygChannelChild* child,
+ const nsCString& data,
+ const uint64_t& offset)
+ : mChild(child), mData(data), mOffset(offset) {}
+ void Run() { mChild->OnDataAvailable(mData, mOffset); }
+private:
+ WyciwygChannelChild* mChild;
+ nsCString mData;
+ uint64_t mOffset;
+};
+
+bool
+WyciwygChannelChild::RecvOnDataAvailable(const nsCString& data,
+ const uint64_t& offset)
+{
+ mEventQ->RunOrEnqueue(new WyciwygDataAvailableEvent(this, data, offset));
+ return true;
+}
+
+void
+WyciwygChannelChild::OnDataAvailable(const nsCString& data,
+ const uint64_t& offset)
+{
+ LOG(("WyciwygChannelChild::RecvOnDataAvailable [this=%p]\n", this));
+
+ if (mCanceled)
+ return;
+
+ mState = WCC_ONDATA;
+
+ // NOTE: the OnDataAvailable contract requires the client to read all the data
+ // in the inputstream. This code relies on that ('data' will go away after
+ // this function). Apparently the previous, non-e10s behavior was to actually
+ // support only reading part of the data, allowing later calls to read the
+ // rest.
+ nsCOMPtr<nsIInputStream> stringStream;
+ nsresult rv = NS_NewByteInputStream(getter_AddRefs(stringStream),
+ data.get(),
+ data.Length(),
+ NS_ASSIGNMENT_DEPEND);
+ if (NS_FAILED(rv)) {
+ Cancel(rv);
+ return;
+ }
+
+ AutoEventEnqueuer ensureSerialDispatch(mEventQ);
+
+ rv = mListener->OnDataAvailable(this, mListenerContext,
+ stringStream, offset, data.Length());
+ if (NS_FAILED(rv))
+ Cancel(rv);
+
+ if (mProgressSink && NS_SUCCEEDED(rv)) {
+ mProgressSink->OnProgress(this, nullptr, offset + data.Length(),
+ mContentLength);
+ }
+}
+
+class WyciwygStopRequestEvent : public ChannelEvent
+{
+public:
+ WyciwygStopRequestEvent(WyciwygChannelChild* child,
+ const nsresult& statusCode)
+ : mChild(child), mStatusCode(statusCode) {}
+ void Run() { mChild->OnStopRequest(mStatusCode); }
+private:
+ WyciwygChannelChild* mChild;
+ nsresult mStatusCode;
+};
+
+bool
+WyciwygChannelChild::RecvOnStopRequest(const nsresult& statusCode)
+{
+ mEventQ->RunOrEnqueue(new WyciwygStopRequestEvent(this, statusCode));
+ return true;
+}
+
+void
+WyciwygChannelChild::OnStopRequest(const nsresult& statusCode)
+{
+ LOG(("WyciwygChannelChild::RecvOnStopRequest [this=%p status=%u]\n",
+ this, statusCode));
+
+ { // We need to ensure that all IPDL message dispatching occurs
+ // before we delete the protocol below
+ AutoEventEnqueuer ensureSerialDispatch(mEventQ);
+
+ mState = WCC_ONSTOP;
+
+ mIsPending = false;
+
+ if (!mCanceled)
+ mStatus = statusCode;
+
+ mListener->OnStopRequest(this, mListenerContext, statusCode);
+
+ mListener = nullptr;
+ mListenerContext = nullptr;
+
+ if (mLoadGroup)
+ mLoadGroup->RemoveRequest(this, nullptr, mStatus);
+
+ mCallbacks = nullptr;
+ mProgressSink = nullptr;
+ }
+
+ if (mIPCOpen)
+ PWyciwygChannelChild::Send__delete__(this);
+}
+
+class WyciwygCancelEvent : public ChannelEvent
+{
+ public:
+ WyciwygCancelEvent(WyciwygChannelChild* child, const nsresult& status)
+ : mChild(child)
+ , mStatus(status) {}
+
+ void Run() { mChild->CancelEarly(mStatus); }
+ private:
+ WyciwygChannelChild* mChild;
+ nsresult mStatus;
+};
+
+bool
+WyciwygChannelChild::RecvCancelEarly(const nsresult& statusCode)
+{
+ mEventQ->RunOrEnqueue(new WyciwygCancelEvent(this, statusCode));
+ return true;
+}
+
+void WyciwygChannelChild::CancelEarly(const nsresult& statusCode)
+{
+ LOG(("WyciwygChannelChild::CancelEarly [this=%p]\n", this));
+
+ if (mCanceled)
+ return;
+
+ mCanceled = true;
+ mStatus = statusCode;
+
+ mIsPending = false;
+ if (mLoadGroup)
+ mLoadGroup->RemoveRequest(this, nullptr, mStatus);
+
+ if (mListener) {
+ mListener->OnStartRequest(this, mListenerContext);
+ mListener->OnStopRequest(this, mListenerContext, mStatus);
+ }
+ mListener = nullptr;
+ mListenerContext = nullptr;
+
+ if (mIPCOpen)
+ PWyciwygChannelChild::Send__delete__(this);
+}
+
+//-----------------------------------------------------------------------------
+// nsIRequest
+//-----------------------------------------------------------------------------
+
+NS_IMETHODIMP
+WyciwygChannelChild::GetName(nsACString & aName)
+{
+ return mURI->GetSpec(aName);
+}
+
+NS_IMETHODIMP
+WyciwygChannelChild::IsPending(bool *aIsPending)
+{
+ *aIsPending = mIsPending;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+WyciwygChannelChild::GetStatus(nsresult *aStatus)
+{
+ *aStatus = mStatus;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+WyciwygChannelChild::Cancel(nsresult aStatus)
+{
+ if (mCanceled)
+ return NS_OK;
+
+ mCanceled = true;
+ mStatus = aStatus;
+ if (mIPCOpen)
+ SendCancel(aStatus);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+WyciwygChannelChild::Suspend()
+{
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+WyciwygChannelChild::Resume()
+{
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+WyciwygChannelChild::GetLoadGroup(nsILoadGroup * *aLoadGroup)
+{
+ *aLoadGroup = mLoadGroup;
+ NS_IF_ADDREF(*aLoadGroup);
+ return NS_OK;
+}
+NS_IMETHODIMP
+WyciwygChannelChild::SetLoadGroup(nsILoadGroup * aLoadGroup)
+{
+ if (!CanSetLoadGroup(aLoadGroup)) {
+ return NS_ERROR_FAILURE;
+ }
+
+ mLoadGroup = aLoadGroup;
+ NS_QueryNotificationCallbacks(mCallbacks,
+ mLoadGroup,
+ NS_GET_IID(nsIProgressEventSink),
+ getter_AddRefs(mProgressSink));
+
+ UpdatePrivateBrowsing();
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+WyciwygChannelChild::GetLoadFlags(nsLoadFlags *aLoadFlags)
+{
+ *aLoadFlags = mLoadFlags;
+ return NS_OK;
+}
+NS_IMETHODIMP
+WyciwygChannelChild::SetLoadFlags(nsLoadFlags aLoadFlags)
+{
+ mLoadFlags = aLoadFlags;
+ return NS_OK;
+}
+
+
+//-----------------------------------------------------------------------------
+// nsIChannel
+//-----------------------------------------------------------------------------
+
+NS_IMETHODIMP
+WyciwygChannelChild::GetOriginalURI(nsIURI * *aOriginalURI)
+{
+ *aOriginalURI = mOriginalURI;
+ NS_ADDREF(*aOriginalURI);
+ return NS_OK;
+}
+NS_IMETHODIMP
+WyciwygChannelChild::SetOriginalURI(nsIURI * aOriginalURI)
+{
+ NS_ENSURE_TRUE(mState == WCC_INIT, NS_ERROR_UNEXPECTED);
+
+ NS_ENSURE_ARG_POINTER(aOriginalURI);
+ mOriginalURI = aOriginalURI;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+WyciwygChannelChild::GetURI(nsIURI * *aURI)
+{
+ *aURI = mURI;
+ NS_IF_ADDREF(*aURI);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+WyciwygChannelChild::GetOwner(nsISupports * *aOwner)
+{
+ NS_IF_ADDREF(*aOwner = mOwner);
+ return NS_OK;
+}
+NS_IMETHODIMP
+WyciwygChannelChild::SetOwner(nsISupports * aOwner)
+{
+ mOwner = aOwner;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+WyciwygChannelChild::GetLoadInfo(nsILoadInfo **aLoadInfo)
+{
+ NS_IF_ADDREF(*aLoadInfo = mLoadInfo);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+WyciwygChannelChild::SetLoadInfo(nsILoadInfo* aLoadInfo)
+{
+ mLoadInfo = aLoadInfo;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+WyciwygChannelChild::GetNotificationCallbacks(nsIInterfaceRequestor * *aCallbacks)
+{
+ *aCallbacks = mCallbacks;
+ NS_IF_ADDREF(*aCallbacks);
+ return NS_OK;
+}
+NS_IMETHODIMP
+WyciwygChannelChild::SetNotificationCallbacks(nsIInterfaceRequestor * aCallbacks)
+{
+ if (!CanSetCallbacks(aCallbacks)) {
+ return NS_ERROR_FAILURE;
+ }
+
+ mCallbacks = aCallbacks;
+ NS_QueryNotificationCallbacks(mCallbacks,
+ mLoadGroup,
+ NS_GET_IID(nsIProgressEventSink),
+ getter_AddRefs(mProgressSink));
+ UpdatePrivateBrowsing();
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+WyciwygChannelChild::GetSecurityInfo(nsISupports * *aSecurityInfo)
+{
+ NS_IF_ADDREF(*aSecurityInfo = mSecurityInfo);
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+WyciwygChannelChild::GetContentType(nsACString & aContentType)
+{
+ aContentType.AssignLiteral(WYCIWYG_TYPE);
+ return NS_OK;
+}
+NS_IMETHODIMP
+WyciwygChannelChild::SetContentType(const nsACString & aContentType)
+{
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+WyciwygChannelChild::GetContentCharset(nsACString & aContentCharset)
+{
+ aContentCharset.AssignLiteral("UTF-16");
+ return NS_OK;
+}
+NS_IMETHODIMP
+WyciwygChannelChild::SetContentCharset(const nsACString & aContentCharset)
+{
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+WyciwygChannelChild::GetContentDisposition(uint32_t *aContentDisposition)
+{
+ return NS_ERROR_NOT_AVAILABLE;
+}
+
+NS_IMETHODIMP
+WyciwygChannelChild::SetContentDisposition(uint32_t aContentDisposition)
+{
+ return NS_ERROR_NOT_AVAILABLE;
+}
+
+NS_IMETHODIMP
+WyciwygChannelChild::GetContentDispositionFilename(nsAString &aContentDispositionFilename)
+{
+ return NS_ERROR_NOT_AVAILABLE;
+}
+
+NS_IMETHODIMP
+WyciwygChannelChild::SetContentDispositionFilename(const nsAString &aContentDispositionFilename)
+{
+ return NS_ERROR_NOT_AVAILABLE;
+}
+
+NS_IMETHODIMP
+WyciwygChannelChild::GetContentDispositionHeader(nsACString &aContentDispositionHeader)
+{
+ return NS_ERROR_NOT_AVAILABLE;
+}
+
+NS_IMETHODIMP
+WyciwygChannelChild::GetContentLength(int64_t *aContentLength)
+{
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+NS_IMETHODIMP
+WyciwygChannelChild::SetContentLength(int64_t aContentLength)
+{
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+WyciwygChannelChild::Open(nsIInputStream **_retval)
+{
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+WyciwygChannelChild::Open2(nsIInputStream** aStream)
+{
+ nsCOMPtr<nsIStreamListener> listener;
+ nsresult rv = nsContentSecurityManager::doContentSecurityCheck(this, listener);
+ NS_ENSURE_SUCCESS(rv, rv);
+ return Open(aStream);
+}
+
+static mozilla::dom::TabChild*
+GetTabChild(nsIChannel* aChannel)
+{
+ nsCOMPtr<nsITabChild> iTabChild;
+ NS_QueryNotificationCallbacks(aChannel, iTabChild);
+ return iTabChild ? static_cast<mozilla::dom::TabChild*>(iTabChild.get()) : nullptr;
+}
+
+NS_IMETHODIMP
+WyciwygChannelChild::AsyncOpen(nsIStreamListener *aListener, nsISupports *aContext)
+{
+ MOZ_ASSERT(!mLoadInfo ||
+ mLoadInfo->GetSecurityMode() == 0 ||
+ mLoadInfo->GetInitialSecurityCheckDone() ||
+ (mLoadInfo->GetSecurityMode() == nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL &&
+ nsContentUtils::IsSystemPrincipal(mLoadInfo->LoadingPrincipal())),
+ "security flags in loadInfo but asyncOpen2() not called");
+
+ LOG(("WyciwygChannelChild::AsyncOpen [this=%p]\n", this));
+
+ // The only places creating wyciwyg: channels should be
+ // HTMLDocument::OpenCommon and session history. Both should be setting an
+ // owner or loadinfo.
+ NS_PRECONDITION(mOwner || mLoadInfo, "Must have a principal");
+ NS_ENSURE_STATE(mOwner || mLoadInfo);
+
+ NS_ENSURE_ARG_POINTER(aListener);
+ NS_ENSURE_TRUE(!mIsPending, NS_ERROR_IN_PROGRESS);
+
+ mListener = aListener;
+ mListenerContext = aContext;
+ mIsPending = true;
+
+ if (mLoadGroup) {
+ mLoadGroup->AddRequest(this, nullptr);
+ }
+
+ URIParams originalURI;
+ SerializeURI(mOriginalURI, originalURI);
+
+ mozilla::dom::TabChild* tabChild = GetTabChild(this);
+ if (MissingRequiredTabChild(tabChild, "wyciwyg")) {
+ return NS_ERROR_ILLEGAL_VALUE;
+ }
+
+ PBrowserOrId browser = static_cast<ContentChild*>(Manager()->Manager())
+ ->GetBrowserOrId(tabChild);
+
+ SendAsyncOpen(originalURI, mLoadFlags, IPC::SerializedLoadContext(this), browser);
+
+ mSentAppData = true;
+ mState = WCC_OPENED;
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+WyciwygChannelChild::AsyncOpen2(nsIStreamListener *aListener)
+{
+ nsCOMPtr<nsIStreamListener> listener = aListener;
+ nsresult rv = nsContentSecurityManager::doContentSecurityCheck(this, listener);
+ NS_ENSURE_SUCCESS(rv, rv);
+ return AsyncOpen(listener, nullptr);
+}
+
+//-----------------------------------------------------------------------------
+// nsIWyciwygChannel
+//-----------------------------------------------------------------------------
+
+NS_IMETHODIMP
+WyciwygChannelChild::WriteToCacheEntry(const nsAString & aData)
+{
+ NS_ENSURE_TRUE((mState == WCC_INIT) ||
+ (mState == WCC_ONWRITE), NS_ERROR_UNEXPECTED);
+
+ if (!mSentAppData) {
+ mozilla::dom::TabChild* tabChild = GetTabChild(this);
+
+ PBrowserOrId browser = static_cast<ContentChild*>(Manager()->Manager())
+ ->GetBrowserOrId(tabChild);
+
+ SendAppData(IPC::SerializedLoadContext(this), browser);
+ mSentAppData = true;
+ }
+
+ SendWriteToCacheEntry(PromiseFlatString(aData));
+ mState = WCC_ONWRITE;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+WyciwygChannelChild::CloseCacheEntry(nsresult reason)
+{
+ NS_ENSURE_TRUE(mState == WCC_ONWRITE, NS_ERROR_UNEXPECTED);
+
+ SendCloseCacheEntry(reason);
+ mState = WCC_ONCLOSED;
+
+ if (mIPCOpen)
+ PWyciwygChannelChild::Send__delete__(this);
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+WyciwygChannelChild::SetSecurityInfo(nsISupports *aSecurityInfo)
+{
+ mSecurityInfo = aSecurityInfo;
+
+ if (mSecurityInfo) {
+ nsCOMPtr<nsISerializable> serializable = do_QueryInterface(mSecurityInfo);
+ if (serializable) {
+ nsCString secInfoStr;
+ NS_SerializeToString(serializable, secInfoStr);
+ SendSetSecurityInfo(secInfoStr);
+ }
+ else {
+ NS_WARNING("Can't serialize security info");
+ }
+ }
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+WyciwygChannelChild::SetCharsetAndSource(int32_t aSource, const nsACString & aCharset)
+{
+ // mState == WCC_ONSTART when reading from the channel
+ // mState == WCC_INIT when writing to the cache
+ NS_ENSURE_TRUE((mState == WCC_ONSTART) ||
+ (mState == WCC_INIT), NS_ERROR_UNEXPECTED);
+
+ mCharsetSource = aSource;
+ mCharset = aCharset;
+
+ // TODO ensure that nsWyciwygChannel in the parent has still the cache entry
+ SendSetCharsetAndSource(mCharsetSource, mCharset);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+WyciwygChannelChild::GetCharsetAndSource(int32_t *aSource, nsACString & _retval)
+{
+ NS_ENSURE_TRUE((mState == WCC_ONSTART) ||
+ (mState == WCC_ONDATA) ||
+ (mState == WCC_ONSTOP), NS_ERROR_NOT_AVAILABLE);
+
+ if (mCharsetSource == kCharsetUninitialized)
+ return NS_ERROR_NOT_AVAILABLE;
+
+ *aSource = mCharsetSource;
+ _retval = mCharset;
+ return NS_OK;
+}
+
+//------------------------------------------------------------------------------
+} // namespace net
+} // namespace mozilla
diff --git a/netwerk/protocol/wyciwyg/WyciwygChannelChild.h b/netwerk/protocol/wyciwyg/WyciwygChannelChild.h
new file mode 100644
index 000000000..a712c4692
--- /dev/null
+++ b/netwerk/protocol/wyciwyg/WyciwygChannelChild.h
@@ -0,0 +1,124 @@
+/* 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/. */
+
+#ifndef mozilla_net_WyciwygChannelChild_h
+#define mozilla_net_WyciwygChannelChild_h
+
+#include "mozilla/net/PWyciwygChannelChild.h"
+#include "nsIWyciwygChannel.h"
+#include "nsIChannel.h"
+#include "nsILoadInfo.h"
+#include "PrivateBrowsingChannel.h"
+
+class nsIProgressEventSink;
+
+namespace mozilla {
+namespace net {
+
+class ChannelEventQueue;
+
+// TODO: replace with IPDL states
+enum WyciwygChannelChildState {
+ WCC_NEW,
+ WCC_INIT,
+
+ // States when reading from the channel
+ WCC_OPENED,
+ WCC_ONSTART,
+ WCC_ONDATA,
+ WCC_ONSTOP,
+
+ // States when writing to the cache
+ WCC_ONWRITE,
+ WCC_ONCLOSED
+};
+
+
+// Header file contents
+class WyciwygChannelChild final : public PWyciwygChannelChild
+ , public nsIWyciwygChannel
+ , public PrivateBrowsingChannel<WyciwygChannelChild>
+{
+public:
+ NS_DECL_ISUPPORTS
+ NS_DECL_NSIREQUEST
+ NS_DECL_NSICHANNEL
+ NS_DECL_NSIWYCIWYGCHANNEL
+
+ WyciwygChannelChild();
+
+ void AddIPDLReference();
+ void ReleaseIPDLReference();
+
+ nsresult Init(nsIURI *uri);
+
+ bool IsSuspended();
+
+protected:
+ virtual ~WyciwygChannelChild();
+
+ bool RecvOnStartRequest(const nsresult& statusCode,
+ const int64_t& contentLength,
+ const int32_t& source,
+ const nsCString& charset,
+ const nsCString& securityInfo) override;
+ bool RecvOnDataAvailable(const nsCString& data,
+ const uint64_t& offset) override;
+ bool RecvOnStopRequest(const nsresult& statusCode) override;
+ bool RecvCancelEarly(const nsresult& statusCode) override;
+
+ void OnStartRequest(const nsresult& statusCode,
+ const int64_t& contentLength,
+ const int32_t& source,
+ const nsCString& charset,
+ const nsCString& securityInfo);
+ void OnDataAvailable(const nsCString& data,
+ const uint64_t& offset);
+ void OnStopRequest(const nsresult& statusCode);
+ void CancelEarly(const nsresult& statusCode);
+
+ friend class PrivateBrowsingChannel<WyciwygChannelChild>;
+
+private:
+ nsresult mStatus;
+ bool mIsPending;
+ bool mCanceled;
+ uint32_t mLoadFlags;
+ int64_t mContentLength;
+ int32_t mCharsetSource;
+ nsCString mCharset;
+ nsCOMPtr<nsIURI> mURI;
+ nsCOMPtr<nsIURI> mOriginalURI;
+ nsCOMPtr<nsISupports> mOwner;
+ nsCOMPtr<nsILoadInfo> mLoadInfo;
+ nsCOMPtr<nsIInterfaceRequestor> mCallbacks;
+ nsCOMPtr<nsIProgressEventSink> mProgressSink;
+ nsCOMPtr<nsILoadGroup> mLoadGroup;
+ nsCOMPtr<nsIStreamListener> mListener;
+ nsCOMPtr<nsISupports> mListenerContext;
+ nsCOMPtr<nsISupports> mSecurityInfo;
+
+ // FIXME: replace with IPDL states (bug 536319)
+ enum WyciwygChannelChildState mState;
+
+ bool mIPCOpen;
+ bool mSentAppData;
+ RefPtr<ChannelEventQueue> mEventQ;
+
+ friend class WyciwygStartRequestEvent;
+ friend class WyciwygDataAvailableEvent;
+ friend class WyciwygStopRequestEvent;
+ friend class WyciwygCancelEvent;
+};
+
+inline bool
+WyciwygChannelChild::IsSuspended()
+{
+ return false;
+}
+
+} // namespace net
+} // namespace mozilla
+
+#endif // mozilla_net_WyciwygChannelChild_h
diff --git a/netwerk/protocol/wyciwyg/WyciwygChannelParent.cpp b/netwerk/protocol/wyciwyg/WyciwygChannelParent.cpp
new file mode 100644
index 000000000..be00c2d86
--- /dev/null
+++ b/netwerk/protocol/wyciwyg/WyciwygChannelParent.cpp
@@ -0,0 +1,373 @@
+/* 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 "nsWyciwyg.h"
+
+#include "mozilla/net/WyciwygChannelParent.h"
+#include "nsWyciwygChannel.h"
+#include "nsNetUtil.h"
+#include "nsCharsetSource.h"
+#include "nsISerializable.h"
+#include "nsSerializationHelper.h"
+#include "mozilla/ipc/URIUtils.h"
+#include "mozilla/net/NeckoParent.h"
+#include "SerializedLoadContext.h"
+#include "nsIContentPolicy.h"
+#include "mozilla/ipc/BackgroundUtils.h"
+
+using namespace mozilla::ipc;
+
+namespace mozilla {
+namespace net {
+
+WyciwygChannelParent::WyciwygChannelParent()
+ : mIPCClosed(false)
+ , mReceivedAppData(false)
+{
+}
+
+WyciwygChannelParent::~WyciwygChannelParent()
+{
+}
+
+void
+WyciwygChannelParent::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;
+
+ // We need to force the cycle to break here
+ if (mChannel) {
+ mChannel->SetNotificationCallbacks(nullptr);
+ }
+}
+
+//-----------------------------------------------------------------------------
+// WyciwygChannelParent::nsISupports
+//-----------------------------------------------------------------------------
+
+NS_IMPL_ISUPPORTS(WyciwygChannelParent,
+ nsIStreamListener,
+ nsIInterfaceRequestor,
+ nsIRequestObserver)
+
+//-----------------------------------------------------------------------------
+// WyciwygChannelParent::PWyciwygChannelParent
+//-----------------------------------------------------------------------------
+
+bool
+WyciwygChannelParent::RecvInit(const URIParams& aURI,
+ const ipc::PrincipalInfo& aRequestingPrincipalInfo,
+ const ipc::PrincipalInfo& aTriggeringPrincipalInfo,
+ const ipc::PrincipalInfo& aPrincipalToInheritInfo,
+ const uint32_t& aSecurityFlags,
+ const uint32_t& aContentPolicyType)
+{
+ nsresult rv;
+
+ nsCOMPtr<nsIURI> uri = DeserializeURI(aURI);
+ if (!uri)
+ return false;
+
+ LOG(("WyciwygChannelParent RecvInit [this=%p uri=%s]\n",
+ this, uri->GetSpecOrDefault().get()));
+
+ nsCOMPtr<nsIIOService> ios(do_GetIOService(&rv));
+ if (NS_FAILED(rv))
+ return SendCancelEarly(rv);
+
+ nsCOMPtr<nsIPrincipal> requestingPrincipal =
+ mozilla::ipc::PrincipalInfoToPrincipal(aRequestingPrincipalInfo, &rv);
+ if (NS_FAILED(rv)) {
+ return SendCancelEarly(rv);
+ }
+
+ nsCOMPtr<nsIPrincipal> triggeringPrincipal =
+ mozilla::ipc::PrincipalInfoToPrincipal(aTriggeringPrincipalInfo, &rv);
+ if (NS_FAILED(rv)) {
+ return SendCancelEarly(rv);
+ }
+
+ nsCOMPtr<nsIPrincipal> principalToInherit =
+ mozilla::ipc::PrincipalInfoToPrincipal(aPrincipalToInheritInfo, &rv);
+ if (NS_FAILED(rv)) {
+ return SendCancelEarly(rv);
+ }
+
+ nsCOMPtr<nsIChannel> chan;
+ rv = NS_NewChannelWithTriggeringPrincipal(getter_AddRefs(chan),
+ uri,
+ requestingPrincipal,
+ triggeringPrincipal,
+ aSecurityFlags,
+ aContentPolicyType,
+ nullptr, // loadGroup
+ nullptr, // aCallbacks
+ nsIRequest::LOAD_NORMAL,
+ ios);
+
+ if (NS_FAILED(rv))
+ return SendCancelEarly(rv);
+
+ nsCOMPtr<nsILoadInfo> loadInfo = chan->GetLoadInfo();
+ rv = loadInfo->SetPrincipalToInherit(principalToInherit);
+ if (NS_FAILED(rv)) {
+ return SendCancelEarly(rv);
+ }
+
+ mChannel = do_QueryInterface(chan, &rv);
+ if (NS_FAILED(rv))
+ return SendCancelEarly(rv);
+
+ return true;
+}
+
+bool
+WyciwygChannelParent::RecvAppData(const IPC::SerializedLoadContext& loadContext,
+ const PBrowserOrId &parent)
+{
+ LOG(("WyciwygChannelParent RecvAppData [this=%p]\n", this));
+
+ if (!SetupAppData(loadContext, parent))
+ return false;
+
+ mChannel->SetNotificationCallbacks(this);
+ return true;
+}
+
+bool
+WyciwygChannelParent::SetupAppData(const IPC::SerializedLoadContext& loadContext,
+ const PBrowserOrId &aParent)
+{
+ if (!mChannel)
+ return true;
+
+ const char* error = NeckoParent::CreateChannelLoadContext(aParent,
+ Manager()->Manager(),
+ loadContext,
+ nullptr,
+ mLoadContext);
+ if (error) {
+ printf_stderr("WyciwygChannelParent::SetupAppData: FATAL ERROR: %s\n",
+ error);
+ return false;
+ }
+
+ if (!mLoadContext && loadContext.IsPrivateBitValid()) {
+ nsCOMPtr<nsIPrivateBrowsingChannel> pbChannel = do_QueryInterface(mChannel);
+ if (pbChannel)
+ pbChannel->SetPrivate(loadContext.mOriginAttributes.mPrivateBrowsingId > 0);
+ }
+
+ mReceivedAppData = true;
+ return true;
+}
+
+bool
+WyciwygChannelParent::RecvAsyncOpen(const URIParams& aOriginal,
+ const uint32_t& aLoadFlags,
+ const IPC::SerializedLoadContext& loadContext,
+ const PBrowserOrId &aParent)
+{
+ nsCOMPtr<nsIURI> original = DeserializeURI(aOriginal);
+ if (!original)
+ return false;
+
+ LOG(("WyciwygChannelParent RecvAsyncOpen [this=%p]\n", this));
+
+ if (!mChannel)
+ return true;
+
+ nsresult rv;
+
+ rv = mChannel->SetOriginalURI(original);
+ if (NS_FAILED(rv))
+ return SendCancelEarly(rv);
+
+ rv = mChannel->SetLoadFlags(aLoadFlags);
+ if (NS_FAILED(rv))
+ return SendCancelEarly(rv);
+
+ if (!mReceivedAppData && !SetupAppData(loadContext, aParent)) {
+ return false;
+ }
+
+ rv = mChannel->SetNotificationCallbacks(this);
+ if (NS_FAILED(rv))
+ return SendCancelEarly(rv);
+
+ nsCOMPtr<nsILoadInfo> loadInfo = mChannel->GetLoadInfo();
+ if (loadInfo && loadInfo->GetEnforceSecurity()) {
+ rv = mChannel->AsyncOpen2(this);
+ }
+ else {
+ rv = mChannel->AsyncOpen(this, nullptr);
+ }
+
+ if (NS_FAILED(rv))
+ return SendCancelEarly(rv);
+
+ return true;
+}
+
+bool
+WyciwygChannelParent::RecvWriteToCacheEntry(const nsString& data)
+{
+ if (!mReceivedAppData) {
+ printf_stderr("WyciwygChannelParent::RecvWriteToCacheEntry: FATAL ERROR: didn't receive app data\n");
+ return false;
+ }
+
+ if (mChannel)
+ mChannel->WriteToCacheEntry(data);
+
+ return true;
+}
+
+bool
+WyciwygChannelParent::RecvCloseCacheEntry(const nsresult& reason)
+{
+ if (mChannel) {
+ mChannel->CloseCacheEntry(reason);
+ }
+
+ return true;
+}
+
+bool
+WyciwygChannelParent::RecvSetCharsetAndSource(const int32_t& aCharsetSource,
+ const nsCString& aCharset)
+{
+ if (mChannel)
+ mChannel->SetCharsetAndSource(aCharsetSource, aCharset);
+
+ return true;
+}
+
+bool
+WyciwygChannelParent::RecvSetSecurityInfo(const nsCString& aSecurityInfo)
+{
+ if (mChannel) {
+ nsCOMPtr<nsISupports> securityInfo;
+ NS_DeserializeObject(aSecurityInfo, getter_AddRefs(securityInfo));
+ mChannel->SetSecurityInfo(securityInfo);
+ }
+
+ return true;
+}
+
+bool
+WyciwygChannelParent::RecvCancel(const nsresult& aStatusCode)
+{
+ if (mChannel)
+ mChannel->Cancel(aStatusCode);
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// WyciwygChannelParent::nsIRequestObserver
+//-----------------------------------------------------------------------------
+
+NS_IMETHODIMP
+WyciwygChannelParent::OnStartRequest(nsIRequest *aRequest, nsISupports *aContext)
+{
+ LOG(("WyciwygChannelParent::OnStartRequest [this=%p]\n", this));
+
+ nsresult rv;
+
+ nsCOMPtr<nsIWyciwygChannel> chan = do_QueryInterface(aRequest, &rv);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ nsresult status;
+ chan->GetStatus(&status);
+
+ int64_t contentLength = -1;
+ chan->GetContentLength(&contentLength);
+
+ int32_t charsetSource = kCharsetUninitialized;
+ nsAutoCString charset;
+ chan->GetCharsetAndSource(&charsetSource, charset);
+
+ nsCOMPtr<nsISupports> securityInfo;
+ chan->GetSecurityInfo(getter_AddRefs(securityInfo));
+ nsCString secInfoStr;
+ if (securityInfo) {
+ nsCOMPtr<nsISerializable> serializable = do_QueryInterface(securityInfo);
+ if (serializable)
+ NS_SerializeToString(serializable, secInfoStr);
+ else {
+ NS_ERROR("Can't serialize security info");
+ return NS_ERROR_UNEXPECTED;
+ }
+ }
+
+ if (mIPCClosed ||
+ !SendOnStartRequest(status, contentLength, charsetSource, charset, secInfoStr)) {
+ return NS_ERROR_UNEXPECTED;
+ }
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+WyciwygChannelParent::OnStopRequest(nsIRequest *aRequest,
+ nsISupports *aContext,
+ nsresult aStatusCode)
+{
+ LOG(("WyciwygChannelParent::OnStopRequest: [this=%p status=%ul]\n",
+ this, aStatusCode));
+
+ if (mIPCClosed || !SendOnStopRequest(aStatusCode)) {
+ return NS_ERROR_UNEXPECTED;
+ }
+
+ return NS_OK;
+}
+
+//-----------------------------------------------------------------------------
+// WyciwygChannelParent::nsIStreamListener
+//-----------------------------------------------------------------------------
+
+NS_IMETHODIMP
+WyciwygChannelParent::OnDataAvailable(nsIRequest *aRequest,
+ nsISupports *aContext,
+ nsIInputStream *aInputStream,
+ uint64_t aOffset,
+ uint32_t aCount)
+{
+ LOG(("WyciwygChannelParent::OnDataAvailable [this=%p]\n", this));
+
+ nsCString data;
+ nsresult rv = NS_ReadInputStreamToString(aInputStream, data, aCount);
+ if (NS_FAILED(rv))
+ return rv;
+
+ if (mIPCClosed || !SendOnDataAvailable(data, aOffset)) {
+ return NS_ERROR_UNEXPECTED;
+ }
+
+ return NS_OK;
+}
+
+//-----------------------------------------------------------------------------
+// WyciwygChannelParent::nsIInterfaceRequestor
+//-----------------------------------------------------------------------------
+
+NS_IMETHODIMP
+WyciwygChannelParent::GetInterface(const nsIID& uuid, void** 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
diff --git a/netwerk/protocol/wyciwyg/WyciwygChannelParent.h b/netwerk/protocol/wyciwyg/WyciwygChannelParent.h
new file mode 100644
index 000000000..be009487b
--- /dev/null
+++ b/netwerk/protocol/wyciwyg/WyciwygChannelParent.h
@@ -0,0 +1,71 @@
+/* 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/. */
+
+#ifndef mozilla_net_WyciwygChannelParent_h
+#define mozilla_net_WyciwygChannelParent_h
+
+#include "mozilla/net/PWyciwygChannelParent.h"
+#include "mozilla/net/NeckoCommon.h"
+#include "nsIStreamListener.h"
+
+#include "nsIWyciwygChannel.h"
+#include "nsIInterfaceRequestor.h"
+#include "nsILoadContext.h"
+
+namespace mozilla {
+namespace dom {
+ class PBrowserParent;
+} // namespace dom
+
+namespace net {
+
+class WyciwygChannelParent : public PWyciwygChannelParent
+ , public nsIStreamListener
+ , public nsIInterfaceRequestor
+{
+public:
+ NS_DECL_ISUPPORTS
+ NS_DECL_NSIREQUESTOBSERVER
+ NS_DECL_NSISTREAMLISTENER
+ NS_DECL_NSIINTERFACEREQUESTOR
+
+ WyciwygChannelParent();
+
+protected:
+ virtual ~WyciwygChannelParent();
+
+ virtual bool RecvInit(const URIParams& uri,
+ const ipc::PrincipalInfo& aRequestingPrincipalInfo,
+ const ipc::PrincipalInfo& aTriggeringPrincipalInfo,
+ const ipc::PrincipalInfo& aPrincipalToInheritInfo,
+ const uint32_t& aSecurityFlags,
+ const uint32_t& aContentPolicyType) override;
+ virtual bool RecvAsyncOpen(const URIParams& original,
+ const uint32_t& loadFlags,
+ const IPC::SerializedLoadContext& loadContext,
+ const PBrowserOrId &parent) override;
+ virtual bool RecvWriteToCacheEntry(const nsString& data) override;
+ virtual bool RecvCloseCacheEntry(const nsresult& reason) override;
+ virtual bool RecvSetCharsetAndSource(const int32_t& source,
+ const nsCString& charset) override;
+ virtual bool RecvSetSecurityInfo(const nsCString& securityInfo) override;
+ virtual bool RecvCancel(const nsresult& statusCode) override;
+ virtual bool RecvAppData(const IPC::SerializedLoadContext& loadContext,
+ const PBrowserOrId &parent) override;
+
+ virtual void ActorDestroy(ActorDestroyReason why) override;
+
+ bool SetupAppData(const IPC::SerializedLoadContext& loadContext,
+ const PBrowserOrId &aParent);
+
+ nsCOMPtr<nsIWyciwygChannel> mChannel;
+ bool mIPCClosed;
+ bool mReceivedAppData;
+ nsCOMPtr<nsILoadContext> mLoadContext;
+};
+
+} // namespace net
+} // namespace mozilla
+
+#endif // mozilla_net_WyciwygChannelParent_h
diff --git a/netwerk/protocol/wyciwyg/moz.build b/netwerk/protocol/wyciwyg/moz.build
new file mode 100644
index 000000000..b043137f7
--- /dev/null
+++ b/netwerk/protocol/wyciwyg/moz.build
@@ -0,0 +1,36 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# 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/.
+
+XPIDL_SOURCES += [
+ 'nsIWyciwygChannel.idl',
+]
+
+XPIDL_MODULE = 'necko_wyciwyg'
+
+EXPORTS.mozilla.net += [
+ 'WyciwygChannelChild.h',
+ 'WyciwygChannelParent.h',
+]
+
+UNIFIED_SOURCES += [
+ 'nsWyciwyg.cpp',
+ 'nsWyciwygChannel.cpp',
+ 'nsWyciwygProtocolHandler.cpp',
+ 'WyciwygChannelChild.cpp',
+ 'WyciwygChannelParent.cpp',
+]
+
+IPDL_SOURCES += [
+ 'PWyciwygChannel.ipdl',
+]
+
+include('/ipc/chromium/chromium-config.mozbuild')
+
+FINAL_LIBRARY = 'xul'
+
+LOCAL_INCLUDES += [
+ '/netwerk/base',
+]
diff --git a/netwerk/protocol/wyciwyg/nsIWyciwygChannel.idl b/netwerk/protocol/wyciwyg/nsIWyciwygChannel.idl
new file mode 100644
index 000000000..29bcc4d77
--- /dev/null
+++ b/netwerk/protocol/wyciwyg/nsIWyciwygChannel.idl
@@ -0,0 +1,45 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 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 "nsIChannel.idl"
+
+/**
+ * A channel to manage all cache-related interactions for layout
+ * when it is dealing with dynamic pages created through
+ * document.write(). This interface provides methods that will
+ * help layout save dynamic pages in cache for future retrievals.
+ */
+
+[scriptable, uuid (8b8f3341-46da-40f5-a16f-41a91f5d25dd)]
+interface nsIWyciwygChannel : nsIChannel
+{
+ /**
+ * Append data to the cache entry; opens the cache entry if necessary.
+ */
+ void writeToCacheEntry(in AString aData);
+
+ /**
+ * Close the cache entry; subsequent writes have undefined behavior.
+ */
+ void closeCacheEntry(in nsresult reason);
+
+ /**
+ * Set the wyciwyg channels security info
+ */
+ void setSecurityInfo(in nsISupports aSecurityInfo);
+
+ /**
+ * Store and read a charset and charset source on the wyciwyg channel. These
+ * are opaque values to the channel; consumers who set them should know what
+ * they mean.
+ */
+ void setCharsetAndSource(in long aSource, in ACString aCharset);
+ /**
+ * The return value is the charset. Throws if either the charset or the
+ * source cannot be retrieved. This is guaranteed to return a nonzero source
+ * and a nonempty charset if it does not throw.
+ */
+ ACString getCharsetAndSource(out long aSource);
+};
diff --git a/netwerk/protocol/wyciwyg/nsWyciwyg.cpp b/netwerk/protocol/wyciwyg/nsWyciwyg.cpp
new file mode 100644
index 000000000..edc716afd
--- /dev/null
+++ b/netwerk/protocol/wyciwyg/nsWyciwyg.cpp
@@ -0,0 +1,10 @@
+/* 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 "nsWyciwyg.h"
+#include "nscore.h"
+
+mozilla::LazyLogModule gWyciwygLog("nsWyciwygChannel");
+
+
diff --git a/netwerk/protocol/wyciwyg/nsWyciwyg.h b/netwerk/protocol/wyciwyg/nsWyciwyg.h
new file mode 100644
index 000000000..48199a9b9
--- /dev/null
+++ b/netwerk/protocol/wyciwyg/nsWyciwyg.h
@@ -0,0 +1,43 @@
+/* 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/. */
+
+#ifndef nsWyciwyg_h__
+#define nsWyciwyg_h__
+
+#include "mozilla/net/NeckoChild.h"
+
+// Get rid of chromium's LOG.
+#undef LOG
+
+#include "mozilla/Logging.h"
+
+//
+// Log module for HTTP Protocol logging...
+//
+// To enable logging (see prlog.h for full details):
+//
+// set MOZ_LOG=nsWyciwyg:5
+// set MOZ_LOG_FILE=wyciwyg.log
+//
+// This enables LogLevel::Debug level information and places all output in
+// the file wyciwyg.log.
+//
+extern mozilla::LazyLogModule gWyciwygLog;
+
+// http logging
+#define LOG1(args) MOZ_LOG(gWyciwygLog, mozilla::LogLevel::Error, args)
+#define LOG2(args) MOZ_LOG(gWyciwygLog, mozilla::LogLevel::Warning, args)
+#define LOG3(args) MOZ_LOG(gWyciwygLog, mozilla::LogLevel::Info, args)
+#define LOG4(args) MOZ_LOG(gWyciwygLog, mozilla::LogLevel::Debug, args)
+#define LOG(args) LOG4(args)
+
+#define LOG1_ENABLED() MOZ_LOG_TEST(gWyciwygLog, mozilla::LogLevel::Error)
+#define LOG2_ENABLED() MOZ_LOG_TEST(gWyciwygLog, mozilla::LogLevel::Warning)
+#define LOG3_ENABLED() MOZ_LOG_TEST(gWyciwygLog, mozilla::LogLevel::Info)
+#define LOG4_ENABLED() MOZ_LOG_TEST(gWyciwygLog, mozilla::LogLevel::Debug)
+#define LOG_ENABLED() LOG4_ENABLED()
+
+#define WYCIWYG_TYPE "text/html"
+
+#endif // nsWyciwyg_h__
diff --git a/netwerk/protocol/wyciwyg/nsWyciwygChannel.cpp b/netwerk/protocol/wyciwyg/nsWyciwygChannel.cpp
new file mode 100644
index 000000000..52949b799
--- /dev/null
+++ b/netwerk/protocol/wyciwyg/nsWyciwygChannel.cpp
@@ -0,0 +1,808 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ *
+ * 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 "nsWyciwyg.h"
+#include "nsWyciwygChannel.h"
+#include "nsILoadGroup.h"
+#include "nsNetUtil.h"
+#include "nsNetCID.h"
+#include "LoadContextInfo.h"
+#include "nsICacheService.h" // only to initialize
+#include "nsICacheStorageService.h"
+#include "nsICacheStorage.h"
+#include "nsICacheEntry.h"
+#include "nsCharsetSource.h"
+#include "nsProxyRelease.h"
+#include "nsThreadUtils.h"
+#include "nsIInputStream.h"
+#include "nsIInputStreamPump.h"
+#include "nsIOutputStream.h"
+#include "nsIProgressEventSink.h"
+#include "nsIURI.h"
+#include "mozilla/DebugOnly.h"
+#include "mozilla/Unused.h"
+#include "mozilla/BasePrincipal.h"
+#include "nsProxyRelease.h"
+#include "nsContentSecurityManager.h"
+#include "nsContentUtils.h"
+
+typedef mozilla::net::LoadContextInfo LoadContextInfo;
+
+// nsWyciwygChannel methods
+nsWyciwygChannel::nsWyciwygChannel()
+ : mMode(NONE),
+ mStatus(NS_OK),
+ mIsPending(false),
+ mNeedToWriteCharset(false),
+ mCharsetSource(kCharsetUninitialized),
+ mContentLength(-1),
+ mLoadFlags(LOAD_NORMAL),
+ mNeedToSetSecurityInfo(false)
+{
+}
+
+nsWyciwygChannel::~nsWyciwygChannel()
+{
+ if (mLoadInfo) {
+ NS_ReleaseOnMainThread(mLoadInfo.forget(), false);
+ }
+}
+
+NS_IMPL_ISUPPORTS(nsWyciwygChannel,
+ nsIChannel,
+ nsIRequest,
+ nsIStreamListener,
+ nsIRequestObserver,
+ nsICacheEntryOpenCallback,
+ nsIWyciwygChannel,
+ nsIPrivateBrowsingChannel)
+
+nsresult
+nsWyciwygChannel::Init(nsIURI* uri)
+{
+ NS_ENSURE_ARG_POINTER(uri);
+
+ mURI = uri;
+ mOriginalURI = uri;
+
+ return NS_OK;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// nsIRequest methods:
+///////////////////////////////////////////////////////////////////////////////
+
+NS_IMETHODIMP
+nsWyciwygChannel::GetName(nsACString &aName)
+{
+ return mURI->GetSpec(aName);
+}
+
+NS_IMETHODIMP
+nsWyciwygChannel::IsPending(bool *aIsPending)
+{
+ *aIsPending = mIsPending;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsWyciwygChannel::GetStatus(nsresult *aStatus)
+{
+ if (NS_SUCCEEDED(mStatus) && mPump)
+ mPump->GetStatus(aStatus);
+ else
+ *aStatus = mStatus;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsWyciwygChannel::Cancel(nsresult status)
+{
+ mStatus = status;
+ if (mPump)
+ mPump->Cancel(status);
+ // else we're waiting for OnCacheEntryAvailable
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsWyciwygChannel::Suspend()
+{
+ if (mPump)
+ mPump->Suspend();
+ // XXX else, we'll ignore this ... and that's probably bad!
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsWyciwygChannel::Resume()
+{
+ if (mPump)
+ mPump->Resume();
+ // XXX else, we'll ignore this ... and that's probably bad!
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsWyciwygChannel::GetLoadGroup(nsILoadGroup* *aLoadGroup)
+{
+ *aLoadGroup = mLoadGroup;
+ NS_IF_ADDREF(*aLoadGroup);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsWyciwygChannel::SetLoadGroup(nsILoadGroup* aLoadGroup)
+{
+ if (!CanSetLoadGroup(aLoadGroup)) {
+ return NS_ERROR_FAILURE;
+ }
+
+ mLoadGroup = aLoadGroup;
+ NS_QueryNotificationCallbacks(mCallbacks,
+ mLoadGroup,
+ NS_GET_IID(nsIProgressEventSink),
+ getter_AddRefs(mProgressSink));
+ UpdatePrivateBrowsing();
+ NS_GetOriginAttributes(this, mOriginAttributes);
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsWyciwygChannel::SetLoadFlags(uint32_t aLoadFlags)
+{
+ mLoadFlags = aLoadFlags;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsWyciwygChannel::GetLoadFlags(uint32_t * aLoadFlags)
+{
+ *aLoadFlags = mLoadFlags;
+ return NS_OK;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// nsIChannel methods:
+///////////////////////////////////////////////////////////////////////////////
+
+NS_IMETHODIMP
+nsWyciwygChannel::GetOriginalURI(nsIURI* *aURI)
+{
+ *aURI = mOriginalURI;
+ NS_ADDREF(*aURI);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsWyciwygChannel::SetOriginalURI(nsIURI* aURI)
+{
+ NS_ENSURE_ARG_POINTER(aURI);
+ mOriginalURI = aURI;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsWyciwygChannel::GetURI(nsIURI* *aURI)
+{
+ *aURI = mURI;
+ NS_IF_ADDREF(*aURI);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsWyciwygChannel::GetOwner(nsISupports **aOwner)
+{
+ NS_IF_ADDREF(*aOwner = mOwner);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsWyciwygChannel::SetOwner(nsISupports* aOwner)
+{
+ mOwner = aOwner;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsWyciwygChannel::GetLoadInfo(nsILoadInfo **aLoadInfo)
+{
+ NS_IF_ADDREF(*aLoadInfo = mLoadInfo);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsWyciwygChannel::SetLoadInfo(nsILoadInfo* aLoadInfo)
+{
+ mLoadInfo = aLoadInfo;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsWyciwygChannel::GetNotificationCallbacks(nsIInterfaceRequestor* *aCallbacks)
+{
+ *aCallbacks = mCallbacks.get();
+ NS_IF_ADDREF(*aCallbacks);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsWyciwygChannel::SetNotificationCallbacks(nsIInterfaceRequestor* aNotificationCallbacks)
+{
+ if (!CanSetCallbacks(aNotificationCallbacks)) {
+ return NS_ERROR_FAILURE;
+ }
+
+ mCallbacks = aNotificationCallbacks;
+ NS_QueryNotificationCallbacks(mCallbacks,
+ mLoadGroup,
+ NS_GET_IID(nsIProgressEventSink),
+ getter_AddRefs(mProgressSink));
+
+ UpdatePrivateBrowsing();
+ NS_GetOriginAttributes(this, mOriginAttributes);
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsWyciwygChannel::GetSecurityInfo(nsISupports * *aSecurityInfo)
+{
+ NS_IF_ADDREF(*aSecurityInfo = mSecurityInfo);
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsWyciwygChannel::GetContentType(nsACString &aContentType)
+{
+ aContentType.AssignLiteral(WYCIWYG_TYPE);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsWyciwygChannel::SetContentType(const nsACString &aContentType)
+{
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+nsWyciwygChannel::GetContentCharset(nsACString &aContentCharset)
+{
+ aContentCharset.AssignLiteral("UTF-16");
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsWyciwygChannel::SetContentCharset(const nsACString &aContentCharset)
+{
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+nsWyciwygChannel::GetContentDisposition(uint32_t *aContentDisposition)
+{
+ return NS_ERROR_NOT_AVAILABLE;
+}
+
+NS_IMETHODIMP
+nsWyciwygChannel::SetContentDisposition(uint32_t aContentDisposition)
+{
+ return NS_ERROR_NOT_AVAILABLE;
+}
+
+NS_IMETHODIMP
+nsWyciwygChannel::GetContentDispositionFilename(nsAString &aContentDispositionFilename)
+{
+ return NS_ERROR_NOT_AVAILABLE;
+}
+
+NS_IMETHODIMP
+nsWyciwygChannel::SetContentDispositionFilename(const nsAString &aContentDispositionFilename)
+{
+ return NS_ERROR_NOT_AVAILABLE;
+}
+
+NS_IMETHODIMP
+nsWyciwygChannel::GetContentDispositionHeader(nsACString &aContentDispositionHeader)
+{
+ return NS_ERROR_NOT_AVAILABLE;
+}
+
+NS_IMETHODIMP
+nsWyciwygChannel::GetContentLength(int64_t *aContentLength)
+{
+ *aContentLength = mContentLength;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsWyciwygChannel::SetContentLength(int64_t aContentLength)
+{
+ mContentLength = aContentLength;
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsWyciwygChannel::Open(nsIInputStream ** aReturn)
+{
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+nsWyciwygChannel::Open2(nsIInputStream** aStream)
+{
+ nsCOMPtr<nsIStreamListener> listener;
+ nsresult rv = nsContentSecurityManager::doContentSecurityCheck(this, listener);
+ NS_ENSURE_SUCCESS(rv, rv);
+ return Open(aStream);
+}
+
+NS_IMETHODIMP
+nsWyciwygChannel::AsyncOpen(nsIStreamListener *listener, nsISupports *ctx)
+{
+ MOZ_ASSERT(!mLoadInfo ||
+ mLoadInfo->GetSecurityMode() == 0 ||
+ mLoadInfo->GetInitialSecurityCheckDone() ||
+ (mLoadInfo->GetSecurityMode() == nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL &&
+ nsContentUtils::IsSystemPrincipal(mLoadInfo->LoadingPrincipal())),
+ "security flags in loadInfo but asyncOpen2() not called");
+
+ LOG(("nsWyciwygChannel::AsyncOpen [this=%p]\n", this));
+ MOZ_ASSERT(mMode == NONE, "nsWyciwygChannel already open");
+
+ NS_ENSURE_TRUE(!mIsPending, NS_ERROR_IN_PROGRESS);
+ NS_ENSURE_TRUE(mMode == NONE, NS_ERROR_IN_PROGRESS);
+ NS_ENSURE_ARG_POINTER(listener);
+
+ mMode = READING;
+
+ // open a cache entry for this channel...
+ // mIsPending set to true since OnCacheEntryAvailable may be called
+ // synchronously and fails when mIsPending found false.
+ mIsPending = true;
+ nsresult rv = OpenCacheEntryForReading(mURI);
+ if (NS_FAILED(rv)) {
+ LOG(("nsWyciwygChannel::OpenCacheEntryForReading failed [rv=%x]\n", rv));
+ mIsPending = false;
+ return rv;
+ }
+
+ // There is no code path that would invoke the listener sooner than
+ // we get to this line in case OnCacheEntryAvailable is invoked
+ // synchronously.
+ mListener = listener;
+ mListenerContext = ctx;
+
+ if (mLoadGroup)
+ mLoadGroup->AddRequest(this, nullptr);
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsWyciwygChannel::AsyncOpen2(nsIStreamListener *aListener)
+{
+ nsCOMPtr<nsIStreamListener> listener = aListener;
+ nsresult rv = nsContentSecurityManager::doContentSecurityCheck(this, listener);
+ NS_ENSURE_SUCCESS(rv, rv);
+ return AsyncOpen(listener, nullptr);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// nsIWyciwygChannel
+//////////////////////////////////////////////////////////////////////////////
+
+NS_IMETHODIMP
+nsWyciwygChannel::WriteToCacheEntry(const nsAString &aData)
+{
+ LOG(("nsWyciwygChannel::WriteToCacheEntry [this=%p]", this));
+
+ nsresult rv;
+
+ if (mMode == READING) {
+ LOG(("nsWyciwygChannel::WriteToCacheEntry already open for reading"));
+ MOZ_ASSERT(false);
+ return NS_ERROR_UNEXPECTED;
+ }
+
+ mMode = WRITING;
+
+ if (!mCacheEntry) {
+ nsresult rv = OpenCacheEntryForWriting(mURI);
+ if (NS_FAILED(rv) || !mCacheEntry) {
+ LOG((" could not synchronously open cache entry for write!"));
+ return NS_ERROR_FAILURE;
+ }
+ }
+
+ if (mLoadFlags & INHIBIT_PERSISTENT_CACHING) {
+ rv = mCacheEntry->SetMetaDataElement("inhibit-persistent-caching", "1");
+ if (NS_FAILED(rv)) return rv;
+ }
+
+ if (mNeedToSetSecurityInfo) {
+ mCacheEntry->SetSecurityInfo(mSecurityInfo);
+ mNeedToSetSecurityInfo = false;
+ }
+
+ if (mNeedToWriteCharset) {
+ WriteCharsetAndSourceToCache(mCharsetSource, mCharset);
+ mNeedToWriteCharset = false;
+ }
+
+ uint32_t out;
+ if (!mCacheOutputStream) {
+ // Get the outputstream from the cache entry.
+ rv = mCacheEntry->OpenOutputStream(0, getter_AddRefs(mCacheOutputStream));
+ if (NS_FAILED(rv)) return rv;
+
+ // Write out a Byte Order Mark, so that we'll know if the data is
+ // BE or LE when we go to read it.
+ char16_t bom = 0xFEFF;
+ rv = mCacheOutputStream->Write((char *)&bom, sizeof(bom), &out);
+ if (NS_FAILED(rv)) return rv;
+ }
+
+ return mCacheOutputStream->Write((const char *)PromiseFlatString(aData).get(),
+ aData.Length() * sizeof(char16_t), &out);
+}
+
+
+NS_IMETHODIMP
+nsWyciwygChannel::CloseCacheEntry(nsresult reason)
+{
+ if (mCacheEntry) {
+ LOG(("nsWyciwygChannel::CloseCacheEntry [this=%p ]", this));
+ mCacheOutputStream = nullptr;
+ mCacheInputStream = nullptr;
+
+ if (NS_FAILED(reason)) {
+ mCacheEntry->AsyncDoom(nullptr);
+ }
+
+ mCacheEntry = nullptr;
+ }
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsWyciwygChannel::SetSecurityInfo(nsISupports *aSecurityInfo)
+{
+ if (mMode == READING) {
+ MOZ_ASSERT(false);
+ return NS_ERROR_UNEXPECTED;
+ }
+
+ mSecurityInfo = aSecurityInfo;
+
+ if (mCacheEntry) {
+ return mCacheEntry->SetSecurityInfo(mSecurityInfo);
+ }
+
+ mNeedToSetSecurityInfo = true;
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsWyciwygChannel::SetCharsetAndSource(int32_t aSource,
+ const nsACString& aCharset)
+{
+ NS_ENSURE_ARG(!aCharset.IsEmpty());
+
+ if (mCacheEntry) {
+ WriteCharsetAndSourceToCache(mCharsetSource, mCharset);
+ } else {
+ MOZ_ASSERT(mMode != WRITING, "We must have an entry!");
+ if (mMode == READING) {
+ return NS_ERROR_NOT_AVAILABLE;
+ }
+ mNeedToWriteCharset = true;
+ mCharsetSource = aSource;
+ mCharset = aCharset;
+ }
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsWyciwygChannel::GetCharsetAndSource(int32_t* aSource, nsACString& aCharset)
+{
+ MOZ_ASSERT(mMode == READING);
+
+ if (!mCacheEntry) {
+ return NS_ERROR_NOT_AVAILABLE;
+ }
+
+ nsXPIDLCString data;
+ mCacheEntry->GetMetaDataElement("charset", getter_Copies(data));
+
+ if (data.IsEmpty()) {
+ return NS_ERROR_NOT_AVAILABLE;
+ }
+
+ nsXPIDLCString sourceStr;
+ mCacheEntry->GetMetaDataElement("charset-source", getter_Copies(sourceStr));
+
+ int32_t source;
+ nsresult err;
+ source = sourceStr.ToInteger(&err);
+ if (NS_FAILED(err) || source == 0) {
+ return NS_ERROR_NOT_AVAILABLE;
+ }
+
+ *aSource = source;
+ aCharset = data;
+ return NS_OK;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// nsICacheEntryOpenCallback
+//////////////////////////////////////////////////////////////////////////////
+
+NS_IMETHODIMP
+nsWyciwygChannel::OnCacheEntryCheck(nsICacheEntry* entry, nsIApplicationCache* appCache,
+ uint32_t* aResult)
+{
+ *aResult = ENTRY_WANTED;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsWyciwygChannel::OnCacheEntryAvailable(nsICacheEntry *aCacheEntry,
+ bool aNew,
+ nsIApplicationCache* aAppCache,
+ nsresult aStatus)
+{
+ LOG(("nsWyciwygChannel::OnCacheEntryAvailable [this=%p entry=%p "
+ "new=%d status=%x]\n", this, aCacheEntry, aNew, aStatus));
+
+ MOZ_RELEASE_ASSERT(!aNew, "New entry must not be returned when flag "
+ "OPEN_READONLY is used!");
+
+ // if the channel's already fired onStopRequest,
+ // then we should ignore this event.
+ if (!mIsPending)
+ return NS_OK;
+
+ if (NS_SUCCEEDED(mStatus)) {
+ if (NS_SUCCEEDED(aStatus)) {
+ MOZ_ASSERT(aCacheEntry);
+ mCacheEntry = aCacheEntry;
+ nsresult rv = ReadFromCache();
+ if (NS_FAILED(rv)) {
+ mStatus = rv;
+ }
+ } else {
+ mStatus = aStatus;
+ }
+ }
+
+ if (NS_FAILED(mStatus)) {
+ LOG(("channel was canceled [this=%p status=%x]\n", this, mStatus));
+ // Since OnCacheEntryAvailable can be called directly from AsyncOpen
+ // we must dispatch.
+ NS_DispatchToCurrentThread(mozilla::NewRunnableMethod(
+ this, &nsWyciwygChannel::NotifyListener));
+ }
+
+ return NS_OK;
+}
+
+//-----------------------------------------------------------------------------
+// nsWyciwygChannel::nsIStreamListener
+//-----------------------------------------------------------------------------
+
+NS_IMETHODIMP
+nsWyciwygChannel::OnDataAvailable(nsIRequest *request, nsISupports *ctx,
+ nsIInputStream *input,
+ uint64_t offset, uint32_t count)
+{
+ LOG(("nsWyciwygChannel::OnDataAvailable [this=%p request=%x offset=%llu count=%u]\n",
+ this, request, offset, count));
+
+ nsresult rv;
+
+ nsCOMPtr<nsIStreamListener> listener = mListener;
+ nsCOMPtr<nsISupports> listenerContext = mListenerContext;
+
+ if (listener) {
+ rv = listener->OnDataAvailable(this, listenerContext, input, offset, count);
+ } else {
+ MOZ_ASSERT(false, "We must have a listener!");
+ rv = NS_ERROR_UNEXPECTED;
+ }
+
+ // XXX handle 64-bit stuff for real
+ if (mProgressSink && NS_SUCCEEDED(rv)) {
+ mProgressSink->OnProgress(this, nullptr, offset + count, mContentLength);
+ }
+
+ return rv; // let the pump cancel on failure
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// nsIRequestObserver
+//////////////////////////////////////////////////////////////////////////////
+
+NS_IMETHODIMP
+nsWyciwygChannel::OnStartRequest(nsIRequest *request, nsISupports *ctx)
+{
+ LOG(("nsWyciwygChannel::OnStartRequest [this=%p request=%x\n",
+ this, request));
+
+ nsCOMPtr<nsIStreamListener> listener = mListener;
+ nsCOMPtr<nsISupports> listenerContext = mListenerContext;
+
+ if (listener) {
+ return listener->OnStartRequest(this, listenerContext);
+ }
+
+ MOZ_ASSERT(false, "We must have a listener!");
+ return NS_ERROR_UNEXPECTED;
+}
+
+
+NS_IMETHODIMP
+nsWyciwygChannel::OnStopRequest(nsIRequest *request, nsISupports *ctx, nsresult status)
+{
+ LOG(("nsWyciwygChannel::OnStopRequest [this=%p request=%x status=%d\n",
+ this, request, status));
+
+ if (NS_SUCCEEDED(mStatus))
+ mStatus = status;
+
+ mIsPending = false;
+
+ nsCOMPtr<nsIStreamListener> listener;
+ nsCOMPtr<nsISupports> listenerContext;
+ listener.swap(mListener);
+ listenerContext.swap(mListenerContext);
+
+ if (listener) {
+ listener->OnStopRequest(this, listenerContext, mStatus);
+ } else {
+ MOZ_ASSERT(false, "We must have a listener!");
+ }
+
+ if (mLoadGroup)
+ mLoadGroup->RemoveRequest(this, nullptr, mStatus);
+
+ CloseCacheEntry(mStatus);
+ mPump = nullptr;
+
+ // Drop notification callbacks to prevent cycles.
+ mCallbacks = nullptr;
+ mProgressSink = nullptr;
+
+ return NS_OK;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// Helper functions
+//////////////////////////////////////////////////////////////////////////////
+
+nsresult
+nsWyciwygChannel::GetCacheStorage(nsICacheStorage **_retval)
+{
+ nsresult rv;
+
+ nsCOMPtr<nsICacheStorageService> cacheService =
+ do_GetService("@mozilla.org/netwerk/cache-storage-service;1", &rv);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ bool anonymous = mLoadFlags & LOAD_ANONYMOUS;
+ mOriginAttributes.SyncAttributesWithPrivateBrowsing(mPrivateBrowsing);
+ RefPtr<LoadContextInfo> loadInfo = mozilla::net::GetLoadContextInfo(anonymous, mOriginAttributes);
+
+ if (mLoadFlags & INHIBIT_PERSISTENT_CACHING) {
+ return cacheService->MemoryCacheStorage(loadInfo, _retval);
+ }
+
+ return cacheService->DiskCacheStorage(loadInfo, false, _retval);
+}
+
+nsresult
+nsWyciwygChannel::OpenCacheEntryForReading(nsIURI *aURI)
+{
+ nsresult rv;
+
+ nsCOMPtr<nsICacheStorage> cacheStorage;
+ rv = GetCacheStorage(getter_AddRefs(cacheStorage));
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ return cacheStorage->AsyncOpenURI(aURI, EmptyCString(),
+ nsICacheStorage::OPEN_READONLY |
+ nsICacheStorage::CHECK_MULTITHREADED,
+ this);
+}
+
+nsresult
+nsWyciwygChannel::OpenCacheEntryForWriting(nsIURI *aURI)
+{
+ nsresult rv;
+
+ nsCOMPtr<nsICacheStorage> cacheStorage;
+ rv = GetCacheStorage(getter_AddRefs(cacheStorage));
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ return cacheStorage->OpenTruncate(aURI, EmptyCString(),
+ getter_AddRefs(mCacheEntry));
+}
+
+nsresult
+nsWyciwygChannel::ReadFromCache()
+{
+ LOG(("nsWyciwygChannel::ReadFromCache [this=%p] ", this));
+
+ NS_ENSURE_TRUE(mCacheEntry, NS_ERROR_FAILURE);
+ nsresult rv;
+
+ // Get the stored security info
+ mCacheEntry->GetSecurityInfo(getter_AddRefs(mSecurityInfo));
+
+ nsAutoCString tmpStr;
+ rv = mCacheEntry->GetMetaDataElement("inhibit-persistent-caching",
+ getter_Copies(tmpStr));
+ if (NS_SUCCEEDED(rv) && tmpStr.EqualsLiteral("1"))
+ mLoadFlags |= INHIBIT_PERSISTENT_CACHING;
+
+ // Get a transport to the cached data...
+ rv = mCacheEntry->OpenInputStream(0, getter_AddRefs(mCacheInputStream));
+ if (NS_FAILED(rv))
+ return rv;
+ NS_ENSURE_TRUE(mCacheInputStream, NS_ERROR_UNEXPECTED);
+
+ rv = NS_NewInputStreamPump(getter_AddRefs(mPump), mCacheInputStream);
+ if (NS_FAILED(rv)) return rv;
+
+ // Pump the cache data downstream
+ return mPump->AsyncRead(this, nullptr);
+}
+
+void
+nsWyciwygChannel::WriteCharsetAndSourceToCache(int32_t aSource,
+ const nsCString& aCharset)
+{
+ NS_PRECONDITION(mCacheEntry, "Better have cache entry!");
+
+ mCacheEntry->SetMetaDataElement("charset", aCharset.get());
+
+ nsAutoCString source;
+ source.AppendInt(aSource);
+ mCacheEntry->SetMetaDataElement("charset-source", source.get());
+}
+
+void
+nsWyciwygChannel::NotifyListener()
+{
+ nsCOMPtr<nsIStreamListener> listener;
+ nsCOMPtr<nsISupports> listenerContext;
+
+ listener.swap(mListener);
+ listenerContext.swap(mListenerContext);
+
+ if (listener) {
+ listener->OnStartRequest(this, listenerContext);
+ mIsPending = false;
+ listener->OnStopRequest(this, listenerContext, mStatus);
+ } else {
+ MOZ_ASSERT(false, "We must have the listener!");
+ mIsPending = false;
+ }
+
+ CloseCacheEntry(mStatus);
+
+ // Remove ourselves from the load group.
+ if (mLoadGroup) {
+ mLoadGroup->RemoveRequest(this, nullptr, mStatus);
+ }
+}
+
+// vim: ts=2 sw=2
diff --git a/netwerk/protocol/wyciwyg/nsWyciwygChannel.h b/netwerk/protocol/wyciwyg/nsWyciwygChannel.h
new file mode 100644
index 000000000..26326e2a4
--- /dev/null
+++ b/netwerk/protocol/wyciwyg/nsWyciwygChannel.h
@@ -0,0 +1,115 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * 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/. */
+
+#ifndef nsWyciwygChannel_h___
+#define nsWyciwygChannel_h___
+
+#include "nsString.h"
+#include "nsCOMPtr.h"
+
+#include "nsILoadInfo.h"
+#include "nsIWyciwygChannel.h"
+#include "nsIStreamListener.h"
+#include "nsICacheEntryOpenCallback.h"
+#include "PrivateBrowsingChannel.h"
+#include "mozilla/BasePrincipal.h"
+
+class nsICacheEntry;
+class nsICacheStorage;
+class nsIInputStream;
+class nsIInputStreamPump;
+class nsILoadGroup;
+class nsIOutputStream;
+class nsIProgressEventSink;
+class nsIURI;
+
+extern mozilla::LazyLogModule gWyciwygLog;
+
+//-----------------------------------------------------------------------------
+
+class nsWyciwygChannel final: public nsIWyciwygChannel,
+ public nsIStreamListener,
+ public nsICacheEntryOpenCallback,
+ public mozilla::net::PrivateBrowsingChannel<nsWyciwygChannel>
+{
+public:
+ NS_DECL_THREADSAFE_ISUPPORTS
+ NS_DECL_NSIREQUEST
+ NS_DECL_NSICHANNEL
+ NS_DECL_NSIWYCIWYGCHANNEL
+ NS_DECL_NSIREQUESTOBSERVER
+ NS_DECL_NSISTREAMLISTENER
+ NS_DECL_NSICACHEENTRYOPENCALLBACK
+
+ // nsWyciwygChannel methods:
+ nsWyciwygChannel();
+
+ nsresult Init(nsIURI *uri);
+
+protected:
+ virtual ~nsWyciwygChannel();
+
+ nsresult ReadFromCache();
+ nsresult EnsureWriteCacheEntry();
+ nsresult GetCacheStorage(nsICacheStorage **_retval);
+ nsresult OpenCacheEntryForReading(nsIURI *aURI);
+ nsresult OpenCacheEntryForWriting(nsIURI *aURI);
+
+ void WriteCharsetAndSourceToCache(int32_t aSource,
+ const nsCString& aCharset);
+
+ void NotifyListener();
+
+ friend class mozilla::net::PrivateBrowsingChannel<nsWyciwygChannel>;
+
+ enum EMode {
+ NONE,
+ WRITING,
+ READING
+ };
+
+ EMode mMode;
+ nsresult mStatus;
+ bool mIsPending;
+ bool mNeedToWriteCharset;
+ int32_t mCharsetSource;
+ nsCString mCharset;
+ int64_t mContentLength;
+ uint32_t mLoadFlags;
+ mozilla::NeckoOriginAttributes mOriginAttributes;
+ nsCOMPtr<nsIURI> mURI;
+ nsCOMPtr<nsIURI> mOriginalURI;
+ nsCOMPtr<nsISupports> mOwner;
+ nsCOMPtr<nsILoadInfo> mLoadInfo;
+ nsCOMPtr<nsIInterfaceRequestor> mCallbacks;
+ nsCOMPtr<nsIProgressEventSink> mProgressSink;
+ nsCOMPtr<nsILoadGroup> mLoadGroup;
+ nsCOMPtr<nsIStreamListener> mListener;
+ nsCOMPtr<nsISupports> mListenerContext;
+
+ // reuse as much of this channel implementation as we can
+ nsCOMPtr<nsIInputStreamPump> mPump;
+
+ // Cache related stuff
+ nsCOMPtr<nsICacheEntry> mCacheEntry;
+ nsCOMPtr<nsIOutputStream> mCacheOutputStream;
+ nsCOMPtr<nsIInputStream> mCacheInputStream;
+
+ bool mNeedToSetSecurityInfo;
+ nsCOMPtr<nsISupports> mSecurityInfo;
+};
+
+/**
+ * Casting nsWyciwygChannel to nsISupports is ambiguous.
+ * This method handles that.
+ */
+inline nsISupports*
+ToSupports(nsWyciwygChannel* p)
+{
+ return NS_ISUPPORTS_CAST(nsIStreamListener*, p);
+}
+
+#endif /* nsWyciwygChannel_h___ */
diff --git a/netwerk/protocol/wyciwyg/nsWyciwygProtocolHandler.cpp b/netwerk/protocol/wyciwyg/nsWyciwygProtocolHandler.cpp
new file mode 100644
index 000000000..4e1f7c22e
--- /dev/null
+++ b/netwerk/protocol/wyciwyg/nsWyciwygProtocolHandler.cpp
@@ -0,0 +1,158 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ *
+ * 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 "nsWyciwyg.h"
+#include "nsWyciwygChannel.h"
+#include "nsWyciwygProtocolHandler.h"
+#include "nsNetCID.h"
+#include "nsServiceManagerUtils.h"
+#include "plstr.h"
+#include "nsIObserverService.h"
+#include "mozIApplicationClearPrivateDataParams.h"
+#include "nsIURI.h"
+
+#include "mozilla/net/NeckoChild.h"
+
+using namespace mozilla::net;
+#include "mozilla/net/WyciwygChannelChild.h"
+
+////////////////////////////////////////////////////////////////////////////////
+
+nsWyciwygProtocolHandler::nsWyciwygProtocolHandler()
+{
+ LOG(("Creating nsWyciwygProtocolHandler [this=%p].\n", this));
+}
+
+nsWyciwygProtocolHandler::~nsWyciwygProtocolHandler()
+{
+ LOG(("Deleting nsWyciwygProtocolHandler [this=%p]\n", this));
+}
+
+NS_IMPL_ISUPPORTS(nsWyciwygProtocolHandler,
+ nsIProtocolHandler)
+
+////////////////////////////////////////////////////////////////////////////////
+// nsIProtocolHandler methods:
+////////////////////////////////////////////////////////////////////////////////
+
+NS_IMETHODIMP
+nsWyciwygProtocolHandler::GetScheme(nsACString &result)
+{
+ result = "wyciwyg";
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsWyciwygProtocolHandler::GetDefaultPort(int32_t *result)
+{
+ return NS_ERROR_NOT_AVAILABLE;
+}
+
+NS_IMETHODIMP
+nsWyciwygProtocolHandler::AllowPort(int32_t port, const char *scheme, bool *_retval)
+{
+ // don't override anything.
+ *_retval = false;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsWyciwygProtocolHandler::NewURI(const nsACString &aSpec,
+ const char *aCharset, // ignored
+ nsIURI *aBaseURI,
+ nsIURI **result)
+{
+ nsresult rv;
+
+ nsCOMPtr<nsIURI> url = do_CreateInstance(NS_SIMPLEURI_CONTRACTID, &rv);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ rv = url->SetSpec(aSpec);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ url.forget(result);
+
+ return rv;
+}
+
+NS_IMETHODIMP
+nsWyciwygProtocolHandler::NewChannel2(nsIURI* url,
+ nsILoadInfo* aLoadInfo,
+ nsIChannel** result)
+{
+ if (mozilla::net::IsNeckoChild())
+ mozilla::net::NeckoChild::InitNeckoChild();
+
+ NS_ENSURE_ARG_POINTER(url);
+ nsresult rv;
+
+ nsCOMPtr<nsIWyciwygChannel> channel;
+ if (IsNeckoChild()) {
+ NS_ENSURE_TRUE(gNeckoChild != nullptr, NS_ERROR_FAILURE);
+
+ WyciwygChannelChild *wcc = static_cast<WyciwygChannelChild *>(
+ gNeckoChild->SendPWyciwygChannelConstructor());
+ if (!wcc)
+ return NS_ERROR_OUT_OF_MEMORY;
+
+ channel = wcc;
+ rv = wcc->Init(url);
+ if (NS_FAILED(rv))
+ PWyciwygChannelChild::Send__delete__(wcc);
+ } else
+ {
+ // If original channel used https, make sure PSM is initialized
+ // (this may be first channel to load during a session restore)
+ nsAutoCString path;
+ rv = url->GetPath(path);
+ NS_ENSURE_SUCCESS(rv, rv);
+ int32_t slashIndex = path.FindChar('/', 2);
+ if (slashIndex == kNotFound)
+ return NS_ERROR_FAILURE;
+ if (path.Length() < (uint32_t)slashIndex + 1 + 5)
+ return NS_ERROR_FAILURE;
+ if (!PL_strncasecmp(path.get() + slashIndex + 1, "https", 5))
+ net_EnsurePSMInit();
+
+ nsWyciwygChannel *wc = new nsWyciwygChannel();
+ channel = wc;
+ rv = wc->Init(url);
+ }
+
+ if (NS_FAILED(rv))
+ return rv;
+
+ // set the loadInfo on the new channel
+ rv = channel->SetLoadInfo(aLoadInfo);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+
+ channel.forget(result);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsWyciwygProtocolHandler::NewChannel(nsIURI* url, nsIChannel* *result)
+{
+ return NewChannel2(url, nullptr, result);
+}
+
+NS_IMETHODIMP
+nsWyciwygProtocolHandler::GetProtocolFlags(uint32_t *result)
+{
+ // Should this be an an nsINestedURI? We don't really want random webpages
+ // loading these URIs...
+
+ // Note that using URI_INHERITS_SECURITY_CONTEXT here is OK -- untrusted code
+ // is not allowed to link to wyciwyg URIs and users shouldn't be able to get
+ // at them, and nsDocShell::InternalLoad forbids non-history loads of these
+ // URIs. And when loading from history we end up using the principal from
+ // the history entry, which we put there ourselves, so all is ok.
+ *result = URI_NORELATIVE | URI_NOAUTH | URI_DANGEROUS_TO_LOAD |
+ URI_INHERITS_SECURITY_CONTEXT;
+ return NS_OK;
+}
diff --git a/netwerk/protocol/wyciwyg/nsWyciwygProtocolHandler.h b/netwerk/protocol/wyciwyg/nsWyciwygProtocolHandler.h
new file mode 100644
index 000000000..d3dbd5ead
--- /dev/null
+++ b/netwerk/protocol/wyciwyg/nsWyciwygProtocolHandler.h
@@ -0,0 +1,23 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * 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/. */
+
+#ifndef nsWyciwygProtocolHandler_h___
+#define nsWyciwygProtocolHandler_h___
+
+#include "nsIProtocolHandler.h"
+
+class nsWyciwygProtocolHandler : public nsIProtocolHandler
+{
+ virtual ~nsWyciwygProtocolHandler();
+
+public:
+ NS_DECL_ISUPPORTS
+ NS_DECL_NSIPROTOCOLHANDLER
+
+ nsWyciwygProtocolHandler();
+};
+
+#endif /* nsWyciwygProtocolHandler_h___ */