1/*
2 * Copyright (C) 2012-2018 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23 * THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include "config.h"
27#include "CookieJar.h"
28
29#include "CookieRequestHeaderFieldProxy.h"
30#include "Document.h"
31#include "DocumentLoader.h"
32#include "Frame.h"
33#include "FrameLoader.h"
34#include "FrameLoaderClient.h"
35#include "NetworkStorageSession.h"
36#include "NetworkingContext.h"
37#include "PlatformStrategies.h"
38#include "SameSiteInfo.h"
39#include "StorageSessionProvider.h"
40#include <wtf/SystemTracing.h>
41
42namespace WebCore {
43
44Ref<CookieJar> CookieJar::create(Ref<StorageSessionProvider>&& storageSessionProvider)
45{
46 return adoptRef(*new CookieJar(WTFMove(storageSessionProvider)));
47}
48
49IncludeSecureCookies CookieJar::shouldIncludeSecureCookies(const Document& document, const URL& url)
50{
51 return (url.protocolIs("https") && !document.foundMixedContent().contains(SecurityContext::MixedContentType::Active)) ? IncludeSecureCookies::Yes : IncludeSecureCookies::No;
52}
53
54SameSiteInfo CookieJar::sameSiteInfo(const Document& document)
55{
56 if (auto* loader = document.loader())
57 return SameSiteInfo::create(loader->request());
58 return { };
59}
60
61CookieJar::CookieJar(Ref<StorageSessionProvider>&& storageSessionProvider)
62 : m_storageSessionProvider(WTFMove(storageSessionProvider))
63{
64}
65
66CookieJar::~CookieJar() = default;
67
68String CookieJar::cookies(Document& document, const URL& url) const
69{
70 TraceScope scope(FetchCookiesStart, FetchCookiesEnd);
71
72 auto includeSecureCookies = shouldIncludeSecureCookies(document, url);
73
74 Optional<uint64_t> frameID;
75 Optional<uint64_t> pageID;
76 if (auto* frame = document.frame()) {
77 frameID = frame->loader().client().frameID();
78 pageID = frame->loader().client().pageID();
79 }
80
81 std::pair<String, bool> result;
82 if (auto* session = m_storageSessionProvider->storageSession())
83 result = session->cookiesForDOM(document.firstPartyForCookies(), sameSiteInfo(document), url, frameID, pageID, includeSecureCookies);
84 else
85 ASSERT_NOT_REACHED();
86
87 if (result.second)
88 document.setSecureCookiesAccessed();
89
90 return result.first;
91}
92
93CookieRequestHeaderFieldProxy CookieJar::cookieRequestHeaderFieldProxy(const Document& document, const URL& url)
94{
95 TraceScope scope(FetchCookiesStart, FetchCookiesEnd);
96
97 CookieRequestHeaderFieldProxy proxy;
98 proxy.sessionID = document.sessionID();
99 proxy.firstParty = document.firstPartyForCookies();
100 proxy.sameSiteInfo = sameSiteInfo(document);
101 proxy.url = url;
102 proxy.includeSecureCookies = shouldIncludeSecureCookies(document, url);
103 if (auto* frame = document.frame()) {
104 proxy.frameID = frame->loader().client().frameID();
105 proxy.pageID = frame->loader().client().pageID();
106 }
107 return proxy;
108}
109
110void CookieJar::setCookies(Document& document, const URL& url, const String& cookieString)
111{
112 Optional<uint64_t> frameID;
113 Optional<uint64_t> pageID;
114 if (auto* frame = document.frame()) {
115 frameID = frame->loader().client().frameID();
116 pageID = frame->loader().client().pageID();
117 }
118
119 if (auto* session = m_storageSessionProvider->storageSession())
120 session->setCookiesFromDOM(document.firstPartyForCookies(), sameSiteInfo(document), url, frameID, pageID, cookieString);
121 else
122 ASSERT_NOT_REACHED();
123}
124
125bool CookieJar::cookiesEnabled(const Document&) const
126{
127 if (auto* session = m_storageSessionProvider->storageSession())
128 return session->cookiesEnabled();
129
130 ASSERT_NOT_REACHED();
131 return false;
132}
133
134std::pair<String, SecureCookiesAccessed> CookieJar::cookieRequestHeaderFieldValue(const PAL::SessionID&, const URL& firstParty, const SameSiteInfo& sameSiteInfo, const URL& url, Optional<uint64_t> frameID, Optional<uint64_t> pageID, IncludeSecureCookies includeSecureCookies) const
135{
136 if (auto* session = m_storageSessionProvider->storageSession()) {
137 std::pair<String, bool> result = session->cookieRequestHeaderFieldValue(firstParty, sameSiteInfo, url, frameID, pageID, includeSecureCookies);
138 return { result.first, result.second ? SecureCookiesAccessed::Yes : SecureCookiesAccessed::No };
139 }
140
141 ASSERT_NOT_REACHED();
142 return { };
143}
144
145String CookieJar::cookieRequestHeaderFieldValue(Document& document, const URL& url) const
146{
147 Optional<uint64_t> frameID;
148 Optional<uint64_t> pageID;
149 if (auto* frame = document.frame()) {
150 frameID = frame->loader().client().frameID();
151 pageID = frame->loader().client().pageID();
152 }
153
154 auto result = cookieRequestHeaderFieldValue(document.sessionID(), document.firstPartyForCookies(), sameSiteInfo(document), url, frameID, pageID, shouldIncludeSecureCookies(document, url));
155 if (result.second == SecureCookiesAccessed::Yes)
156 document.setSecureCookiesAccessed();
157 return result.first;
158}
159
160bool CookieJar::getRawCookies(const Document& document, const URL& url, Vector<Cookie>& cookies) const
161{
162 Optional<uint64_t> frameID;
163 Optional<uint64_t> pageID;
164 if (auto* frame = document.frame()) {
165 frameID = frame->loader().client().frameID();
166 pageID = frame->loader().client().pageID();
167 }
168
169 if (auto* session = m_storageSessionProvider->storageSession())
170 return session->getRawCookies(document.firstPartyForCookies(), sameSiteInfo(document), url, frameID, pageID, cookies);
171
172 ASSERT_NOT_REACHED();
173 return false;
174}
175
176void CookieJar::deleteCookie(const Document&, const URL& url, const String& cookieName)
177{
178 if (auto* session = m_storageSessionProvider->storageSession())
179 session->deleteCookie(url, cookieName);
180 else
181 ASSERT_NOT_REACHED();
182}
183
184}
185