1/*
2 * Copyright (C) 2011, 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 "WebPluginSiteDataManager.h"
28
29#if ENABLE(NETSCAPE_PLUGIN_API)
30
31#include "APIArray.h"
32#include "PluginProcessManager.h"
33#include "WebContext.h"
34#include "WebProcessMessages.h"
35
36using namespace WebCore;
37
38namespace WebKit {
39
40class WebPluginSiteDataManager::GetSitesWithDataState {
41public:
42    explicit GetSitesWithDataState(WebPluginSiteDataManager* webPluginSiteDataManager, uint64_t callbackID)
43        : m_webPluginSiteDataManager(webPluginSiteDataManager)
44        , m_callbackID(callbackID)
45        , m_plugins(webPluginSiteDataManager->m_webContext->pluginInfoStore().plugins())
46    {
47    }
48
49    void getSitesWithDataForNextPlugin()
50    {
51        if (m_plugins.isEmpty()) {
52            Vector<String> sites;
53            copyToVector(m_sites, sites);
54
55            m_webPluginSiteDataManager->didGetSitesWithDataForAllPlugins(sites, m_callbackID);
56            return;
57        }
58
59        PluginProcessManager::shared().getSitesWithData(m_plugins.last(), m_webPluginSiteDataManager, m_callbackID);
60        m_plugins.removeLast();
61    }
62
63    void didGetSitesWithDataForSinglePlugin(const Vector<String>& sites)
64    {
65        for (size_t i = 0; i < sites.size(); ++i)
66            m_sites.add(sites[i]);
67
68        getSitesWithDataForNextPlugin();
69    }
70
71private:
72    WebPluginSiteDataManager* m_webPluginSiteDataManager;
73    uint64_t m_callbackID;
74    Vector<PluginModuleInfo> m_plugins;
75    HashSet<String> m_sites;
76};
77
78class WebPluginSiteDataManager::ClearSiteDataState {
79public:
80    explicit ClearSiteDataState(WebPluginSiteDataManager* webPluginSiteDataManager, const Vector<String>& sites, uint64_t flags, uint64_t maxAgeInSeconds, uint64_t callbackID)
81        : m_webPluginSiteDataManager(webPluginSiteDataManager)
82        , m_sites(sites)
83        , m_flags(flags)
84        , m_maxAgeInSeconds(maxAgeInSeconds)
85        , m_callbackID(callbackID)
86        , m_plugins(webPluginSiteDataManager->m_webContext->pluginInfoStore().plugins())
87    {
88    }
89
90    void clearSiteDataForNextPlugin()
91    {
92        if (m_plugins.isEmpty()) {
93            m_webPluginSiteDataManager->didClearSiteDataForAllPlugins(m_callbackID);
94            return;
95        }
96
97        PluginProcessManager::shared().clearSiteData(m_plugins.last(), m_webPluginSiteDataManager, m_sites, m_flags, m_maxAgeInSeconds, m_callbackID);
98        m_plugins.removeLast();
99    }
100
101    void didClearSiteDataForSinglePlugin()
102    {
103        clearSiteDataForNextPlugin();
104    }
105
106private:
107    WebPluginSiteDataManager* m_webPluginSiteDataManager;
108    Vector<String> m_sites;
109    uint64_t m_flags;
110    uint64_t m_maxAgeInSeconds;
111    uint64_t m_callbackID;
112    Vector<PluginModuleInfo> m_plugins;
113};
114
115PassRefPtr<WebPluginSiteDataManager> WebPluginSiteDataManager::create(WebContext* webContext)
116{
117    return adoptRef(new WebPluginSiteDataManager(webContext));
118}
119
120WebPluginSiteDataManager::WebPluginSiteDataManager(WebContext* webContext)
121    : m_webContext(webContext)
122{
123}
124
125WebPluginSiteDataManager::~WebPluginSiteDataManager()
126{
127    ASSERT(m_arrayCallbacks.isEmpty());
128    ASSERT(m_voidCallbacks.isEmpty());
129    ASSERT(m_pendingGetSitesWithData.isEmpty());
130    ASSERT(m_pendingClearSiteData.isEmpty());
131}
132
133void WebPluginSiteDataManager::invalidate()
134{
135    invalidateCallbackMap(m_arrayCallbacks, CallbackBase::Error::OwnerWasInvalidated);
136
137    m_pendingGetSitesWithData.clear();
138    m_pendingClearSiteData.clear();
139}
140
141void WebPluginSiteDataManager::getSitesWithData(std::function<void (API::Array*, CallbackBase::Error)> callbackFunction)
142{
143    RefPtr<ArrayCallback> callback = ArrayCallback::create(WTF::move(callbackFunction));
144
145    if (!m_webContext) {
146        callback->invalidate();
147        return;
148    }
149
150    uint64_t callbackID = callback->callbackID();
151    m_arrayCallbacks.set(callbackID, callback.release());
152
153    ASSERT(!m_pendingGetSitesWithData.contains(callbackID));
154
155    GetSitesWithDataState* state = new GetSitesWithDataState(this, callbackID);
156    m_pendingGetSitesWithData.set(callbackID, std::unique_ptr<GetSitesWithDataState>(state));
157    state->getSitesWithDataForNextPlugin();
158}
159
160void WebPluginSiteDataManager::didGetSitesWithData(const Vector<String>& sites, uint64_t callbackID)
161{
162    RefPtr<ArrayCallback> callback = m_arrayCallbacks.take(callbackID);
163    if (!callback) {
164        // FIXME: Log error or assert.
165        return;
166    }
167
168    callback->performCallbackWithReturnValue(API::Array::createStringArray(sites).get());
169}
170
171void WebPluginSiteDataManager::clearSiteData(API::Array* sites, uint64_t flags, uint64_t maxAgeInSeconds, std::function<void (CallbackBase::Error)> callbackFunction)
172{
173    RefPtr<VoidCallback> callback = VoidCallback::create(WTF::move(callbackFunction));
174    if (!m_webContext) {
175        // FIXME: If the context is invalid we should not call the callback. It'd be better to just return false from clearSiteData.
176        callback->invalidate(CallbackBase::Error::OwnerWasInvalidated);
177        return;
178    }
179
180    Vector<String> sitesVector;
181
182    // If the array is empty, don't do anything.
183    if (sites) {
184        if (!sites->size()) {
185            callback->performCallback();
186            return;
187        }
188
189        for (size_t i = 0; i < sites->size(); ++i) {
190            if (API::String* site = sites->at<API::String>(i))
191                sitesVector.append(site->string());
192        }
193    }
194
195    uint64_t callbackID = callback->callbackID();
196    m_voidCallbacks.set(callbackID, callback.release());
197
198    ASSERT(!m_pendingClearSiteData.contains(callbackID));
199
200    ClearSiteDataState* state = new ClearSiteDataState(this, sitesVector, flags, maxAgeInSeconds, callbackID);
201    m_pendingClearSiteData.set(callbackID, std::unique_ptr<ClearSiteDataState>(state));
202    state->clearSiteDataForNextPlugin();
203}
204
205void WebPluginSiteDataManager::didClearSiteData(uint64_t callbackID)
206{
207    RefPtr<VoidCallback> callback = m_voidCallbacks.take(callbackID);
208    if (!callback) {
209        // FIXME: Log error or assert.
210        return;
211    }
212
213    callback->performCallback();
214}
215
216void WebPluginSiteDataManager::didGetSitesWithDataForSinglePlugin(const Vector<String>& sites, uint64_t callbackID)
217{
218    GetSitesWithDataState* state = m_pendingGetSitesWithData.get(callbackID);
219    ASSERT(state);
220
221    state->didGetSitesWithDataForSinglePlugin(sites);
222}
223
224void WebPluginSiteDataManager::didGetSitesWithDataForAllPlugins(const Vector<String>& sites, uint64_t callbackID)
225{
226    std::unique_ptr<GetSitesWithDataState> state = m_pendingGetSitesWithData.take(callbackID);
227    ASSERT(state);
228
229    didGetSitesWithData(sites, callbackID);
230}
231
232void WebPluginSiteDataManager::didClearSiteDataForSinglePlugin(uint64_t callbackID)
233{
234    ClearSiteDataState* state = m_pendingClearSiteData.get(callbackID);
235    ASSERT(state);
236
237    state->didClearSiteDataForSinglePlugin();
238}
239
240void WebPluginSiteDataManager::didClearSiteDataForAllPlugins(uint64_t callbackID)
241{
242    std::unique_ptr<ClearSiteDataState> state = m_pendingClearSiteData.take(callbackID);
243    ASSERT(state);
244
245    didClearSiteData(callbackID);
246}
247
248} // namespace WebKit
249
250#endif // ENABLE(NETSCAPE_PLUGIN_API)
251