| 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 |