diff options
| author | Michael Biebl <biebl@debian.org> | 2021-10-01 23:05:04 +0200 |
|---|---|---|
| committer | Michael Biebl <biebl@debian.org> | 2021-10-01 23:05:04 +0200 |
| commit | e74c568b07b50b97873fb4ee1d776dedefbd54d6 (patch) | |
| tree | 3469f17ea9af91f7ff169b890633bda68b0cf76e /clients/cloud-setup/nm-http-client.c | |
| parent | bfe522304da217296e2a61040f58e35ec5d6f3f2 (diff) | |
New upstream version 1.32.12 upstream/1.32.12
Diffstat (limited to 'clients/cloud-setup/nm-http-client.c')
| -rw-r--r-- | clients/cloud-setup/nm-http-client.c | 801 |
1 files changed, 0 insertions, 801 deletions
diff --git a/clients/cloud-setup/nm-http-client.c b/clients/cloud-setup/nm-http-client.c deleted file mode 100644 index 144513fc..00000000 --- a/clients/cloud-setup/nm-http-client.c +++ /dev/null @@ -1,801 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1-or-later */ - -#include "libnm/nm-default-client.h" - -#include "nm-http-client.h" - -#include <curl/curl.h> - -#include "nm-cloud-setup-utils.h" -#include "nm-glib-aux/nm-str-buf.h" - -#define NM_CURL_DEBUG 0 - -/*****************************************************************************/ - -typedef struct { - GMainContext *context; - CURLM * mhandle; - GSource * mhandle_source_timeout; - GHashTable * source_sockets_hashtable; -} NMHttpClientPrivate; - -struct _NMHttpClient { - GObject parent; - NMHttpClientPrivate _priv; -}; - -struct _NMHttpClientClass { - GObjectClass parent; -}; - -G_DEFINE_TYPE(NMHttpClient, nm_http_client, G_TYPE_OBJECT); - -#define NM_HTTP_CLIENT_GET_PRIVATE(self) _NM_GET_PRIVATE(self, NMHttpClient, NM_IS_HTTP_CLIENT) - -/*****************************************************************************/ - -#define _NMLOG2(level, edata, ...) \ - G_STMT_START \ - { \ - EHandleData *_edata = (edata); \ - \ - _NMLOG(level, \ - "http-request[" NM_HASH_OBFUSCATE_PTR_FMT \ - ", \"%s\"]: " _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \ - NM_HASH_OBFUSCATE_PTR(_edata), \ - (_edata)->url _NM_UTILS_MACRO_REST(__VA_ARGS__)); \ - } \ - G_STMT_END - -/*****************************************************************************/ - -G_LOCK_DEFINE_STATIC(_my_curl_initalized_lock); -static bool _my_curl_initialized = FALSE; - -__attribute__((destructor)) static void -_my_curl_global_cleanup(void) -{ - G_LOCK(_my_curl_initalized_lock); - if (_my_curl_initialized) { - _my_curl_initialized = FALSE; - curl_global_cleanup(); - } - G_UNLOCK(_my_curl_initalized_lock); -} - -static void -nm_http_client_curl_global_init(void) -{ - G_LOCK(_my_curl_initalized_lock); - if (!_my_curl_initialized) { - _my_curl_initialized = TRUE; - if (curl_global_init(CURL_GLOBAL_ALL) != CURLE_OK) { - /* Even if this fails, we are partly initialized. WTF. */ - _LOGE("curl: curl_global_init() failed!"); - } - } - G_UNLOCK(_my_curl_initalized_lock); -} - -/*****************************************************************************/ - -GMainContext * -nm_http_client_get_main_context(NMHttpClient *self) -{ - g_return_val_if_fail(NM_IS_HTTP_CLIENT(self), NULL); - - return NM_HTTP_CLIENT_GET_PRIVATE(self)->context; -} - -/*****************************************************************************/ - -static GSource * -_source_attach(NMHttpClient *self, GSource *source) -{ - return nm_g_source_attach(source, NM_HTTP_CLIENT_GET_PRIVATE(self)->context); -} - -/*****************************************************************************/ - -typedef struct { - long response_code; - GBytes *response_data; -} GetResult; - -static void -_get_result_free(gpointer data) -{ - GetResult *get_result = data; - - g_bytes_unref(get_result->response_data); - nm_g_slice_free(get_result); -} - -typedef struct { - GTask * task; - GSource * timeout_source; - CURLcode ehandle_result; - CURL * ehandle; - char * url; - NMStrBuf recv_data; - struct curl_slist *headers; - gssize max_data; - gulong cancellable_id; -} EHandleData; - -static void -_ehandle_free_ehandle(EHandleData *edata) -{ - if (edata->ehandle) { - NMHttpClient * self = g_task_get_source_object(edata->task); - NMHttpClientPrivate *priv = NM_HTTP_CLIENT_GET_PRIVATE(self); - - curl_multi_remove_handle(priv->mhandle, edata->ehandle); - curl_easy_cleanup(g_steal_pointer(&edata->ehandle)); - } -} - -static void -_ehandle_free(EHandleData *edata) -{ - nm_assert(!edata->ehandle); - nm_assert(!edata->timeout_source); - - g_object_unref(edata->task); - - nm_str_buf_destroy(&edata->recv_data); - if (edata->headers) - curl_slist_free_all(edata->headers); - g_free(edata->url); - nm_g_slice_free(edata); -} - -static void -_ehandle_complete(EHandleData *edata, GError *error_take) -{ - GetResult * get_result; - gs_free char *str_tmp_1 = NULL; - long response_code = -1; - - nm_clear_pointer(&edata->timeout_source, nm_g_source_destroy_and_unref); - - nm_clear_g_cancellable_disconnect(g_task_get_cancellable(edata->task), &edata->cancellable_id); - - if (error_take) { - if (nm_utils_error_is_cancelled(error_take)) - _LOG2T(edata, "cancelled"); - else - _LOG2D(edata, "failed with %s", error_take->message); - } else if (edata->ehandle_result != CURLE_OK) { - _LOG2D(edata, "failed with curl error \"%s\"", curl_easy_strerror(edata->ehandle_result)); - nm_utils_error_set(&error_take, - NM_UTILS_ERROR_UNKNOWN, - "failed with curl error \"%s\"", - curl_easy_strerror(edata->ehandle_result)); - } - - if (error_take) { - _ehandle_free_ehandle(edata); - g_task_return_error(edata->task, error_take); - _ehandle_free(edata); - return; - } - - if (curl_easy_getinfo(edata->ehandle, CURLINFO_RESPONSE_CODE, &response_code) != CURLE_OK) - _LOG2E(edata, "failed to get response code from curl easy handle"); - - _LOG2D(edata, - "success getting %" G_GSIZE_FORMAT " bytes (response code %ld)", - edata->recv_data.len, - response_code); - - _LOG2T(edata, - "received %" G_GSIZE_FORMAT " bytes: [[%s]]", - edata->recv_data.len, - nm_utils_buf_utf8safe_escape(nm_str_buf_get_str(&edata->recv_data), - edata->recv_data.len, - NM_UTILS_STR_UTF8_SAFE_FLAG_ESCAPE_CTRL, - &str_tmp_1)); - - _ehandle_free_ehandle(edata); - - get_result = g_slice_new(GetResult); - *get_result = (GetResult){ - .response_code = response_code, - /* This ensures that response_data is always NUL terminated. This is an important guarantee - * that NMHttpClient makes. */ - .response_data = nm_str_buf_finalize_to_gbytes(&edata->recv_data), - }; - - g_task_return_pointer(edata->task, get_result, _get_result_free); - - _ehandle_free(edata); -} - -/*****************************************************************************/ - -static size_t -_get_writefunction_cb(char *ptr, size_t size, size_t nmemb, void *user_data) -{ - EHandleData *edata = user_data; - gsize nconsume; - - /* size should always be 1, but still. Multiply them to be sure. */ - nmemb *= size; - - if (edata->max_data >= 0) { - nm_assert(edata->recv_data.len <= edata->max_data); - nconsume = (((gsize) edata->max_data) - edata->recv_data.len); - if (nconsume > nmemb) - nconsume = nmemb; - } else - nconsume = nmemb; - - nm_str_buf_append_len(&edata->recv_data, ptr, nconsume); - return nconsume; -} - -static gboolean -_get_timeout_cb(gpointer user_data) -{ - _ehandle_complete( - user_data, - g_error_new_literal(NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN, "HTTP request timed out")); - return G_SOURCE_REMOVE; -} - -static void -_get_cancelled_cb(GObject *object, gpointer user_data) -{ - EHandleData *edata = user_data; - GError * error = NULL; - - nm_clear_g_signal_handler(g_task_get_cancellable(edata->task), &edata->cancellable_id); - nm_utils_error_set_cancelled(&error, FALSE, NULL); - _ehandle_complete(edata, error); -} - -void -nm_http_client_get(NMHttpClient * self, - const char * url, - int timeout_msec, - gssize max_data, - const char *const * http_headers, - GCancellable * cancellable, - GAsyncReadyCallback callback, - gpointer user_data) -{ - NMHttpClientPrivate *priv; - EHandleData * edata; - guint i; - - g_return_if_fail(NM_IS_HTTP_CLIENT(self)); - g_return_if_fail(url); - g_return_if_fail(!cancellable || G_IS_CANCELLABLE(cancellable)); - g_return_if_fail(timeout_msec >= 0); - g_return_if_fail(max_data >= -1); - - priv = NM_HTTP_CLIENT_GET_PRIVATE(self); - - edata = g_slice_new(EHandleData); - *edata = (EHandleData){ - .task = nm_g_task_new(self, cancellable, nm_http_client_get, callback, user_data), - .recv_data = NM_STR_BUF_INIT(0, FALSE), - .max_data = max_data, - .url = g_strdup(url), - .headers = NULL, - }; - - nmcs_wait_for_objects_register(edata->task); - - _LOG2D(edata, "start get ..."); - - edata->ehandle = curl_easy_init(); - if (!edata->ehandle) { - _ehandle_complete(edata, - g_error_new_literal(NM_UTILS_ERROR, - NM_UTILS_ERROR_UNKNOWN, - "HTTP request failed to create curl handle")); - return; - } - - curl_easy_setopt(edata->ehandle, CURLOPT_URL, url); - - curl_easy_setopt(edata->ehandle, CURLOPT_WRITEFUNCTION, _get_writefunction_cb); - curl_easy_setopt(edata->ehandle, CURLOPT_WRITEDATA, edata); - curl_easy_setopt(edata->ehandle, CURLOPT_PRIVATE, edata); - - if (http_headers) { - for (i = 0; http_headers[i]; ++i) { - struct curl_slist *tmp; - - tmp = curl_slist_append(edata->headers, http_headers[i]); - if (!tmp) { - curl_slist_free_all(tmp); - _LOGE("curl: curl_slist_append() failed adding %s", http_headers[i]); - continue; - } - edata->headers = tmp; - } - - curl_easy_setopt(edata->ehandle, CURLOPT_HTTPHEADER, edata->headers); - } - - if (timeout_msec > 0) { - edata->timeout_source = _source_attach(self, - nm_g_timeout_source_new(timeout_msec, - G_PRIORITY_DEFAULT, - _get_timeout_cb, - edata, - NULL)); - } - - curl_multi_add_handle(priv->mhandle, edata->ehandle); - - if (cancellable) { - gulong signal_id; - - signal_id = g_cancellable_connect(cancellable, G_CALLBACK(_get_cancelled_cb), edata, NULL); - if (signal_id == 0) { - /* the request is already cancelled. Return. */ - return; - } - edata->cancellable_id = signal_id; - } -} - -/** - * nm_http_client_get_finish: - * @self: the #NMHttpClient instance - * @result: the #GAsyncResult which to complete. - * @out_response_code: (allow-none) (out): the HTTP response code or -1 on other error. - * @out_response_data: (allow-none) (transfer full): the HTTP response data, if any. - * The GBytes buffer is guaranteed to have a trailing NUL character *after* the - * returned buffer size. That means, you can always trust that the buffer is NUL terminated - * and that there is one additional hidden byte after the data. - * Also, the returned buffer is allocated just for you. While GBytes is immutable, you are - * allowed to modify the buffer as it's not used by anybody else. - * @error: the error - * - * Returns: %TRUE on success or %FALSE with an error code. - */ -gboolean -nm_http_client_get_finish(NMHttpClient *self, - GAsyncResult *result, - long * out_response_code, - GBytes ** out_response_data, - GError ** error) -{ - GetResult *get_result; - - g_return_val_if_fail(NM_IS_HTTP_CLIENT(self), FALSE); - g_return_val_if_fail(nm_g_task_is_valid(result, self, nm_http_client_get), FALSE); - - get_result = g_task_propagate_pointer(G_TASK(result), error); - - nm_assert(!error || (!!get_result) == (!*error)); - - if (!get_result) { - NM_SET_OUT(out_response_code, -1); - NM_SET_OUT(out_response_data, NULL); - return FALSE; - } - - NM_SET_OUT(out_response_code, get_result->response_code); - - /* response_data is binary, but is also guaranteed to be NUL terminated! */ - NM_SET_OUT(out_response_data, g_steal_pointer(&get_result->response_data)); - - _get_result_free(get_result); - return TRUE; -} - -/*****************************************************************************/ - -typedef struct { - GTask * task; - char * uri; - const char *const * http_headers; - NMHttpClientPollGetCheckFcn check_fcn; - gpointer check_user_data; - GBytes * response_data; - gsize request_max_data; - long response_code; - int request_timeout_ms; -} PollGetData; - -static void -_poll_get_data_free(gpointer data) -{ - PollGetData *poll_get_data = data; - - g_free(poll_get_data->uri); - - nm_clear_pointer(&poll_get_data->response_data, g_bytes_unref); - g_strfreev((char **) poll_get_data->http_headers); - - nm_g_slice_free(poll_get_data); -} - -static void -_poll_get_probe_start_fcn(GCancellable * cancellable, - gpointer probe_user_data, - GAsyncReadyCallback callback, - gpointer user_data) -{ - PollGetData *poll_get_data = probe_user_data; - - /* balanced by _poll_get_probe_finish_fcn() */ - g_object_ref(poll_get_data->task); - - nm_http_client_get(g_task_get_source_object(poll_get_data->task), - poll_get_data->uri, - poll_get_data->request_timeout_ms, - poll_get_data->request_max_data, - poll_get_data->http_headers, - cancellable, - callback, - user_data); -} - -static gboolean -_poll_get_probe_finish_fcn(GObject * source, - GAsyncResult *result, - gpointer probe_user_data, - GError ** error) -{ - PollGetData * poll_get_data = probe_user_data; - _nm_unused gs_unref_object GTask *task = - poll_get_data->task; /* balance ref from _poll_get_probe_start_fcn() */ - gboolean success; - gs_free_error GError *local_error = NULL; - gs_unref_bytes GBytes *response_data = NULL; - long response_code = -1; - - success = nm_http_client_get_finish(g_task_get_source_object(poll_get_data->task), - result, - &response_code, - &response_data, - &local_error); - - nm_assert((!!success) == (!local_error)); - - if (local_error) { - if (nm_utils_error_is_cancelled(local_error)) { - g_propagate_error(error, g_steal_pointer(&local_error)); - return TRUE; - } - /* any other error. Continue polling. */ - return FALSE; - } - - if (poll_get_data->check_fcn) { - success = poll_get_data->check_fcn(response_code, - response_data, - poll_get_data->check_user_data, - &local_error); - } else - success = (response_code == 200); - - if (local_error) { - g_propagate_error(error, g_steal_pointer(&local_error)); - return TRUE; - } - - if (!success) { - /* Not yet ready. Continue polling. */ - return FALSE; - } - - poll_get_data->response_code = response_code; - poll_get_data->response_data = g_steal_pointer(&response_data); - return TRUE; -} - -static void -_poll_get_done_cb(GObject *source, GAsyncResult *result, gpointer user_data) -{ - PollGetData * poll_get_data = user_data; - gs_free_error GError *error = NULL; - gboolean success; - - success = nmcs_utils_poll_finish(result, NULL, &error); - - nm_assert((!!success) == (!error)); - - if (error) - g_task_return_error(poll_get_data->task, g_steal_pointer(&error)); - else - g_task_return_boolean(poll_get_data->task, TRUE); - - g_object_unref(poll_get_data->task); -} - -void -nm_http_client_poll_get(NMHttpClient * self, - const char * uri, - int request_timeout_ms, - gssize request_max_data, - int poll_timeout_ms, - int ratelimit_timeout_ms, - const char *const * http_headers, - GCancellable * cancellable, - NMHttpClientPollGetCheckFcn check_fcn, - gpointer check_user_data, - GAsyncReadyCallback callback, - gpointer user_data) -{ - nm_auto_pop_gmaincontext GMainContext *context = NULL; - PollGetData * poll_get_data; - - g_return_if_fail(NM_IS_HTTP_CLIENT(self)); - g_return_if_fail(uri && uri[0]); - g_return_if_fail(request_timeout_ms >= -1); - g_return_if_fail(request_max_data >= -1); - g_return_if_fail(poll_timeout_ms >= -1); - g_return_if_fail(ratelimit_timeout_ms >= -1); - g_return_if_fail(!cancellable || G_CANCELLABLE(cancellable)); - - poll_get_data = g_slice_new(PollGetData); - *poll_get_data = (PollGetData){ - .task = nm_g_task_new(self, cancellable, nm_http_client_poll_get, callback, user_data), - .uri = g_strdup(uri), - .request_timeout_ms = request_timeout_ms, - .request_max_data = request_max_data, - .check_fcn = check_fcn, - .check_user_data = check_user_data, - .response_code = -1, - .http_headers = NM_CAST_STRV_CC(g_strdupv((char **) http_headers)), - }; - - nmcs_wait_for_objects_register(poll_get_data->task); - - g_task_set_task_data(poll_get_data->task, poll_get_data, _poll_get_data_free); - - context = - nm_g_main_context_push_thread_default_if_necessary(nm_http_client_get_main_context(self)); - - nmcs_utils_poll(poll_timeout_ms, - ratelimit_timeout_ms, - 0, - _poll_get_probe_start_fcn, - _poll_get_probe_finish_fcn, - poll_get_data, - cancellable, - _poll_get_done_cb, - poll_get_data); -} - -gboolean -nm_http_client_poll_get_finish(NMHttpClient *self, - GAsyncResult *result, - long * out_response_code, - GBytes ** out_response_data, - GError ** error) -{ - PollGetData * poll_get_data; - GTask * task; - gboolean success; - gs_free_error GError *local_error = NULL; - - g_return_val_if_fail(NM_HTTP_CLIENT(self), FALSE); - g_return_val_if_fail(nm_g_task_is_valid(result, self, nm_http_client_poll_get), FALSE); - - task = G_TASK(result); - - success = g_task_propagate_boolean(task, &local_error); - - nm_assert((!!success) == (!local_error)); - - if (local_error) { - g_propagate_error(error, g_steal_pointer(&local_error)); - NM_SET_OUT(out_response_code, -1); - NM_SET_OUT(out_response_data, NULL); - return FALSE; - } - - poll_get_data = g_task_get_task_data(task); - - NM_SET_OUT(out_response_code, poll_get_data->response_code); - NM_SET_OUT(out_response_data, g_steal_pointer(&poll_get_data->response_data)); - return TRUE; -} - -/*****************************************************************************/ - -static void -_mhandle_action(NMHttpClient *self, int sockfd, int ev_bitmask) -{ - NMHttpClientPrivate *priv = NM_HTTP_CLIENT_GET_PRIVATE(self); - EHandleData * edata; - CURLMsg * msg; - CURLcode eret; - int m_left; - CURLMcode ret; - int running_handles; - - ret = curl_multi_socket_action(priv->mhandle, sockfd, ev_bitmask, &running_handles); - if (ret != CURLM_OK) { - _LOGE("curl: curl_multi_socket_action() failed: (%d) %s", ret, curl_multi_strerror(ret)); - /* really unexpected. Not clear how to handle this. */ - } - - while ((msg = curl_multi_info_read(priv->mhandle, &m_left))) { - if (msg->msg != CURLMSG_DONE) - continue; - - eret = curl_easy_getinfo(msg->easy_handle, CURLINFO_PRIVATE, (char **) &edata); - - nm_assert(eret == CURLE_OK); - nm_assert(edata); - - edata->ehandle_result = msg->data.result; - _ehandle_complete(edata, NULL); - } -} - -static gboolean -_mhandle_socket_cb(int fd, GIOCondition condition, gpointer user_data) -{ - int ev_bitmask = 0; - - if (condition & G_IO_IN) - ev_bitmask |= CURL_CSELECT_IN; - if (condition & G_IO_OUT) - ev_bitmask |= CURL_CSELECT_OUT; - if (condition & G_IO_ERR) - ev_bitmask |= CURL_CSELECT_ERR; - - _mhandle_action(user_data, fd, ev_bitmask); - return G_SOURCE_CONTINUE; -} - -static int -_mhandle_socketfunction_cb(CURL * e_handle, - curl_socket_t fd, - int what, - void * user_data, - void * socketp) -{ - GSource * source_socket; - NMHttpClient * self = user_data; - NMHttpClientPrivate *priv = NM_HTTP_CLIENT_GET_PRIVATE(self); - - (void) _NM_ENSURE_TYPE(int, fd); - - g_hash_table_remove(priv->source_sockets_hashtable, GINT_TO_POINTER(fd)); - - if (what != CURL_POLL_REMOVE) { - GIOCondition condition = 0; - - if (what == CURL_POLL_IN) - condition = G_IO_IN; - else if (what == CURL_POLL_OUT) - condition = G_IO_OUT; - else if (what == CURL_POLL_INOUT) - condition = G_IO_IN | G_IO_OUT; - else - condition = 0; - - if (condition) { - source_socket = nm_g_unix_fd_source_new(fd, - condition, - G_PRIORITY_DEFAULT, - _mhandle_socket_cb, - self, - NULL); - g_source_attach(source_socket, priv->context); - - g_hash_table_insert(priv->source_sockets_hashtable, GINT_TO_POINTER(fd), source_socket); - } - } - - return CURLM_OK; -} - -static gboolean -_mhandle_timeout_cb(gpointer user_data) -{ - _mhandle_action(user_data, CURL_SOCKET_TIMEOUT, 0); - return G_SOURCE_REMOVE; -} - -static int -_mhandle_timerfunction_cb(CURLM *multi, long timeout_msec, void *user_data) -{ - NMHttpClient * self = user_data; - NMHttpClientPrivate *priv = NM_HTTP_CLIENT_GET_PRIVATE(self); - - nm_clear_pointer(&priv->mhandle_source_timeout, nm_g_source_destroy_and_unref); - if (timeout_msec >= 0) { - priv->mhandle_source_timeout = - _source_attach(self, - nm_g_timeout_source_new(NM_MIN(timeout_msec, G_MAXINT), - G_PRIORITY_DEFAULT, - _mhandle_timeout_cb, - self, - NULL)); - } - return 0; -} - -/*****************************************************************************/ - -static void -nm_http_client_init(NMHttpClient *self) -{ - NMHttpClientPrivate *priv = NM_HTTP_CLIENT_GET_PRIVATE(self); - - priv->source_sockets_hashtable = - g_hash_table_new_full(nm_direct_hash, - NULL, - NULL, - (GDestroyNotify) nm_g_source_destroy_and_unref); -} - -static void -constructed(GObject *object) -{ - NMHttpClient * self = NM_HTTP_CLIENT(object); - NMHttpClientPrivate *priv = NM_HTTP_CLIENT_GET_PRIVATE(self); - - priv->context = g_main_context_ref_thread_default(); - - priv->mhandle = curl_multi_init(); - if (!priv->mhandle) - _LOGE("curl: failed to create multi-handle"); - else { - curl_multi_setopt(priv->mhandle, CURLMOPT_SOCKETFUNCTION, _mhandle_socketfunction_cb); - curl_multi_setopt(priv->mhandle, CURLMOPT_SOCKETDATA, self); - curl_multi_setopt(priv->mhandle, CURLMOPT_TIMERFUNCTION, _mhandle_timerfunction_cb); - curl_multi_setopt(priv->mhandle, CURLMOPT_TIMERDATA, self); - } - - G_OBJECT_CLASS(nm_http_client_parent_class)->constructed(object); -} - -NMHttpClient * -nm_http_client_new(void) -{ - return g_object_new(NM_TYPE_HTTP_CLIENT, NULL); -} - -static void -dispose(GObject *object) -{ - NMHttpClient * self = NM_HTTP_CLIENT(object); - NMHttpClientPrivate *priv = NM_HTTP_CLIENT_GET_PRIVATE(self); - - nm_clear_pointer(&priv->mhandle, curl_multi_cleanup); - nm_clear_pointer(&priv->source_sockets_hashtable, g_hash_table_unref); - - nm_clear_g_source_inst(&priv->mhandle_source_timeout); - - G_OBJECT_CLASS(nm_http_client_parent_class)->dispose(object); -} - -static void -finalize(GObject *object) -{ - NMHttpClient * self = NM_HTTP_CLIENT(object); - NMHttpClientPrivate *priv = NM_HTTP_CLIENT_GET_PRIVATE(self); - - G_OBJECT_CLASS(nm_http_client_parent_class)->finalize(object); - - g_main_context_unref(priv->context); - - curl_global_cleanup(); -} - -static void -nm_http_client_class_init(NMHttpClientClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS(klass); - - object_class->constructed = constructed; - object_class->dispose = dispose; - object_class->finalize = finalize; - - nm_http_client_curl_global_init(); -} |