static void aws_s3_client_read_got_chunk (SoupMessage *message, SoupBuffer *buffer, GTask *task) { AwsS3Client *client; ReadState *state; g_assert (SOUP_IS_MESSAGE (message)); g_assert (buffer != NULL); g_assert (G_IS_TASK (task)); client = g_task_get_source_object (task); g_assert (AWS_IS_S3_CLIENT (client)); state = g_task_get_task_data (task); g_assert (state != NULL); g_assert (state->handler != NULL); if (!state->handler (client, message, buffer, state->handler_data)) { g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_CANCELLED, "The request was cancelled"); soup_session_cancel_message (SOUP_SESSION (client), message, SOUP_STATUS_CANCELLED); } }
static void finalize (GObject *object) { SoupSession *session = SOUP_SESSION (object); SoupSessionPrivate *priv = SOUP_SESSION_GET_PRIVATE (session); soup_message_queue_destroy (priv->queue); g_mutex_free (priv->host_lock); g_hash_table_destroy (priv->hosts); g_hash_table_destroy (priv->conns); g_free (priv->user_agent); if (priv->auth_manager) g_object_unref (priv->auth_manager); if (priv->ssl_creds) soup_ssl_free_client_credentials (priv->ssl_creds); if (priv->async_context) g_main_context_unref (priv->async_context); G_OBJECT_CLASS (soup_session_parent_class)->finalize (object); }
static void run_queue (SoupSessionAsync *sa) { SoupSession *session = SOUP_SESSION (sa); SoupMessageQueue *queue = soup_session_get_queue (session); SoupMessageQueueItem *item; SoupProxyURIResolver *proxy_resolver; SoupMessage *msg; SoupConnection *conn; gboolean try_pruning = TRUE, should_prune = FALSE; soup_session_cleanup_connections (session, FALSE); try_again: for (item = soup_message_queue_first (queue); item && !should_prune; item = soup_message_queue_next (queue, item)) { msg = item->msg; /* CONNECT messages are handled specially */ if (msg->method == SOUP_METHOD_CONNECT) continue; if (soup_message_io_in_progress (msg)) continue; if (!item->resolved_proxy_addr) { proxy_resolver = (SoupProxyURIResolver *)soup_session_get_feature_for_message (session, SOUP_TYPE_PROXY_URI_RESOLVER, msg); if (proxy_resolver) { resolve_proxy_addr (item, proxy_resolver); continue; } else item->resolved_proxy_addr = TRUE; } conn = soup_session_get_connection (session, item, &should_prune); if (!conn) continue; if (soup_connection_get_state (conn) == SOUP_CONNECTION_NEW) { soup_connection_connect_async (conn, got_connection, session); } else soup_session_send_queue_item (session, item, conn); } if (item) soup_message_queue_item_unref (item); if (try_pruning && should_prune) { /* There is at least one message in the queue that * could be sent if we pruned an idle connection from * some other server. */ if (soup_session_cleanup_connections (session, TRUE)) { try_pruning = should_prune = FALSE; goto try_again; } } }
static void aws_s3_client_read_got_headers (SoupMessage *message, GTask *task) { AwsS3Client *client; g_assert (SOUP_IS_MESSAGE(message)); g_assert (G_IS_TASK (task)); client = g_task_get_source_object (task); g_assert (AWS_IS_S3_CLIENT (client)); if (!SOUP_STATUS_IS_SUCCESSFUL (message->status_code)) { /* * Extract the given error type. */ if (message->status_code == SOUP_STATUS_NOT_FOUND) { g_task_return_new_error (task, AWS_S3_CLIENT_ERROR, AWS_S3_CLIENT_ERROR_NOT_FOUND, "The requested object was not found."); soup_session_cancel_message (SOUP_SESSION (client), message, message->status_code); } else if (SOUP_STATUS_IS_CLIENT_ERROR (message->status_code)) { g_task_return_new_error (task, AWS_S3_CLIENT_ERROR, AWS_S3_CLIENT_ERROR_BAD_REQUEST, "The request was invalid."); soup_session_cancel_message (SOUP_SESSION (client), message, message->status_code); } else { g_task_return_new_error (task, AWS_S3_CLIENT_ERROR, AWS_S3_CLIENT_ERROR_UNKNOWN, "An unknown error occurred."); soup_session_cancel_message (SOUP_SESSION (client), message, SOUP_STATUS_CANCELLED); } } }
static void dispose (GObject *object) { SoupSession *session = SOUP_SESSION (object); SoupSessionPrivate *priv = SOUP_SESSION_GET_PRIVATE (session); soup_session_abort (session); while (priv->features) soup_session_remove_feature (session, priv->features->data); G_OBJECT_CLASS (soup_session_parent_class)->dispose (object); }
/** * push_c2dm_client_deliver_async: * @client: A #PushC2dmClient. * @identity: A #PushC2dmIdentity. * @message: A #PushC2dmMessage. * @cancellable: (allow-none): A #GCancellable, or %NULL. * @callback: A callback to execute upon completion. * @user_data: User data for @callback. * * Requests that @message is pushed to the device identified by @identity. * Upon completion, @callback will be executed and is expected to call * push_c2dm_client_deliver_finish() to retrieve the result. */ void push_c2dm_client_deliver_async (PushC2dmClient *client, PushC2dmIdentity *identity, PushC2dmMessage *message, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) { PushC2dmClientPrivate *priv; GSimpleAsyncResult *simple; const gchar *auth_header; const gchar *registration_id; SoupMessage *request; GHashTable *params; ENTRY; g_return_if_fail(PUSH_IS_C2DM_CLIENT(client)); g_return_if_fail(PUSH_IS_C2DM_IDENTITY(identity)); g_return_if_fail(PUSH_IS_C2DM_MESSAGE(message)); g_return_if_fail(!cancellable || G_IS_CANCELLABLE(cancellable)); g_return_if_fail(callback); priv = client->priv; registration_id = push_c2dm_identity_get_registration_id(identity); params = push_c2dm_message_build_params(message); g_hash_table_insert(params, g_strdup("registration_id"), g_strdup(registration_id)); request = soup_form_request_new_from_hash(SOUP_METHOD_POST, PUSH_C2DM_CLIENT_URL, params); auth_header = g_strdup_printf("GoogleLogin auth=%s", priv->auth_token); soup_message_headers_append(request->request_headers, "Authorization", auth_header); simple = g_simple_async_result_new(G_OBJECT(client), callback, user_data, push_c2dm_client_deliver_async); g_simple_async_result_set_check_cancellable(simple, cancellable); g_object_set_data_full(G_OBJECT(simple), "registration-id", g_strdup(registration_id), g_free); soup_session_queue_message(SOUP_SESSION(client), request, push_c2dm_client_message_cb, simple); g_hash_table_unref(params); EXIT; }
static void get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { SoupSession *session = SOUP_SESSION (object); SoupSessionPrivate *priv = SOUP_SESSION_GET_PRIVATE (session); switch (prop_id) { case PROP_PROXY_URI: if (priv->proxy_resolver && SOUP_IS_PROXY_RESOLVER_STATIC (priv->proxy_resolver)) { g_object_get_property (G_OBJECT (priv->proxy_resolver), SOUP_PROXY_RESOLVER_STATIC_PROXY_URI, value); } else g_value_set_boxed (value, NULL); break; case PROP_MAX_CONNS: g_value_set_int (value, priv->max_conns); break; case PROP_MAX_CONNS_PER_HOST: g_value_set_int (value, priv->max_conns_per_host); break; case PROP_USE_NTLM: g_object_get_property (G_OBJECT (priv->auth_manager), SOUP_AUTH_MANAGER_NTLM_USE_NTLM, value); break; case PROP_SSL_CA_FILE: g_value_set_string (value, priv->ssl_ca_file); break; case PROP_ASYNC_CONTEXT: g_value_set_pointer (value, priv->async_context ? g_main_context_ref (priv->async_context) : NULL); break; case PROP_TIMEOUT: g_value_set_uint (value, priv->io_timeout); break; case PROP_USER_AGENT: g_value_set_string (value, priv->user_agent); break; case PROP_IDLE_TIMEOUT: g_value_set_uint (value, priv->idle_timeout); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } }
static void run_queue (SoupSessionAsync *sa) { SoupSession *session = SOUP_SESSION (sa); SoupMessageQueue *queue = soup_session_get_queue (session); SoupMessageQueueItem *item; SoupMessage *msg; gboolean try_pruning = TRUE, should_prune = FALSE; g_object_ref (session); soup_session_cleanup_connections (session, FALSE); try_again: for (item = soup_message_queue_first (queue); item && !should_prune; item = soup_message_queue_next (queue, item)) { msg = item->msg; /* CONNECT messages are handled specially */ if (msg->method != SOUP_METHOD_CONNECT) process_queue_item (item, &should_prune, TRUE); } if (item) soup_message_queue_item_unref (item); if (try_pruning && should_prune) { /* There is at least one message in the queue that * could be sent if we pruned an idle connection from * some other server. */ if (soup_session_cleanup_connections (session, TRUE)) { try_pruning = should_prune = FALSE; goto try_again; } } g_object_unref (session); }
static void send_message_cb(GObject* source, GAsyncResult* res, gpointer udata) { RETURN_IF_FAIL(SOUP_IS_SESSION(source)); RETURN_IF_FAIL(G_IS_ASYNC_RESULT(res)); RETURN_IF_FAIL(udata != NULL); ResourceData* data = udata; GtResourceDownloader* self = GT_RESOURCE_DOWNLOADER(data->self); GtResourceDownloaderPrivate* priv = gt_resource_downloader_get_instance_private(self); g_autoptr(GError) err = NULL; data->istream = soup_session_send_finish(SOUP_SESSION(source), res, &err); if (!err) g_thread_pool_push(dl_pool, data, NULL); else { data->cb(NULL, data->udata, g_steal_pointer(&err)); resource_data_free(data); } }
/** * push_gcm_client_deliver_async: * @client: (in): A #PushGcmClient. * @identities: (element-type PushGcmIdentity*): A #GList of #PushGcmIdentity. * @message: A #PushGcmMessage. * @cancellable: (allow-none): A #GCancellable or %NULL. * @callback: A #GAsyncReadyCallback. * @user_data: User data for @callback. * * Asynchronously deliver a #PushGcmMessage to one or more GCM enabled * devices. */ void push_gcm_client_deliver_async (PushGcmClient *client, GList *identities, PushGcmMessage *message, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) { PushGcmClientPrivate *priv; GSimpleAsyncResult *simple; SoupMessage *request; const gchar *registration_id; const gchar *collapse_key; JsonGenerator *g; JsonObject *obj; JsonObject *data; JsonObject *mdata; JsonArray *ar; JsonNode *node; GList *iter; GList *list; gchar *str; gsize length; guint time_to_live; ENTRY; g_return_if_fail(PUSH_IS_GCM_CLIENT(client)); g_return_if_fail(identities); g_return_if_fail(PUSH_IS_GCM_MESSAGE(message)); g_return_if_fail(!cancellable || G_IS_CANCELLABLE(cancellable)); g_return_if_fail(callback); priv = client->priv; request = soup_message_new("POST", PUSH_GCM_CLIENT_URL); ar = json_array_new(); for (iter = identities; iter; iter = iter->next) { g_assert(PUSH_IS_GCM_IDENTITY(iter->data)); registration_id = push_gcm_identity_get_registration_id(iter->data); json_array_add_string_element(ar, registration_id); } str = g_strdup_printf("key=%s", priv->auth_token); soup_message_headers_append(request->request_headers, "Authorization", str); g_free(str); soup_message_headers_append(request->request_headers, "Accept", "application/json"); data = json_object_new(); if ((collapse_key = push_gcm_message_get_collapse_key(message))) { json_object_set_string_member(data, "collapse_key", collapse_key); } json_object_set_boolean_member(data, "delay_while_idle", push_gcm_message_get_delay_while_idle(message)); json_object_set_boolean_member(data, "dry_run", push_gcm_message_get_dry_run(message)); if ((time_to_live = push_gcm_message_get_time_to_live(message))) { json_object_set_int_member(data, "time_to_live", time_to_live); } if ((mdata = push_gcm_message_get_data(message))) { json_object_set_object_member(data, "data", mdata); } obj = json_object_new(); json_object_set_array_member(obj, "registration_ids", ar); json_object_set_object_member(obj, "data", data); node = json_node_new(JSON_NODE_OBJECT); json_node_set_object(node, obj); json_object_unref(obj); g = json_generator_new(); json_generator_set_pretty(g, TRUE); json_generator_set_indent(g, 2); json_generator_set_root(g, node); str = json_generator_to_data(g, &length); json_node_free(node); g_object_unref(g); g_print("REQUEST: \"%s\"\n", str); soup_message_set_request(request, "application/json", SOUP_MEMORY_TAKE, str, length); simple = g_simple_async_result_new(G_OBJECT(client), callback, user_data, push_gcm_client_deliver_async); /* * Keep the list of identities around until we receive our result. * We need them to key with the resulting array. */ list = g_list_copy(identities); g_list_foreach(list, (GFunc)g_object_ref, NULL); g_object_set_data_full(G_OBJECT(simple), "identities", list, _push_gcm_identities_free); soup_session_queue_message(SOUP_SESSION(client), request, push_gcm_client_deliver_cb, simple); EXIT; }
static void set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { SoupSession *session = SOUP_SESSION (object); SoupSessionPrivate *priv = SOUP_SESSION_GET_PRIVATE (session); SoupURI *uri; gboolean ca_file_changed = FALSE; const char *new_ca_file, *user_agent; switch (prop_id) { case PROP_PROXY_URI: uri = g_value_get_boxed (value); if (uri) { soup_session_remove_feature_by_type (session, SOUP_TYPE_PROXY_RESOLVER); priv->proxy_resolver = SOUP_PROXY_URI_RESOLVER (soup_proxy_resolver_static_new (uri)); soup_session_add_feature (session, SOUP_SESSION_FEATURE (priv->proxy_resolver)); g_object_unref (priv->proxy_resolver); } else if (priv->proxy_resolver && SOUP_IS_PROXY_RESOLVER_STATIC (priv->proxy_resolver)) soup_session_remove_feature_by_type (session, SOUP_TYPE_PROXY_RESOLVER); soup_session_abort (session); break; case PROP_MAX_CONNS: priv->max_conns = g_value_get_int (value); break; case PROP_MAX_CONNS_PER_HOST: priv->max_conns_per_host = g_value_get_int (value); break; case PROP_USE_NTLM: g_object_set_property (G_OBJECT (priv->auth_manager), SOUP_AUTH_MANAGER_NTLM_USE_NTLM, value); break; case PROP_SSL_CA_FILE: new_ca_file = g_value_get_string (value); if (!safe_str_equal (priv->ssl_ca_file, new_ca_file)) ca_file_changed = TRUE; g_free (priv->ssl_ca_file); priv->ssl_ca_file = g_strdup (new_ca_file); if (ca_file_changed && priv->ssl_creds) { soup_ssl_free_client_credentials (priv->ssl_creds); priv->ssl_creds = NULL; } break; case PROP_ASYNC_CONTEXT: priv->async_context = g_value_get_pointer (value); if (priv->async_context) g_main_context_ref (priv->async_context); break; case PROP_TIMEOUT: priv->io_timeout = g_value_get_uint (value); break; case PROP_USER_AGENT: g_free (priv->user_agent); user_agent = g_value_get_string (value); if (!user_agent) priv->user_agent = NULL; else if (!*user_agent) { priv->user_agent = g_strdup (SOUP_SESSION_USER_AGENT_BASE); } else if (g_str_has_suffix (user_agent, " ")) { priv->user_agent = g_strdup_printf ("%s%s", user_agent, SOUP_SESSION_USER_AGENT_BASE); } else priv->user_agent = g_strdup (user_agent); break; case PROP_IDLE_TIMEOUT: priv->idle_timeout = g_value_get_uint (value); break; case PROP_ADD_FEATURE: soup_session_add_feature (session, g_value_get_object (value)); break; case PROP_ADD_FEATURE_BY_TYPE: soup_session_add_feature_by_type (session, g_value_get_gtype (value)); break; case PROP_REMOVE_FEATURE_BY_TYPE: soup_session_remove_feature_by_type (session, g_value_get_gtype (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } }
void aws_s3_client_read_async (AwsS3Client *client, const gchar *bucket, const gchar *path, AwsS3ClientDataHandler handler, gpointer handler_data, GDestroyNotify handler_notify, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) { AwsS3ClientPrivate *priv = aws_s3_client_get_instance_private (client); g_autoptr(GTask) task = NULL; g_autofree gchar *auth = NULL; g_autofree gchar *date_str = NULL; g_autofree gchar *signature = NULL; g_autofree gchar *uri = NULL; g_autoptr(SoupDate) date = NULL; g_autoptr(GString) str = NULL; g_autoptr(SoupMessage) message = NULL; ReadState *state; guint16 port; g_return_if_fail (AWS_IS_S3_CLIENT(client)); g_return_if_fail (bucket); g_return_if_fail (path); g_return_if_fail (g_utf8_validate(bucket, -1, NULL)); g_return_if_fail (g_utf8_validate(path, -1, NULL)); g_return_if_fail (handler != NULL); task = g_task_new (client, cancellable, callback, user_data); g_task_set_source_tag (task, aws_s3_client_read_async); state = read_state_new (handler, handler_data, handler_notify); g_task_set_task_data (task, state, read_state_free); /* * Strip leading '/' from the path. */ while (g_utf8_get_char (path) == '/') path = g_utf8_next_char (path); /* * Determine our connection port. */ port = priv->port_set ? priv->port : (priv->secure ? 443 : 80); /* * Build our HTTP request message. */ uri = g_strdup_printf ("%s://%s:%d/%s/%s", priv->secure ? "https" : "http", priv->host, port, bucket, path); message = soup_message_new (SOUP_METHOD_GET, uri); soup_message_body_set_accumulate (message->response_body, FALSE); g_signal_connect_object (message, "got-chunk", G_CALLBACK (aws_s3_client_read_got_chunk), task, 0); g_signal_connect_object (message, "got-headers", G_CALLBACK (aws_s3_client_read_got_headers), task, 0); /* * Set the Host header for systems that may be proxying. */ if (priv->host != NULL) soup_message_headers_append (message->request_headers, "Host", priv->host); /* * Add the Date header which we need for signing. */ date = soup_date_new_from_now (0); date_str = soup_date_to_string (date, SOUP_DATE_HTTP); soup_message_headers_append (message->request_headers, "Date", date_str); /* * Sign our request. */ str = g_string_new ("GET\n\n\n"); g_string_append_printf (str, "%s\n", date_str); g_string_append_printf (str, "/%s/%s", bucket, path); signature = aws_credentials_sign (priv->creds, str->str, str->len, G_CHECKSUM_SHA1); /* * Attach request signature to our headers. */ auth = g_strdup_printf ("AWS %s:%s", aws_credentials_get_access_key (priv->creds), signature); soup_message_headers_append (message->request_headers, "Authorization", auth); /* * Submit our request to the target. */ soup_session_queue_message (SOUP_SESSION (client), g_steal_pointer (&message), aws_s3_client_read_cb, g_steal_pointer (&task)); }
static void catch_resource_group_api_fetch_async (CatchResourceGroup *group, guint index_, guint count, GAsyncReadyCallback callback, gpointer user_data) { CatchResourceGroupPrivate *priv; CatchMessageBuilder *builder; GSimpleAsyncResult *simple; SoupMessage *message; const gchar *space = NULL; /* TODO */ ENTRY; g_return_if_fail(CATCH_IS_RESOURCE_GROUP(group)); g_return_if_fail(callback != NULL); priv = group->priv; g_assert(priv->resource_type); g_assert(priv->session); if (count && ((index_ + count) > priv->count)) { count = priv->count - index_; } /* * If we can satisfy the request immediately, do so. */ if (priv->first_page_size && priv->first_page_size >= (index_ + count)) { simple = g_simple_async_result_new(G_OBJECT(group), callback, user_data, catch_resource_group_fetch_async); g_simple_async_result_set_op_res_gboolean(simple, TRUE); g_simple_async_result_complete_in_idle(simple); g_object_unref(simple); EXIT; } /* * Ignore the first page of results if we have already fetched them. */ if (!index_) { index_ = priv->first_page_size; count -= priv->first_page_size; } simple = g_simple_async_result_new(G_OBJECT(group), callback, user_data, catch_resource_group_fetch_async); g_object_set_data(G_OBJECT(simple), "index", GINT_TO_POINTER(index_)); g_object_set_data(G_OBJECT(simple), "count", GINT_TO_POINTER(count)); builder = catch_resource_group_get_builder(group); if (index_) { catch_message_builder_add_int_param(builder, "offset", index_); } if (count) { catch_message_builder_add_int_param(builder, "limit", count); } /* * TODO: Filtering. */ #if 0 filter = catch_resource_group_get_filter(set); if (filter && (search_query = catch_resource_filter_get_search_query(filter))) { catch_message_builder_add_string_param(builder, "q", search_query); } if (filter && (sma = catch_resource_filter_get_server_modified_at(filter))) { catch_message_builder_add_string_param(builder, "server_modified_at$gte", sma); } #endif /* * TODO: If the whole range doesn't come back on our request, we should pump * the next request. */ if (g_type_is_a(priv->resource_type, CATCH_TYPE_SPACE)) { catch_message_builder_set_path(builder, "v3", "streams", NULL); } else if (g_type_is_a(priv->resource_type, CATCH_TYPE_OBJECT)) { #if 0 if (filter) { if ((spaces = catch_resource_filter_get_spaces(filter))) { space = spaces[0]; } } #endif catch_message_builder_set_path(builder, "v3", "streams", space ? space : "sync", NULL); } else if (g_type_is_a(priv->resource_type, CATCH_TYPE_ACTIVITY)) { catch_message_builder_set_path(builder, "v3", "activities", NULL); } else { g_assert_not_reached(); } message = catch_message_builder_build(builder); soup_session_queue_message(SOUP_SESSION(priv->session), message, catch_resource_group_api_fetch_cb, simple); catch_message_builder_unref(builder); EXIT; }
static void catch_resource_group_api_fetch_cb (SoupSession *session, SoupMessage *message, gpointer user_data) { CatchResourceGroupPrivate *priv; CatchMessageBuilder *builder; GSimpleAsyncResult *simple = user_data; CatchResourceGroup *group; const gchar *uri; JsonNode *node = NULL; GError *error = NULL; guint offset; guint n_resources; guint count; guint index_; ENTRY; g_return_if_fail(G_IS_SIMPLE_ASYNC_RESULT(simple)); group = CATCH_RESOURCE_GROUP(g_async_result_get_source_object(user_data)); g_return_if_fail(CATCH_IS_RESOURCE_GROUP(group)); priv = group->priv; if (!(node = catch_resource_group_api_parse_response(group, message, &error))) { g_simple_async_result_take_error(simple, error); GOTO(finish); } if (g_type_is_a(priv->resource_type, CATCH_TYPE_SPACE)) { if (!catch_resource_group_api_parse_spaces(group, node, &offset, &n_resources, &error)) { g_simple_async_result_take_error(simple, error); GOTO(finish); } g_simple_async_result_set_op_res_gboolean(simple, TRUE); } else if (g_type_is_a(priv->resource_type, CATCH_TYPE_OBJECT)) { if (!catch_resource_group_api_parse_objects(group, node, &offset, &n_resources, &error)) { g_simple_async_result_take_error(simple, error); GOTO(finish); } g_simple_async_result_set_op_res_gboolean(simple, TRUE); } else if (g_type_is_a(priv->resource_type, CATCH_TYPE_ACTIVITY)) { if (!catch_resource_group_api_parse_activities(group, node, &offset, &n_resources, &error)) { g_simple_async_result_take_error(simple, error); GOTO(finish); } g_simple_async_result_set_op_res_gboolean(simple, TRUE); } else { g_assert_not_reached(); } /* * If we did not satisfy the range of items to load on this query, we need * to start another one. */ count = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(simple), "count")); index_ = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(simple), "index")); if ((offset + n_resources) < (index_ + count)) { offset += n_resources; builder = catch_resource_group_get_builder(group); catch_message_builder_add_int_param(builder, "offset", offset); uri = soup_uri_get_path(soup_message_get_uri(message)); catch_message_builder_set_path(builder, uri, NULL); message = catch_message_builder_build(builder); /* * TODO: Limit range to what we need, rather than server max. */ soup_session_queue_message(SOUP_SESSION(priv->session), message, catch_resource_group_api_fetch_cb, simple); catch_message_builder_unref(builder); if (node) { json_node_free(node); } EXIT; } g_simple_async_result_set_op_res_gboolean(simple, TRUE); finish: if (node) { json_node_free(node); } g_simple_async_result_complete_in_idle(simple); g_object_unref(simple); EXIT; }