GCC Code Coverage Report


Directory: src/
File: src/backend/px-manager.c
Date: 2023-01-04 17:35:37
Exec Total Coverage
Lines: 69 118 58.5%
Branches: 31 75 41.3%

Line Branch Exec Source
1 /* px-manager.c
2 *
3 * Copyright 2022-2023 Jan-Michael Brummer
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 *
19 * SPDX-License-Identifier: LGPL-2.1-or-later
20 */
21
22 #include "config.h"
23
24 #include "px-manager.h"
25 #include "px-module.h"
26 #include "px-config-module.h"
27 #include "px-pacrunner-module.h"
28
29 #include <gio/gio.h>
30 #include <libsoup/soup.h>
31
32 enum {
33 PROP_0,
34 PROP_MODULE_PATH,
35 LAST_PROP
36 };
37
38 static GParamSpec *obj_properties[LAST_PROP];
39
40 /**
41 * PxManager:
42 *
43 * Manage libproxy modules
44 */
45
46 struct _PxManager {
47 GObject parent_instance;
48 GList *modules;
49 char *module_path;
50 GCancellable *cancellable;
51 SoupSession *session;
52 };
53
54
6/7
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 38 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 3 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 3 times.
✓ Branch 6 taken 38 times.
94 G_DEFINE_TYPE (PxManager, px_manager, G_TYPE_OBJECT)
55
56
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 G_DEFINE_QUARK (px - manager - error - quark, px_manager_error)
57
58 static void
59 10 px_manager_constructed (GObject *object)
60 {
61 10 PxManager *self = PX_MANAGER (object);
62
1/2
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
20 g_autoptr (GFile) module_dir = g_file_new_for_path (self->module_path);
63
1/2
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
10 g_autoptr (GError) error = NULL;
64 GFileEnumerator *enumerator;
65
66
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 if (!module_dir) {
67 g_warning ("Error accessing module path: %s. Abort!", g_file_peek_path (module_dir));
68 return;
69 }
70
71 10 enumerator = g_file_enumerate_children (module_dir,
72 G_FILE_ATTRIBUTE_STANDARD_NAME,
73 G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
74 self->cancellable,
75 NULL);
76
77
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 if (!enumerator) {
78 g_warning ("Error enumerating module path: %s. Abort!", g_file_peek_path (module_dir));
79 return;
80 }
81
82 10 g_print ("Loading modules from %s\n", self->module_path);
83
84 60 while (TRUE) {
85 GFileInfo *info;
86 GFile *child;
87 PxModule *module;
88
89
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 70 times.
70 if (!g_file_enumerator_iterate (enumerator, &info, &child, NULL, &error)) {
90 g_warning ("Error enumerating module directory: %s", error->message);
91 10 break;
92 }
93
94
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 60 times.
70 if (!info)
95 10 break;
96
97
2/2
✓ Branch 0 taken 30 times.
✓ Branch 1 taken 30 times.
60 if (!g_str_has_suffix (g_file_peek_path (child), ".so"))
98 30 continue;
99
100 30 module = px_module_load (child, info, self);
101 30 self->modules = g_list_append (self->modules, module);
102 }
103 }
104
105 static void
106 10 px_manager_dispose (GObject *object)
107 {
108 10 PxManager *self = PX_MANAGER (object);
109
110 10 g_cancellable_cancel (self->cancellable);
111
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 g_clear_object (&self->cancellable);
112
1/2
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
10 g_clear_pointer (&self->module_path, g_free);
113
114
1/2
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
10 g_clear_list (&self->modules, g_object_unref);
115
116 10 G_OBJECT_CLASS (px_manager_parent_class)->dispose (object);
117 10 }
118
119 static void
120 10 px_manager_set_property (GObject *object,
121 guint prop_id,
122 const GValue *value,
123 GParamSpec *pspec)
124 {
125 10 PxManager *self = PX_MANAGER (object);
126
127
1/2
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
10 switch (prop_id) {
128 10 case PROP_MODULE_PATH:
129 10 self->module_path = g_strdup (g_value_get_string (value));
130 10 break;
131 default:
132 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
133 }
134 10 }
135
136 static void
137 px_manager_get_property (GObject *object,
138 guint prop_id,
139 GValue *value,
140 GParamSpec *pspec)
141 {
142 switch (prop_id) {
143 case PROP_MODULE_PATH:
144 break;
145 default:
146 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
147 break;
148 }
149 }
150
151 static void
152 3 px_manager_class_init (PxManagerClass *klass)
153 {
154 3 GObjectClass *object_class = G_OBJECT_CLASS (klass);
155
156 3 object_class->constructed = px_manager_constructed;
157 3 object_class->dispose = px_manager_dispose;
158 3 object_class->set_property = px_manager_set_property;
159 3 object_class->get_property = px_manager_get_property;
160
161 3 obj_properties[PROP_MODULE_PATH] = g_param_spec_string ("module-path",
162 "Module Path",
163 "The path where modules are stored.",
164 NULL,
165 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
166
167 3 g_object_class_install_properties (object_class, LAST_PROP, obj_properties);
168 3 }
169
170 static void
171 10 px_manager_init (PxManager *self)
172 {
173 10 self->session = soup_session_new ();
174 10 }
175
176 /**
177 * px_manager_new:
178 *
179 * Create a new `PxManager`.
180 *
181 * Returns: the newly created `PxManager`
182 */
183 PxManager *
184 px_manager_new (void)
185 {
186 return g_object_new (PX_TYPE_MANAGER, "module-path", PX_MODULE_DIR, NULL);
187 }
188
189 /**
190 * px_manager_pac_download:
191 * @self: a px manager
192 * @url: PAC url
193 *
194 * Downloads a PAC file from provided @url.
195 *
196 * Returns: (nullable): a newly created `GBytes` containing PAC data, or %NULL on error.
197 */
198 GBytes *
199 1 px_manager_pac_download (PxManager *self,
200 const char *uri)
201 {
202
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
2 g_autoptr (SoupMessage) msg = soup_message_new (SOUP_METHOD_GET, uri);
203 1 g_autoptr (GError) error = NULL;
204 1 g_autoptr (GBytes) bytes = NULL;
205
206 1 g_print ("%s: ENTER %s\n", __FUNCTION__, uri);
207 #if SOUP_CHECK_VERSION (2, 99, 4)
208 1 bytes = soup_session_send_and_read (
209 self->session,
210 msg,
211 NULL, /* Pass a GCancellable here if you want to cancel a download */
212 &error);
213 #else
214 soup_session_send_message (self->session, msg);
215 bytes = g_bytes_new_static (msg->response_body->data, msg->response_body->length);
216 #endif
217
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!bytes) {
218 g_debug ("Failed to download: %s\n", error ? error->message : "");
219 g_warning ("Cannot download pac file: %s", error ? error->message : "");
220 return NULL;
221 }
222
223 /* g_debug ("Downloaded %zu bytes\n", g_bytes_get_size (bytes)); */
224 /* g_print ("Data: %s\n", (char*)g_bytes_get_data (bytes, NULL)); */
225
226 1 return g_steal_pointer (&bytes);
227 }
228
229 char **
230 9 px_manager_get_configuration (PxManager *self,
231 GUri *uri,
232 GError **error)
233 {
234 9 g_auto (GStrv) config = NULL;
235 9 GList *list = self->modules;
236 const char *requested_config_module;
237
238 9 requested_config_module = g_getenv ("PX_CONFIG_MODULE");
239
240
2/4
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9 times.
✗ Branch 3 not taken.
9 for (; list && list->data; list = list->next) {
241 9 PxModule *module = PX_MODULE (list->data);
242 9 PxConfigModule *conf_module = NULL;
243 9 PxConfigModuleInterface *iface = NULL;
244
245
4/8
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
✓ Branch 2 taken 9 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 9 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 9 times.
9 if (!PX_IS_CONFIG_MODULE (module))
246 continue;
247
248
2/4
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 9 times.
9 if (requested_config_module && g_strcmp0 (requested_config_module, px_module_get_name (module)) != 0)
249 continue;
250
251 /* First config module wins at the moment */
252 9 conf_module = PX_CONFIG_MODULE (module);
253 9 iface = PX_CONFIG_MODULE_GET_INTERFACE (conf_module);
254
255
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
9 if (!iface->check_available ())
256 continue;
257
258 9 config = iface->get_config (module, uri, error);
259 9 return g_steal_pointer (&config);
260 }
261
262 return NULL;
263 }
264
265 char **
266 px_manager_get_proxies_sync (PxManager *self,
267 const char *url,
268 GError **error)
269 {
270 GList *list;
271 g_autoptr (GUri) uri = g_uri_parse (url, G_URI_FLAGS_PARSE_RELAXED, error);
272 g_auto (GStrv) config = NULL;
273 g_auto (GStrv) ret = NULL;
274 char *pac;
275 GBytes *pac_bytes;
276 GTimer *timer;
277
278 timer = g_timer_new ();
279 if (!uri)
280 return NULL;
281
282 config = px_manager_get_configuration (self, uri, error);
283 if (!config)
284 return NULL;
285
286 pac_bytes = px_manager_pac_download (self, config[0]);
287 pac = g_strdup (g_bytes_get_data (pac_bytes, NULL));
288
289 g_debug ("PAC loaded: %f\n", g_timer_elapsed (timer, NULL));
290
291 for (list = self->modules; list && list->data; list = list->next) {
292 PxModule *module = PX_MODULE (list->data);
293
294 /* First pacrunner module wins at the moment */
295 if (PX_IS_PACRUNNER_MODULE (module)) {
296 PxPacrunnerModule *pacrunner_module = PX_PACRUNNER_MODULE (module);
297 PxPacrunnerModuleInterface *iface = PX_PACRUNNER_MODULE_GET_INTERFACE (pacrunner_module);
298 char *pac_ret;
299
300 iface->set_pac (module, pac);
301 g_debug ("PAC set: %f\n", g_timer_elapsed (timer, NULL));
302 pac_ret = iface->run (module, uri);
303
304 ret = g_malloc0 (sizeof (char *) * 2);
305 ret[0] = g_strdup (pac_ret);
306 break;
307 }
308 }
309 g_debug ("PAC parsed: %f\n", g_timer_elapsed (timer, NULL));
310
311 return g_steal_pointer (&ret);
312 }
313