|
rpm-build |
0fba15 |
/*
|
|
rpm-build |
0fba15 |
* Copyright (C) 2016 Colin Walters <walters@verbum.org>
|
|
rpm-build |
0fba15 |
*
|
|
rpm-build |
0fba15 |
* SPDX-License-Identifier: LGPL-2.0+
|
|
rpm-build |
0fba15 |
*
|
|
rpm-build |
0fba15 |
* This library is free software; you can redistribute it and/or
|
|
rpm-build |
0fba15 |
* modify it under the terms of the GNU Lesser General Public
|
|
rpm-build |
0fba15 |
* License as published by the Free Software Foundation; either
|
|
rpm-build |
0fba15 |
* version 2 of the License, or (at your option) any later version.
|
|
rpm-build |
0fba15 |
*
|
|
rpm-build |
0fba15 |
* This library is distributed in the hope that it will be useful,
|
|
rpm-build |
0fba15 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
rpm-build |
0fba15 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
rpm-build |
0fba15 |
* Lesser General Public License for more details.
|
|
rpm-build |
0fba15 |
*
|
|
rpm-build |
0fba15 |
* You should have received a copy of the GNU Lesser General Public
|
|
rpm-build |
0fba15 |
* License along with this library; if not, write to the
|
|
rpm-build |
0fba15 |
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
|
rpm-build |
0fba15 |
* Boston, MA 02111-1307, USA.
|
|
rpm-build |
0fba15 |
*/
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
#include "config.h"
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
#include <gio/gfiledescriptorbased.h>
|
|
rpm-build |
0fba15 |
#include <gio/gunixoutputstream.h>
|
|
rpm-build |
0fba15 |
#include <glib-unix.h>
|
|
rpm-build |
0fba15 |
#include <curl/curl.h>
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
/* These macros came from 7.43.0, but we want to check
|
|
rpm-build |
0fba15 |
* for versions a bit earlier than that (to work on CentOS 7),
|
|
rpm-build |
0fba15 |
* so define them here if we're using an older version.
|
|
rpm-build |
0fba15 |
*/
|
|
rpm-build |
0fba15 |
#ifndef CURL_VERSION_BITS
|
|
rpm-build |
0fba15 |
#define CURL_VERSION_BITS(x,y,z) ((x)<<16|(y)<<8|z)
|
|
rpm-build |
0fba15 |
#endif
|
|
rpm-build |
0fba15 |
#ifndef CURL_AT_LEAST_VERSION
|
|
rpm-build |
0fba15 |
#define CURL_AT_LEAST_VERSION(x,y,z) (LIBCURL_VERSION_NUM >= CURL_VERSION_BITS(x, y, z))
|
|
rpm-build |
0fba15 |
#endif
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
/* Cargo culted from https://github.com/curl/curl/blob/curl-7_53_0/docs/examples/http2-download.c */
|
|
rpm-build |
0fba15 |
#ifndef CURLPIPE_MULTIPLEX
|
|
rpm-build |
0fba15 |
/* This little trick will just make sure that we don't enable pipelining for
|
|
rpm-build |
0fba15 |
libcurls old enough to not have this symbol. It is _not_ defined to zero in
|
|
rpm-build |
0fba15 |
a recent libcurl header. */
|
|
rpm-build |
0fba15 |
#define CURLPIPE_MULTIPLEX 0
|
|
rpm-build |
0fba15 |
#endif
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
#include "ostree-fetcher.h"
|
|
rpm-build |
0fba15 |
#include "ostree-fetcher-util.h"
|
|
rpm-build |
0fba15 |
#include "ostree-enumtypes.h"
|
|
rpm-build |
0fba15 |
#include "ostree-repo-private.h"
|
|
rpm-build |
0fba15 |
#include "otutil.h"
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
#include "ostree-soup-uri.h"
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
typedef struct FetcherRequest FetcherRequest;
|
|
rpm-build |
0fba15 |
typedef struct SockInfo SockInfo;
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
static int sock_cb (CURL *e, curl_socket_t s, int what, void *cbp, void *sockp);
|
|
rpm-build |
0fba15 |
static gboolean timer_cb (gpointer data);
|
|
rpm-build |
0fba15 |
static void sock_unref (SockInfo *f);
|
|
rpm-build |
0fba15 |
static int update_timeout_cb (CURLM *multi, long timeout_ms, void *userp);
|
|
rpm-build |
0fba15 |
static void request_unref (FetcherRequest *req);
|
|
rpm-build |
0fba15 |
static void initiate_next_curl_request (FetcherRequest *req, GTask *task);
|
|
rpm-build |
0fba15 |
static void destroy_and_unref_source (GSource *source);
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
struct OstreeFetcher
|
|
rpm-build |
0fba15 |
{
|
|
rpm-build |
0fba15 |
GObject parent_instance;
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
OstreeFetcherConfigFlags config_flags;
|
|
rpm-build |
0fba15 |
char *remote_name;
|
|
rpm-build |
0fba15 |
char *tls_ca_db_path;
|
|
rpm-build |
0fba15 |
char *tls_client_cert_path;
|
|
rpm-build |
0fba15 |
char *tls_client_key_path;
|
|
rpm-build |
0fba15 |
char *cookie_jar_path;
|
|
rpm-build |
0fba15 |
char *proxy;
|
|
rpm-build |
0fba15 |
struct curl_slist *extra_headers;
|
|
rpm-build |
0fba15 |
int tmpdir_dfd;
|
|
rpm-build |
0fba15 |
char *custom_user_agent;
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
GMainContext *mainctx;
|
|
rpm-build |
0fba15 |
CURLM *multi;
|
|
rpm-build |
0fba15 |
GSource *timer_event;
|
|
rpm-build |
0fba15 |
int curl_running;
|
|
rpm-build |
0fba15 |
GHashTable *outstanding_requests; /* Set<GTask> */
|
|
rpm-build |
0fba15 |
GHashTable *sockets; /* Set<SockInfo> */
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
guint64 bytes_transferred;
|
|
rpm-build |
0fba15 |
};
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
/* Information associated with a request */
|
|
rpm-build |
0fba15 |
struct FetcherRequest {
|
|
rpm-build |
0fba15 |
guint refcount;
|
|
rpm-build |
0fba15 |
GPtrArray *mirrorlist;
|
|
rpm-build |
0fba15 |
guint idx;
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
char *filename;
|
|
rpm-build |
0fba15 |
guint64 current_size;
|
|
rpm-build |
0fba15 |
guint64 max_size;
|
|
rpm-build |
0fba15 |
OstreeFetcherRequestFlags flags;
|
|
rpm-build |
0fba15 |
gboolean is_membuf;
|
|
rpm-build |
0fba15 |
GError *caught_write_error;
|
|
rpm-build |
0fba15 |
GLnxTmpfile tmpf;
|
|
rpm-build |
0fba15 |
GString *output_buf;
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
CURL *easy;
|
|
rpm-build |
0fba15 |
char error[CURL_ERROR_SIZE];
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
OstreeFetcher *fetcher;
|
|
rpm-build |
0fba15 |
};
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
/* Information associated with a specific socket */
|
|
rpm-build |
0fba15 |
struct SockInfo {
|
|
rpm-build |
0fba15 |
guint refcount;
|
|
rpm-build |
0fba15 |
curl_socket_t sockfd;
|
|
rpm-build |
0fba15 |
int action;
|
|
rpm-build |
0fba15 |
long timeout;
|
|
rpm-build |
0fba15 |
GSource *ch;
|
|
rpm-build |
0fba15 |
OstreeFetcher *fetcher;
|
|
rpm-build |
0fba15 |
};
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
enum {
|
|
rpm-build |
0fba15 |
PROP_0,
|
|
rpm-build |
0fba15 |
PROP_CONFIG_FLAGS
|
|
rpm-build |
0fba15 |
};
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
G_DEFINE_TYPE (OstreeFetcher, _ostree_fetcher, G_TYPE_OBJECT)
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
static void
|
|
rpm-build |
0fba15 |
_ostree_fetcher_set_property (GObject *object,
|
|
rpm-build |
0fba15 |
guint prop_id,
|
|
rpm-build |
0fba15 |
const GValue *value,
|
|
rpm-build |
0fba15 |
GParamSpec *pspec)
|
|
rpm-build |
0fba15 |
{
|
|
rpm-build |
0fba15 |
OstreeFetcher *self = OSTREE_FETCHER (object);
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
switch (prop_id)
|
|
rpm-build |
0fba15 |
{
|
|
rpm-build |
0fba15 |
case PROP_CONFIG_FLAGS:
|
|
rpm-build |
0fba15 |
self->config_flags = g_value_get_flags (value);
|
|
rpm-build |
0fba15 |
break;
|
|
rpm-build |
0fba15 |
default:
|
|
rpm-build |
0fba15 |
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
|
rpm-build |
0fba15 |
break;
|
|
rpm-build |
0fba15 |
}
|
|
rpm-build |
0fba15 |
}
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
static void
|
|
rpm-build |
0fba15 |
_ostree_fetcher_get_property (GObject *object,
|
|
rpm-build |
0fba15 |
guint prop_id,
|
|
rpm-build |
0fba15 |
GValue *value,
|
|
rpm-build |
0fba15 |
GParamSpec *pspec)
|
|
rpm-build |
0fba15 |
{
|
|
rpm-build |
0fba15 |
OstreeFetcher *self = OSTREE_FETCHER (object);
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
switch (prop_id)
|
|
rpm-build |
0fba15 |
{
|
|
rpm-build |
0fba15 |
case PROP_CONFIG_FLAGS:
|
|
rpm-build |
0fba15 |
g_value_set_flags (value, self->config_flags);
|
|
rpm-build |
0fba15 |
break;
|
|
rpm-build |
0fba15 |
default:
|
|
rpm-build |
0fba15 |
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
|
rpm-build |
0fba15 |
break;
|
|
rpm-build |
0fba15 |
}
|
|
rpm-build |
0fba15 |
}
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
static void
|
|
rpm-build |
0fba15 |
_ostree_fetcher_finalize (GObject *object)
|
|
rpm-build |
0fba15 |
{
|
|
rpm-build |
0fba15 |
OstreeFetcher *self = OSTREE_FETCHER (object);
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
curl_multi_cleanup (self->multi);
|
|
rpm-build |
0fba15 |
g_free (self->remote_name);
|
|
rpm-build |
0fba15 |
g_free (self->tls_ca_db_path);
|
|
rpm-build |
0fba15 |
g_free (self->tls_client_cert_path);
|
|
rpm-build |
0fba15 |
g_free (self->tls_client_key_path);
|
|
rpm-build |
0fba15 |
g_free (self->cookie_jar_path);
|
|
rpm-build |
0fba15 |
g_free (self->proxy);
|
|
rpm-build |
0fba15 |
g_assert_cmpint (g_hash_table_size (self->outstanding_requests), ==, 0);
|
|
rpm-build |
0fba15 |
g_clear_pointer (&self->extra_headers, (GDestroyNotify)curl_slist_free_all);
|
|
rpm-build |
0fba15 |
g_hash_table_unref (self->outstanding_requests);
|
|
rpm-build |
0fba15 |
g_hash_table_unref (self->sockets);
|
|
rpm-build |
0fba15 |
g_clear_pointer (&self->timer_event, (GDestroyNotify)destroy_and_unref_source);
|
|
rpm-build |
0fba15 |
if (self->mainctx)
|
|
rpm-build |
0fba15 |
g_main_context_unref (self->mainctx);
|
|
rpm-build |
0fba15 |
g_clear_pointer (&self->custom_user_agent, (GDestroyNotify)g_free);
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
G_OBJECT_CLASS (_ostree_fetcher_parent_class)->finalize (object);
|
|
rpm-build |
0fba15 |
}
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
static void
|
|
rpm-build |
0fba15 |
_ostree_fetcher_constructed (GObject *object)
|
|
rpm-build |
0fba15 |
{
|
|
rpm-build |
0fba15 |
// OstreeFetcher *self = OSTREE_FETCHER (object);
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
G_OBJECT_CLASS (_ostree_fetcher_parent_class)->constructed (object);
|
|
rpm-build |
0fba15 |
}
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
static void
|
|
rpm-build |
0fba15 |
_ostree_fetcher_class_init (OstreeFetcherClass *klass)
|
|
rpm-build |
0fba15 |
{
|
|
rpm-build |
0fba15 |
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
gobject_class->set_property = _ostree_fetcher_set_property;
|
|
rpm-build |
0fba15 |
gobject_class->get_property = _ostree_fetcher_get_property;
|
|
rpm-build |
0fba15 |
gobject_class->finalize = _ostree_fetcher_finalize;
|
|
rpm-build |
0fba15 |
gobject_class->constructed = _ostree_fetcher_constructed;
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
g_object_class_install_property (gobject_class,
|
|
rpm-build |
0fba15 |
PROP_CONFIG_FLAGS,
|
|
rpm-build |
0fba15 |
g_param_spec_flags ("config-flags",
|
|
rpm-build |
0fba15 |
"",
|
|
rpm-build |
0fba15 |
"",
|
|
rpm-build |
0fba15 |
OSTREE_TYPE_FETCHER_CONFIG_FLAGS,
|
|
rpm-build |
0fba15 |
OSTREE_FETCHER_FLAGS_NONE,
|
|
rpm-build |
0fba15 |
G_PARAM_READWRITE |
|
|
rpm-build |
0fba15 |
G_PARAM_CONSTRUCT_ONLY |
|
|
rpm-build |
0fba15 |
G_PARAM_STATIC_STRINGS));
|
|
rpm-build |
0fba15 |
}
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
static void
|
|
rpm-build |
0fba15 |
_ostree_fetcher_init (OstreeFetcher *self)
|
|
rpm-build |
0fba15 |
{
|
|
rpm-build |
0fba15 |
self->multi = curl_multi_init();
|
|
rpm-build |
0fba15 |
self->outstanding_requests = g_hash_table_new_full (NULL, NULL, (GDestroyNotify)g_object_unref, NULL);
|
|
rpm-build |
0fba15 |
self->sockets = g_hash_table_new_full (NULL, NULL, (GDestroyNotify)sock_unref, NULL);
|
|
rpm-build |
0fba15 |
curl_multi_setopt (self->multi, CURLMOPT_SOCKETFUNCTION, sock_cb);
|
|
rpm-build |
0fba15 |
curl_multi_setopt (self->multi, CURLMOPT_SOCKETDATA, self);
|
|
rpm-build |
0fba15 |
curl_multi_setopt (self->multi, CURLMOPT_TIMERFUNCTION, update_timeout_cb);
|
|
rpm-build |
0fba15 |
curl_multi_setopt (self->multi, CURLMOPT_TIMERDATA, self);
|
|
rpm-build |
0fba15 |
#if CURL_AT_LEAST_VERSION(7, 30, 0)
|
|
rpm-build |
0fba15 |
/* Let's do something reasonable here. */
|
|
rpm-build |
0fba15 |
curl_multi_setopt (self->multi, CURLMOPT_MAX_TOTAL_CONNECTIONS, 8);
|
|
rpm-build |
0fba15 |
#endif
|
|
rpm-build |
0fba15 |
/* This version mirrors the version at which we're enabling HTTP2 support.
|
|
rpm-build |
0fba15 |
* See also https://github.com/curl/curl/blob/curl-7_53_0/docs/examples/http2-download.c
|
|
rpm-build |
0fba15 |
*/
|
|
rpm-build |
0fba15 |
#if CURL_AT_LEAST_VERSION(7, 51, 0)
|
|
rpm-build |
0fba15 |
curl_multi_setopt (self->multi, CURLMOPT_PIPELINING, CURLPIPE_MULTIPLEX);
|
|
rpm-build |
0fba15 |
#endif
|
|
rpm-build |
0fba15 |
}
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
OstreeFetcher *
|
|
rpm-build |
0fba15 |
_ostree_fetcher_new (int tmpdir_dfd,
|
|
rpm-build |
0fba15 |
const char *remote_name,
|
|
rpm-build |
0fba15 |
OstreeFetcherConfigFlags flags)
|
|
rpm-build |
0fba15 |
{
|
|
rpm-build |
0fba15 |
OstreeFetcher *fetcher = g_object_new (OSTREE_TYPE_FETCHER, "config-flags", flags, NULL);
|
|
rpm-build |
0fba15 |
fetcher->remote_name = g_strdup (remote_name);
|
|
rpm-build |
0fba15 |
fetcher->tmpdir_dfd = tmpdir_dfd;
|
|
rpm-build |
0fba15 |
return fetcher;
|
|
rpm-build |
0fba15 |
}
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
static void
|
|
rpm-build |
0fba15 |
destroy_and_unref_source (GSource *source)
|
|
rpm-build |
0fba15 |
{
|
|
rpm-build |
0fba15 |
g_source_destroy (source);
|
|
rpm-build |
0fba15 |
g_source_unref (source);
|
|
rpm-build |
0fba15 |
}
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
static char *
|
|
rpm-build |
0fba15 |
request_get_uri (FetcherRequest *req, SoupURI *baseuri)
|
|
rpm-build |
0fba15 |
{
|
|
rpm-build |
0fba15 |
if (!req->filename)
|
|
rpm-build |
0fba15 |
return soup_uri_to_string (baseuri, FALSE);
|
|
rpm-build |
0fba15 |
{ g_autofree char *uristr = soup_uri_to_string (baseuri, FALSE);
|
|
rpm-build |
0fba15 |
return g_build_filename (uristr, req->filename, NULL);
|
|
rpm-build |
0fba15 |
}
|
|
rpm-build |
0fba15 |
}
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
static gboolean
|
|
rpm-build |
0fba15 |
ensure_tmpfile (FetcherRequest *req, GError **error)
|
|
rpm-build |
0fba15 |
{
|
|
rpm-build |
0fba15 |
if (!req->tmpf.initialized)
|
|
rpm-build |
0fba15 |
{
|
|
rpm-build |
0fba15 |
if (!_ostree_fetcher_tmpf_from_flags (req->flags, req->fetcher->tmpdir_dfd,
|
|
rpm-build |
0fba15 |
&req->tmpf, error))
|
|
rpm-build |
0fba15 |
return FALSE;
|
|
rpm-build |
0fba15 |
}
|
|
rpm-build |
0fba15 |
return TRUE;
|
|
rpm-build |
0fba15 |
}
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
/* Check for completed transfers, and remove their easy handles */
|
|
rpm-build |
0fba15 |
static void
|
|
rpm-build |
0fba15 |
check_multi_info (OstreeFetcher *fetcher)
|
|
rpm-build |
0fba15 |
{
|
|
rpm-build |
0fba15 |
CURLMsg *msg;
|
|
rpm-build |
0fba15 |
int msgs_left;
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
while ((msg = curl_multi_info_read (fetcher->multi, &msgs_left)) != NULL)
|
|
rpm-build |
0fba15 |
{
|
|
rpm-build |
0fba15 |
long response;
|
|
rpm-build |
0fba15 |
CURL *easy = msg->easy_handle;
|
|
rpm-build |
0fba15 |
CURLcode curlres = msg->data.result;
|
|
rpm-build |
0fba15 |
GTask *task;
|
|
rpm-build |
0fba15 |
FetcherRequest *req;
|
|
rpm-build |
0fba15 |
const char *eff_url;
|
|
rpm-build |
0fba15 |
gboolean is_file;
|
|
rpm-build |
0fba15 |
gboolean continued_request = FALSE;
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
if (msg->msg != CURLMSG_DONE)
|
|
rpm-build |
0fba15 |
continue;
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
curl_easy_getinfo (easy, CURLINFO_PRIVATE, &task);
|
|
rpm-build |
0fba15 |
curl_easy_getinfo (easy, CURLINFO_EFFECTIVE_URL, &eff_url);
|
|
rpm-build |
0fba15 |
/* We should have limited the protocols; this is what
|
|
rpm-build |
0fba15 |
* curl's tool_operate.c does.
|
|
rpm-build |
0fba15 |
*/
|
|
rpm-build |
0fba15 |
is_file = g_str_has_prefix (eff_url, "file:");
|
|
rpm-build |
0fba15 |
g_assert (is_file || g_str_has_prefix (eff_url, "http"));
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
req = g_task_get_task_data (task);
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
if (req->caught_write_error)
|
|
rpm-build |
0fba15 |
g_task_return_error (task, g_steal_pointer (&req->caught_write_error));
|
|
rpm-build |
0fba15 |
else if (curlres != CURLE_OK)
|
|
rpm-build |
0fba15 |
{
|
|
rpm-build |
0fba15 |
if (is_file && curlres == CURLE_FILE_COULDNT_READ_FILE)
|
|
rpm-build |
0fba15 |
{
|
|
rpm-build |
0fba15 |
/* Handle file not found */
|
|
rpm-build |
0fba15 |
g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
|
|
rpm-build |
0fba15 |
"%s", curl_easy_strerror (curlres));
|
|
rpm-build |
0fba15 |
}
|
|
rpm-build |
0fba15 |
else
|
|
rpm-build |
0fba15 |
{
|
|
rpm-build |
0fba15 |
g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_FAILED,
|
|
rpm-build |
0fba15 |
"While fetching %s: [%u] %s", eff_url, curlres,
|
|
rpm-build |
0fba15 |
curl_easy_strerror (curlres));
|
|
rpm-build |
0fba15 |
_ostree_fetcher_journal_failure (req->fetcher->remote_name,
|
|
rpm-build |
0fba15 |
eff_url, curl_easy_strerror (curlres));
|
|
rpm-build |
0fba15 |
}
|
|
rpm-build |
0fba15 |
}
|
|
rpm-build |
0fba15 |
else
|
|
rpm-build |
0fba15 |
{
|
|
rpm-build |
0fba15 |
curl_easy_getinfo (easy, CURLINFO_RESPONSE_CODE, &response);
|
|
rpm-build |
0fba15 |
if (!is_file && !(response >= 200 && response < 300))
|
|
rpm-build |
0fba15 |
{
|
|
rpm-build |
0fba15 |
GIOErrorEnum giocode = _ostree_fetcher_http_status_code_to_io_error (response);
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
if (req->idx + 1 == req->mirrorlist->len)
|
|
rpm-build |
0fba15 |
{
|
|
rpm-build |
0fba15 |
g_autofree char *msg = g_strdup_printf ("Server returned HTTP %lu", response);
|
|
rpm-build |
0fba15 |
g_task_return_new_error (task, G_IO_ERROR, giocode,
|
|
rpm-build |
0fba15 |
"%s", msg);
|
|
rpm-build |
0fba15 |
if (req->fetcher->remote_name &&
|
|
rpm-build |
0fba15 |
!((req->flags & OSTREE_FETCHER_REQUEST_OPTIONAL_CONTENT) > 0 &&
|
|
rpm-build |
0fba15 |
giocode == G_IO_ERROR_NOT_FOUND))
|
|
rpm-build |
0fba15 |
_ostree_fetcher_journal_failure (req->fetcher->remote_name,
|
|
rpm-build |
0fba15 |
eff_url, msg);
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
}
|
|
rpm-build |
0fba15 |
else
|
|
rpm-build |
0fba15 |
{
|
|
rpm-build |
0fba15 |
continued_request = TRUE;
|
|
rpm-build |
0fba15 |
}
|
|
rpm-build |
0fba15 |
}
|
|
rpm-build |
0fba15 |
else if (req->is_membuf)
|
|
rpm-build |
0fba15 |
{
|
|
rpm-build |
0fba15 |
GBytes *ret;
|
|
rpm-build |
0fba15 |
if ((req->flags & OSTREE_FETCHER_REQUEST_NUL_TERMINATION) > 0)
|
|
rpm-build |
0fba15 |
g_string_append_c (req->output_buf, '\0');
|
|
rpm-build |
0fba15 |
ret = g_string_free_to_bytes (req->output_buf);
|
|
rpm-build |
0fba15 |
req->output_buf = NULL;
|
|
rpm-build |
0fba15 |
g_task_return_pointer (task, ret, (GDestroyNotify)g_bytes_unref);
|
|
rpm-build |
0fba15 |
}
|
|
rpm-build |
0fba15 |
else
|
|
rpm-build |
0fba15 |
{
|
|
rpm-build |
0fba15 |
g_autoptr(GError) local_error = NULL;
|
|
rpm-build |
0fba15 |
GError **error = &local_error;
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
if (!ensure_tmpfile (req, error))
|
|
rpm-build |
0fba15 |
{
|
|
rpm-build |
0fba15 |
g_task_return_error (task, g_steal_pointer (&local_error));
|
|
rpm-build |
0fba15 |
}
|
|
rpm-build |
0fba15 |
else if (lseek (req->tmpf.fd, 0, SEEK_SET) < 0)
|
|
rpm-build |
0fba15 |
{
|
|
rpm-build |
0fba15 |
glnx_set_error_from_errno (error);
|
|
rpm-build |
0fba15 |
g_task_return_error (task, g_steal_pointer (&local_error));
|
|
rpm-build |
0fba15 |
}
|
|
rpm-build |
0fba15 |
else
|
|
rpm-build |
0fba15 |
{
|
|
rpm-build |
0fba15 |
/* We return the tmpfile in the _finish wrapper */
|
|
rpm-build |
0fba15 |
g_task_return_boolean (task, TRUE);
|
|
rpm-build |
0fba15 |
}
|
|
rpm-build |
0fba15 |
}
|
|
rpm-build |
0fba15 |
}
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
curl_multi_remove_handle (fetcher->multi, easy);
|
|
rpm-build |
0fba15 |
if (continued_request)
|
|
rpm-build |
0fba15 |
{
|
|
rpm-build |
0fba15 |
req->idx++;
|
|
rpm-build |
0fba15 |
initiate_next_curl_request (req, task);
|
|
rpm-build |
0fba15 |
}
|
|
rpm-build |
0fba15 |
else
|
|
rpm-build |
0fba15 |
{
|
|
rpm-build |
0fba15 |
g_hash_table_remove (fetcher->outstanding_requests, task);
|
|
rpm-build |
0fba15 |
if (g_hash_table_size (fetcher->outstanding_requests) == 0)
|
|
rpm-build |
0fba15 |
{
|
|
rpm-build |
0fba15 |
g_clear_pointer (&fetcher->mainctx, g_main_context_unref);
|
|
rpm-build |
0fba15 |
}
|
|
rpm-build |
0fba15 |
}
|
|
rpm-build |
0fba15 |
}
|
|
rpm-build |
0fba15 |
}
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
/* Called by glib when our timeout expires */
|
|
rpm-build |
0fba15 |
static gboolean
|
|
rpm-build |
0fba15 |
timer_cb (gpointer data)
|
|
rpm-build |
0fba15 |
{
|
|
rpm-build |
0fba15 |
OstreeFetcher *fetcher = data;
|
|
rpm-build |
0fba15 |
GSource *orig_src = fetcher->timer_event;
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
(void)curl_multi_socket_action (fetcher->multi, CURL_SOCKET_TIMEOUT, 0, &fetcher->curl_running);
|
|
rpm-build |
0fba15 |
check_multi_info (fetcher);
|
|
rpm-build |
0fba15 |
if (fetcher->timer_event == orig_src)
|
|
rpm-build |
0fba15 |
fetcher->timer_event = NULL;
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
return FALSE;
|
|
rpm-build |
0fba15 |
}
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
/* Update the event timer after curl_multi library calls */
|
|
rpm-build |
0fba15 |
static int
|
|
rpm-build |
0fba15 |
update_timeout_cb (CURLM *multi, long timeout_ms, void *userp)
|
|
rpm-build |
0fba15 |
{
|
|
rpm-build |
0fba15 |
OstreeFetcher *fetcher = userp;
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
g_clear_pointer (&fetcher->timer_event, (GDestroyNotify)destroy_and_unref_source);
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
if (timeout_ms != -1)
|
|
rpm-build |
0fba15 |
{
|
|
rpm-build |
0fba15 |
fetcher->timer_event = g_timeout_source_new (timeout_ms);
|
|
rpm-build |
0fba15 |
g_source_set_callback (fetcher->timer_event, timer_cb, fetcher, NULL);
|
|
rpm-build |
0fba15 |
g_source_attach (fetcher->timer_event, fetcher->mainctx);
|
|
rpm-build |
0fba15 |
}
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
return 0;
|
|
rpm-build |
0fba15 |
}
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
/* Called by glib when we get action on a multi socket */
|
|
rpm-build |
0fba15 |
static gboolean
|
|
rpm-build |
0fba15 |
event_cb (int fd, GIOCondition condition, gpointer data)
|
|
rpm-build |
0fba15 |
{
|
|
rpm-build |
0fba15 |
OstreeFetcher *fetcher = data;
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
int action =
|
|
rpm-build |
0fba15 |
(condition & G_IO_IN ? CURL_CSELECT_IN : 0) |
|
|
rpm-build |
0fba15 |
(condition & G_IO_OUT ? CURL_CSELECT_OUT : 0);
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
(void)curl_multi_socket_action (fetcher->multi, fd, action, &fetcher->curl_running);
|
|
rpm-build |
0fba15 |
check_multi_info (fetcher);
|
|
rpm-build |
0fba15 |
if (fetcher->curl_running > 0)
|
|
rpm-build |
0fba15 |
{
|
|
rpm-build |
0fba15 |
return TRUE;
|
|
rpm-build |
0fba15 |
}
|
|
rpm-build |
0fba15 |
else
|
|
rpm-build |
0fba15 |
{
|
|
rpm-build |
0fba15 |
return FALSE;
|
|
rpm-build |
0fba15 |
}
|
|
rpm-build |
0fba15 |
}
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
/* Clean up the SockInfo structure */
|
|
rpm-build |
0fba15 |
static void
|
|
rpm-build |
0fba15 |
sock_unref (SockInfo *f)
|
|
rpm-build |
0fba15 |
{
|
|
rpm-build |
0fba15 |
if (!f)
|
|
rpm-build |
0fba15 |
return;
|
|
rpm-build |
0fba15 |
if (--f->refcount != 0)
|
|
rpm-build |
0fba15 |
return;
|
|
rpm-build |
0fba15 |
g_clear_pointer (&f->ch, (GDestroyNotify)destroy_and_unref_source);
|
|
rpm-build |
0fba15 |
g_free (f);
|
|
rpm-build |
0fba15 |
}
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
/* Assign information to a SockInfo structure */
|
|
rpm-build |
0fba15 |
static void
|
|
rpm-build |
0fba15 |
setsock (SockInfo*f, curl_socket_t s, int act, OstreeFetcher *fetcher)
|
|
rpm-build |
0fba15 |
{
|
|
rpm-build |
0fba15 |
GIOCondition kind =
|
|
rpm-build |
0fba15 |
(act&CURL_POLL_IN?G_IO_IN:0)|(act&CURL_POLL_OUT?G_IO_OUT:0);
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
f->sockfd = s;
|
|
rpm-build |
0fba15 |
f->action = act;
|
|
rpm-build |
0fba15 |
g_clear_pointer (&f->ch, (GDestroyNotify)destroy_and_unref_source);
|
|
rpm-build |
0fba15 |
/* TODO - investigate new g_source_modify_unix_fd() so changing the poll
|
|
rpm-build |
0fba15 |
* flags involves less allocation.
|
|
rpm-build |
0fba15 |
*/
|
|
rpm-build |
0fba15 |
f->ch = g_unix_fd_source_new (f->sockfd, kind);
|
|
rpm-build |
0fba15 |
g_source_set_callback (f->ch, (GSourceFunc) event_cb, fetcher, NULL);
|
|
rpm-build |
0fba15 |
g_source_attach (f->ch, fetcher->mainctx);
|
|
rpm-build |
0fba15 |
}
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
/* Initialize a new SockInfo structure */
|
|
rpm-build |
0fba15 |
static void
|
|
rpm-build |
0fba15 |
addsock (curl_socket_t s, CURL *easy, int action, OstreeFetcher *fetcher)
|
|
rpm-build |
0fba15 |
{
|
|
rpm-build |
0fba15 |
SockInfo *fdp = g_new0 (SockInfo, 1);
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
fdp->refcount = 1;
|
|
rpm-build |
0fba15 |
fdp->fetcher = fetcher;
|
|
rpm-build |
0fba15 |
setsock (fdp, s, action, fetcher);
|
|
rpm-build |
0fba15 |
curl_multi_assign (fetcher->multi, s, fdp);
|
|
rpm-build |
0fba15 |
g_hash_table_add (fetcher->sockets, fdp);
|
|
rpm-build |
0fba15 |
}
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
/* CURLMOPT_SOCKETFUNCTION */
|
|
rpm-build |
0fba15 |
static int
|
|
rpm-build |
0fba15 |
sock_cb (CURL *easy, curl_socket_t s, int what, void *cbp, void *sockp)
|
|
rpm-build |
0fba15 |
{
|
|
rpm-build |
0fba15 |
OstreeFetcher *fetcher = cbp;
|
|
rpm-build |
0fba15 |
SockInfo *fdp = (SockInfo*) sockp;
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
if (what == CURL_POLL_REMOVE)
|
|
rpm-build |
0fba15 |
{
|
|
rpm-build |
0fba15 |
if (!g_hash_table_remove (fetcher->sockets, fdp))
|
|
rpm-build |
0fba15 |
g_assert_not_reached ();
|
|
rpm-build |
0fba15 |
}
|
|
rpm-build |
0fba15 |
else
|
|
rpm-build |
0fba15 |
{
|
|
rpm-build |
0fba15 |
if (!fdp)
|
|
rpm-build |
0fba15 |
{
|
|
rpm-build |
0fba15 |
addsock (s, easy, what, fetcher);
|
|
rpm-build |
0fba15 |
}
|
|
rpm-build |
0fba15 |
else
|
|
rpm-build |
0fba15 |
{
|
|
rpm-build |
0fba15 |
setsock (fdp, s, what, fetcher);
|
|
rpm-build |
0fba15 |
}
|
|
rpm-build |
0fba15 |
}
|
|
rpm-build |
0fba15 |
return 0;
|
|
rpm-build |
0fba15 |
}
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
/* CURLOPT_WRITEFUNCTION */
|
|
rpm-build |
0fba15 |
static size_t
|
|
rpm-build |
0fba15 |
write_cb (void *ptr, size_t size, size_t nmemb, void *data)
|
|
rpm-build |
0fba15 |
{
|
|
rpm-build |
0fba15 |
const size_t realsize = size * nmemb;
|
|
rpm-build |
0fba15 |
GTask *task = data;
|
|
rpm-build |
0fba15 |
FetcherRequest *req;
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
req = g_task_get_task_data (task);
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
if (req->caught_write_error)
|
|
rpm-build |
0fba15 |
return -1;
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
if (req->max_size > 0)
|
|
rpm-build |
0fba15 |
{
|
|
rpm-build |
0fba15 |
if (realsize > req->max_size ||
|
|
rpm-build |
0fba15 |
(realsize + req->current_size) > req->max_size)
|
|
rpm-build |
0fba15 |
{
|
|
rpm-build |
0fba15 |
const char *eff_url;
|
|
rpm-build |
0fba15 |
curl_easy_getinfo (req->easy, CURLINFO_EFFECTIVE_URL, &eff_url);
|
|
rpm-build |
0fba15 |
req->caught_write_error = g_error_new (G_IO_ERROR, G_IO_ERROR_FAILED,
|
|
rpm-build |
0fba15 |
"URI %s exceeded maximum size of %" G_GUINT64_FORMAT " bytes",
|
|
rpm-build |
0fba15 |
eff_url, req->max_size);
|
|
rpm-build |
0fba15 |
return -1;
|
|
rpm-build |
0fba15 |
}
|
|
rpm-build |
0fba15 |
}
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
if (req->is_membuf)
|
|
rpm-build |
0fba15 |
g_string_append_len (req->output_buf, ptr, realsize);
|
|
rpm-build |
0fba15 |
else
|
|
rpm-build |
0fba15 |
{
|
|
rpm-build |
0fba15 |
if (!ensure_tmpfile (req, &req->caught_write_error))
|
|
rpm-build |
0fba15 |
return -1;
|
|
rpm-build |
0fba15 |
g_assert (req->tmpf.fd >= 0);
|
|
rpm-build |
0fba15 |
if (glnx_loop_write (req->tmpf.fd, ptr, realsize) < 0)
|
|
rpm-build |
0fba15 |
{
|
|
rpm-build |
0fba15 |
glnx_set_error_from_errno (&req->caught_write_error);
|
|
rpm-build |
0fba15 |
return -1;
|
|
rpm-build |
0fba15 |
}
|
|
rpm-build |
0fba15 |
}
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
req->current_size += realsize;
|
|
rpm-build |
0fba15 |
req->fetcher->bytes_transferred += realsize;
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
return realsize;
|
|
rpm-build |
0fba15 |
}
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
/* CURLOPT_PROGRESSFUNCTION */
|
|
rpm-build |
0fba15 |
static int
|
|
rpm-build |
0fba15 |
prog_cb (void *p, double dltotal, double dlnow, double ult, double uln)
|
|
rpm-build |
0fba15 |
{
|
|
rpm-build |
0fba15 |
GTask *task = p;
|
|
rpm-build |
0fba15 |
FetcherRequest *req;
|
|
rpm-build |
0fba15 |
char *eff_url;
|
|
rpm-build |
0fba15 |
req = g_task_get_task_data (task);
|
|
rpm-build |
0fba15 |
curl_easy_getinfo (req->easy, CURLINFO_EFFECTIVE_URL, &eff_url);
|
|
rpm-build |
0fba15 |
g_printerr ("Progress: %s (%g/%g)\n", eff_url, dlnow, dltotal);
|
|
rpm-build |
0fba15 |
return 0;
|
|
rpm-build |
0fba15 |
}
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
static void
|
|
rpm-build |
0fba15 |
request_unref (FetcherRequest *req)
|
|
rpm-build |
0fba15 |
{
|
|
rpm-build |
0fba15 |
if (--req->refcount != 0)
|
|
rpm-build |
0fba15 |
return;
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
g_ptr_array_unref (req->mirrorlist);
|
|
rpm-build |
0fba15 |
g_free (req->filename);
|
|
rpm-build |
0fba15 |
g_clear_error (&req->caught_write_error);
|
|
rpm-build |
0fba15 |
glnx_tmpfile_clear (&req->tmpf);
|
|
rpm-build |
0fba15 |
if (req->output_buf)
|
|
rpm-build |
0fba15 |
g_string_free (req->output_buf, TRUE);
|
|
rpm-build |
0fba15 |
curl_easy_cleanup (req->easy);
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
g_free (req);
|
|
rpm-build |
0fba15 |
}
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
int
|
|
rpm-build |
0fba15 |
_ostree_fetcher_get_dfd (OstreeFetcher *fetcher)
|
|
rpm-build |
0fba15 |
{
|
|
rpm-build |
0fba15 |
return fetcher->tmpdir_dfd;
|
|
rpm-build |
0fba15 |
}
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
void
|
|
rpm-build |
0fba15 |
_ostree_fetcher_set_proxy (OstreeFetcher *self,
|
|
rpm-build |
0fba15 |
const char *http_proxy)
|
|
rpm-build |
0fba15 |
{
|
|
rpm-build |
0fba15 |
g_free (self->proxy);
|
|
rpm-build |
0fba15 |
self->proxy = g_strdup (http_proxy);
|
|
rpm-build |
0fba15 |
}
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
void
|
|
rpm-build |
0fba15 |
_ostree_fetcher_set_cookie_jar (OstreeFetcher *self,
|
|
rpm-build |
0fba15 |
const char *jar_path)
|
|
rpm-build |
0fba15 |
{
|
|
rpm-build |
0fba15 |
g_free (self->cookie_jar_path);
|
|
rpm-build |
0fba15 |
self->cookie_jar_path = g_strdup (jar_path);
|
|
rpm-build |
0fba15 |
}
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
void
|
|
rpm-build |
0fba15 |
_ostree_fetcher_set_client_cert (OstreeFetcher *self,
|
|
rpm-build |
0fba15 |
const char *cert_path,
|
|
rpm-build |
0fba15 |
const char *key_path)
|
|
rpm-build |
0fba15 |
{
|
|
rpm-build |
0fba15 |
g_assert ((cert_path == NULL && key_path == NULL)
|
|
rpm-build |
0fba15 |
|| (cert_path != NULL && key_path != NULL));
|
|
rpm-build |
0fba15 |
g_free (self->tls_client_cert_path);
|
|
rpm-build |
0fba15 |
self->tls_client_cert_path = g_strdup (cert_path);
|
|
rpm-build |
0fba15 |
g_free (self->tls_client_key_path);
|
|
rpm-build |
0fba15 |
self->tls_client_key_path = g_strdup (key_path);
|
|
rpm-build |
0fba15 |
}
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
void
|
|
rpm-build |
0fba15 |
_ostree_fetcher_set_tls_database (OstreeFetcher *self,
|
|
rpm-build |
0fba15 |
const char *dbpath)
|
|
rpm-build |
0fba15 |
{
|
|
rpm-build |
0fba15 |
g_free (self->tls_ca_db_path);
|
|
rpm-build |
0fba15 |
self->tls_ca_db_path = g_strdup (dbpath);
|
|
rpm-build |
0fba15 |
}
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
void
|
|
rpm-build |
0fba15 |
_ostree_fetcher_set_extra_headers (OstreeFetcher *self,
|
|
rpm-build |
0fba15 |
GVariant *extra_headers)
|
|
rpm-build |
0fba15 |
{
|
|
rpm-build |
0fba15 |
GVariantIter viter;
|
|
rpm-build |
0fba15 |
const char *key;
|
|
rpm-build |
0fba15 |
const char *value;
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
g_clear_pointer (&self->extra_headers, (GDestroyNotify)curl_slist_free_all);
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
g_variant_iter_init (&viter, extra_headers);
|
|
rpm-build |
0fba15 |
while (g_variant_iter_loop (&viter, "(&s&s)", &key, &value))
|
|
rpm-build |
0fba15 |
{
|
|
rpm-build |
0fba15 |
g_autofree char *header = g_strdup_printf ("%s: %s", key, value);
|
|
rpm-build |
0fba15 |
self->extra_headers = curl_slist_append (self->extra_headers, header);
|
|
rpm-build |
0fba15 |
}
|
|
rpm-build |
0fba15 |
}
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
void
|
|
rpm-build |
0fba15 |
_ostree_fetcher_set_extra_user_agent (OstreeFetcher *self,
|
|
rpm-build |
0fba15 |
const char *extra_user_agent)
|
|
rpm-build |
0fba15 |
{
|
|
rpm-build |
0fba15 |
g_clear_pointer (&self->custom_user_agent, (GDestroyNotify)g_free);
|
|
rpm-build |
0fba15 |
if (extra_user_agent)
|
|
rpm-build |
0fba15 |
{
|
|
rpm-build |
0fba15 |
self->custom_user_agent =
|
|
rpm-build |
0fba15 |
g_strdup_printf ("%s %s", OSTREE_FETCHER_USERAGENT_STRING, extra_user_agent);
|
|
rpm-build |
0fba15 |
}
|
|
rpm-build |
0fba15 |
}
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
/* Re-bind all of the outstanding curl items to our new main context */
|
|
rpm-build |
0fba15 |
static void
|
|
rpm-build |
0fba15 |
adopt_steal_mainctx (OstreeFetcher *self,
|
|
rpm-build |
0fba15 |
GMainContext *mainctx)
|
|
rpm-build |
0fba15 |
{
|
|
rpm-build |
0fba15 |
g_assert (self->mainctx == NULL);
|
|
rpm-build |
0fba15 |
self->mainctx = mainctx; /* Transfer */
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
if (self->timer_event != NULL)
|
|
rpm-build |
0fba15 |
{
|
|
rpm-build |
0fba15 |
guint64 readytime = g_source_get_ready_time (self->timer_event);
|
|
rpm-build |
0fba15 |
guint64 curtime = g_source_get_time (self->timer_event);
|
|
rpm-build |
0fba15 |
guint64 timeout_micros = curtime - readytime;
|
|
rpm-build |
0fba15 |
if (curtime < readytime)
|
|
rpm-build |
0fba15 |
timeout_micros = 0;
|
|
rpm-build |
0fba15 |
update_timeout_cb (self->multi, timeout_micros / 1000, self);
|
|
rpm-build |
0fba15 |
}
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
GLNX_HASH_TABLE_FOREACH (self->sockets, SockInfo*, fdp)
|
|
rpm-build |
0fba15 |
setsock (fdp, fdp->sockfd, fdp->action, self);
|
|
rpm-build |
0fba15 |
}
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
static void
|
|
rpm-build |
0fba15 |
initiate_next_curl_request (FetcherRequest *req,
|
|
rpm-build |
0fba15 |
GTask *task)
|
|
rpm-build |
0fba15 |
{
|
|
rpm-build |
0fba15 |
CURLcode rc;
|
|
rpm-build |
0fba15 |
OstreeFetcher *self = req->fetcher;
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
if (req->easy)
|
|
rpm-build |
0fba15 |
curl_easy_cleanup (req->easy);
|
|
rpm-build |
0fba15 |
req->easy = curl_easy_init ();
|
|
rpm-build |
0fba15 |
g_assert (req->easy);
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
g_assert_cmpint (req->idx, <, req->mirrorlist->len);
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
SoupURI *baseuri = req->mirrorlist->pdata[req->idx];
|
|
rpm-build |
0fba15 |
{ g_autofree char *uri = request_get_uri (req, baseuri);
|
|
rpm-build |
0fba15 |
curl_easy_setopt (req->easy, CURLOPT_URL, uri);
|
|
rpm-build |
0fba15 |
}
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
curl_easy_setopt (req->easy, CURLOPT_USERAGENT,
|
|
rpm-build |
0fba15 |
self->custom_user_agent ?: OSTREE_FETCHER_USERAGENT_STRING);
|
|
rpm-build |
0fba15 |
if (self->extra_headers)
|
|
rpm-build |
0fba15 |
curl_easy_setopt (req->easy, CURLOPT_HTTPHEADER, self->extra_headers);
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
if (self->cookie_jar_path)
|
|
rpm-build |
0fba15 |
{
|
|
rpm-build |
0fba15 |
rc = curl_easy_setopt (req->easy, CURLOPT_COOKIEFILE, self->cookie_jar_path);
|
|
rpm-build |
0fba15 |
g_assert_cmpint (rc, ==, CURLM_OK);
|
|
rpm-build |
0fba15 |
rc = curl_easy_setopt (req->easy, CURLOPT_COOKIELIST, "RELOAD");
|
|
rpm-build |
0fba15 |
g_assert_cmpint (rc, ==, CURLM_OK);
|
|
rpm-build |
0fba15 |
}
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
if (self->proxy)
|
|
rpm-build |
0fba15 |
{
|
|
rpm-build |
0fba15 |
rc = curl_easy_setopt (req->easy, CURLOPT_PROXY, self->proxy);
|
|
rpm-build |
0fba15 |
g_assert_cmpint (rc, ==, CURLM_OK);
|
|
rpm-build |
0fba15 |
}
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
if (self->tls_ca_db_path)
|
|
rpm-build |
0fba15 |
curl_easy_setopt (req->easy, CURLOPT_CAINFO, self->tls_ca_db_path);
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
if ((self->config_flags & OSTREE_FETCHER_FLAGS_TLS_PERMISSIVE) > 0)
|
|
rpm-build |
0fba15 |
curl_easy_setopt (req->easy, CURLOPT_SSL_VERIFYPEER, 0L);
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
if (self->tls_client_cert_path)
|
|
rpm-build |
0fba15 |
{
|
|
rpm-build |
0fba15 |
/* Support for pkcs11:
|
|
rpm-build |
0fba15 |
* https://github.com/ostreedev/ostree/pull/1183
|
|
rpm-build |
0fba15 |
* This will be used by https://github.com/advancedtelematic/aktualizr
|
|
rpm-build |
0fba15 |
* at least to fetch certificates. No test coverage at the moment
|
|
rpm-build |
0fba15 |
* though. See https://gitlab.com/gnutls/gnutls/tree/master/tests/pkcs11
|
|
rpm-build |
0fba15 |
* and https://github.com/opendnssec/SoftHSMv2 and
|
|
rpm-build |
0fba15 |
* https://github.com/p11-glue/p11-kit/tree/master/p11-kit for
|
|
rpm-build |
0fba15 |
* possible ideas there.
|
|
rpm-build |
0fba15 |
*/
|
|
rpm-build |
0fba15 |
if (g_str_has_prefix (self->tls_client_key_path, "pkcs11:"))
|
|
rpm-build |
0fba15 |
{
|
|
rpm-build |
0fba15 |
curl_easy_setopt (req->easy, CURLOPT_SSLENGINE, "pkcs11");
|
|
rpm-build |
0fba15 |
curl_easy_setopt (req->easy, CURLOPT_SSLENGINE_DEFAULT, 1L);
|
|
rpm-build |
0fba15 |
curl_easy_setopt (req->easy, CURLOPT_SSLKEYTYPE, "ENG");
|
|
rpm-build |
0fba15 |
}
|
|
rpm-build |
0fba15 |
if (g_str_has_prefix (self->tls_client_cert_path, "pkcs11:"))
|
|
rpm-build |
0fba15 |
curl_easy_setopt (req->easy, CURLOPT_SSLCERTTYPE, "ENG");
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
curl_easy_setopt (req->easy, CURLOPT_SSLCERT, self->tls_client_cert_path);
|
|
rpm-build |
0fba15 |
curl_easy_setopt (req->easy, CURLOPT_SSLKEY, self->tls_client_key_path);
|
|
rpm-build |
0fba15 |
}
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
if ((self->config_flags & OSTREE_FETCHER_FLAGS_TRANSFER_GZIP) > 0)
|
|
rpm-build |
0fba15 |
curl_easy_setopt (req->easy, CURLOPT_ACCEPT_ENCODING, "");
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
/* If we have e.g. basic auth in the URL string, let's honor that */
|
|
rpm-build |
0fba15 |
const char *username = soup_uri_get_user (baseuri);
|
|
rpm-build |
0fba15 |
curl_easy_setopt (req->easy, CURLOPT_USERNAME, username);
|
|
rpm-build |
0fba15 |
const char *password = soup_uri_get_password (baseuri);
|
|
rpm-build |
0fba15 |
curl_easy_setopt (req->easy, CURLOPT_PASSWORD, password);
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
/* We should only speak HTTP; TODO: only enable file if specified */
|
|
rpm-build |
0fba15 |
curl_easy_setopt (req->easy, CURLOPT_PROTOCOLS, (long)(CURLPROTO_HTTP | CURLPROTO_HTTPS | CURLPROTO_FILE));
|
|
rpm-build |
0fba15 |
/* Picked the current version in F25 as of 20170127, since
|
|
rpm-build |
0fba15 |
* there are numerous HTTP/2 fixes since the original version in
|
|
rpm-build |
0fba15 |
* libcurl 7.43.0.
|
|
rpm-build |
0fba15 |
*/
|
|
rpm-build |
0fba15 |
if (!(self->config_flags & OSTREE_FETCHER_FLAGS_DISABLE_HTTP2))
|
|
rpm-build |
0fba15 |
{
|
|
rpm-build |
0fba15 |
#if CURL_AT_LEAST_VERSION(7, 51, 0)
|
|
rpm-build |
0fba15 |
curl_easy_setopt (req->easy, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2_0);
|
|
rpm-build |
0fba15 |
#endif
|
|
rpm-build |
0fba15 |
/* https://github.com/curl/curl/blob/curl-7_53_0/docs/examples/http2-download.c */
|
|
rpm-build |
0fba15 |
#if (CURLPIPE_MULTIPLEX > 0)
|
|
rpm-build |
0fba15 |
/* wait for pipe connection to confirm */
|
|
rpm-build |
0fba15 |
curl_easy_setopt (req->easy, CURLOPT_PIPEWAIT, 1L);
|
|
rpm-build |
0fba15 |
#endif
|
|
rpm-build |
0fba15 |
}
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
curl_easy_setopt (req->easy, CURLOPT_WRITEFUNCTION, write_cb);
|
|
rpm-build |
0fba15 |
if (g_getenv ("OSTREE_DEBUG_HTTP"))
|
|
rpm-build |
0fba15 |
curl_easy_setopt (req->easy, CURLOPT_VERBOSE, 1L);
|
|
rpm-build |
0fba15 |
curl_easy_setopt (req->easy, CURLOPT_ERRORBUFFER, req->error);
|
|
rpm-build |
0fba15 |
/* Note that the "easy" object's privdata is the task */
|
|
rpm-build |
0fba15 |
curl_easy_setopt (req->easy, CURLOPT_NOPROGRESS, 1L);
|
|
rpm-build |
0fba15 |
curl_easy_setopt (req->easy, CURLOPT_PROGRESSFUNCTION, prog_cb);
|
|
rpm-build |
0fba15 |
curl_easy_setopt (req->easy, CURLOPT_FOLLOWLOCATION, 1L);
|
|
rpm-build |
0fba15 |
curl_easy_setopt (req->easy, CURLOPT_CONNECTTIMEOUT, 30L);
|
|
rpm-build |
0fba15 |
/* We used to set CURLOPT_LOW_SPEED_LIMIT and CURLOPT_LOW_SPEED_TIME
|
|
rpm-build |
0fba15 |
* here, but see https://github.com/ostreedev/ostree/issues/878#issuecomment-347228854
|
|
rpm-build |
0fba15 |
* basically those options don't play well with HTTP2 at the moment
|
|
rpm-build |
0fba15 |
* where we can have lots of outstanding requests. Further,
|
|
rpm-build |
0fba15 |
* we could implement that functionality at a higher level
|
|
rpm-build |
0fba15 |
* more consistently too.
|
|
rpm-build |
0fba15 |
*/
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
/* closure bindings -> task */
|
|
rpm-build |
0fba15 |
curl_easy_setopt (req->easy, CURLOPT_PRIVATE, task);
|
|
rpm-build |
0fba15 |
curl_easy_setopt (req->easy, CURLOPT_WRITEDATA, task);
|
|
rpm-build |
0fba15 |
curl_easy_setopt (req->easy, CURLOPT_PROGRESSDATA, task);
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
CURLMcode multi_rc = curl_multi_add_handle (self->multi, req->easy);
|
|
rpm-build |
0fba15 |
g_assert (multi_rc == CURLM_OK);
|
|
rpm-build |
0fba15 |
}
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
static void
|
|
rpm-build |
0fba15 |
_ostree_fetcher_request_async (OstreeFetcher *self,
|
|
rpm-build |
0fba15 |
GPtrArray *mirrorlist,
|
|
rpm-build |
0fba15 |
const char *filename,
|
|
rpm-build |
0fba15 |
OstreeFetcherRequestFlags flags,
|
|
rpm-build |
0fba15 |
gboolean is_membuf,
|
|
rpm-build |
0fba15 |
guint64 max_size,
|
|
rpm-build |
0fba15 |
int priority,
|
|
rpm-build |
0fba15 |
GCancellable *cancellable,
|
|
rpm-build |
0fba15 |
GAsyncReadyCallback callback,
|
|
rpm-build |
0fba15 |
gpointer user_data)
|
|
rpm-build |
0fba15 |
{
|
|
rpm-build |
0fba15 |
g_autoptr(GTask) task = NULL;
|
|
rpm-build |
0fba15 |
FetcherRequest *req;
|
|
rpm-build |
0fba15 |
g_autoptr(GMainContext) mainctx = g_main_context_ref_thread_default ();
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
/* We don't support multiple concurrent main contexts; take
|
|
rpm-build |
0fba15 |
* a ref to the first one, and require that later invocations
|
|
rpm-build |
0fba15 |
* share it.
|
|
rpm-build |
0fba15 |
*/
|
|
rpm-build |
0fba15 |
if (g_hash_table_size (self->outstanding_requests) == 0
|
|
rpm-build |
0fba15 |
&& mainctx != self->mainctx)
|
|
rpm-build |
0fba15 |
{
|
|
rpm-build |
0fba15 |
adopt_steal_mainctx (self, g_steal_pointer (&mainctx));
|
|
rpm-build |
0fba15 |
}
|
|
rpm-build |
0fba15 |
else
|
|
rpm-build |
0fba15 |
{
|
|
rpm-build |
0fba15 |
g_assert (self->mainctx == mainctx);
|
|
rpm-build |
0fba15 |
}
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
req = g_new0 (FetcherRequest, 1);
|
|
rpm-build |
0fba15 |
req->refcount = 1;
|
|
rpm-build |
0fba15 |
req->error[0]='\0';
|
|
rpm-build |
0fba15 |
req->fetcher = self;
|
|
rpm-build |
0fba15 |
req->mirrorlist = g_ptr_array_ref (mirrorlist);
|
|
rpm-build |
0fba15 |
req->filename = g_strdup (filename);
|
|
rpm-build |
0fba15 |
req->max_size = max_size;
|
|
rpm-build |
0fba15 |
req->flags = flags;
|
|
rpm-build |
0fba15 |
req->is_membuf = is_membuf;
|
|
rpm-build |
0fba15 |
/* We'll allocate the tmpfile on demand, so we handle
|
|
rpm-build |
0fba15 |
* file I/O errors just in the write func.
|
|
rpm-build |
0fba15 |
*/
|
|
rpm-build |
0fba15 |
if (req->is_membuf)
|
|
rpm-build |
0fba15 |
req->output_buf = g_string_new ("");
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
task = g_task_new (self, cancellable, callback, user_data);
|
|
rpm-build |
0fba15 |
/* We'll use the GTask priority for our own priority queue. */
|
|
rpm-build |
0fba15 |
g_task_set_priority (task, priority);
|
|
rpm-build |
0fba15 |
g_task_set_source_tag (task, _ostree_fetcher_request_async);
|
|
rpm-build |
0fba15 |
g_task_set_task_data (task, req, (GDestroyNotify) request_unref);
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
initiate_next_curl_request (req, task);
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
g_hash_table_add (self->outstanding_requests, g_steal_pointer (&task));
|
|
rpm-build |
0fba15 |
}
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
void
|
|
rpm-build |
0fba15 |
_ostree_fetcher_request_to_tmpfile (OstreeFetcher *self,
|
|
rpm-build |
0fba15 |
GPtrArray *mirrorlist,
|
|
rpm-build |
0fba15 |
const char *filename,
|
|
rpm-build |
0fba15 |
OstreeFetcherRequestFlags flags,
|
|
rpm-build |
0fba15 |
guint64 max_size,
|
|
rpm-build |
0fba15 |
int priority,
|
|
rpm-build |
0fba15 |
GCancellable *cancellable,
|
|
rpm-build |
0fba15 |
GAsyncReadyCallback callback,
|
|
rpm-build |
0fba15 |
gpointer user_data)
|
|
rpm-build |
0fba15 |
{
|
|
rpm-build |
0fba15 |
_ostree_fetcher_request_async (self, mirrorlist, filename, flags, FALSE,
|
|
rpm-build |
0fba15 |
max_size, priority, cancellable,
|
|
rpm-build |
0fba15 |
callback, user_data);
|
|
rpm-build |
0fba15 |
}
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
gboolean
|
|
rpm-build |
0fba15 |
_ostree_fetcher_request_to_tmpfile_finish (OstreeFetcher *self,
|
|
rpm-build |
0fba15 |
GAsyncResult *result,
|
|
rpm-build |
0fba15 |
GLnxTmpfile *out_tmpf,
|
|
rpm-build |
0fba15 |
GError **error)
|
|
rpm-build |
0fba15 |
{
|
|
rpm-build |
0fba15 |
g_return_val_if_fail (g_task_is_valid (result, self), FALSE);
|
|
rpm-build |
0fba15 |
g_return_val_if_fail (g_async_result_is_tagged (result, _ostree_fetcher_request_async), FALSE);
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
GTask *task = (GTask*)result;
|
|
rpm-build |
0fba15 |
FetcherRequest *req = g_task_get_task_data (task);
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
if (!g_task_propagate_boolean (task, error))
|
|
rpm-build |
0fba15 |
return FALSE;
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
g_assert (!req->is_membuf);
|
|
rpm-build |
0fba15 |
*out_tmpf = req->tmpf;
|
|
rpm-build |
0fba15 |
req->tmpf.initialized = FALSE; /* Transfer ownership */
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
return TRUE;
|
|
rpm-build |
0fba15 |
}
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
void
|
|
rpm-build |
0fba15 |
_ostree_fetcher_request_to_membuf (OstreeFetcher *self,
|
|
rpm-build |
0fba15 |
GPtrArray *mirrorlist,
|
|
rpm-build |
0fba15 |
const char *filename,
|
|
rpm-build |
0fba15 |
OstreeFetcherRequestFlags flags,
|
|
rpm-build |
0fba15 |
guint64 max_size,
|
|
rpm-build |
0fba15 |
int priority,
|
|
rpm-build |
0fba15 |
GCancellable *cancellable,
|
|
rpm-build |
0fba15 |
GAsyncReadyCallback callback,
|
|
rpm-build |
0fba15 |
gpointer user_data)
|
|
rpm-build |
0fba15 |
{
|
|
rpm-build |
0fba15 |
_ostree_fetcher_request_async (self, mirrorlist, filename, flags, TRUE,
|
|
rpm-build |
0fba15 |
max_size, priority, cancellable,
|
|
rpm-build |
0fba15 |
callback, user_data);
|
|
rpm-build |
0fba15 |
}
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
gboolean
|
|
rpm-build |
0fba15 |
_ostree_fetcher_request_to_membuf_finish (OstreeFetcher *self,
|
|
rpm-build |
0fba15 |
GAsyncResult *result,
|
|
rpm-build |
0fba15 |
GBytes **out_buf,
|
|
rpm-build |
0fba15 |
GError **error)
|
|
rpm-build |
0fba15 |
{
|
|
rpm-build |
0fba15 |
GTask *task;
|
|
rpm-build |
0fba15 |
FetcherRequest *req;
|
|
rpm-build |
0fba15 |
gpointer ret;
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
g_return_val_if_fail (g_task_is_valid (result, self), FALSE);
|
|
rpm-build |
0fba15 |
g_return_val_if_fail (g_async_result_is_tagged (result, _ostree_fetcher_request_async), FALSE);
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
task = (GTask*)result;
|
|
rpm-build |
0fba15 |
req = g_task_get_task_data (task);
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
ret = g_task_propagate_pointer (task, error);
|
|
rpm-build |
0fba15 |
if (!ret)
|
|
rpm-build |
0fba15 |
return FALSE;
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
g_assert (req->is_membuf);
|
|
rpm-build |
0fba15 |
g_assert (out_buf);
|
|
rpm-build |
0fba15 |
*out_buf = ret;
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
return TRUE;
|
|
rpm-build |
0fba15 |
}
|
|
rpm-build |
0fba15 |
|
|
rpm-build |
0fba15 |
guint64
|
|
rpm-build |
0fba15 |
_ostree_fetcher_bytes_transferred (OstreeFetcher *self)
|
|
rpm-build |
0fba15 |
{
|
|
rpm-build |
0fba15 |
return self->bytes_transferred;
|
|
rpm-build |
0fba15 |
}
|