From 9c3f77da3a0e66546334e58d9ea24bb4e94bfa63 Mon Sep 17 00:00:00 2001 From: Alexander Larsson Date: Thu, 20 Oct 2016 14:24:32 +0200 Subject: [PATCH] utils: Add flatpak_load_http_uri helper function --- common/flatpak-utils.c | 148 +++++++++++++++++++++++++++++++++++++++++ common/flatpak-utils.h | 10 +++ 2 files changed, 158 insertions(+) diff --git a/common/flatpak-utils.c b/common/flatpak-utils.c index f6ab785a..b738b221 100644 --- a/common/flatpak-utils.c +++ b/common/flatpak-utils.c @@ -3892,6 +3892,154 @@ flatpak_number_prompt (int min, int max, const char *prompt, ...) } +typedef struct { + GMainLoop *loop; + GError *error; + GString *content; + char buffer[16*1024]; + FlatpakLoadUriProgress progress; + gpointer user_data; + guint64 last_progress_time; +} LoadUriData; + +static void +stream_closed (GObject *source, GAsyncResult *res, gpointer user_data) +{ + LoadUriData *data = user_data; + GInputStream *stream = G_INPUT_STREAM (source); + g_autoptr(GError) error = NULL; + + if (!g_input_stream_close_finish (stream, res, &error)) + g_warning ("Error closing http stream: %s\n", error->message); + + g_main_loop_quit (data->loop); +} + +static void +load_uri_read_cb (GObject *source, GAsyncResult *res, gpointer user_data) +{ + LoadUriData *data = user_data; + GInputStream *stream = G_INPUT_STREAM (source); + gsize nread; + + nread = g_input_stream_read_finish (stream, res, &data->error); + if (nread == -1 || nread == 0) + { + data->progress (data->content->len, data->user_data); + g_input_stream_close_async (stream, + G_PRIORITY_DEFAULT, NULL, + stream_closed, data); + return; + } + + g_string_append_len (data->content, data->buffer, nread); + + if (g_get_monotonic_time () - data->last_progress_time > 1 * G_USEC_PER_SEC) + { + data->progress (data->content->len, data->user_data); + data->last_progress_time = g_get_monotonic_time (); + } + + g_input_stream_read_async (stream, data->buffer, sizeof (data->buffer), + G_PRIORITY_DEFAULT, NULL, + load_uri_read_cb, data); +} + +static void +load_uri_callback (GObject *source_object, + GAsyncResult *res, + gpointer user_data) +{ + SoupRequestHTTP *request = SOUP_REQUEST_HTTP(source_object); + g_autoptr(GError) error = NULL; + g_autoptr(GInputStream) in = NULL; + LoadUriData *data = user_data; + + in = soup_request_send_finish (SOUP_REQUEST (request), res, &data->error); + if (in == NULL) + { + g_main_loop_quit (data->loop); + return; + } + + g_autoptr(SoupMessage) msg = soup_request_http_get_message ((SoupRequestHTTP*) request); + if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code)) + { + GIOErrorEnum code; + + switch (msg->status_code) + { + case 404: + case 410: + code = G_IO_ERROR_NOT_FOUND; + break; + default: + code = G_IO_ERROR_FAILED; + } + + data->error = g_error_new (G_IO_ERROR, code, + "Server returned status %u: %s", + msg->status_code, + soup_status_get_phrase (msg->status_code)); + g_main_loop_quit (data->loop); + return; + } + + g_input_stream_read_async (in, data->buffer, sizeof (data->buffer), + G_PRIORITY_DEFAULT, NULL, + load_uri_read_cb, data); +} + +GBytes * +flatpak_load_http_uri (SoupSession *soup_session, + const char *uri, + FlatpakLoadUriProgress progress, + gpointer user_data, + GCancellable *cancellable, + GError **error) +{ + GBytes *bytes = NULL; + g_autoptr(SoupMessage) msg = NULL; + g_autoptr(SoupRequestHTTP) request = NULL; + g_autoptr(GMainLoop) loop = NULL; + g_autoptr(GString) content = g_string_new (""); + LoadUriData data = { NULL }; + + g_debug ("Loading %s using libsoup", uri); + + loop = g_main_loop_new (NULL, TRUE); + data.loop = loop; + data.content = content; + data.progress = progress; + data.user_data = user_data; + data.last_progress_time = g_get_monotonic_time (); + + request = soup_session_request_http (soup_session, "GET", + uri, error); + if (request == NULL) + return NULL; + + soup_request_send_async (SOUP_REQUEST(request), + cancellable, + load_uri_callback, &data); + + g_main_loop_run (loop); + + if (data.error) + { + g_propagate_error (error, data.error); + return NULL; + } + + bytes = g_string_free_to_bytes (g_steal_pointer (&content)); + g_debug ("Received %" G_GSIZE_FORMAT " bytes", g_bytes_get_size (bytes)); + + return bytes; +} + + + + /* Uncomment to get debug traces in /tmp/flatpak-completion-debug.txt (nice * to not have it interfere with stdout/stderr) */ diff --git a/common/flatpak-utils.h b/common/flatpak-utils.h index 57bdc9fa..d3593ccb 100644 --- a/common/flatpak-utils.h +++ b/common/flatpak-utils.h @@ -470,6 +470,16 @@ gboolean flatpak_allocate_tmpdir (int tmpdir_dfd, gboolean flatpak_yes_no_prompt (const char *prompt, ...); long flatpak_number_prompt (int min, int max, const char *prompt, ...); +typedef void (*FlatpakLoadUriProgress) (guint64 downloaded_bytes, + gpointer user_data); + +GBytes * flatpak_load_http_uri (SoupSession *soup_session, + const char *uri, + FlatpakLoadUriProgress progress, + gpointer user_data, + GCancellable *cancellable, + GError **error); + typedef struct { char *shell_cur; char *cur;