diff options
Diffstat (limited to 'netwerk/test/gtest/TestCookie.cpp')
-rw-r--r-- | netwerk/test/gtest/TestCookie.cpp | 1126 |
1 files changed, 1126 insertions, 0 deletions
diff --git a/netwerk/test/gtest/TestCookie.cpp b/netwerk/test/gtest/TestCookie.cpp new file mode 100644 index 0000000000..4812ee47f1 --- /dev/null +++ b/netwerk/test/gtest/TestCookie.cpp @@ -0,0 +1,1126 @@ +/* -*- 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 "TestCommon.h" +#include "gtest/gtest.h" +#include "nsContentUtils.h" +#include "nsICookieService.h" +#include "nsICookieManager.h" +#include "nsICookie.h" +#include <stdio.h> +#include "plstr.h" +#include "nsNetUtil.h" +#include "nsIChannel.h" +#include "nsIPrincipal.h" +#include "nsIScriptSecurityManager.h" +#include "nsServiceManagerUtils.h" +#include "nsNetCID.h" +#include "nsIPrefBranch.h" +#include "nsIPrefService.h" +#include "mozilla/dom/Document.h" +#include "mozilla/gtest/MozAssertions.h" +#include "mozilla/Preferences.h" +#include "mozilla/Unused.h" +#include "mozilla/net/CookieJarSettings.h" +#include "Cookie.h" +#include "nsIURI.h" + +using namespace mozilla; +using namespace mozilla::net; + +static NS_DEFINE_CID(kCookieServiceCID, NS_COOKIESERVICE_CID); +static NS_DEFINE_CID(kPrefServiceCID, NS_PREFSERVICE_CID); + +// various pref strings +static const char kCookiesPermissions[] = "network.cookie.cookieBehavior"; +static const char kPrefCookieQuotaPerHost[] = "network.cookie.quotaPerHost"; +static const char kCookiesMaxPerHost[] = "network.cookie.maxPerHost"; + +#define OFFSET_ONE_WEEK int64_t(604800) * PR_USEC_PER_SEC +#define OFFSET_ONE_DAY int64_t(86400) * PR_USEC_PER_SEC + +// Set server time or expiry time +void SetTime(PRTime offsetTime, nsAutoCString& serverString, + nsAutoCString& cookieString, bool expiry) { + char timeStringPreset[40]; + PRTime CurrentTime = PR_Now(); + PRTime SetCookieTime = CurrentTime + offsetTime; + PRTime SetExpiryTime; + if (expiry) { + SetExpiryTime = SetCookieTime - OFFSET_ONE_DAY; + } else { + SetExpiryTime = SetCookieTime + OFFSET_ONE_DAY; + } + + // Set server time string + PRExplodedTime explodedTime; + PR_ExplodeTime(SetCookieTime, PR_GMTParameters, &explodedTime); + PR_FormatTimeUSEnglish(timeStringPreset, 40, "%c GMT", &explodedTime); + serverString.Assign(timeStringPreset); + + // Set cookie string + PR_ExplodeTime(SetExpiryTime, PR_GMTParameters, &explodedTime); + PR_FormatTimeUSEnglish(timeStringPreset, 40, "%c GMT", &explodedTime); + cookieString.ReplaceLiteral( + 0, strlen("test=expiry; expires=") + strlen(timeStringPreset) + 1, + "test=expiry; expires="); + cookieString.Append(timeStringPreset); +} + +void SetACookieInternal(nsICookieService* aCookieService, const char* aSpec, + const char* aCookieString, bool aAllowed) { + nsCOMPtr<nsIURI> uri; + NS_NewURI(getter_AddRefs(uri), aSpec); + + // We create a dummy channel using the aSpec to simulate same-siteness + nsresult rv0; + nsCOMPtr<nsIScriptSecurityManager> ssm = + do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv0); + ASSERT_NS_SUCCEEDED(rv0); + nsCOMPtr<nsIPrincipal> specPrincipal; + nsCString tmpString(aSpec); + ssm->CreateContentPrincipalFromOrigin(tmpString, + getter_AddRefs(specPrincipal)); + + nsCOMPtr<nsIChannel> dummyChannel; + NS_NewChannel(getter_AddRefs(dummyChannel), uri, specPrincipal, + nsILoadInfo::SEC_ONLY_FOR_EXPLICIT_CONTENTSEC_CHECK, + nsIContentPolicy::TYPE_OTHER); + + nsCOMPtr<nsICookieJarSettings> cookieJarSettings = + aAllowed + ? CookieJarSettings::Create(CookieJarSettings::eRegular, + /* shouldResistFingerprinting */ false) + : CookieJarSettings::GetBlockingAll( + /* shouldResistFingerprinting */ false); + MOZ_ASSERT(cookieJarSettings); + + nsCOMPtr<nsILoadInfo> loadInfo = dummyChannel->LoadInfo(); + loadInfo->SetCookieJarSettings(cookieJarSettings); + + nsresult rv = aCookieService->SetCookieStringFromHttp( + uri, nsDependentCString(aCookieString), dummyChannel); + EXPECT_NS_SUCCEEDED(rv); +} + +void SetACookieJarBlocked(nsICookieService* aCookieService, const char* aSpec, + const char* aCookieString) { + SetACookieInternal(aCookieService, aSpec, aCookieString, false); +} + +void SetACookie(nsICookieService* aCookieService, const char* aSpec, + const char* aCookieString) { + SetACookieInternal(aCookieService, aSpec, aCookieString, true); +} + +// The cookie string is returned via aCookie. +void GetACookie(nsICookieService* aCookieService, const char* aSpec, + nsACString& aCookie) { + nsCOMPtr<nsIURI> uri; + NS_NewURI(getter_AddRefs(uri), aSpec); + + nsCOMPtr<nsIIOService> service = do_GetIOService(); + + nsCOMPtr<nsIChannel> channel; + Unused << service->NewChannelFromURI( + uri, nullptr, nsContentUtils::GetSystemPrincipal(), + nsContentUtils::GetSystemPrincipal(), 0, nsIContentPolicy::TYPE_DOCUMENT, + getter_AddRefs(channel)); + + Unused << aCookieService->GetCookieStringFromHttp(uri, channel, aCookie); +} + +// The cookie string is returned via aCookie. +void GetACookieNoHttp(nsICookieService* aCookieService, const char* aSpec, + nsACString& aCookie) { + nsCOMPtr<nsIURI> uri; + NS_NewURI(getter_AddRefs(uri), aSpec); + + RefPtr<BasePrincipal> principal = + BasePrincipal::CreateContentPrincipal(uri, OriginAttributes()); + MOZ_ASSERT(principal); + + nsCOMPtr<mozilla::dom::Document> document; + nsresult rv = NS_NewDOMDocument(getter_AddRefs(document), + u""_ns, // aNamespaceURI + u""_ns, // aQualifiedName + nullptr, // aDoctype + uri, uri, principal, + false, // aLoadedAsData + nullptr, // aEventObject + DocumentFlavorHTML); + Unused << NS_WARN_IF(NS_FAILED(rv)); + + Unused << aCookieService->GetCookieStringFromDocument(document, aCookie); +} + +// some #defines for comparison rules +#define MUST_BE_NULL 0 +#define MUST_EQUAL 1 +#define MUST_CONTAIN 2 +#define MUST_NOT_CONTAIN 3 +#define MUST_NOT_EQUAL 4 + +// a simple helper function to improve readability: +// takes one of the #defined rules above, and performs the appropriate test. +// true means the test passed; false means the test failed. +static inline bool CheckResult(const char* aLhs, uint32_t aRule, + const char* aRhs = nullptr) { + switch (aRule) { + case MUST_BE_NULL: + return !aLhs || !*aLhs; + + case MUST_EQUAL: + return !PL_strcmp(aLhs, aRhs); + + case MUST_NOT_EQUAL: + return PL_strcmp(aLhs, aRhs); + + case MUST_CONTAIN: + return strstr(aLhs, aRhs) != nullptr; + + case MUST_NOT_CONTAIN: + return strstr(aLhs, aRhs) == nullptr; + + default: + return false; // failure + } +} + +void InitPrefs(nsIPrefBranch* aPrefBranch) { + // init some relevant prefs, so the tests don't go awry. + // we use the most restrictive set of prefs we can; + // however, we don't test third party blocking here. + aPrefBranch->SetIntPref(kCookiesPermissions, 0); // accept all + // Set quotaPerHost to maxPerHost - 1, so there is only one cookie + // will be evicted everytime. + aPrefBranch->SetIntPref(kPrefCookieQuotaPerHost, 49); + // Set the base domain limit to 50 so we have a known value. + aPrefBranch->SetIntPref(kCookiesMaxPerHost, 50); + + // SameSite=None by default. We have other tests for lax-by-default. + // XXX: Bug 1617611 - Fix all the tests broken by "cookies SameSite=Lax by + // default" + Preferences::SetBool("network.cookie.sameSite.laxByDefault", false); + Preferences::SetBool("network.cookieJarSettings.unblocked_for_testing", true); + Preferences::SetBool("dom.securecontext.allowlist_onions", false); + Preferences::SetBool("network.cookie.sameSite.schemeful", false); +} + +TEST(TestCookie, TestCookieMain) +{ + nsresult rv0; + + nsCOMPtr<nsICookieService> cookieService = + do_GetService(kCookieServiceCID, &rv0); + ASSERT_NS_SUCCEEDED(rv0); + + nsCOMPtr<nsIPrefBranch> prefBranch = do_GetService(kPrefServiceCID, &rv0); + ASSERT_NS_SUCCEEDED(rv0); + + InitPrefs(prefBranch); + + nsCString cookie; + + /* The basic idea behind these tests is the following: + * + * we set() some cookie, then try to get() it in various ways. we have + * several possible tests we perform on the cookie string returned from + * get(): + * + * a) check whether the returned string is null (i.e. we got no cookies + * back). this is used e.g. to ensure a given cookie was deleted + * correctly, or to ensure a certain cookie wasn't returned to a given + * host. + * b) check whether the returned string exactly matches a given string. + * this is used where we want to make sure our cookie service adheres to + * some strict spec (e.g. ordering of multiple cookies), or where we + * just know exactly what the returned string should be. + * c) check whether the returned string contains/does not contain a given + * string. this is used where we don't know/don't care about the + * ordering of multiple cookies - we just want to make sure the cookie + * string contains them all, in some order. + * + * NOTE: this testsuite is not yet comprehensive or complete, and is + * somewhat contrived - still under development, and needs improving! + */ + + // test some basic variations of the domain & path + SetACookie(cookieService, "http://www.basic.com", "test=basic"); + GetACookie(cookieService, "http://www.basic.com", cookie); + EXPECT_TRUE(CheckResult(cookie.get(), MUST_EQUAL, "test=basic")); + GetACookie(cookieService, "http://www.basic.com/testPath/testfile.txt", + cookie); + EXPECT_TRUE(CheckResult(cookie.get(), MUST_EQUAL, "test=basic")); + GetACookie(cookieService, "http://www.basic.com./", cookie); + EXPECT_TRUE(CheckResult(cookie.get(), MUST_BE_NULL)); + GetACookie(cookieService, "http://www.basic.com.", cookie); + EXPECT_TRUE(CheckResult(cookie.get(), MUST_BE_NULL)); + GetACookie(cookieService, "http://www.basic.com./testPath/testfile.txt", + cookie); + EXPECT_TRUE(CheckResult(cookie.get(), MUST_BE_NULL)); + GetACookie(cookieService, "http://www.basic2.com/", cookie); + EXPECT_TRUE(CheckResult(cookie.get(), MUST_BE_NULL)); + SetACookie(cookieService, "http://www.basic.com", "test=basic; max-age=-1"); + GetACookie(cookieService, "http://www.basic.com/", cookie); + EXPECT_TRUE(CheckResult(cookie.get(), MUST_BE_NULL)); + + // *** domain tests + + // test some variations of the domain & path, for different domains of + // a domain cookie + SetACookie(cookieService, "http://www.domain.com", + "test=domain; domain=domain.com"); + GetACookie(cookieService, "http://domain.com", cookie); + EXPECT_TRUE(CheckResult(cookie.get(), MUST_EQUAL, "test=domain")); + GetACookie(cookieService, "http://domain.com.", cookie); + EXPECT_TRUE(CheckResult(cookie.get(), MUST_BE_NULL)); + GetACookie(cookieService, "http://www.domain.com", cookie); + EXPECT_TRUE(CheckResult(cookie.get(), MUST_EQUAL, "test=domain")); + GetACookie(cookieService, "http://foo.domain.com", cookie); + EXPECT_TRUE(CheckResult(cookie.get(), MUST_EQUAL, "test=domain")); + SetACookie(cookieService, "http://www.domain.com", + "test=domain; domain=domain.com; max-age=-1"); + GetACookie(cookieService, "http://domain.com", cookie); + EXPECT_TRUE(CheckResult(cookie.get(), MUST_BE_NULL)); + + SetACookie(cookieService, "http://www.domain.com", + "test=domain; domain=.domain.com"); + GetACookie(cookieService, "http://domain.com", cookie); + EXPECT_TRUE(CheckResult(cookie.get(), MUST_EQUAL, "test=domain")); + GetACookie(cookieService, "http://www.domain.com", cookie); + EXPECT_TRUE(CheckResult(cookie.get(), MUST_EQUAL, "test=domain")); + GetACookie(cookieService, "http://bah.domain.com", cookie); + EXPECT_TRUE(CheckResult(cookie.get(), MUST_EQUAL, "test=domain")); + SetACookie(cookieService, "http://www.domain.com", + "test=domain; domain=.domain.com; max-age=-1"); + GetACookie(cookieService, "http://domain.com", cookie); + EXPECT_TRUE(CheckResult(cookie.get(), MUST_BE_NULL)); + + SetACookie(cookieService, "http://www.domain.com", + "test=domain; domain=.foo.domain.com"); + GetACookie(cookieService, "http://foo.domain.com", cookie); + EXPECT_TRUE(CheckResult(cookie.get(), MUST_BE_NULL)); + + SetACookie(cookieService, "http://www.domain.com", + "test=domain; domain=moose.com"); + GetACookie(cookieService, "http://foo.domain.com", cookie); + EXPECT_TRUE(CheckResult(cookie.get(), MUST_BE_NULL)); + + SetACookie(cookieService, "http://www.domain.com", + "test=domain; domain=domain.com."); + GetACookie(cookieService, "http://foo.domain.com", cookie); + EXPECT_TRUE(CheckResult(cookie.get(), MUST_BE_NULL)); + + SetACookie(cookieService, "http://www.domain.com", + "test=domain; domain=..domain.com"); + GetACookie(cookieService, "http://foo.domain.com", cookie); + EXPECT_TRUE(CheckResult(cookie.get(), MUST_BE_NULL)); + + SetACookie(cookieService, "http://www.domain.com", + "test=domain; domain=..domain.com."); + GetACookie(cookieService, "http://foo.domain.com", cookie); + EXPECT_TRUE(CheckResult(cookie.get(), MUST_BE_NULL)); + + SetACookie(cookieService, "http://path.net/path/file", + R"(test=taco; path="/bogus")"); + GetACookie(cookieService, "http://path.net/path/file", cookie); + EXPECT_TRUE(CheckResult(cookie.get(), MUST_EQUAL, "test=taco")); + SetACookie(cookieService, "http://path.net/path/file", + "test=taco; max-age=-1"); + GetACookie(cookieService, "http://path.net/path/file", cookie); + EXPECT_TRUE(CheckResult(cookie.get(), MUST_BE_NULL)); + + // *** path tests + + // test some variations of the domain & path, for different paths of + // a path cookie + SetACookie(cookieService, "http://path.net/path/file", + "test=path; path=/path"); + GetACookie(cookieService, "http://path.net/path", cookie); + EXPECT_TRUE(CheckResult(cookie.get(), MUST_EQUAL, "test=path")); + GetACookie(cookieService, "http://path.net/path/", cookie); + EXPECT_TRUE(CheckResult(cookie.get(), MUST_EQUAL, "test=path")); + GetACookie(cookieService, "http://path.net/path/hithere.foo", cookie); + EXPECT_TRUE(CheckResult(cookie.get(), MUST_EQUAL, "test=path")); + GetACookie(cookieService, "http://path.net/path?hithere/foo", cookie); + EXPECT_TRUE(CheckResult(cookie.get(), MUST_EQUAL, "test=path")); + GetACookie(cookieService, "http://path.net/path2", cookie); + EXPECT_TRUE(CheckResult(cookie.get(), MUST_BE_NULL)); + GetACookie(cookieService, "http://path.net/path2/", cookie); + EXPECT_TRUE(CheckResult(cookie.get(), MUST_BE_NULL)); + SetACookie(cookieService, "http://path.net/path/file", + "test=path; path=/path; max-age=-1"); + GetACookie(cookieService, "http://path.net/path/", cookie); + EXPECT_TRUE(CheckResult(cookie.get(), MUST_BE_NULL)); + + SetACookie(cookieService, "http://path.net/path/file", + "test=path; path=/path/"); + GetACookie(cookieService, "http://path.net/path", cookie); + EXPECT_TRUE(CheckResult(cookie.get(), MUST_BE_NULL)); + GetACookie(cookieService, "http://path.net/path/", cookie); + EXPECT_TRUE(CheckResult(cookie.get(), MUST_EQUAL, "test=path")); + SetACookie(cookieService, "http://path.net/path/file", + "test=path; path=/path/; max-age=-1"); + GetACookie(cookieService, "http://path.net/path/", cookie); + EXPECT_TRUE(CheckResult(cookie.get(), MUST_BE_NULL)); + + // note that a site can set a cookie for a path it's not on. + // this is an intentional deviation from spec (see comments in + // CookieService::CheckPath()), so we test this functionality too + SetACookie(cookieService, "http://path.net/path/file", + "test=path; path=/foo/"); + GetACookie(cookieService, "http://path.net/path", cookie); + EXPECT_TRUE(CheckResult(cookie.get(), MUST_BE_NULL)); + GetACookie(cookieService, "http://path.net/foo", cookie); + EXPECT_TRUE(CheckResult(cookie.get(), MUST_BE_NULL)); + SetACookie(cookieService, "http://path.net/path/file", + "test=path; path=/foo/; max-age=-1"); + GetACookie(cookieService, "http://path.net/foo/", cookie); + EXPECT_TRUE(CheckResult(cookie.get(), MUST_BE_NULL)); + + // bug 373228: make sure cookies with paths longer than 1024 bytes, + // and cookies with paths or names containing tabs, are rejected. + // the following cookie has a path > 1024 bytes explicitly specified in the + // cookie + SetACookie( + cookieService, "http://path.net/", + "test=path; " + "path=/" + "123456789012345678901234567890123456789012345678901234567890123456789012" + "345678901234567890123456789012345678901234567890123456789012345678901234" + "567890123456789012345678901234567890123456789012345678901234567890123456" + "789012345678901234567890123456789012345678901234567890123456789012345678" + "901234567890123456789012345678901234567890123456789012345678901234567890" + "123456789012345678901234567890123456789012345678901234567890123456789012" + "345678901234567890123456789012345678901234567890123456789012345678901234" + "567890123456789012345678901234567890123456789012345678901234567890123456" + "789012345678901234567890123456789012345678901234567890123456789012345678" + "901234567890123456789012345678901234567890123456789012345678901234567890" + "123456789012345678901234567890123456789012345678901234567890123456789012" + "345678901234567890123456789012345678901234567890123456789012345678901234" + "567890123456789012345678901234567890123456789012345678901234567890123456" + "789012345678901234567890123456789012345678901234567890123456789012345678" + "9012345678901234567890/"); + GetACookie( + cookieService, + "http://path.net/" + "123456789012345678901234567890123456789012345678901234567890123456789012" + "345678901234567890123456789012345678901234567890123456789012345678901234" + "567890123456789012345678901234567890123456789012345678901234567890123456" + "789012345678901234567890123456789012345678901234567890123456789012345678" + "901234567890123456789012345678901234567890123456789012345678901234567890" + "123456789012345678901234567890123456789012345678901234567890123456789012" + "345678901234567890123456789012345678901234567890123456789012345678901234" + "567890123456789012345678901234567890123456789012345678901234567890123456" + "789012345678901234567890123456789012345678901234567890123456789012345678" + "901234567890123456789012345678901234567890123456789012345678901234567890" + "123456789012345678901234567890123456789012345678901234567890123456789012" + "345678901234567890123456789012345678901234567890123456789012345678901234" + "567890123456789012345678901234567890123456789012345678901234567890123456" + "789012345678901234567890123456789012345678901234567890123456789012345678" + "9012345678901234567890", + cookie); + EXPECT_TRUE(CheckResult(cookie.get(), MUST_BE_NULL)); + // the following cookie has a path > 1024 bytes implicitly specified by the + // uri path + SetACookie( + cookieService, + "http://path.net/" + "123456789012345678901234567890123456789012345678901234567890123456789012" + "345678901234567890123456789012345678901234567890123456789012345678901234" + "567890123456789012345678901234567890123456789012345678901234567890123456" + "789012345678901234567890123456789012345678901234567890123456789012345678" + "901234567890123456789012345678901234567890123456789012345678901234567890" + "123456789012345678901234567890123456789012345678901234567890123456789012" + "345678901234567890123456789012345678901234567890123456789012345678901234" + "567890123456789012345678901234567890123456789012345678901234567890123456" + "789012345678901234567890123456789012345678901234567890123456789012345678" + "901234567890123456789012345678901234567890123456789012345678901234567890" + "123456789012345678901234567890123456789012345678901234567890123456789012" + "345678901234567890123456789012345678901234567890123456789012345678901234" + "567890123456789012345678901234567890123456789012345678901234567890123456" + "789012345678901234567890123456789012345678901234567890123456789012345678" + "9012345678901234567890/", + "test=path"); + GetACookie( + cookieService, + "http://path.net/" + "123456789012345678901234567890123456789012345678901234567890123456789012" + "345678901234567890123456789012345678901234567890123456789012345678901234" + "567890123456789012345678901234567890123456789012345678901234567890123456" + "789012345678901234567890123456789012345678901234567890123456789012345678" + "901234567890123456789012345678901234567890123456789012345678901234567890" + "123456789012345678901234567890123456789012345678901234567890123456789012" + "345678901234567890123456789012345678901234567890123456789012345678901234" + "567890123456789012345678901234567890123456789012345678901234567890123456" + "789012345678901234567890123456789012345678901234567890123456789012345678" + "901234567890123456789012345678901234567890123456789012345678901234567890" + "123456789012345678901234567890123456789012345678901234567890123456789012" + "345678901234567890123456789012345678901234567890123456789012345678901234" + "567890123456789012345678901234567890123456789012345678901234567890123456" + "789012345678901234567890123456789012345678901234567890123456789012345678" + "9012345678901234567890/", + cookie); + EXPECT_TRUE(CheckResult(cookie.get(), MUST_BE_NULL)); + // the following cookie includes a tab in the path + SetACookie(cookieService, "http://path.net/", "test=path; path=/foo\tbar/"); + GetACookie(cookieService, "http://path.net/foo\tbar/", cookie); + EXPECT_TRUE(CheckResult(cookie.get(), MUST_BE_NULL)); + // the following cookie includes a tab in the name + SetACookie(cookieService, "http://path.net/", "test\ttabs=tab"); + GetACookie(cookieService, "http://path.net/", cookie); + EXPECT_TRUE(CheckResult(cookie.get(), MUST_BE_NULL)); + // the following cookie includes a tab in the value - allowed + SetACookie(cookieService, "http://path.net/", "test=tab\ttest"); + GetACookie(cookieService, "http://path.net/", cookie); + EXPECT_TRUE(CheckResult(cookie.get(), MUST_EQUAL, "test=tab\ttest")); + SetACookie(cookieService, "http://path.net/", "test=tab\ttest; max-age=-1"); + GetACookie(cookieService, "http://path.net/", cookie); + EXPECT_TRUE(CheckResult(cookie.get(), MUST_BE_NULL)); + + // *** expiry & deletion tests + // XXX add server time str parsing tests here + + // test some variations of the expiry time, + // and test deletion of previously set cookies + SetACookie(cookieService, "http://expireme.org/", "test=expiry; max-age=-1"); + GetACookie(cookieService, "http://expireme.org/", cookie); + EXPECT_TRUE(CheckResult(cookie.get(), MUST_BE_NULL)); + SetACookie(cookieService, "http://expireme.org/", "test=expiry; max-age=0"); + GetACookie(cookieService, "http://expireme.org/", cookie); + EXPECT_TRUE(CheckResult(cookie.get(), MUST_BE_NULL)); + SetACookie(cookieService, "http://expireme.org/", "test=expiry; expires=bad"); + GetACookie(cookieService, "http://expireme.org/", cookie); + EXPECT_TRUE(CheckResult(cookie.get(), MUST_EQUAL, "test=expiry")); + SetACookie(cookieService, "http://expireme.org/", + "test=expiry; expires=Thu, 10 Apr 1980 16:33:12 GMT"); + GetACookie(cookieService, "http://expireme.org/", cookie); + EXPECT_TRUE(CheckResult(cookie.get(), MUST_BE_NULL)); + SetACookie(cookieService, "http://expireme.org/", + R"(test=expiry; expires="Thu, 10 Apr 1980 16:33:12 GMT)"); + GetACookie(cookieService, "http://expireme.org/", cookie); + EXPECT_TRUE(CheckResult(cookie.get(), MUST_BE_NULL)); + SetACookie(cookieService, "http://expireme.org/", + R"(test=expiry; expires="Thu, 10 Apr 1980 16:33:12 GMT")"); + GetACookie(cookieService, "http://expireme.org/", cookie); + EXPECT_TRUE(CheckResult(cookie.get(), MUST_BE_NULL)); + + SetACookie(cookieService, "http://expireme.org/", "test=expiry; max-age=60"); + GetACookie(cookieService, "http://expireme.org/", cookie); + EXPECT_TRUE(CheckResult(cookie.get(), MUST_EQUAL, "test=expiry")); + SetACookie(cookieService, "http://expireme.org/", "test=expiry; max-age=-20"); + GetACookie(cookieService, "http://expireme.org/", cookie); + EXPECT_TRUE(CheckResult(cookie.get(), MUST_BE_NULL)); + SetACookie(cookieService, "http://expireme.org/", "test=expiry; max-age=60"); + GetACookie(cookieService, "http://expireme.org/", cookie); + EXPECT_TRUE(CheckResult(cookie.get(), MUST_EQUAL, "test=expiry")); + SetACookie(cookieService, "http://expireme.org/", + "test=expiry; expires=Thu, 10 Apr 1980 16:33:12 GMT"); + GetACookie(cookieService, "http://expireme.org/", cookie); + EXPECT_TRUE(CheckResult(cookie.get(), MUST_BE_NULL)); + SetACookie(cookieService, "http://expireme.org/", "test=expiry; max-age=60"); + SetACookie(cookieService, "http://expireme.org/", + "newtest=expiry; max-age=60"); + GetACookie(cookieService, "http://expireme.org/", cookie); + EXPECT_TRUE(CheckResult(cookie.get(), MUST_CONTAIN, "test=expiry")); + EXPECT_TRUE(CheckResult(cookie.get(), MUST_CONTAIN, "newtest=expiry")); + SetACookie(cookieService, "http://expireme.org/", + "test=differentvalue; max-age=0"); + GetACookie(cookieService, "http://expireme.org/", cookie); + EXPECT_TRUE(CheckResult(cookie.get(), MUST_EQUAL, "newtest=expiry")); + SetACookie(cookieService, "http://expireme.org/", + "newtest=evendifferentvalue; max-age=0"); + GetACookie(cookieService, "http://expireme.org/", cookie); + EXPECT_TRUE(CheckResult(cookie.get(), MUST_BE_NULL)); + + SetACookie(cookieService, "http://foo.expireme.org/", + "test=expiry; domain=.expireme.org; max-age=60"); + GetACookie(cookieService, "http://expireme.org/", cookie); + EXPECT_TRUE(CheckResult(cookie.get(), MUST_EQUAL, "test=expiry")); + SetACookie(cookieService, "http://bar.expireme.org/", + "test=differentvalue; domain=.expireme.org; max-age=0"); + GetACookie(cookieService, "http://expireme.org/", cookie); + EXPECT_TRUE(CheckResult(cookie.get(), MUST_BE_NULL)); + + nsAutoCString ServerTime; + nsAutoCString CookieString; + + // *** multiple cookie tests + + // test the setting of multiple cookies, and test the order of precedence + // (a later cookie overwriting an earlier one, in the same header string) + SetACookie(cookieService, "http://multiple.cookies/", + "test=multiple; domain=.multiple.cookies \n test=different \n " + "test=same; domain=.multiple.cookies \n newtest=ciao \n " + "newtest=foo; max-age=-6 \n newtest=reincarnated"); + GetACookie(cookieService, "http://multiple.cookies/", cookie); + EXPECT_TRUE(CheckResult(cookie.get(), MUST_NOT_CONTAIN, "test=multiple")); + EXPECT_TRUE(CheckResult(cookie.get(), MUST_CONTAIN, "test=different")); + EXPECT_TRUE(CheckResult(cookie.get(), MUST_CONTAIN, "test=same")); + EXPECT_TRUE(CheckResult(cookie.get(), MUST_NOT_CONTAIN, "newtest=ciao")); + EXPECT_TRUE(CheckResult(cookie.get(), MUST_NOT_CONTAIN, "newtest=foo")); + EXPECT_TRUE(CheckResult(cookie.get(), MUST_CONTAIN, "newtest=reincarnated")); + SetACookie(cookieService, "http://multiple.cookies/", + "test=expiry; domain=.multiple.cookies; max-age=0"); + GetACookie(cookieService, "http://multiple.cookies/", cookie); + EXPECT_TRUE(CheckResult(cookie.get(), MUST_NOT_CONTAIN, "test=same")); + SetACookie(cookieService, "http://multiple.cookies/", + "\n test=different; max-age=0 \n"); + GetACookie(cookieService, "http://multiple.cookies/", cookie); + EXPECT_TRUE(CheckResult(cookie.get(), MUST_NOT_CONTAIN, "test=different")); + SetACookie(cookieService, "http://multiple.cookies/", + "newtest=dead; max-age=0"); + GetACookie(cookieService, "http://multiple.cookies/", cookie); + EXPECT_TRUE(CheckResult(cookie.get(), MUST_BE_NULL)); + + // *** parser tests + + // test the cookie header parser, under various circumstances. + SetACookie(cookieService, "http://parser.test/", + "test=parser; domain=.parser.test; ;; ;=; ,,, ===,abc,=; " + "abracadabra! max-age=20;=;;"); + GetACookie(cookieService, "http://parser.test/", cookie); + EXPECT_TRUE(CheckResult(cookie.get(), MUST_EQUAL, "test=parser")); + SetACookie(cookieService, "http://parser.test/", + "test=parser; domain=.parser.test; max-age=0"); + GetACookie(cookieService, "http://parser.test/", cookie); + EXPECT_TRUE(CheckResult(cookie.get(), MUST_BE_NULL)); + SetACookie(cookieService, "http://parser.test/", + "test=\"fubar! = foo;bar\\\";\" parser; domain=.parser.test; " + "max-age=6\nfive; max-age=2.63,"); + GetACookie(cookieService, "http://parser.test/", cookie); + EXPECT_TRUE(CheckResult(cookie.get(), MUST_CONTAIN, R"(test="fubar! = foo)")); + EXPECT_TRUE(CheckResult(cookie.get(), MUST_CONTAIN, "five")); + SetACookie(cookieService, "http://parser.test/", + "test=kill; domain=.parser.test; max-age=0 \n five; max-age=0"); + GetACookie(cookieService, "http://parser.test/", cookie); + EXPECT_TRUE(CheckResult(cookie.get(), MUST_BE_NULL)); + + // test the handling of VALUE-only cookies (see bug 169091), + // i.e. "six" should assume an empty NAME, which allows other VALUE-only + // cookies to overwrite it + SetACookie(cookieService, "http://parser.test/", "six"); + GetACookie(cookieService, "http://parser.test/", cookie); + EXPECT_TRUE(CheckResult(cookie.get(), MUST_EQUAL, "six")); + SetACookie(cookieService, "http://parser.test/", "seven"); + GetACookie(cookieService, "http://parser.test/", cookie); + EXPECT_TRUE(CheckResult(cookie.get(), MUST_EQUAL, "seven")); + SetACookie(cookieService, "http://parser.test/", " =eight"); + GetACookie(cookieService, "http://parser.test/", cookie); + EXPECT_TRUE(CheckResult(cookie.get(), MUST_EQUAL, "eight")); + SetACookie(cookieService, "http://parser.test/", "test=six"); + GetACookie(cookieService, "http://parser.test/", cookie); + EXPECT_TRUE(CheckResult(cookie.get(), MUST_CONTAIN, "test=six")); + + // *** path ordering tests + + // test that cookies are returned in path order - longest to shortest. + // if the header doesn't specify a path, it's taken from the host URI. + SetACookie(cookieService, "http://multi.path.tests/", + "test1=path; path=/one/two/three"); + SetACookie(cookieService, "http://multi.path.tests/", + "test2=path; path=/one \n test3=path; path=/one/two/three/four \n " + "test4=path; path=/one/two \n test5=path; path=/one/two/"); + SetACookie(cookieService, "http://multi.path.tests/one/two/three/four/five/", + "test6=path"); + SetACookie(cookieService, + "http://multi.path.tests/one/two/three/four/five/six/", + "test7=path; path="); + SetACookie(cookieService, "http://multi.path.tests/", "test8=path; path=/"); + GetACookie(cookieService, + "http://multi.path.tests/one/two/three/four/five/six/", cookie); + EXPECT_TRUE(CheckResult(cookie.get(), MUST_EQUAL, + "test7=path; test6=path; test3=path; test1=path; " + "test5=path; test4=path; test2=path; test8=path")); + + // *** Cookie prefix tests + + // prefixed cookies can't be set from insecure HTTP + SetACookie(cookieService, "http://prefixed.test/", "__Secure-test1=test"); + SetACookie(cookieService, "http://prefixed.test/", + "__Secure-test2=test; secure"); + SetACookie(cookieService, "http://prefixed.test/", "__Host-test1=test"); + SetACookie(cookieService, "http://prefixed.test/", + "__Host-test2=test; secure"); + GetACookie(cookieService, "http://prefixed.test/", cookie); + EXPECT_TRUE(CheckResult(cookie.get(), MUST_BE_NULL)); + + // prefixed cookies won't be set without the secure flag + SetACookie(cookieService, "https://prefixed.test/", "__Secure-test=test"); + SetACookie(cookieService, "https://prefixed.test/", "__Host-test=test"); + GetACookie(cookieService, "https://prefixed.test/", cookie); + EXPECT_TRUE(CheckResult(cookie.get(), MUST_BE_NULL)); + + // prefixed cookies can be set when done correctly + SetACookie(cookieService, "https://prefixed.test/", + "__Secure-test=test; secure"); + SetACookie(cookieService, "https://prefixed.test/", + "__Host-test=test; secure"); + GetACookie(cookieService, "https://prefixed.test/", cookie); + EXPECT_TRUE(CheckResult(cookie.get(), MUST_CONTAIN, "__Secure-test=test")); + EXPECT_TRUE(CheckResult(cookie.get(), MUST_CONTAIN, "__Host-test=test")); + + // but when set must not be returned to the host insecurely + GetACookie(cookieService, "http://prefixed.test/", cookie); + EXPECT_TRUE(CheckResult(cookie.get(), MUST_BE_NULL)); + + // Host-prefixed cookies cannot specify a domain + SetACookie(cookieService, "https://host.prefixed.test/", + "__Host-a=test; secure; domain=prefixed.test"); + SetACookie(cookieService, "https://host.prefixed.test/", + "__Host-b=test; secure; domain=.prefixed.test"); + SetACookie(cookieService, "https://host.prefixed.test/", + "__Host-c=test; secure; domain=host.prefixed.test"); + SetACookie(cookieService, "https://host.prefixed.test/", + "__Host-d=test; secure; domain=.host.prefixed.test"); + GetACookie(cookieService, "https://host.prefixed.test/", cookie); + EXPECT_TRUE(CheckResult(cookie.get(), MUST_BE_NULL)); + + // Host-prefixed cookies can only have a path of "/" + SetACookie(cookieService, "https://host.prefixed.test/some/path", + "__Host-e=test; secure"); + SetACookie(cookieService, "https://host.prefixed.test/some/path", + "__Host-f=test; secure; path=/"); + SetACookie(cookieService, "https://host.prefixed.test/some/path", + "__Host-g=test; secure; path=/some"); + GetACookie(cookieService, "https://host.prefixed.test/", cookie); + EXPECT_TRUE(CheckResult(cookie.get(), MUST_EQUAL, "__Host-f=test")); + + // *** leave-secure-alone tests + + // testing items 0 & 1 for 3.1 of spec Deprecate modification of ’secure’ + // cookies from non-secure origins + SetACookie(cookieService, "http://www.security.test/", + "test=non-security; secure"); + GetACookieNoHttp(cookieService, "https://www.security.test/", cookie); + EXPECT_TRUE(CheckResult(cookie.get(), MUST_BE_NULL)); + SetACookie(cookieService, "https://www.security.test/path/", + "test=security; secure; path=/path/"); + GetACookieNoHttp(cookieService, "https://www.security.test/path/", cookie); + EXPECT_TRUE(CheckResult(cookie.get(), MUST_EQUAL, "test=security")); + // testing items 2 & 3 & 4 for 3.2 of spec Deprecate modification of ’secure’ + // cookies from non-secure origins + // Secure site can modify cookie value + SetACookie(cookieService, "https://www.security.test/path/", + "test=security2; secure; path=/path/"); + GetACookieNoHttp(cookieService, "https://www.security.test/path/", cookie); + EXPECT_TRUE(CheckResult(cookie.get(), MUST_EQUAL, "test=security2")); + // If new cookie contains same name, same host and partially matching path + // with an existing security cookie on non-security site, it can't modify an + // existing security cookie. + SetACookie(cookieService, "http://www.security.test/path/foo/", + "test=non-security; path=/path/foo"); + GetACookieNoHttp(cookieService, "https://www.security.test/path/foo/", + cookie); + EXPECT_TRUE(CheckResult(cookie.get(), MUST_EQUAL, "test=security2")); + // Non-secure cookie can set by same name, same host and non-matching path. + SetACookie(cookieService, "http://www.security.test/bar/", + "test=non-security; path=/bar"); + GetACookieNoHttp(cookieService, "http://www.security.test/bar/", cookie); + EXPECT_TRUE(CheckResult(cookie.get(), MUST_EQUAL, "test=non-security")); + // Modify value and downgrade secure level. + SetACookie( + cookieService, "https://www.security.test/", + "test_modify_cookie=security-cookie; secure; domain=.security.test"); + GetACookieNoHttp(cookieService, "https://www.security.test/", cookie); + EXPECT_TRUE(CheckResult(cookie.get(), MUST_EQUAL, + "test_modify_cookie=security-cookie")); + SetACookie(cookieService, "https://www.security.test/", + "test_modify_cookie=non-security-cookie; domain=.security.test"); + GetACookieNoHttp(cookieService, "https://www.security.test/", cookie); + EXPECT_TRUE(CheckResult(cookie.get(), MUST_EQUAL, + "test_modify_cookie=non-security-cookie")); + + // Test the non-security cookie can set when domain or path not same to secure + // cookie of same name. + SetACookie(cookieService, "https://www.security.test/", "test=security3"); + GetACookieNoHttp(cookieService, "http://www.security.test/", cookie); + EXPECT_TRUE(CheckResult(cookie.get(), MUST_CONTAIN, "test=security3")); + SetACookie(cookieService, "http://www.security.test/", + "test=non-security2; domain=security.test"); + GetACookieNoHttp(cookieService, "http://www.security.test/", cookie); + EXPECT_TRUE(CheckResult(cookie.get(), MUST_CONTAIN, "test=non-security2")); + + // *** nsICookieManager interface tests + nsCOMPtr<nsICookieManager> cookieMgr = + do_GetService(NS_COOKIEMANAGER_CONTRACTID, &rv0); + ASSERT_NS_SUCCEEDED(rv0); + + const nsCOMPtr<nsICookieManager>& cookieMgr2 = cookieMgr; + ASSERT_TRUE(cookieMgr2); + + mozilla::OriginAttributes attrs; + + // first, ensure a clean slate + EXPECT_NS_SUCCEEDED(cookieMgr->RemoveAll()); + // add some cookies + EXPECT_TRUE(NS_SUCCEEDED(cookieMgr2->AddNative("cookiemgr.test"_ns, // domain + "/foo"_ns, // path + "test1"_ns, // name + "yes"_ns, // value + false, // is secure + false, // is httponly + true, // is session + INT64_MAX, // expiry time + &attrs, // originAttributes + nsICookie::SAMESITE_NONE, + nsICookie::SCHEME_HTTPS))); + EXPECT_TRUE(NS_SUCCEEDED(cookieMgr2->AddNative( + "cookiemgr.test"_ns, // domain + "/foo"_ns, // path + "test2"_ns, // name + "yes"_ns, // value + false, // is secure + true, // is httponly + true, // is session + PR_Now() / PR_USEC_PER_SEC + 2, // expiry time + &attrs, // originAttributes + nsICookie::SAMESITE_NONE, nsICookie::SCHEME_HTTPS))); + EXPECT_TRUE(NS_SUCCEEDED(cookieMgr2->AddNative("new.domain"_ns, // domain + "/rabbit"_ns, // path + "test3"_ns, // name + "yes"_ns, // value + false, // is secure + false, // is httponly + true, // is session + INT64_MAX, // expiry time + &attrs, // originAttributes + nsICookie::SAMESITE_NONE, + nsICookie::SCHEME_HTTPS))); + // confirm using enumerator + nsTArray<RefPtr<nsICookie>> cookies; + EXPECT_NS_SUCCEEDED(cookieMgr->GetCookies(cookies)); + nsCOMPtr<nsICookie> expiredCookie, newDomainCookie; + for (const auto& cookie : cookies) { + nsAutoCString name; + cookie->GetName(name); + if (name.EqualsLiteral("test2")) { + expiredCookie = cookie; + } else if (name.EqualsLiteral("test3")) { + newDomainCookie = cookie; + } + } + EXPECT_EQ(cookies.Length(), 3ul); + // check the httpOnly attribute of the second cookie is honored + GetACookie(cookieService, "http://cookiemgr.test/foo/", cookie); + EXPECT_TRUE(CheckResult(cookie.get(), MUST_CONTAIN, "test2=yes")); + GetACookieNoHttp(cookieService, "http://cookiemgr.test/foo/", cookie); + EXPECT_TRUE(CheckResult(cookie.get(), MUST_NOT_CONTAIN, "test2=yes")); + // check CountCookiesFromHost() + uint32_t hostCookies = 0; + EXPECT_TRUE(NS_SUCCEEDED( + cookieMgr2->CountCookiesFromHost("cookiemgr.test"_ns, &hostCookies))); + EXPECT_EQ(hostCookies, 2u); + // check CookieExistsNative() using the third cookie + bool found; + EXPECT_TRUE(NS_SUCCEEDED(cookieMgr2->CookieExistsNative( + "new.domain"_ns, "/rabbit"_ns, "test3"_ns, &attrs, &found))); + EXPECT_TRUE(found); + + // sleep four seconds, to make sure the second cookie has expired + PR_Sleep(4 * PR_TicksPerSecond()); + // check that both CountCookiesFromHost() and CookieExistsNative() count the + // expired cookie + EXPECT_TRUE(NS_SUCCEEDED( + cookieMgr2->CountCookiesFromHost("cookiemgr.test"_ns, &hostCookies))); + EXPECT_EQ(hostCookies, 2u); + EXPECT_TRUE(NS_SUCCEEDED(cookieMgr2->CookieExistsNative( + "cookiemgr.test"_ns, "/foo"_ns, "test2"_ns, &attrs, &found))); + EXPECT_TRUE(found); + // double-check RemoveAll() using the enumerator + EXPECT_NS_SUCCEEDED(cookieMgr->RemoveAll()); + cookies.SetLength(0); + EXPECT_TRUE(NS_SUCCEEDED(cookieMgr->GetCookies(cookies)) && + cookies.IsEmpty()); + + // *** eviction and creation ordering tests + + // test that cookies are + // a) returned by order of creation time (oldest first, newest last) + // b) evicted by order of lastAccessed time, if the limit on cookies per host + // (50) is reached + nsAutoCString name; + nsAutoCString expected; + for (int32_t i = 0; i < 60; ++i) { + name = "test"_ns; + name.AppendInt(i); + name += "=creation"_ns; + SetACookie(cookieService, "http://creation.ordering.tests/", name.get()); + + if (i >= 10) { + expected += name; + if (i < 59) expected += "; "_ns; + } + } + GetACookie(cookieService, "http://creation.ordering.tests/", cookie); + EXPECT_TRUE(CheckResult(cookie.get(), MUST_EQUAL, expected.get())); + + cookieMgr->RemoveAll(); + + for (int32_t i = 0; i < 60; ++i) { + name = "test"_ns; + name.AppendInt(i); + name += "=delete_non_security"_ns; + + // Create 50 cookies that include the secure flag. + if (i < 50) { + name += "; secure"_ns; + SetACookie(cookieService, "https://creation.ordering.tests/", name.get()); + } else { + // non-security cookies will be removed beside the latest cookie that be + // created. + SetACookie(cookieService, "http://creation.ordering.tests/", name.get()); + } + } + GetACookie(cookieService, "http://creation.ordering.tests/", cookie); + + EXPECT_TRUE(CheckResult(cookie.get(), MUST_BE_NULL)); + + // *** SameSite attribute - parsing and cookie storage tests + // Clear the cookies + EXPECT_NS_SUCCEEDED(cookieMgr->RemoveAll()); + + // None of these cookies will be set because using + // CookieJarSettings::GetBlockingAll(). + SetACookieJarBlocked(cookieService, "http://samesite.test", "unset=yes"); + SetACookieJarBlocked(cookieService, "http://samesite.test", + "unspecified=yes; samesite"); + SetACookieJarBlocked(cookieService, "http://samesite.test", + "empty=yes; samesite="); + SetACookieJarBlocked(cookieService, "http://samesite.test", + "bogus=yes; samesite=bogus"); + SetACookieJarBlocked(cookieService, "http://samesite.test", + "strict=yes; samesite=strict"); + SetACookieJarBlocked(cookieService, "http://samesite.test", + "lax=yes; samesite=lax"); + + cookies.SetLength(0); + EXPECT_NS_SUCCEEDED(cookieMgr->GetCookies(cookies)); + + EXPECT_TRUE(cookies.IsEmpty()); + + // Set cookies with various incantations of the samesite attribute: + // No same site attribute present + SetACookie(cookieService, "http://samesite.test", "unset=yes"); + // samesite attribute present but with no value + SetACookie(cookieService, "http://samesite.test", + "unspecified=yes; samesite"); + // samesite attribute present but with an empty value + SetACookie(cookieService, "http://samesite.test", "empty=yes; samesite="); + // samesite attribute present but with an invalid value + SetACookie(cookieService, "http://samesite.test", + "bogus=yes; samesite=bogus"); + // samesite=strict + SetACookie(cookieService, "http://samesite.test", + "strict=yes; samesite=strict"); + // samesite=lax + SetACookie(cookieService, "http://samesite.test", "lax=yes; samesite=lax"); + + cookies.SetLength(0); + EXPECT_NS_SUCCEEDED(cookieMgr->GetCookies(cookies)); + + // check the cookies for the required samesite value + for (const auto& cookie : cookies) { + nsAutoCString name; + cookie->GetName(name); + int32_t sameSiteAttr; + cookie->GetSameSite(&sameSiteAttr); + if (name.EqualsLiteral("unset")) { + EXPECT_TRUE(sameSiteAttr == nsICookie::SAMESITE_NONE); + } else if (name.EqualsLiteral("unspecified")) { + EXPECT_TRUE(sameSiteAttr == nsICookie::SAMESITE_NONE); + } else if (name.EqualsLiteral("empty")) { + EXPECT_TRUE(sameSiteAttr == nsICookie::SAMESITE_NONE); + } else if (name.EqualsLiteral("bogus")) { + EXPECT_TRUE(sameSiteAttr == nsICookie::SAMESITE_NONE); + } else if (name.EqualsLiteral("strict")) { + EXPECT_TRUE(sameSiteAttr == nsICookie::SAMESITE_STRICT); + } else if (name.EqualsLiteral("lax")) { + EXPECT_TRUE(sameSiteAttr == nsICookie::SAMESITE_LAX); + } + } + + EXPECT_TRUE(cookies.Length() == 6); + + // *** SameSite attribute + // Clear the cookies + EXPECT_NS_SUCCEEDED(cookieMgr->RemoveAll()); + + // please note that the flag aForeign is always set to true using this test + // setup because no nsIChannel is passed to SetCookieString(). therefore we + // can only test that no cookies are sent for cross origin requests using + // same-site cookies. + SetACookie(cookieService, "http://www.samesite.com", + "test=sameSiteStrictVal; samesite=strict"); + GetACookie(cookieService, "http://www.notsamesite.com", cookie); + EXPECT_TRUE(CheckResult(cookie.get(), MUST_BE_NULL)); + + SetACookie(cookieService, "http://www.samesite.test", + "test=sameSiteLaxVal; samesite=lax"); + GetACookie(cookieService, "http://www.notsamesite.com", cookie); + EXPECT_TRUE(CheckResult(cookie.get(), MUST_BE_NULL)); + + static const char* secureURIs[] = { + "http://localhost", "http://localhost:1234", "http://127.0.0.1", + "http://127.0.0.2", "http://127.1.0.1", "http://[::1]", + // TODO bug 1220810 "http://xyzzy.localhost" + }; + + uint32_t numSecureURIs = sizeof(secureURIs) / sizeof(const char*); + for (uint32_t i = 0; i < numSecureURIs; ++i) { + SetACookie(cookieService, secureURIs[i], "test=basic; secure"); + GetACookie(cookieService, secureURIs[i], cookie); + EXPECT_TRUE(CheckResult(cookie.get(), MUST_EQUAL, "test=basic")); + SetACookie(cookieService, secureURIs[i], "test=basic1"); + GetACookie(cookieService, secureURIs[i], cookie); + EXPECT_TRUE(CheckResult(cookie.get(), MUST_EQUAL, "test=basic1")); + } + + // XXX the following are placeholders: add these tests please! + // *** "noncompliant cookie" tests + // *** IP address tests + // *** speed tests +} + +TEST(TestCookie, SameSiteLax) +{ + Preferences::SetBool("network.cookie.sameSite.laxByDefault", true); + + nsresult rv; + + nsCOMPtr<nsICookieService> cookieService = + do_GetService(kCookieServiceCID, &rv); + ASSERT_NS_SUCCEEDED(rv); + + nsCOMPtr<nsICookieManager> cookieMgr = + do_GetService(NS_COOKIEMANAGER_CONTRACTID, &rv); + ASSERT_NS_SUCCEEDED(rv); + + EXPECT_NS_SUCCEEDED(cookieMgr->RemoveAll()); + + SetACookie(cookieService, "http://samesite.test", "unset=yes"); + + nsTArray<RefPtr<nsICookie>> cookies; + EXPECT_NS_SUCCEEDED(cookieMgr->GetCookies(cookies)); + EXPECT_EQ(cookies.Length(), (uint64_t)1); + + Cookie* cookie = static_cast<Cookie*>(cookies[0].get()); + EXPECT_EQ(cookie->RawSameSite(), nsICookie::SAMESITE_NONE); + EXPECT_EQ(cookie->SameSite(), nsICookie::SAMESITE_LAX); + + Preferences::SetCString("network.cookie.sameSite.laxByDefault.disabledHosts", + "foo.com,samesite.test,bar.net"); + + EXPECT_NS_SUCCEEDED(cookieMgr->RemoveAll()); + + cookies.SetLength(0); + EXPECT_NS_SUCCEEDED(cookieMgr->GetCookies(cookies)); + EXPECT_EQ(cookies.Length(), (uint64_t)0); + + SetACookie(cookieService, "http://samesite.test", "unset=yes"); + + cookies.SetLength(0); + EXPECT_NS_SUCCEEDED(cookieMgr->GetCookies(cookies)); + EXPECT_EQ(cookies.Length(), (uint64_t)1); + + cookie = static_cast<Cookie*>(cookies[0].get()); + EXPECT_EQ(cookie->RawSameSite(), nsICookie::SAMESITE_NONE); + EXPECT_EQ(cookie->SameSite(), nsICookie::SAMESITE_LAX); +} + +TEST(TestCookie, OnionSite) +{ + Preferences::SetBool("dom.securecontext.allowlist_onions", true); + Preferences::SetBool("network.cookie.sameSite.laxByDefault", false); + + nsresult rv; + nsCString cookie; + + nsCOMPtr<nsICookieService> cookieService = + do_GetService(kCookieServiceCID, &rv); + ASSERT_NS_SUCCEEDED(rv); + + // .onion secure cookie tests + SetACookie(cookieService, "http://123456789abcdef.onion/", + "test=onion-security; secure"); + GetACookieNoHttp(cookieService, "https://123456789abcdef.onion/", cookie); + EXPECT_TRUE(CheckResult(cookie.get(), MUST_EQUAL, "test=onion-security")); + SetACookie(cookieService, "http://123456789abcdef.onion/", + "test=onion-security2; secure"); + GetACookieNoHttp(cookieService, "http://123456789abcdef.onion/", cookie); + EXPECT_TRUE(CheckResult(cookie.get(), MUST_EQUAL, "test=onion-security2")); + SetACookie(cookieService, "https://123456789abcdef.onion/", + "test=onion-security3; secure"); + GetACookieNoHttp(cookieService, "http://123456789abcdef.onion/", cookie); + EXPECT_TRUE(CheckResult(cookie.get(), MUST_EQUAL, "test=onion-security3")); + SetACookie(cookieService, "http://123456789abcdef.onion/", + "test=onion-security4"); + GetACookieNoHttp(cookieService, "http://123456789abcdef.onion/", cookie); + EXPECT_TRUE(CheckResult(cookie.get(), MUST_EQUAL, "test=onion-security4")); +} + +TEST(TestCookie, HiddenPrefix) +{ + nsresult rv; + nsCString cookie; + + nsCOMPtr<nsICookieService> cookieService = + do_GetService(kCookieServiceCID, &rv); + ASSERT_NS_SUCCEEDED(rv); + + SetACookie(cookieService, "http://hiddenprefix.test/", "=__Host-test=a"); + GetACookie(cookieService, "http://hiddenprefix.test/", cookie); + EXPECT_TRUE(CheckResult(cookie.get(), MUST_BE_NULL)); + + SetACookie(cookieService, "http://hiddenprefix.test/", "=__Secure-test=a"); + GetACookie(cookieService, "http://hiddenprefix.test/", cookie); + EXPECT_TRUE(CheckResult(cookie.get(), MUST_BE_NULL)); + + SetACookie(cookieService, "http://hiddenprefix.test/", "=__Host-check"); + GetACookie(cookieService, "http://hiddenprefix.test/", cookie); + EXPECT_TRUE(CheckResult(cookie.get(), MUST_BE_NULL)); + + SetACookie(cookieService, "http://hiddenprefix.test/", "=__Secure-check"); + GetACookie(cookieService, "http://hiddenprefix.test/", cookie); + EXPECT_TRUE(CheckResult(cookie.get(), MUST_BE_NULL)); +} + +TEST(TestCookie, BlockUnicode) +{ + Preferences::SetBool("network.cookie.blockUnicode", true); + + nsresult rv; + nsCString cookie; + + nsCOMPtr<nsICookieService> cookieService = + do_GetService(kCookieServiceCID, &rv); + ASSERT_NS_SUCCEEDED(rv); + + SetACookie(cookieService, "http://unicode.com/", "name=🍪"); + GetACookie(cookieService, "http://unicode.com/", cookie); + EXPECT_TRUE(CheckResult(cookie.get(), MUST_BE_NULL)); + + SetACookie(cookieService, "http://unicode.com/", "🍪=value"); + GetACookie(cookieService, "http://unicode.com/", cookie); + EXPECT_TRUE(CheckResult(cookie.get(), MUST_BE_NULL)); + + Preferences::SetBool("network.cookie.blockUnicode", false); + + SetACookie(cookieService, "http://unicode.com/", "name=🍪"); + GetACookie(cookieService, "http://unicode.com/", cookie); + EXPECT_TRUE(CheckResult(cookie.get(), MUST_EQUAL, "name=🍪")); + + nsCOMPtr<nsICookieManager> cookieMgr = + do_GetService(NS_COOKIEMANAGER_CONTRACTID); + EXPECT_NS_SUCCEEDED(cookieMgr->RemoveAll()); + + SetACookie(cookieService, "http://unicode.com/", "🍪=value"); + GetACookie(cookieService, "http://unicode.com/", cookie); + EXPECT_TRUE(CheckResult(cookie.get(), MUST_EQUAL, "🍪=value")); + + EXPECT_NS_SUCCEEDED(cookieMgr->RemoveAll()); + Preferences::ClearUser("network.cookie.blockUnicode"); +} |