Crash under WebCore::deleteCookiesForHostnames()
[WebKit-https.git] / Source / WebCore / platform / network / cocoa / CookieStorageObserver.mm
1 /*
2  * Copyright (C) 2017-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 #import "config.h"
27 #import "CookieStorageObserver.h"
28
29 #import <pal/spi/cocoa/NSURLConnectionSPI.h>
30 #import <wtf/MainThread.h>
31 #import <wtf/ProcessPrivilege.h>
32
33 @interface WebNSHTTPCookieStorageDummyForInternalAccess : NSObject {
34 @public
35     NSHTTPCookieStorageInternal *_internal;
36 }
37 @end
38
39 @implementation WebNSHTTPCookieStorageDummyForInternalAccess
40 @end
41
42 @interface NSHTTPCookieStorageInternal : NSObject
43 - (void)registerForPostingNotificationsWithContext:(NSHTTPCookieStorage *)context;
44 @end
45
46 @interface WebCookieObserverAdapter : NSObject {
47     WebCore::CookieStorageObserver* observer;
48 }
49 - (instancetype)initWithObserver:(WebCore::CookieStorageObserver&)theObserver;
50 - (void)cookiesChangedNotificationHandler:(NSNotification *)notification;
51
52 @end
53
54 @implementation WebCookieObserverAdapter
55
56 - (instancetype)initWithObserver:(WebCore::CookieStorageObserver&)theObserver
57 {
58     self = [super init];
59     if (!self)
60         return nil;
61
62     observer = &theObserver;
63
64     return self;
65 }
66
67 - (void)cookiesChangedNotificationHandler:(NSNotification *)notification
68 {
69     UNUSED_PARAM(notification);
70     observer->cookiesDidChange();
71 }
72
73 @end
74
75 namespace WebCore {
76
77 RefPtr<CookieStorageObserver> CookieStorageObserver::create(NSHTTPCookieStorage *cookieStorage)
78 {
79     return adoptRef(new CookieStorageObserver(cookieStorage));
80 }
81
82 CookieStorageObserver::CookieStorageObserver(NSHTTPCookieStorage *cookieStorage)
83     : m_cookieStorage(cookieStorage)
84 {
85     ASSERT(isMainThread());
86     ASSERT(m_cookieStorage);
87     ASSERT(hasProcessPrivilege(ProcessPrivilege::CanAccessRawCookies));
88 }
89
90 CookieStorageObserver::~CookieStorageObserver()
91 {
92     ASSERT(isMainThread());
93
94     if (m_cookieChangeCallback) {
95         ASSERT(m_observerAdapter);
96         stopObserving();
97     }
98 }
99
100 void CookieStorageObserver::startObserving(WTF::Function<void()>&& callback)
101 {
102     ASSERT(isMainThread());
103     ASSERT(!m_cookieChangeCallback);
104     ASSERT(!m_observerAdapter);
105     ASSERT(hasProcessPrivilege(ProcessPrivilege::CanAccessRawCookies));
106
107     m_cookieChangeCallback = WTFMove(callback);
108     m_observerAdapter = adoptNS([[WebCookieObserverAdapter alloc] initWithObserver:*this]);
109
110     if (!m_hasRegisteredInternalsForNotifications) {
111         if (m_cookieStorage.get() != [NSHTTPCookieStorage sharedHTTPCookieStorage]) {
112             auto internalObject = (static_cast<WebNSHTTPCookieStorageDummyForInternalAccess *>(m_cookieStorage.get()))->_internal;
113             [internalObject registerForPostingNotificationsWithContext:m_cookieStorage.get()];
114         }
115
116         m_hasRegisteredInternalsForNotifications = true;
117     }
118
119     [[NSNotificationCenter defaultCenter] addObserver:m_observerAdapter.get() selector:@selector(cookiesChangedNotificationHandler:) name:NSHTTPCookieManagerCookiesChangedNotification object:m_cookieStorage.get()];
120 }
121
122 void CookieStorageObserver::stopObserving()
123 {
124     ASSERT(isMainThread());
125     ASSERT(m_cookieChangeCallback);
126     ASSERT(m_observerAdapter);
127     ASSERT(hasProcessPrivilege(ProcessPrivilege::CanAccessRawCookies));
128
129     [[NSNotificationCenter defaultCenter] removeObserver:m_observerAdapter.get() name:NSHTTPCookieManagerCookiesChangedNotification object:nil];
130
131     m_cookieChangeCallback = nullptr;
132     m_observerAdapter = nil;
133 }
134
135 void CookieStorageObserver::cookiesDidChange()
136 {
137     callOnMainThread([protectedThis = makeRef(*this), this] {
138         if (m_cookieChangeCallback)
139             m_cookieChangeCallback();
140     });
141 }
142
143 } // namespace WebCore