From fd15d2199a70befd3440657252460bf3a0340676 Mon Sep 17 00:00:00 2001 From: Tim Huang Date: Wed, 11 Nov 2020 11:13:55 +0000 Subject: [PATCH] Bug 1641270 - Part 3: Make nsICookieJarSetting serializable. r=dimi In order to send the cookieJarSetting across processes in JS. We need to make it serializable. Differential Revision: https://phabricator.services.mozilla.com/D95613 --- netwerk/build/components.conf | 7 ++ netwerk/cookie/CookieJarSettings.cpp | 149 +++++++++++++++++++++++- netwerk/cookie/CookieJarSettings.h | 10 ++ netwerk/cookie/nsICookieJarSettings.idl | 3 +- toolkit/modules/E10SUtils.jsm | 44 +++++++ 5 files changed, 211 insertions(+), 2 deletions(-) diff --git a/netwerk/build/components.conf b/netwerk/build/components.conf index 34e1e9e4ae01..3c5f612158f7 100644 --- a/netwerk/build/components.conf +++ b/netwerk/build/components.conf @@ -603,6 +603,13 @@ Classes = [ 'constructor': 'mozilla::net::GetSFVService', 'headers': ['mozilla/net/SFVService.h'], }, + { + 'cid': '{4ce234f1-52e8-47a9-8c8d-b02f815733c7}', + 'contract_ids': ['@mozilla.org/cookieJarSettings;1'], + 'type': 'nsICookieJarSettings', + 'constructor': 'mozilla::net::CookieJarSettings::Create', + 'headers': ['mozilla/net/CookieJarSettings.h'], + }, ] if defined('NECKO_WIFI'): diff --git a/netwerk/cookie/CookieJarSettings.cpp b/netwerk/cookie/CookieJarSettings.cpp index 76ff20347bda..9da16f7dbc5d 100644 --- a/netwerk/cookie/CookieJarSettings.cpp +++ b/netwerk/cookie/CookieJarSettings.cpp @@ -20,13 +20,21 @@ #if defined(MOZ_THUNDERBIRD) || defined(MOZ_SUITE) # include "nsIProtocolHandler.h" #endif +#include "nsIClassInfoImpl.h" #include "nsICookieManager.h" #include "nsICookieService.h" +#include "nsIObjectInputStream.h" +#include "nsIObjectOutputStream.h" #include "nsNetUtil.h" namespace mozilla { namespace net { +NS_IMPL_CLASSINFO(CookieJarSettings, nullptr, nsIClassInfo::THREADSAFE, + COOKIEJARSETTINGS_CID) + +NS_IMPL_ISUPPORTS_CI(CookieJarSettings, nsICookieJarSettings, nsISerializable) + static StaticRefPtr sBlockinAll; namespace { @@ -466,7 +474,146 @@ bool CookieJarSettings::IsRejectThirdPartyWithExceptions( StaticPrefs::network_cookie_rejectForeignWithExceptions_enabled(); } -NS_IMPL_ISUPPORTS(CookieJarSettings, nsICookieJarSettings) +NS_IMETHODIMP +CookieJarSettings::Read(nsIObjectInputStream* aStream) { + nsresult rv = aStream->Read32(&mCookieBehavior); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + rv = aStream->ReadBoolean(&mIsFirstPartyIsolated); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + bool isFixed; + aStream->ReadBoolean(&isFixed); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + mState = isFixed ? eFixed : eProgressive; + + rv = aStream->ReadBoolean(&mIsOnContentBlockingAllowList); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + rv = aStream->ReadString(mPartitionKey); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + // Deserializing the cookie permission list. + uint32_t cookiePermissionsLength; + rv = aStream->Read32(&cookiePermissionsLength); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + if (!cookiePermissionsLength) { + // Bailing out early because there is no cookie permission. + return NS_OK; + } + + CookiePermissionList list; + mCookiePermissions.SetCapacity(cookiePermissionsLength); + for (uint32_t i = 0; i < cookiePermissionsLength; ++i) { + nsAutoCString principalJSON; + aStream->ReadCString(principalJSON); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + nsCOMPtr principal = BasePrincipal::FromJSON(principalJSON); + + if (NS_WARN_IF(!principal)) { + continue; + } + + uint32_t cookiePermission; + aStream->Read32(&cookiePermission); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + nsCOMPtr permission = + Permission::Create(principal, "cookie"_ns, cookiePermission, 0, 0, 0); + if (NS_WARN_IF(!permission)) { + continue; + } + + list.AppendElement(permission); + } + + mCookiePermissions = std::move(list); + + return NS_OK; +} + +NS_IMETHODIMP +CookieJarSettings::Write(nsIObjectOutputStream* aStream) { + nsresult rv = aStream->Write32(mCookieBehavior); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + rv = aStream->WriteBoolean(mIsFirstPartyIsolated); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + rv = aStream->WriteBoolean(mState == eFixed); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + rv = aStream->WriteBoolean(mIsOnContentBlockingAllowList); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + rv = aStream->WriteWStringZ(mPartitionKey.get()); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + // Serializing the cookie permission list. It will first write the length of + // the list, and then, write the cookie permission consecutively. + uint32_t cookiePermissionsLength = mCookiePermissions.Length(); + rv = aStream->Write32(cookiePermissionsLength); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + for (const RefPtr& permission : mCookiePermissions) { + nsCOMPtr principal; + nsresult rv = permission->GetPrincipal(getter_AddRefs(principal)); + if (NS_WARN_IF(NS_FAILED(rv))) { + continue; + } + + nsAutoCString principalJSON; + BasePrincipal::Cast(principal)->ToJSON(principalJSON); + + rv = aStream->WriteStringZ(principalJSON.get()); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + uint32_t cookiePermission = 0; + rv = permission->GetCapability(&cookiePermission); + if (NS_WARN_IF(NS_FAILED(rv))) { + continue; + } + + rv = aStream->Write32(cookiePermission); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + } + + return NS_OK; +} } // namespace net } // namespace mozilla diff --git a/netwerk/cookie/CookieJarSettings.h b/netwerk/cookie/CookieJarSettings.h index 69589c998f7e..34a8e3e79650 100644 --- a/netwerk/cookie/CookieJarSettings.h +++ b/netwerk/cookie/CookieJarSettings.h @@ -11,6 +11,15 @@ #include "nsDataHashtable.h" #include "nsTArray.h" +#define COOKIEJARSETTINGS_CONTRACTID "@mozilla.org/cookieJarSettings;1" +// 4ce234f1-52e8-47a9-8c8d-b02f815733c7 +#define COOKIEJARSETTINGS_CID \ + { \ + 0x4ce234f1, 0x52e8, 0x47a9, { \ + 0x8c, 0x8d, 0xb0, 0x2f, 0x81, 0x57, 0x33, 0xc7 \ + } \ + } + class nsIPermission; namespace mozilla { @@ -111,6 +120,7 @@ class CookieJarSettings final : public nsICookieJarSettings { NS_DECL_THREADSAFE_ISUPPORTS NS_DECL_NSICOOKIEJARSETTINGS + NS_DECL_NSISERIALIZABLE static already_AddRefed GetBlockingAll(); diff --git a/netwerk/cookie/nsICookieJarSettings.idl b/netwerk/cookie/nsICookieJarSettings.idl index 32ed2b3b1e15..052c957557b4 100644 --- a/netwerk/cookie/nsICookieJarSettings.idl +++ b/netwerk/cookie/nsICookieJarSettings.idl @@ -5,6 +5,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "nsISupports.idl" +#include "nsISerializable.idl" interface nsIPrincipal; @@ -13,7 +14,7 @@ interface nsIPrincipal; * for more details. */ [scriptable, builtinclass, uuid(3ec40331-7cf0-4b71-ba2a-2265aab8f6bc)] -interface nsICookieJarSettings : nsISupports +interface nsICookieJarSettings : nsISerializable { /** * CookieBehavior at the loading of the document. Any other loadInfo diff --git a/toolkit/modules/E10SUtils.jsm b/toolkit/modules/E10SUtils.jsm index 3d78984a925c..a9f3bfad2f73 100644 --- a/toolkit/modules/E10SUtils.jsm +++ b/toolkit/modules/E10SUtils.jsm @@ -814,6 +814,50 @@ var E10SUtils = { return fallbackPrincipalCallback(); }, + /** + * Serialize cookieJarSettings. + * + * @param {nsICookieJarSettings} cookieJarSettings The cookieJarSettings to + * serialize. + * @return {String} The base64 encoded cookieJarSettings data. + */ + serializeCookieJarSettings(cookieJarSettings) { + let serialized = null; + if (cookieJarSettings) { + try { + serialized = serializationHelper.serializeToString(cookieJarSettings); + } catch (e) { + this.log().error( + `Failed to serialize cookieJarSettings '${cookieJarSettings}' ${e}` + ); + } + } + return serialized; + }, + + /** + * Deserialize a base64 encoded cookieJarSettings + * + * @param {String} cookieJarSettings_b64 A base64 encoded serialized cookieJarSettings. + * @return {nsICookieJarSettings} A deserialized cookieJarSettings. + */ + deserializeCookieJarSettings(cookieJarSettings_b64) { + let deserialized = null; + if (cookieJarSettings_b64) { + try { + deserialized = serializationHelper.deserializeObject( + cookieJarSettings_b64 + ); + deserialized.QueryInterface(Ci.nsICookieJarSettings); + } catch (e) { + this.log().error( + `Failed to deserialize cookieJarSettings_b64 '${cookieJarSettings_b64}' ${e}` + ); + } + } + return deserialized; + }, + /** * Returns whether or not a URI is supposed to load in a particular * browser given its current remote type.