1/*
2 * Copyright (C) 2012 Igalia S.L.
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
13 *
14 * You should have received a copy of the GNU Library General Public License
15 * along with this library; see the file COPYING.LIB. If not, write to
16 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
18 */
19
20#include "config.h"
21#include "WebKitExtensionManager.h"
22
23#include "APIString.h"
24#include "InjectedBundle.h"
25#include "WebKitWebExtensionPrivate.h"
26#include <memory>
27#include <wtf/FileSystem.h>
28#include <wtf/text/CString.h>
29
30namespace WebKit {
31
32WebKitExtensionManager& WebKitExtensionManager::singleton()
33{
34 static NeverDestroyed<WebKitExtensionManager> extensionManager;
35 return extensionManager;
36}
37
38WebKitExtensionManager::WebKitExtensionManager()
39{
40}
41
42void WebKitExtensionManager::scanModules(const String& webExtensionsDirectory, Vector<String>& modules)
43{
44 Vector<String> modulePaths = FileSystem::listDirectory(webExtensionsDirectory, String("*.so"));
45 for (size_t i = 0; i < modulePaths.size(); ++i) {
46 if (FileSystem::fileExists(modulePaths[i]))
47 modules.append(modulePaths[i]);
48 }
49}
50
51static void parseUserData(API::Object* userData, String& webExtensionsDirectory, GRefPtr<GVariant>& initializationUserData)
52{
53 ASSERT(userData->type() == API::Object::Type::String);
54
55 CString userDataString = static_cast<API::String*>(userData)->string().utf8();
56 GRefPtr<GVariant> variant = g_variant_parse(nullptr, userDataString.data(),
57 userDataString.data() + userDataString.length(), nullptr, nullptr);
58
59 ASSERT(variant);
60 ASSERT(g_variant_check_format_string(variant.get(), "(m&smv)", FALSE));
61
62 const char* directory = nullptr;
63 GVariant* data = nullptr;
64 g_variant_get(variant.get(), "(m&smv)", &directory, &data);
65
66 webExtensionsDirectory = FileSystem::stringFromFileSystemRepresentation(directory);
67 initializationUserData = adoptGRef(data);
68}
69
70bool WebKitExtensionManager::initializeWebExtension(Module* extensionModule, GVariant* userData)
71{
72 WebKitWebExtensionInitializeWithUserDataFunction initializeWithUserDataFunction =
73 extensionModule->functionPointer<WebKitWebExtensionInitializeWithUserDataFunction>("webkit_web_extension_initialize_with_user_data");
74 if (initializeWithUserDataFunction) {
75 initializeWithUserDataFunction(m_extension.get(), userData);
76 return true;
77 }
78
79 WebKitWebExtensionInitializeFunction initializeFunction =
80 extensionModule->functionPointer<WebKitWebExtensionInitializeFunction>("webkit_web_extension_initialize");
81 if (initializeFunction) {
82 initializeFunction(m_extension.get());
83 return true;
84 }
85
86 return false;
87}
88
89void WebKitExtensionManager::initialize(InjectedBundle* bundle, API::Object* userDataObject)
90{
91 ASSERT(bundle);
92 ASSERT(userDataObject);
93 m_extension = adoptGRef(webkitWebExtensionCreate(bundle));
94
95 String webExtensionsDirectory;
96 GRefPtr<GVariant> userData;
97 parseUserData(userDataObject, webExtensionsDirectory, userData);
98
99 if (webExtensionsDirectory.isNull())
100 return;
101
102 Vector<String> modulePaths;
103 scanModules(webExtensionsDirectory, modulePaths);
104
105 for (size_t i = 0; i < modulePaths.size(); ++i) {
106 auto module = std::make_unique<Module>(modulePaths[i]);
107 if (!module->load())
108 continue;
109 if (initializeWebExtension(module.get(), userData.get()))
110 m_extensionModules.append(module.release());
111 }
112}
113
114} // namespace WebKit
115