abb10670c0d5233dfaba119ae0a8e48c87ccd10c
[WebKit-https.git] / Source / WebCore / platform / network / cf / NetworkStorageSessionCFNet.cpp
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 "NetworkStorageSession.h"
28
29 #include <wtf/MainThread.h>
30 #include <wtf/NeverDestroyed.h>
31 #include <wtf/ProcessID.h>
32 #include <wtf/ProcessPrivilege.h>
33
34 #if PLATFORM(COCOA)
35 #include "PublicSuffix.h"
36 #include "ResourceRequest.h"
37 #endif
38
39 namespace WebCore {
40
41 static bool storageAccessAPIEnabled;
42
43 static RetainPtr<CFURLStorageSessionRef> createCFStorageSessionForIdentifier(CFStringRef identifier)
44 {
45     auto storageSession = adoptCF(_CFURLStorageSessionCreate(kCFAllocatorDefault, identifier, nullptr));
46
47     if (!storageSession)
48         return nullptr;
49
50     auto cache = adoptCF(_CFURLStorageSessionCopyCache(kCFAllocatorDefault, storageSession.get()));
51     if (!cache)
52         return nullptr;
53
54     CFURLCacheSetDiskCapacity(cache.get(), 0);
55
56     auto sharedCache = adoptCF(CFURLCacheCopySharedURLCache());
57     CFURLCacheSetMemoryCapacity(cache.get(), CFURLCacheMemoryCapacity(sharedCache.get()));
58
59     if (!NetworkStorageSession::processMayUseCookieAPI())
60         return storageSession;
61
62     ASSERT(hasProcessPrivilege(ProcessPrivilege::CanAccessRawCookies));
63
64     auto cookieStorage = adoptCF(_CFURLStorageSessionCopyCookieStorage(kCFAllocatorDefault, storageSession.get()));
65     if (!cookieStorage)
66         return nullptr;
67
68     auto sharedCookieStorage = _CFHTTPCookieStorageGetDefault(kCFAllocatorDefault);
69     auto sharedPolicy = CFHTTPCookieStorageGetCookieAcceptPolicy(sharedCookieStorage);
70     CFHTTPCookieStorageSetCookieAcceptPolicy(cookieStorage.get(), sharedPolicy);
71
72     return storageSession;
73 }
74
75 NetworkStorageSession::NetworkStorageSession(PAL::SessionID sessionID, RetainPtr<CFURLStorageSessionRef>&& platformSession, RetainPtr<CFHTTPCookieStorageRef>&& platformCookieStorage)
76     : m_sessionID(sessionID)
77     , m_platformSession(WTFMove(platformSession))
78 {
79     ASSERT(processMayUseCookieAPI() || !platformCookieStorage);
80     m_platformCookieStorage = platformCookieStorage ? WTFMove(platformCookieStorage) : cookieStorage();
81 }
82
83 NetworkStorageSession::NetworkStorageSession(PAL::SessionID sessionID)
84     : m_sessionID(sessionID)
85 {
86 }
87
88
89 static std::unique_ptr<NetworkStorageSession>& defaultNetworkStorageSession()
90 {
91     ASSERT(isMainThread());
92     static NeverDestroyed<std::unique_ptr<NetworkStorageSession>> session;
93     return session;
94 }
95
96 void NetworkStorageSession::switchToNewTestingSession()
97 {
98     // 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>).
99     String sessionName = String::format("WebKit Test-%u", static_cast<uint32_t>(getCurrentProcessID()));
100
101     auto session = adoptCF(createPrivateStorageSession(sessionName.createCFString().get()));
102
103     RetainPtr<CFHTTPCookieStorageRef> cookieStorage;
104     if (NetworkStorageSession::processMayUseCookieAPI()) {
105         ASSERT(hasProcessPrivilege(ProcessPrivilege::CanAccessRawCookies));
106         if (session)
107             cookieStorage = adoptCF(_CFURLStorageSessionCopyCookieStorage(kCFAllocatorDefault, session.get()));
108     }
109
110     defaultNetworkStorageSession() = std::make_unique<NetworkStorageSession>(PAL::SessionID::defaultSessionID(), WTFMove(session), WTFMove(cookieStorage));
111 }
112
113 NetworkStorageSession& NetworkStorageSession::defaultStorageSession()
114 {
115     if (!defaultNetworkStorageSession())
116         defaultNetworkStorageSession() = std::make_unique<NetworkStorageSession>(PAL::SessionID::defaultSessionID());
117     return *defaultNetworkStorageSession();
118 }
119
120 void NetworkStorageSession::ensureSession(PAL::SessionID sessionID, const String& identifierBase, RetainPtr<CFHTTPCookieStorageRef>&& cookieStorage)
121 {
122     auto addResult = globalSessionMap().add(sessionID, nullptr);
123     if (!addResult.isNewEntry)
124         return;
125
126     RetainPtr<CFStringRef> cfIdentifier = String(identifierBase + ".PrivateBrowsing").createCFString();
127
128     RetainPtr<CFURLStorageSessionRef> storageSession;
129     if (sessionID.isEphemeral())
130         storageSession = adoptCF(createPrivateStorageSession(cfIdentifier.get()));
131     else
132         storageSession = createCFStorageSessionForIdentifier(cfIdentifier.get());
133
134     if (NetworkStorageSession::processMayUseCookieAPI()) {
135         ASSERT(hasProcessPrivilege(ProcessPrivilege::CanAccessRawCookies));
136         if (!cookieStorage && storageSession)
137             cookieStorage = adoptCF(_CFURLStorageSessionCopyCookieStorage(kCFAllocatorDefault, storageSession.get()));
138     }
139
140     addResult.iterator->value = std::make_unique<NetworkStorageSession>(sessionID, WTFMove(storageSession), WTFMove(cookieStorage));
141 }
142
143 void NetworkStorageSession::ensureSession(PAL::SessionID sessionID, const String& identifierBase)
144 {
145     ensureSession(sessionID, identifierBase, nullptr);
146 }
147
148 RetainPtr<CFHTTPCookieStorageRef> NetworkStorageSession::cookieStorage() const
149 {
150     if (!processMayUseCookieAPI())
151         return nullptr;
152
153     ASSERT(hasProcessPrivilege(ProcessPrivilege::CanAccessRawCookies));
154
155     if (m_platformCookieStorage)
156         return m_platformCookieStorage;
157
158     if (m_platformSession)
159         return adoptCF(_CFURLStorageSessionCopyCookieStorage(kCFAllocatorDefault, m_platformSession.get()));
160
161 #if USE(CFURLCONNECTION)
162     return _CFHTTPCookieStorageGetDefault(kCFAllocatorDefault);
163 #else
164     // When using NSURLConnection, we also use its shared cookie storage.
165     return nullptr;
166 #endif
167 }
168
169 void NetworkStorageSession::setStorageAccessAPIEnabled(bool enabled)
170 {
171     storageAccessAPIEnabled = enabled;
172 }
173
174 } // namespace WebCore