Resource Load Statistics: More efficient network process messaging + Fix bug in user...
[WebKit-https.git] / Source / WebCore / platform / network / cf / NetworkStorageSessionCFNet.cpp
1 /*
2  * Copyright (C) 2012 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 "NetworkStorageSession.h"
28
29 #include <wtf/MainThread.h>
30 #include <wtf/NeverDestroyed.h>
31 #include <wtf/ProcessID.h>
32
33 #if PLATFORM(COCOA)
34 #include "PublicSuffix.h"
35 #include "ResourceRequest.h"
36 #include "WebCoreSystemInterface.h"
37 #else
38 #include <WebKitSystemInterface/WebKitSystemInterface.h>
39 #endif
40
41 // FIXME: This file is mostly Cocoa code, not CFNetwork code. This code should be moved.
42
43 namespace WebCore {
44
45 static bool cookieStoragePartitioningEnabled;
46
47 NetworkStorageSession::NetworkStorageSession(SessionID sessionID, RetainPtr<CFURLStorageSessionRef> platformSession)
48     : m_sessionID(sessionID)
49     , m_platformSession(platformSession)
50 {
51 }
52
53 static std::unique_ptr<NetworkStorageSession>& defaultNetworkStorageSession()
54 {
55     ASSERT(isMainThread());
56     static NeverDestroyed<std::unique_ptr<NetworkStorageSession>> session;
57     return session;
58 }
59
60 void NetworkStorageSession::switchToNewTestingSession()
61 {
62     // Session name should be short enough for shared memory region name to be under the limit, otehrwise sandbox rules won't work (see <rdar://problem/13642852>).
63     String sessionName = String::format("WebKit Test-%u", static_cast<uint32_t>(getCurrentProcessID()));
64 #if PLATFORM(COCOA)
65     defaultNetworkStorageSession() = std::make_unique<NetworkStorageSession>(SessionID::defaultSessionID(), adoptCF(wkCreatePrivateStorageSession(sessionName.createCFString().get())));
66 #else
67     defaultNetworkStorageSession() = std::make_unique<NetworkStorageSession>(SessionID::defaultSessionID(), adoptCF(wkCreatePrivateStorageSession(sessionName.createCFString().get(), defaultNetworkStorageSession()->platformSession())));
68 #endif
69 }
70
71 NetworkStorageSession& NetworkStorageSession::defaultStorageSession()
72 {
73     if (!defaultNetworkStorageSession())
74         defaultNetworkStorageSession() = std::make_unique<NetworkStorageSession>(SessionID::defaultSessionID(), nullptr);
75     return *defaultNetworkStorageSession();
76 }
77
78 void NetworkStorageSession::ensurePrivateBrowsingSession(SessionID sessionID, const String& identifierBase)
79 {
80     if (globalSessionMap().contains(sessionID))
81         return;
82     RetainPtr<CFStringRef> cfIdentifier = String(identifierBase + ".PrivateBrowsing").createCFString();
83
84 #if PLATFORM(COCOA)
85     auto session = std::make_unique<NetworkStorageSession>(sessionID, adoptCF(wkCreatePrivateStorageSession(cfIdentifier.get())));
86 #else
87     auto session = std::make_unique<NetworkStorageSession>(sessionID, adoptCF(wkCreatePrivateStorageSession(cfIdentifier.get(), defaultNetworkStorageSession()->platformSession())));
88 #endif
89
90     globalSessionMap().add(sessionID, WTFMove(session));
91 }
92
93 RetainPtr<CFHTTPCookieStorageRef> NetworkStorageSession::cookieStorage() const
94 {
95     if (m_platformSession)
96         return adoptCF(_CFURLStorageSessionCopyCookieStorage(kCFAllocatorDefault, m_platformSession.get()));
97
98 #if USE(CFURLCONNECTION)
99     return _CFHTTPCookieStorageGetDefault(kCFAllocatorDefault);
100 #else
101     // When using NSURLConnection, we also use its shared cookie storage.
102     return nullptr;
103 #endif
104 }
105
106 void NetworkStorageSession::setCookieStoragePartitioningEnabled(bool enabled)
107 {
108     cookieStoragePartitioningEnabled = enabled;
109 }
110
111 #if PLATFORM(COCOA)
112
113 String cookieStoragePartition(const ResourceRequest& request)
114 {
115     return cookieStoragePartition(request.firstPartyForCookies(), request.url());
116 }
117
118 static inline bool hostIsInDomain(StringView host, StringView domain)
119 {
120     if (!host.endsWithIgnoringASCIICase(domain))
121         return false;
122
123     ASSERT(host.length() >= domain.length());
124     unsigned suffixOffset = host.length() - domain.length();
125     return suffixOffset == 0 || host[suffixOffset - 1] == '.';
126 }
127
128 String cookieStoragePartition(const URL& firstPartyForCookies, const URL& resource)
129 {
130     if (!cookieStoragePartitioningEnabled)
131         return emptyString();
132
133     String firstPartyDomain = firstPartyForCookies.host();
134 #if ENABLE(PUBLIC_SUFFIX_LIST)
135     firstPartyDomain = topPrivatelyControlledDomain(firstPartyDomain);
136 #endif
137     
138     return hostIsInDomain(resource.host(), firstPartyDomain) ? emptyString() : firstPartyDomain;
139 }
140
141 #endif
142
143 #if HAVE(CFNETWORK_STORAGE_PARTITIONING)
144
145 bool NetworkStorageSession::shouldPartitionCookiesForHost(const String& host)
146 {
147     if (host.isEmpty())
148         return false;
149
150     auto domain = topPrivatelyControlledDomain(host);
151     if (domain.isEmpty())
152         domain = host;
153
154     return m_topPrivatelyControlledDomainsForCookiePartitioning.contains(domain);
155 }
156
157 void NetworkStorageSession::setShouldPartitionCookiesForHosts(const Vector<String>& domainsToRemove, const Vector<String>& domainsToAdd)
158 {
159     if (!domainsToRemove.isEmpty()) {
160         for (auto& domain : domainsToRemove)
161             m_topPrivatelyControlledDomainsForCookiePartitioning.remove(domain);
162     }
163         
164     if (!domainsToAdd.isEmpty())
165         m_topPrivatelyControlledDomainsForCookiePartitioning.add(domainsToAdd.begin(), domainsToAdd.end());
166 }
167
168 #endif // HAVE(CFNETWORK_STORAGE_PARTITIONING)
169
170 #if !PLATFORM(COCOA)
171 void NetworkStorageSession::setCookies(const Vector<Cookie>&, const URL&, const URL&)
172 {
173     // FIXME: Implement this. <https://webkit.org/b/156298>
174 }
175 #endif
176
177 }