pull: Add support for http-headers option

Some deployments may want to gate access to content based on things
like OAuth.  In this model, the client system would normally compute a
token and pass it to the server via an API.

We could theoretically support this in the remote config too, but
that'd be a bit weird for OAuth as the information is dynamic.
Therefore this cleans up the code a little bit to more clearly handle
the case that the fetcher is initialized from both remote config
data plus pull options.

Closes: #574
Approved by: giuseppe
This commit is contained in:
Colin Walters authored and Atomic Bot committed 2016-11-16 10:04:22 +00:00
1 parent 4b7ab5167c
commit 37c07d2f1c
7 files changed
+171 -6

No files matched your search

+34
View File
@@ -53,6 +53,7 @@ typedef struct {
GLnxLockFile tmpdir_lock;
int base_tmpdir_dfd;
GVariant *extra_headers;
int max_outstanding;
/* Queue for libsoup, see bgo#708591 */
@@ -148,6 +149,8 @@ thread_closure_unref (ThreadClosure *thread_closure)
g_clear_pointer (&thread_closure->main_context, g_main_context_unref);
g_clear_pointer (&thread_closure->extra_headers, (GDestroyNotify)g_variant_unref);
if (thread_closure->tmpdir_dfd != -1)
close (thread_closure->tmpdir_dfd);
@@ -336,6 +339,16 @@ session_thread_set_cookie_jar_cb (ThreadClosure *thread_closure,
SOUP_SESSION_FEATURE (jar));
}
static void
session_thread_set_headers_cb (ThreadClosure *thread_closure,
gpointer data)
{
GVariant *headers = data;
g_clear_pointer (&thread_closure->extra_headers, (GDestroyNotify)g_variant_unref);
thread_closure->extra_headers = g_variant_ref (headers);
}
#ifdef HAVE_LIBSOUP_CLIENT_CERTS
static void
session_thread_set_tls_interaction_cb (ThreadClosure *thread_closure,
@@ -448,6 +461,17 @@ session_thread_request_uri (ThreadClosure *thread_closure,
return;
}
if (SOUP_IS_REQUEST_HTTP (pending->request) && thread_closure->extra_headers)
{
glnx_unref_object SoupMessage *msg = soup_request_http_get_message ((SoupRequestHTTP*) pending->request);
g_autoptr(GVariantIter) viter = g_variant_iter_new (thread_closure->extra_headers);
const char *key;
const char *value;
while (g_variant_iter_next (viter, "(&s&s)", &key, &value))
soup_message_headers_append (msg->request_headers, key, value);
}
if (pending->is_stream)
{
soup_request_send_async (pending->request,
@@ -812,6 +836,16 @@ _ostree_fetcher_set_tls_database (OstreeFetcher *self,
}
}
void
_ostree_fetcher_set_extra_headers (OstreeFetcher *self,
GVariant *extra_headers)
{
session_thread_idle_add (self->thread_closure,
session_thread_set_headers_cb,
g_variant_ref (extra_headers),
(GDestroyNotify) g_variant_unref);
}
static gboolean
finish_stream (OstreeFetcherPendingURI *pending,
GCancellable *cancellable,
+3
View File
@@ -71,6 +71,9 @@ void _ostree_fetcher_set_client_cert (OstreeFetcher *fetcher,
void _ostree_fetcher_set_tls_database (OstreeFetcher *self,
GTlsDatabase *db);
void _ostree_fetcher_set_extra_headers (OstreeFetcher *self,
GVariant *extra_headers);
guint64 _ostree_fetcher_bytes_transferred (OstreeFetcher *self);
void _ostree_fetcher_mirrored_request_with_partial_async (OstreeFetcher *self,
+24 -5
View File
@@ -54,6 +54,8 @@ typedef struct {
GCancellable *cancellable;
OstreeAsyncProgress *progress;
GVariant *extra_headers;
gboolean dry_run;
gboolean dry_run_emitted_progress;
gboolean legacy_transaction_resuming;
@@ -2276,6 +2278,23 @@ repo_remote_fetch_summary (OstreeRepo *self,
return ret;
}
/* Create the fetcher by unioning options from the remote config, plus
* any options specific to this pull (such as extra headers).
*/
static gboolean
reinitialize_fetcher (OtPullData *pull_data, const char *remote_name, GError **error)
{
g_clear_object (&pull_data->fetcher);
pull_data->fetcher = _ostree_repo_remote_new_fetcher (pull_data->repo, remote_name, error);
if (pull_data->fetcher == NULL)
return FALSE;
if (pull_data->extra_headers)
_ostree_fetcher_set_extra_headers (pull_data->fetcher, pull_data->extra_headers);
return TRUE;
}
/* ------------------------------------------------------------------------------------------
* Below is the libsoup-invariant API; these should match
* the stub functions in the #else clause
@@ -2308,6 +2327,7 @@ repo_remote_fetch_summary (OstreeRepo *self,
* * dry-run (b): Only print information on what will be downloaded (requires static deltas)
* * override-url (s): Fetch objects from this URL if remote specifies no metalink in options
* * inherit-transaction (b): Don't initiate, finish or abort a transaction, usefult to do mutliple pulls in one transaction.
* * http-headers (a(ss)): Additional headers to add to all HTTP requests
*/
gboolean
ostree_repo_pull_with_options (OstreeRepo *self,
@@ -2368,6 +2388,7 @@ ostree_repo_pull_with_options (OstreeRepo *self,
(void) g_variant_lookup (options, "dry-run", "b", &pull_data->dry_run);
(void) g_variant_lookup (options, "override-url", "&s", &url_override);
(void) g_variant_lookup (options, "inherit-transaction", "b", &inherit_transaction);
(void) g_variant_lookup (options, "http-headers", "@a(ss)", &pull_data->extra_headers);
}
g_return_val_if_fail (pull_data->maxdepth >= -1, FALSE);
@@ -2467,8 +2488,7 @@ ostree_repo_pull_with_options (OstreeRepo *self,
pull_data->phase = OSTREE_PULL_PHASE_FETCHING_REFS;
pull_data->fetcher = _ostree_repo_remote_new_fetcher (self, remote_name_or_baseurl, error);
if (pull_data->fetcher == NULL)
if (!reinitialize_fetcher (pull_data, remote_name_or_baseurl, error))
goto out;
pull_data->tmpdir_dfd = pull_data->repo->tmp_dir_fd;
@@ -2906,9 +2926,7 @@ ostree_repo_pull_with_options (OstreeRepo *self,
/* Now discard the previous fetcher, as it was bound to a temporary main context
* for synchronous requests.
*/
g_clear_object (&pull_data->fetcher);
pull_data->fetcher = _ostree_repo_remote_new_fetcher (self, remote_name_or_baseurl, error);
if (pull_data->fetcher == NULL)
if (!reinitialize_fetcher (pull_data, remote_name_or_baseurl, error))
goto out;
pull_data->legacy_transaction_resuming = FALSE;
@@ -3120,6 +3138,7 @@ ostree_repo_pull_with_options (OstreeRepo *self,
g_source_destroy (update_timeout);
g_strfreev (configured_branches);
g_clear_object (&pull_data->fetcher);
g_clear_pointer (&pull_data->extra_headers, (GDestroyNotify)g_variant_unref);
g_clear_object (&pull_data->cancellable);
g_clear_object (&pull_data->remote_repo_local);
g_free (pull_data->remote_name);