/*
 * FIXME: make this bullet proof wrt uri scheme.
 */
static char *
url (GSList const	*args,
     void		*user_data)
{
	char		*resolved_path;
	char		*ret;
#ifdef CCSS_WITH_SOUP
	char		*given_path;
	SoupURI		*uri;

	g_return_val_if_fail (args, NULL);

	given_path = g_strdup_printf ("file:///%s", (char const *) args->data);
	uri = soup_uri_new (given_path);
	g_free (given_path), given_path = NULL;

	resolved_path = gtk_rc_find_pixmap_in_path (gtk_settings_get_default (), NULL, uri->path);
	soup_uri_set_path (uri, resolved_path);
	g_free (resolved_path), resolved_path = NULL;

	ret = soup_uri_to_string (uri, false);
	soup_uri_free (uri), uri = NULL;
#else
	char const *given_path;

	g_return_val_if_fail (args, NULL);

	given_path = (char const *) args->data;
	resolved_path = gtk_rc_find_pixmap_in_path (gtk_settings_get_default (), NULL, given_path);
	ret = g_strdup_printf ("file:///%s", resolved_path);
	g_free (resolved_path), resolved_path = NULL;
#endif

	return ret;
}
Example #2
0
/**
 * self: The SeahorseSource to use as server for the uri
 * path: The path to add to the SOUP uri
 *
 * Returns: A #SoupUri with server, port and paths
 */
static SoupURI*
get_http_server_uri (SeahorseHKPSource *self, const char *path)
{
    g_autoptr(SoupURI) uri = NULL;
    g_autofree gchar *server = NULL;
    gchar *port;

    g_object_get (self, "key-server", &server, NULL);
    g_return_val_if_fail (server != NULL, NULL);

    uri = soup_uri_new (NULL);
    soup_uri_set_scheme (uri, SOUP_URI_SCHEME_HTTP);

    /* If it already has a port then use that */
    port = strchr (server, ':');
    if (port) {
        *port++ = '\0';
        soup_uri_set_port (uri, atoi (port));
    } else {
        /* default HKP port */
        soup_uri_set_port (uri, 11371);
    }

    soup_uri_set_host (uri, server);
    soup_uri_set_path (uri, path);

    return g_steal_pointer (&uri);
}
Example #3
0
static SoupURI *
suburi_new (SoupURI   *base,
            const char *first,
            ...)
{
  va_list args;
  GPtrArray *arg_array;
  const char *arg;
  char *subpath;
  SoupURI *ret;

  arg_array = g_ptr_array_new ();
  g_ptr_array_add (arg_array, (char*)soup_uri_get_path (base));
  g_ptr_array_add (arg_array, (char*)first);

  va_start (args, first);
  
  while ((arg = va_arg (args, const char *)) != NULL)
    g_ptr_array_add (arg_array, (char*)arg);
  g_ptr_array_add (arg_array, NULL);

  subpath = g_build_filenamev ((char**)arg_array->pdata);
  g_ptr_array_unref (arg_array);
  
  ret = soup_uri_copy (base);
  soup_uri_set_path (ret, subpath);
  g_free (subpath);
  
  va_end (args);
  
  return ret;
}
Example #4
0
static GSocketAddressEnumerator *
soup_address_connectable_proxy_enumerate (GSocketConnectable *connectable)
{
	SoupAddress *addr = SOUP_ADDRESS (connectable);
	SoupAddressPrivate *priv = SOUP_ADDRESS_GET_PRIVATE (addr);
	GSocketAddressEnumerator *proxy_enum;
	SoupURI *uri;
	char *uri_string;

	/* We cheerily assume "http" here because you shouldn't be
	 * using SoupAddress any more if you're not doing HTTP anyway.
	 */
	uri = soup_uri_new (NULL);
	soup_uri_set_scheme (uri, priv->protocol ? priv->protocol : "http");
	soup_uri_set_host (uri, priv->name ? priv->name : soup_address_get_physical (addr));
	soup_uri_set_port (uri, priv->port);
	soup_uri_set_path (uri, "");
	uri_string = soup_uri_to_string_internal (uri, FALSE, TRUE);

	proxy_enum = g_object_new (G_TYPE_PROXY_ADDRESS_ENUMERATOR,
				   "connectable", connectable,
				   "uri", uri_string,
				   NULL);
	g_free (uri_string);
	soup_uri_free (uri);

	return proxy_enum;
}
Example #5
0
/* Server handlers for "*" work but are separate from handlers for
 * all other URIs. #590751
 */
static void
do_star_test (void)
{
	SoupSession *session;
	SoupMessage *msg;
	SoupURI *star_uri;
	const char *handled_by;

	debug_printf (1, "\nOPTIONS *\n");

	session = soup_test_session_new (SOUP_TYPE_SESSION_SYNC, NULL);
	star_uri = soup_uri_copy (base_uri);
	soup_uri_set_path (star_uri, "*");

	debug_printf (1, "  Testing with no handler\n");
	msg = soup_message_new_from_uri ("OPTIONS", star_uri);
	soup_session_send_message (session, msg);

	if (msg->status_code != SOUP_STATUS_NOT_FOUND) {
		debug_printf (1, "    Unexpected response: %d %s\n",
			      msg->status_code, msg->reason_phrase);
		errors++;
	}
	handled_by = soup_message_headers_get_one (msg->response_headers,
						   "X-Handled-By");
	if (handled_by) {
		/* Should have been rejected by SoupServer directly */
		debug_printf (1, "    Message reached handler '%s'\n",
			      handled_by);
		errors++;
	}
	g_object_unref (msg);

	soup_server_add_handler (server, "*", server_star_callback, NULL, NULL);

	debug_printf (1, "  Testing with handler\n");
	msg = soup_message_new_from_uri ("OPTIONS", star_uri);
	soup_session_send_message (session, msg);

	if (msg->status_code != SOUP_STATUS_OK) {
		debug_printf (1, "    Unexpected response: %d %s\n",
			      msg->status_code, msg->reason_phrase);
		errors++;
	}
	handled_by = soup_message_headers_get_one (msg->response_headers,
						   "X-Handled-By");
	if (!handled_by) {
		debug_printf (1, "    Message did not reach handler!\n");
		errors++;
	} else if (strcmp (handled_by, "star_callback") != 0) {
		debug_printf (1, "    Message reached incorrect handler '%s'\n",
			      handled_by);
		errors++;
	}
	g_object_unref (msg);

	soup_test_session_abort_unref (session);
	soup_uri_free (star_uri);
}
static SoupURI *
get_uri_to_sig (SoupURI *uri)
{
  g_autofree gchar *sig_path = NULL;
  SoupURI *sig_uri = soup_uri_copy (uri);

  sig_path = g_strconcat (soup_uri_get_path (uri), ".sig", NULL);
  soup_uri_set_path (sig_uri, sig_path);

  return sig_uri;
}
Example #7
0
static void
do_auth_close_test (void)
{
	SoupServer *server;
	SoupAuthDomain *basic_auth_domain;
	SoupURI *uri;
	AuthCloseData acd;

	server = soup_test_server_new (SOUP_TEST_SERVER_DEFAULT);
	soup_server_add_handler (server, NULL,
				 server_callback, NULL, NULL);

	uri = soup_test_server_get_uri (server, "http", NULL);
	soup_uri_set_path (uri, "/close");

	basic_auth_domain = soup_auth_domain_basic_new (
		SOUP_AUTH_DOMAIN_REALM, "auth-test",
		SOUP_AUTH_DOMAIN_ADD_PATH, "/",
		SOUP_AUTH_DOMAIN_BASIC_AUTH_CALLBACK, server_basic_auth_callback,
		NULL);
	soup_server_add_auth_domain (server, basic_auth_domain);
	g_object_unref (basic_auth_domain);

	g_signal_connect (server, "request-started",
			  G_CALLBACK (auth_close_request_started), NULL);

	acd.session = soup_test_session_new (SOUP_TYPE_SESSION_ASYNC, NULL);
	g_signal_connect (acd.session, "authenticate",
			  G_CALLBACK (auth_close_authenticate), &acd);

	acd.msg = soup_message_new_from_uri ("GET", uri);
	soup_uri_free (uri);
	soup_session_send_message (acd.session, acd.msg);

	soup_test_assert_message_status (acd.msg, SOUP_STATUS_OK);

	g_object_unref (acd.msg);
	soup_test_session_abort_unref (acd.session);
	soup_test_server_quit_unref (server);
}
Example #8
0
static void
do_proxy_redirect_test (void)
{
	SoupSession *session;
	SoupURI *proxy_uri, *req_uri, *new_uri;
	SoupMessage *msg;

	debug_printf (1, "\nTesting redirection through proxy\n");

	proxy_uri = soup_uri_new (proxies[SIMPLE_PROXY]);
	session = soup_test_session_new (SOUP_TYPE_SESSION_ASYNC,
					 SOUP_SESSION_PROXY_URI, proxy_uri,
					 NULL);
	soup_uri_free (proxy_uri);

	req_uri = soup_uri_new (HTTPS_SERVER);
	soup_uri_set_path (req_uri, "/redirected");
	msg = soup_message_new_from_uri (SOUP_METHOD_GET, req_uri);
	soup_message_headers_append (msg->request_headers,
				     "Connection", "close");
	soup_session_send_message (session, msg);

	new_uri = soup_message_get_uri (msg);
	if (!strcmp (req_uri->path, new_uri->path)) {
		debug_printf (1, "  message was not redirected!\n");
		errors++;
	}
	soup_uri_free (req_uri);

	if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code)) {
		debug_printf (1, "  unexpected status %d %s!\n",
			      msg->status_code, msg->reason_phrase);
		errors++;
	}

	g_object_unref (msg);
	soup_test_session_abort_unref (session);
}
Example #9
0
const gchar *
soupcut_server_build_uri(SoupServer   *server,
                              const gchar  *path)
{
    SoupAddress *address;
    SoupURI *uri;
    const gchar *uri_string;

    g_object_get(server,
                 SOUP_SERVER_INTERFACE, &address,
                 NULL);

    uri = soup_uri_new(NULL);
    soup_uri_set_scheme(uri, SOUP_URI_SCHEME_HTTP);
    soup_uri_set_host(uri, "localhost");
    soup_uri_set_port(uri, soup_address_get_port(address));
    soup_uri_set_path(uri, path);

    uri_string = cut_take_string(soup_uri_to_string(uri, FALSE));
    soup_uri_free(uri);

    return uri_string;
}
Example #10
0
static void
network_set_soup_session_proxy (SoupSession *session, ProxyDetectMode mode, const gchar *host, guint port, const gchar *user, const gchar *password)
{
	SoupURI *uri = NULL;

	switch (mode) {
		case PROXY_DETECT_MODE_AUTO:
			/* Sets proxy-resolver to the default resolver, this unsets proxy-uri. */
			g_object_set (G_OBJECT (session),
				SOUP_SESSION_PROXY_RESOLVER, g_proxy_resolver_get_default (),
				NULL);
			break;
		case PROXY_DETECT_MODE_NONE:
			/* Sets proxy-resolver to NULL, this unsets proxy-uri. */
			g_object_set (G_OBJECT (session),
				SOUP_SESSION_PROXY_RESOLVER, NULL,
				NULL);
			break;
		case PROXY_DETECT_MODE_MANUAL:
			uri = soup_uri_new (NULL);
			soup_uri_set_scheme (uri, SOUP_URI_SCHEME_HTTP);
			soup_uri_set_host (uri, host);
			soup_uri_set_port (uri, port);
			soup_uri_set_user (uri, user);
			soup_uri_set_password (uri, password);
			soup_uri_set_path (uri, "/");

			if (SOUP_URI_IS_VALID (uri)) {
				/* Sets proxy-uri, this unsets proxy-resolver. */
				g_object_set (G_OBJECT (session),
					SOUP_SESSION_PROXY_URI, uri,
					NULL);
			}
			soup_uri_free (uri);
			break;
	}
}
Example #11
0
SoupMessageQueueItem *
soup_session_make_connect_message (SoupSession *session,
				   SoupAddress *server_addr)
{
	SoupSessionPrivate *priv = SOUP_SESSION_GET_PRIVATE (session);
	SoupURI *uri;
	SoupMessage *msg;

	uri = soup_uri_new (NULL);
	soup_uri_set_scheme (uri, SOUP_URI_SCHEME_HTTPS);
	soup_uri_set_host (uri, soup_address_get_name (server_addr));
	soup_uri_set_port (uri, soup_address_get_port (server_addr));
	soup_uri_set_path (uri, "");
	msg = soup_message_new_from_uri (SOUP_METHOD_CONNECT, uri);
	soup_message_set_flags (msg, SOUP_MESSAGE_NO_REDIRECT);
	soup_uri_free (uri);

	/* Call the base implementation of soup_session_queue_message
	 * directly, to add msg to the SoupMessageQueue and cause all
	 * the right signals to be emitted.
	 */
	queue_message (session, msg, tunnel_connected, NULL);
	return soup_message_queue_lookup (priv->queue, msg);
}
Example #12
0
gboolean
ostree_repo_pull (OstreeRepo               *self,
                  const char               *remote_name,
                  char                    **refs_to_fetch,
                  OstreeRepoPullFlags       flags,
                  OstreeAsyncProgress      *progress,
                  GCancellable             *cancellable,
                  GError                  **error)
{
  gboolean ret = FALSE;
  GHashTableIter hash_iter;
  gpointer key, value;
  gboolean tls_permissive = FALSE;
  OstreeFetcherConfigFlags fetcher_flags = 0;
  gs_free char *remote_key = NULL;
  gs_free char *path = NULL;
  gs_free char *baseurl = NULL;
  gs_free char *summary_data = NULL;
  gs_unref_hashtable GHashTable *requested_refs_to_fetch = NULL;
  gs_unref_hashtable GHashTable *updated_refs = NULL;
  gs_unref_hashtable GHashTable *commits_to_fetch = NULL;
  gs_free char *remote_mode_str = NULL;
  GSource *queue_src = NULL;
  OtPullData pull_data_real = { 0, };
  OtPullData *pull_data = &pull_data_real;
  SoupURI *summary_uri = NULL;
  GKeyFile *config = NULL;
  GKeyFile *remote_config = NULL;
  char **configured_branches = NULL;
  guint64 bytes_transferred;
  guint64 start_time;
  guint64 end_time;

  pull_data->async_error = error;
  pull_data->main_context = g_main_context_ref_thread_default ();
  pull_data->loop = g_main_loop_new (pull_data->main_context, FALSE);
  pull_data->flags = flags;

  pull_data->repo = self;
  pull_data->progress = progress;

  pull_data->scanned_metadata = g_hash_table_new_full (ostree_hash_object_name, g_variant_equal,
                                                       (GDestroyNotify)g_variant_unref, NULL);
  pull_data->requested_content = g_hash_table_new_full (g_str_hash, g_str_equal,
                                                        (GDestroyNotify)g_free, NULL);
  pull_data->requested_metadata = g_hash_table_new_full (g_str_hash, g_str_equal,
                                                         (GDestroyNotify)g_free, NULL);

  start_time = g_get_monotonic_time ();

  pull_data->remote_name = g_strdup (remote_name);
  config = ostree_repo_get_config (self);

  remote_key = g_strdup_printf ("remote \"%s\"", pull_data->remote_name);
  if (!repo_get_string_key_inherit (self, remote_key, "url", &baseurl, error))
    goto out;
  pull_data->base_uri = soup_uri_new (baseurl);

#ifdef HAVE_GPGME
  if (!ot_keyfile_get_boolean_with_default (config, remote_key, "gpg-verify",
                                            TRUE, &pull_data->gpg_verify, error))
    goto out;
#else
  pull_data->gpg_verify = FALSE;
#endif

  if (!ot_keyfile_get_boolean_with_default (config, remote_key, "tls-permissive",
                                            FALSE, &tls_permissive, error))
    goto out;
  if (tls_permissive)
    fetcher_flags |= OSTREE_FETCHER_FLAGS_TLS_PERMISSIVE;

  pull_data->fetcher = ostree_fetcher_new (pull_data->repo->tmp_dir,
                                           fetcher_flags);

  if (!pull_data->base_uri)
    {
      g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
                   "Failed to parse url '%s'", baseurl);
      goto out;
    }

  if (!load_remote_repo_config (pull_data, &remote_config, cancellable, error))
    goto out;

  if (!ot_keyfile_get_value_with_default (remote_config, "core", "mode", "bare",
                                          &remote_mode_str, error))
    goto out;

  if (!ostree_repo_mode_from_string (remote_mode_str, &pull_data->remote_mode, error))
    goto out;

  if (pull_data->remote_mode != OSTREE_REPO_MODE_ARCHIVE_Z2)
    {
      g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
                   "Can't pull from archives with mode \"%s\"",
                   remote_mode_str);
      goto out;
    }

  requested_refs_to_fetch = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
  updated_refs = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
  commits_to_fetch = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);

  if (refs_to_fetch != NULL)
    {
      char **strviter;
      for (strviter = refs_to_fetch; *strviter; strviter++)
        {
          const char *branch = *strviter;
          char *contents;

          if (ostree_validate_checksum_string (branch, NULL))
            {
              char *key = g_strdup (branch);
              g_hash_table_insert (commits_to_fetch, key, key);
            }
          else
            {
              if (!fetch_ref_contents (pull_data, branch, &contents, cancellable, error))
                goto out;
      
              /* Transfer ownership of contents */
              g_hash_table_insert (requested_refs_to_fetch, g_strdup (branch), contents);
            }
        }
    }
  else
    {
      GError *temp_error = NULL;
      gboolean fetch_all_refs;

      configured_branches = g_key_file_get_string_list (config, remote_key, "branches", NULL, &temp_error);
      if (configured_branches == NULL && temp_error != NULL)
        {
          if (g_error_matches (temp_error, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_KEY_NOT_FOUND))
            {
              g_clear_error (&temp_error);
              fetch_all_refs = TRUE;
            }
          else
            {
              g_propagate_error (error, temp_error);
              goto out;
            }
        }
      else
        fetch_all_refs = FALSE;

      if (fetch_all_refs)
        {
          summary_uri = soup_uri_copy (pull_data->base_uri);
          path = g_build_filename (soup_uri_get_path (summary_uri), "refs", "summary", NULL);
          soup_uri_set_path (summary_uri, path);
          
          if (!fetch_uri_contents_utf8_sync (pull_data, summary_uri, &summary_data, cancellable, error))
            goto out;
          
          if (!parse_ref_summary (summary_data, &requested_refs_to_fetch, error))
            goto out;
        }
      else
        {
          char **branches_iter = configured_branches;

          if (!(branches_iter && *branches_iter))
            g_print ("No configured branches for remote %s\n", pull_data->remote_name);
          for (;branches_iter && *branches_iter; branches_iter++)
            {
              const char *branch = *branches_iter;
              char *contents;
              
              if (!fetch_ref_contents (pull_data, branch, &contents, cancellable, error))
                goto out;
              
              /* Transfer ownership of contents */
              g_hash_table_insert (requested_refs_to_fetch, g_strdup (branch), contents);
            }
        }
    }

  if (!ostree_repo_prepare_transaction (pull_data->repo, &pull_data->transaction_resuming,
                                        cancellable, error))
    goto out;

  pull_data->metadata_objects_to_fetch = ot_waitable_queue_new ();
  pull_data->metadata_objects_to_scan = ot_waitable_queue_new ();
  pull_data->metadata_thread = g_thread_new ("metadatascan", metadata_thread_main, pull_data);

  g_hash_table_iter_init (&hash_iter, commits_to_fetch);
  while (g_hash_table_iter_next (&hash_iter, &key, &value))
    {
      const char *commit = value;

      ot_waitable_queue_push (pull_data->metadata_objects_to_scan,
                              pull_worker_message_new (PULL_MSG_SCAN,
                                                       ostree_object_name_serialize (commit, OSTREE_OBJECT_TYPE_COMMIT)));
    }

  g_hash_table_iter_init (&hash_iter, requested_refs_to_fetch);
  while (g_hash_table_iter_next (&hash_iter, &key, &value))
    {
      const char *ref = key;
      const char *sha256 = value;

      ot_waitable_queue_push (pull_data->metadata_objects_to_scan,
                              pull_worker_message_new (PULL_MSG_SCAN,
                                                       ostree_object_name_serialize (sha256, OSTREE_OBJECT_TYPE_COMMIT)));
      g_hash_table_insert (updated_refs, g_strdup (ref), g_strdup (sha256));
    }
  
  {
    queue_src = ot_waitable_queue_create_source (pull_data->metadata_objects_to_fetch);
    g_source_set_callback (queue_src, (GSourceFunc)on_metadata_objects_to_fetch_ready, pull_data, NULL);
    g_source_attach (queue_src, pull_data->main_context);
    g_source_unref (queue_src);
  }

  /* Prime the message queue */
  pull_data->idle_serial++;
  ot_waitable_queue_push (pull_data->metadata_objects_to_scan,
                          pull_worker_message_new (PULL_MSG_MAIN_IDLE, GUINT_TO_POINTER (pull_data->idle_serial)));
  
  /* Now await work completion */
  if (!run_mainloop_monitor_fetcher (pull_data))
    goto out;
  

  g_hash_table_iter_init (&hash_iter, updated_refs);
  while (g_hash_table_iter_next (&hash_iter, &key, &value))
    {
      const char *ref = key;
      const char *checksum = value;
      gs_free char *remote_ref = NULL;
      gs_free char *original_rev = NULL;
          
      remote_ref = g_strdup_printf ("%s/%s", pull_data->remote_name, ref);

      if (!ostree_repo_resolve_rev (pull_data->repo, remote_ref, TRUE, &original_rev, error))
        goto out;
          
      if (original_rev && strcmp (checksum, original_rev) == 0)
        {
          g_print ("remote %s is unchanged from %s\n", remote_ref, original_rev);
        }
      else
        {
          ostree_repo_transaction_set_ref (pull_data->repo, pull_data->remote_name, ref, checksum);

          g_print ("remote %s is now %s\n", remote_ref, checksum);
        }
    }

  if (!ostree_repo_commit_transaction (pull_data->repo, NULL, cancellable, error))
    goto out;

  end_time = g_get_monotonic_time ();

  bytes_transferred = ostree_fetcher_bytes_transferred (pull_data->fetcher);
  if (bytes_transferred > 0)
    {
      guint shift; 
      if (bytes_transferred < 1024)
        shift = 1;
      else
        shift = 1024;
      g_print ("%u metadata, %u content objects fetched; %" G_GUINT64_FORMAT " %s transferred in %u seconds\n", 
               pull_data->n_fetched_metadata, pull_data->n_fetched_content,
               (guint64)(bytes_transferred / shift),
               shift == 1 ? "B" : "KiB",
               (guint) ((end_time - start_time) / G_USEC_PER_SEC));
    }

  ret = TRUE;
 out:
  if (pull_data->main_context)
    g_main_context_unref (pull_data->main_context);
  if (pull_data->loop)
    g_main_loop_unref (pull_data->loop);
  g_strfreev (configured_branches);
  g_clear_object (&pull_data->fetcher);
  g_free (pull_data->remote_name);
  if (pull_data->base_uri)
    soup_uri_free (pull_data->base_uri);
  if (queue_src)
    g_source_destroy (queue_src);
  if (pull_data->metadata_thread)
    {
      ot_waitable_queue_push (pull_data->metadata_objects_to_scan,
                              pull_worker_message_new (PULL_MSG_QUIT, NULL));
      g_thread_join (pull_data->metadata_thread);
    }
  g_clear_pointer (&pull_data->metadata_objects_to_scan, (GDestroyNotify) ot_waitable_queue_unref);
  g_clear_pointer (&pull_data->metadata_objects_to_fetch, (GDestroyNotify) ot_waitable_queue_unref);
  g_clear_pointer (&pull_data->scanned_metadata, (GDestroyNotify) g_hash_table_unref);
  g_clear_pointer (&pull_data->requested_content, (GDestroyNotify) g_hash_table_unref);
  g_clear_pointer (&pull_data->requested_metadata, (GDestroyNotify) g_hash_table_unref);
  g_clear_pointer (&remote_config, (GDestroyNotify) g_key_file_unref);
  if (summary_uri)
    soup_uri_free (summary_uri);
  return ret;
}
static void
do_request_test (SoupSession *session, SoupURI *base_uri, RequestTestFlags flags)
{
	SoupURI *uri = base_uri;
	PutTestData ptd;
	SoupMessage *msg;
	const char *client_md5, *server_md5;
	GChecksum *check;
	int i, length;

	debug_printf (1, "PUT");
	if (flags & HACKY_STREAMING)
		debug_printf (1, " w/ hacky streaming");
	else if (flags & PROPER_STREAMING)
		debug_printf (1, " w/ proper streaming");
	if (flags & RESTART) {
		debug_printf (1, " and restart");
		uri = soup_uri_copy (base_uri);
		soup_uri_set_path (uri, "/redirect");
	}
	debug_printf (1, "\n");

	ptd.session = session;
	setup_request_body (&ptd);
	ptd.streaming = flags & (HACKY_STREAMING | PROPER_STREAMING);

	check = g_checksum_new (G_CHECKSUM_MD5);
	length = 0;
	for (i = 0; i < 3; i++) {
		g_checksum_update (check, (guchar *)ptd.chunks[i]->data,
				   ptd.chunks[i]->length);
		length += ptd.chunks[i]->length;
	}
	client_md5 = g_checksum_get_string (check);

	msg = soup_message_new_from_uri ("PUT", uri);
	soup_message_headers_set_encoding (msg->request_headers, SOUP_ENCODING_CHUNKED);
	soup_message_body_set_accumulate (msg->request_body, FALSE);
	soup_message_set_chunk_allocator (msg, error_chunk_allocator, NULL, NULL);
	if (flags & HACKY_STREAMING) {
		g_signal_connect (msg, "wrote_chunk",
				  G_CALLBACK (write_next_chunk_streaming_hack), &ptd);
		if (flags & RESTART) {
			g_signal_connect (msg, "restarted",
					  G_CALLBACK (restarted_streaming_hack), &ptd);
		}
	} else {
		g_signal_connect (msg, "wrote_chunk",
				  G_CALLBACK (write_next_chunk), &ptd);
	}

	if (flags & PROPER_STREAMING) {
		soup_message_set_flags (msg, SOUP_MESSAGE_CAN_REBUILD);
		if (flags & RESTART) {
			g_signal_connect (msg, "restarted",
					  G_CALLBACK (restarted_streaming), &ptd);
		}
	}

	g_signal_connect (msg, "wrote_headers",
			  G_CALLBACK (write_next_chunk), &ptd);
	g_signal_connect (msg, "wrote_body_data",
			  G_CALLBACK (wrote_body_data), &ptd);
	soup_session_send_message (session, msg);

	if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code)) {
		debug_printf (1, "  message failed: %d %s\n",
			      msg->status_code, msg->reason_phrase);
		errors++;
	}

	if (msg->request_body->data) {
		debug_printf (1, "  msg->request_body set!\n");
		errors++;
	}
	if (msg->request_body->length != length || length != ptd.nwrote) {
		debug_printf (1, "  sent length mismatch: %d vs %d vs %d\n",
			      (int)msg->request_body->length, length, ptd.nwrote);
		errors++;
	}

	server_md5 = soup_message_headers_get_one (msg->response_headers,
						   "Content-MD5");
	if (!server_md5 || strcmp (client_md5, server_md5) != 0) {
		debug_printf (1, "  client/server data mismatch: %s vs %s\n",
			      client_md5, server_md5 ? server_md5 : "(null)");
		errors++;
	}

	g_object_unref (msg);
	g_checksum_free (check);

	if (uri != base_uri)
		soup_uri_free (uri);
}
static guint
upload_contact (EBookBackendWebdav *webdav,
                EContact *contact,
                gchar **reason,
                GCancellable *cancellable)
{
	ESource     *source;
	ESourceWebdav *webdav_extension;
	SoupMessage *message;
	gchar       *uri;
	gchar       *etag;
	const gchar  *new_etag, *redir_uri;
	gchar        *request;
	guint        status;
	gboolean     avoid_ifmatch;
	const gchar *extension_name;

	source = e_backend_get_source (E_BACKEND (webdav));

	extension_name = E_SOURCE_EXTENSION_WEBDAV_BACKEND;
	webdav_extension = e_source_get_extension (source, extension_name);

	source = e_backend_get_source (E_BACKEND (webdav));

	uri = e_contact_get (contact, E_CONTACT_UID);
	if (uri == NULL) {
		g_warning ("can't upload contact without UID");
		return 400;
	}

	message = soup_message_new (SOUP_METHOD_PUT, uri);
	soup_message_headers_append (message->request_headers, "User-Agent", USERAGENT);
	soup_message_headers_append (message->request_headers, "Connection", "close");

	avoid_ifmatch = e_source_webdav_get_avoid_ifmatch (webdav_extension);

	/* some servers (like apache < 2.2.8) don't handle If-Match, correctly so
	 * we can leave it out */
	if (!avoid_ifmatch) {
		/* only override if etag is still the same on the server */
		etag = e_contact_get (contact, E_CONTACT_REV);
		if (etag == NULL) {
			soup_message_headers_append (
				message->request_headers,
				"If-None-Match", "*");
		} else if (etag[0] == 'W' && etag[1] == '/') {
			g_warning ("we only have a weak ETag, don't use If-Match synchronisation");
		} else {
			soup_message_headers_append (
				message->request_headers,
				"If-Match", etag);
			g_free (etag);
		}
	}

	request = e_vcard_to_string (E_VCARD (contact), EVC_FORMAT_VCARD_30);
	soup_message_set_request (
		message, "text/vcard", SOUP_MEMORY_TEMPORARY,
		request, strlen (request));

	status   = send_and_handle_ssl (webdav, message, cancellable);
	new_etag = soup_message_headers_get_list (message->response_headers, "ETag");

	redir_uri = soup_message_headers_get_list (message->response_headers, "Location");

	/* set UID and REV fields */
	e_contact_set (contact, E_CONTACT_REV, (gconstpointer) new_etag);
	if (redir_uri && *redir_uri) {
		if (!strstr (redir_uri, "://")) {
			/* it's a relative URI */
			SoupURI *suri = soup_uri_new (uri);
			gchar *full_uri;

			soup_uri_set_path (suri, redir_uri);
			full_uri = soup_uri_to_string (suri, TRUE);

			e_contact_set (contact, E_CONTACT_UID, full_uri);

			g_free (full_uri);
			soup_uri_free (suri);
		} else {
			e_contact_set (contact, E_CONTACT_UID, redir_uri);
		}
	} else {
		e_contact_set (contact, E_CONTACT_UID, uri);
	}

	if (reason) {
		*reason = g_strdup (message->reason_phrase && *message->reason_phrase ? message->reason_phrase :
				    (soup_status_get_phrase (message->status_code) ? soup_status_get_phrase (message->status_code) : _("Unknown error")));
	}

	g_object_unref (message);
	g_free (request);
	g_free (uri);

	return status;
}
Example #15
0
static void
got_headers (SoupMessage *req, SoupClientContext *client)
{
	SoupServer *server = client->server;
	SoupServerPrivate *priv = SOUP_SERVER_GET_PRIVATE (server);
	SoupURI *uri;
	SoupDate *date;
	char *date_string;
	SoupAuthDomain *domain;
	GSList *iter;
	gboolean rejected = FALSE;
	char *auth_user;

	if (!priv->raw_paths) {
		char *decoded_path;

		uri = soup_message_get_uri (req);
		decoded_path = soup_uri_decode (uri->path);
		soup_uri_set_path (uri, decoded_path);
		g_free (decoded_path);
	}

	/* Add required response headers */
	date = soup_date_new_from_now (0);
	date_string = soup_date_to_string (date, SOUP_DATE_HTTP);
	soup_message_headers_replace (req->response_headers, "Date",
				      date_string);
	g_free (date_string);
	soup_date_free (date);
	
	/* Now handle authentication. (We do this here so that if
	 * the request uses "Expect: 100-continue", we can reject it
	 * immediately rather than waiting for the request body to
	 * be sent.
	 */
	for (iter = priv->auth_domains; iter; iter = iter->next) {
		domain = iter->data;

		if (soup_auth_domain_covers (domain, req)) {
			auth_user = soup_auth_domain_accepts (domain, req);
			if (auth_user) {
				client->auth_domain = g_object_ref (domain);
				client->auth_user = auth_user;
				return;
			}

			rejected = TRUE;
		}
	}

	/* If no auth domain rejected it, then it's ok. */
	if (!rejected)
		return;

	for (iter = priv->auth_domains; iter; iter = iter->next) {
		domain = iter->data;

		if (soup_auth_domain_covers (domain, req))
			soup_auth_domain_challenge (domain, req);
	}
}
static guint
parse_request_headers (SoupMessage *msg, char *headers, guint headers_len,
		       SoupEncoding *encoding, gpointer sock)
{
	SoupMessagePrivate *priv = SOUP_MESSAGE_GET_PRIVATE (msg);
	char *req_method, *req_path, *url;
	SoupHTTPVersion version;
	const char *req_host;
	guint status;
	SoupURI *uri;

	status = soup_headers_parse_request (headers, headers_len,
					     msg->request_headers,
					     &req_method,
					     &req_path,
					     &version);
	if (!SOUP_STATUS_IS_SUCCESSFUL (status))
		return status;

	g_object_set (G_OBJECT (msg),
		      SOUP_MESSAGE_METHOD, req_method,
		      SOUP_MESSAGE_HTTP_VERSION, version,
		      NULL);
	g_free (req_method);

	/* Handle request body encoding */
	*encoding = soup_message_headers_get_encoding (msg->request_headers);
	if (*encoding == SOUP_ENCODING_UNRECOGNIZED) {
		if (soup_message_headers_get_list (msg->request_headers, "Transfer-Encoding"))
			return SOUP_STATUS_NOT_IMPLEMENTED;
		else
			return SOUP_STATUS_BAD_REQUEST;
	}

	/* Generate correct context for request */
	req_host = soup_message_headers_get_one (msg->request_headers, "Host");
	if (req_host && strchr (req_host, '/')) {
		g_free (req_path);
		return SOUP_STATUS_BAD_REQUEST;
	}

	if (!strcmp (req_path, "*") && req_host) {
		/* Eg, "OPTIONS * HTTP/1.1" */
		url = g_strdup_printf ("%s://%s",
				       soup_socket_is_ssl (sock) ? "https" : "http",
				       req_host);
		uri = soup_uri_new (url);
		if (uri)
			soup_uri_set_path (uri, "*");
		g_free (url);
	} else if (*req_path != '/') {
		/* Must be an absolute URI */
		uri = soup_uri_new (req_path);
	} else if (req_host) {
		url = g_strdup_printf ("%s://%s%s",
				       soup_socket_is_ssl (sock) ? "https" : "http",
				       req_host, req_path);
		uri = soup_uri_new (url);
		g_free (url);
	} else if (priv->http_version == SOUP_HTTP_1_0) {
		/* No Host header, no AbsoluteUri */
		SoupAddress *addr = soup_socket_get_local_address (sock);

		uri = soup_uri_new (NULL);
		soup_uri_set_scheme (uri, soup_socket_is_ssl (sock) ?
				     SOUP_URI_SCHEME_HTTPS :
				     SOUP_URI_SCHEME_HTTP);
		soup_uri_set_host (uri, soup_address_get_physical (addr));
		soup_uri_set_port (uri, soup_address_get_port (addr));
		soup_uri_set_path (uri, req_path);
	} else
		uri = NULL;

	g_free (req_path);

	if (!SOUP_URI_VALID_FOR_HTTP (uri)) {
		/* certainly not "a valid host on the server" (RFC2616 5.2.3)
		 * SOUP_URI_VALID_FOR_HTTP also guards against uri == NULL
		 */
		if (uri)
			soup_uri_free (uri);
		return SOUP_STATUS_BAD_REQUEST;
	}

	soup_message_set_uri (msg, uri);
	soup_uri_free (uri);

	return SOUP_STATUS_OK;
}
Example #17
0
static SoupURI *
fwupd_remote_build_uri (FwupdRemote *self, const gchar *url, GError **error)
{
	FwupdRemotePrivate *priv = GET_PRIVATE (self);
	SoupURI *uri;

	g_return_val_if_fail (FWUPD_IS_REMOTE (self), NULL);
	g_return_val_if_fail (url != NULL, NULL);
	g_return_val_if_fail (error == NULL || *error == NULL, NULL);

	/* create URI, substituting if required */
	if (priv->firmware_base_uri != NULL) {
		g_autoptr(SoupURI) uri_tmp = NULL;
		g_autofree gchar *basename = NULL;
		g_autofree gchar *url2 = NULL;
		uri_tmp = soup_uri_new (url);
		if (uri_tmp == NULL) {
			g_set_error (error,
				     FWUPD_ERROR,
				     FWUPD_ERROR_INVALID_FILE,
				     "Failed to parse URI '%s'", url);
			return NULL;
		}
		basename = g_path_get_basename (soup_uri_get_path (uri_tmp));
		url2 = g_build_filename (priv->firmware_base_uri, basename, NULL);
		uri = soup_uri_new (url2);
		if (uri == NULL) {
			g_set_error (error,
				     FWUPD_ERROR,
				     FWUPD_ERROR_INVALID_FILE,
				     "Failed to parse URI '%s'", url2);
			return NULL;
		}

	/* use the base URI of the metadata to build the full path */
	} else if (g_strstr_len (url, -1, "/") == NULL) {
		g_autofree gchar *basename = NULL;
		g_autofree gchar *path = NULL;
		uri = soup_uri_new (priv->metadata_uri);
		if (uri == NULL) {
			g_set_error (error,
				     FWUPD_ERROR,
				     FWUPD_ERROR_INVALID_FILE,
				     "Failed to parse metadata URI '%s'", url);
			return NULL;
		}
		basename = g_path_get_dirname (soup_uri_get_path (uri));
		path = g_build_filename (basename, url, NULL);
		soup_uri_set_path (uri, path);

	/* a normal URI */
	} else {
		uri = soup_uri_new (url);
		if (uri == NULL) {
			g_set_error (error,
				     FWUPD_ERROR,
				     FWUPD_ERROR_INVALID_FILE,
				     "Failed to parse URI '%s'", url);
			return NULL;
		}
	}

	/* set the username and password */
	if (priv->username != NULL)
		soup_uri_set_user (uri, priv->username);
	if (priv->password != NULL)
		soup_uri_set_password (uri, priv->password);
	return uri;
}
Example #18
0
static void
server_callback (SoupServer *server, SoupMessage *msg,
		 const char *path, GHashTable *query,
		 SoupClientContext *context, gpointer data)
{
	SoupURI *uri = soup_message_get_uri (msg);
	const char *server_protocol = data;

	soup_message_headers_append (msg->response_headers,
				     "X-Handled-By", "server_callback");

	if (!strcmp (path, "*")) {
		debug_printf (1, "    default server_callback got request for '*'!\n");
		errors++;
		soup_message_set_status (msg, SOUP_STATUS_INTERNAL_SERVER_ERROR);
		return;
	}

	if (msg->method != SOUP_METHOD_GET && msg->method != SOUP_METHOD_POST) {
		soup_message_set_status (msg, SOUP_STATUS_NOT_IMPLEMENTED);
		return;
	}

	if (!strcmp (path, "/redirect")) {
		soup_message_set_redirect (msg, SOUP_STATUS_FOUND, "/");
		return;
	}

	if (!strcmp (path, "/alias-redirect")) {
		SoupURI *redirect_uri;
		char *redirect_string;
		const char *redirect_protocol;

		redirect_protocol = soup_message_headers_get_one (msg->request_headers, "X-Redirect-Protocol");

		redirect_uri = soup_uri_copy (uri);
		soup_uri_set_scheme (redirect_uri, "foo");
		if (!g_strcmp0 (redirect_protocol, "https"))
			soup_uri_set_port (redirect_uri, ssl_base_uri->port);
		else
			soup_uri_set_port (redirect_uri, base_uri->port);
		soup_uri_set_path (redirect_uri, "/alias-redirected");
		redirect_string = soup_uri_to_string (redirect_uri, FALSE);

		soup_message_set_redirect (msg, SOUP_STATUS_FOUND, redirect_string);
		g_free (redirect_string);
		soup_uri_free (redirect_uri);
		return;
	} else if (!strcmp (path, "/alias-redirected")) {
		soup_message_set_status (msg, SOUP_STATUS_OK);
		soup_message_headers_append (msg->response_headers,
					     "X-Redirected-Protocol",
					     server_protocol);
		return;
	}

	if (!strcmp (path, "/slow")) {
		soup_server_pause_message (server, msg);
		g_object_set_data (G_OBJECT (msg), "server", server);
		soup_add_timeout (soup_server_get_async_context (server),
				  1000, timeout_finish_message, msg);
	}

	soup_message_set_status (msg, SOUP_STATUS_OK);
	if (!strcmp (uri->host, "foo")) {
		soup_message_set_response (msg, "text/plain",
					   SOUP_MEMORY_STATIC, "foo-index", 9);
		return;
	} else {
		soup_message_set_response (msg, "text/plain",
					   SOUP_MEMORY_STATIC, "index", 5);
		return;
	}
}
static void
do_soup_uri_null_tests (void)
{
	SoupURI *uri, *uri2;
	char *uri_string;

	debug_printf (1, "\nsoup_uri_new (NULL)\n");
	uri = soup_uri_new (NULL);
	if (SOUP_URI_IS_VALID (uri) || SOUP_URI_VALID_FOR_HTTP (uri)) {
		debug_printf (1, "  ERROR: soup_uri_new(NULL) returns valid URI?\n");
		errors++;
	}

	/* This implicitly also verifies that none of these methods g_warn */
	if (soup_uri_get_scheme (uri) ||
	    soup_uri_get_user (uri) ||
	    soup_uri_get_password (uri) ||
	    soup_uri_get_host (uri) ||
	    soup_uri_get_port (uri) ||
	    soup_uri_get_path (uri) ||
	    soup_uri_get_query (uri) ||
	    soup_uri_get_fragment (uri)) {
		debug_printf (1, "  ERROR: soup_uri_new(NULL) returns non-empty URI?\n");
		errors++;
	}

	expect_warning = TRUE;
	uri2 = soup_uri_new_with_base (uri, "/path");
	if (uri2 || expect_warning) {
		debug_printf (1, "  ERROR: soup_uri_new_with_base didn't fail on NULL URI?\n");
		errors++;
		expect_warning = FALSE;
	}

	expect_warning = TRUE;
	uri_string = soup_uri_to_string (uri, FALSE);
	if (expect_warning) {
		debug_printf (1, "  ERROR: soup_uri_to_string didn't fail on NULL URI?\n");
		errors++;
		expect_warning = FALSE;
	} else if (*uri_string) {
		debug_printf (1, "  ERROR: soup_uri_to_string on NULL URI returned '%s'\n",
			      uri_string);
		errors++;
	}
	g_free (uri_string);

	soup_uri_set_scheme (uri, SOUP_URI_SCHEME_HTTP);
	if (SOUP_URI_IS_VALID (uri) || SOUP_URI_VALID_FOR_HTTP (uri)) {
		debug_printf (1, "  ERROR: setting scheme on NULL URI makes it valid?\n");
		errors++;
	}

	expect_warning = TRUE;
	uri_string = soup_uri_to_string (uri, FALSE);
	if (expect_warning) {
		debug_printf (1, "  ERROR: soup_uri_to_string didn't fail on scheme-only URI?\n");
		errors++;
		expect_warning = FALSE;
	} else if (strcmp (uri_string, "http:") != 0) {
		debug_printf (1, "  ERROR: soup_uri_to_string returned '%s' instead of 'http:'\n",
			      uri_string);
		errors++;
	}
	g_free (uri_string);

	soup_uri_set_host (uri, "localhost");
	if (SOUP_URI_IS_VALID (uri)) {
		debug_printf (1, "  ERROR: setting scheme+host on NULL URI makes it valid?\n");
		errors++;
	}
	if (SOUP_URI_VALID_FOR_HTTP (uri)) {
		debug_printf (1, "  ERROR: setting scheme+host on NULL URI makes it valid for http?\n");
		errors++;
	}

	expect_warning = TRUE;
	uri_string = soup_uri_to_string (uri, FALSE);
	if (expect_warning) {
		debug_printf (1, "  ERROR: soup_uri_to_string didn't fail on scheme+host URI?\n");
		errors++;
		expect_warning = FALSE;
	} else if (strcmp (uri_string, "http://localhost/") != 0) {
		debug_printf (1, "  ERROR: soup_uri_to_string with NULL path returned '%s' instead of 'http://localhost/'\n",
			      uri_string);
		errors++;
	}
	g_free (uri_string);

	expect_warning = TRUE;
	uri2 = soup_uri_new_with_base (uri, "/path");
	if (expect_warning) {
		debug_printf (1, "  ERROR: soup_uri_new_with_base didn't warn on NULL+scheme URI?\n");
		errors++;
		expect_warning = FALSE;
	} else if (!uri2) {
		debug_printf (1, "  ERROR: soup_uri_new_with_base didn't fix path on NULL+scheme URI\n");
		errors++;
	}

	if (uri2) {
		uri_string = soup_uri_to_string (uri2, FALSE);
		if (!uri_string) {
			debug_printf (1, "  ERROR: soup_uri_to_string failed on uri2?\n");
			errors++;
		} else if (strcmp (uri_string, "http://localhost/path") != 0) {
			debug_printf (1, "  ERROR: soup_uri_to_string returned '%s' instead of 'http://localhost/path'\n",
				      uri_string);
			errors++;
		}
		g_free (uri_string);
		soup_uri_free (uri2);
	}

	expect_warning = TRUE;
	soup_uri_set_path (uri, NULL);
	if (expect_warning) {
		debug_printf (1, "  ERROR: setting path to NULL doesn't warn\n");
		errors++;
		expect_warning = FALSE;
	}
	if (!uri->path || *uri->path) {
		debug_printf (1, "  ERROR: setting path to NULL != \"\"\n");
		errors++;
		soup_uri_set_path (uri, "");
	}

	uri_string = soup_uri_to_string (uri, FALSE);
	if (!uri_string) {
		debug_printf (1, "  ERROR: soup_uri_to_string failed on complete URI?\n");
		errors++;
	} else if (strcmp (uri_string, "http://localhost/") != 0) {
		debug_printf (1, "  ERROR: soup_uri_to_string with empty path returned '%s' instead of 'http://localhost/'\n",
			      uri_string);
		errors++;
	}
	g_free (uri_string);

	if (!SOUP_URI_IS_VALID (uri)) {
		debug_printf (1, "  ERROR: setting scheme+path on NULL URI doesn't make it valid?\n");
		errors++;
	}
	if (!SOUP_URI_VALID_FOR_HTTP (uri)) {
		debug_printf (1, "  ERROR: setting scheme+host+path on NULL URI doesn't make it valid for http?\n");
		errors++;
	}

	soup_uri_free (uri);
}
Example #20
0
/* Open database containing policies for cookie domains.
 * Create database and setup table structure if it does not exist yet.
 */
static void _cookie_permission_manager_open_database(CookiePermissionManager *self)
{
	CookiePermissionManagerPrivate	*priv=self->priv;
	const gchar						*configDir;
	gchar							*error=NULL;
	gint							success;
	sqlite3_stmt					*statement=NULL;

	/* Close any open database */
	if(priv->database)
	{
		g_free(priv->databaseFilename);
		priv->databaseFilename=NULL;

		sqlite3_close(priv->database);
		priv->database=NULL;

		g_object_notify_by_pspec(G_OBJECT(self), CookiePermissionManagerProperties[PROP_DATABASE]);
		g_object_notify_by_pspec(G_OBJECT(self), CookiePermissionManagerProperties[PROP_DATABASE_FILENAME]);
	}

	/* Build path to database file */
	configDir=midori_extension_get_config_dir(priv->extension);
	if(!configDir)
		return;
	
	if(katze_mkdir_with_parents(configDir, 0700))
	{
		g_warning(_("Could not create configuration folder for extension: %s"), g_strerror(errno));

		_cookie_permission_manager_error(self, _("Could not create configuration folder for extension."));
		return;
	}

	/* Open database */
	priv->databaseFilename=g_build_filename(configDir, COOKIE_PERMISSION_DATABASE, NULL);
	success=sqlite3_open(priv->databaseFilename, &priv->database);
	if(success!=SQLITE_OK)
	{
		g_warning(_("Could not open database of extenstion: %s"), sqlite3_errmsg(priv->database));

		g_free(priv->databaseFilename);
		priv->databaseFilename=NULL;

		if(priv->database) sqlite3_close(priv->database);
		priv->database=NULL;

		_cookie_permission_manager_error(self, _("Could not open database of extension."));
		return;
	}

	/* Create table structure if it does not exist */
	success=sqlite3_exec(priv->database,
							"CREATE TABLE IF NOT EXISTS "
							"policies(domain text, value integer);",
							NULL,
							NULL,
							&error);

	if(success==SQLITE_OK)
	{
		success=sqlite3_exec(priv->database,
								"CREATE UNIQUE INDEX IF NOT EXISTS "
								"domain ON policies (domain);",
								NULL,
								NULL,
								&error);
	}

	if(success==SQLITE_OK)
	{
		success=sqlite3_exec(priv->database,
								"PRAGMA journal_mode=TRUNCATE;",
								NULL,
								NULL,
								&error);
	}

	if(success!=SQLITE_OK || error)
	{
		_cookie_permission_manager_error(self, _("Could not set up database structure of extension."));

		if(error)
		{
			g_critical(_("Failed to execute database statement: %s"), error);
			sqlite3_free(error);
		}

		g_free(priv->databaseFilename);
		priv->databaseFilename=NULL;

		sqlite3_close(priv->database);
		priv->database=NULL;
		return;
	}

	// Delete all cookies allowed only in one session
	success=sqlite3_prepare_v2(priv->database,
								"SELECT domain FROM policies WHERE value=? ORDER BY domain DESC;",
								-1,
								&statement,
								NULL);
	if(statement && success==SQLITE_OK) success=sqlite3_bind_int(statement, 1, COOKIE_PERMISSION_MANAGER_POLICY_ACCEPT_FOR_SESSION);
	if(statement && success==SQLITE_OK)
	{
		while(sqlite3_step(statement)==SQLITE_ROW)
		{
			gchar		*domain=(gchar*)sqlite3_column_text(statement, 0);
			GSList		*cookies, *cookie;

#ifdef HAVE_LIBSOUP_2_40_0
			SoupURI		*uri;

			uri=soup_uri_new(NULL);
			soup_uri_set_host(uri, domain);
			soup_uri_set_path(uri, "/");
			cookies=soup_cookie_jar_get_cookie_list(priv->cookieJar, uri, TRUE);
			for(cookie=cookies; cookie; cookie=cookie->next)
			{
				soup_cookie_jar_delete_cookie(priv->cookieJar, (SoupCookie*)cookie->data);
			}
			soup_cookies_free(cookies);
			soup_uri_free(uri);
#else
			cookies=soup_cookie_jar_all_cookies(priv->cookieJar);
			for(cookie=cookies; cookie; cookie=cookie->next)
			{
				if(soup_cookie_domain_matches((SoupCookie*)cookie->data, domain))
				{
					soup_cookie_jar_delete_cookie(priv->cookieJar, (SoupCookie*)cookie->data);
				}
			}
			soup_cookies_free(cookies);
#endif
		}
	}
		else g_warning(_("SQL fails: %s"), sqlite3_errmsg(priv->database));

	sqlite3_finalize(statement);

	g_object_notify_by_pspec(G_OBJECT(self), CookiePermissionManagerProperties[PROP_DATABASE]);
	g_object_notify_by_pspec(G_OBJECT(self), CookiePermissionManagerProperties[PROP_DATABASE_FILENAME]);
}
static void _do_token_query(GSignondOauthPlugin *self,
                         GSignondSessionData *session_data,
                         GHashTable* params,
                         GError** error)
{
    gboolean force_request_body_auth;
    if (gsignond_dictionary_get_boolean(session_data, 
        "ForceClientAuthViaRequestBody",
        &force_request_body_auth) && force_request_body_auth)
    {
        const gchar* client_id = gsignond_dictionary_get_string(session_data,
                                                            "ClientId");
        const gchar* client_secret = gsignond_dictionary_get_string(session_data,
                                                            "ClientSecret");
        if (client_id != NULL && client_secret != NULL) {
            g_hash_table_insert(params, "client_id", (gchar*)client_id);
            g_hash_table_insert(params, "client_secret", (gchar*)client_secret);
        }
    }
    
    const gchar* host = gsignond_dictionary_get_string(session_data, "TokenHost");
    if (host == NULL) {
        *error = g_error_new(GSIGNOND_ERROR,
                            GSIGNOND_ERROR_MISSING_DATA,
                            "TokenHost not set");
        return;
    }
    gsignond_oauth_plugin_check_host(host, gsignond_session_data_get_allowed_realms (session_data), error);
    if (*error != NULL)
        return;

    const gchar* token_path = gsignond_dictionary_get_string(session_data, "TokenPath");
    if (token_path == NULL) {
        *error = g_error_new(GSIGNOND_ERROR,
                            GSIGNOND_ERROR_MISSING_DATA,
                            "TokenPath not set");
        return;
    }
    
    const gchar* token_query_str = gsignond_dictionary_get_string(session_data, "TokenQuery");
    
    SoupURI* open_url = soup_uri_new(NULL);
    soup_uri_set_scheme(open_url, SOUP_URI_SCHEME_HTTPS);
    soup_uri_set_host(open_url, host);
    soup_uri_set_path(open_url, token_path);

    guint port;
    if (gsignond_dictionary_get_uint32(session_data, "TokenPort", &port) != FALSE)
        soup_uri_set_port(open_url, port);    

    if (token_query_str != NULL) {
        soup_uri_set_query(open_url, token_query_str);
    }
    
    SoupMessage *msg = soup_message_new_from_uri ("POST", open_url);
    soup_uri_free(open_url);
    gchar* formdata = soup_form_encode_hash(params);
    soup_message_set_request (msg, "application/x-www-form-urlencoded",
              SOUP_MEMORY_TAKE, formdata, strlen (formdata));
    
    soup_session_queue_message (self->soup_session, msg, _http_token_callback, self);
}
static void _request_new_token(GSignondOauthPlugin *self, 
                        GSignondSessionData *session_data,
                        GError** error)
{
    const gchar* response_type = gsignond_dictionary_get_string(session_data, "ResponseType");
    const gchar* grant_type = gsignond_dictionary_get_string(session_data, "GrantType");
    
    if (response_type != NULL &&
            (g_strcmp0(response_type, "code") == 0 || 
            g_strcmp0(response_type, "token") == 0)) {
        const gchar* host = gsignond_dictionary_get_string(session_data, "AuthHost");
        if (host == NULL) {
            *error = g_error_new(GSIGNOND_ERROR,
                                 GSIGNOND_ERROR_MISSING_DATA,
                                 "AuthHost not set");
            return;
        }

        gsignond_oauth_plugin_check_host(host, gsignond_session_data_get_allowed_realms (session_data), error);
        if (*error != NULL)
            return;
        
        const gchar* auth_path = gsignond_dictionary_get_string(session_data, "AuthPath");
        if (auth_path == NULL) {
            *error = g_error_new(GSIGNOND_ERROR,
                                 GSIGNOND_ERROR_MISSING_DATA,
                                 "AuthPath not set");
            return;
        }
        const gchar* client_id = gsignond_dictionary_get_string(session_data, "ClientId");
        if (client_id == NULL) {
            *error = g_error_new(GSIGNOND_ERROR,
                                 GSIGNOND_ERROR_MISSING_DATA,
                                 "ClientId not set");
            return;
        }

        SoupURI* open_url = soup_uri_new(NULL);
        soup_uri_set_scheme(open_url, SOUP_URI_SCHEME_HTTPS);
        soup_uri_set_host(open_url, host);
        soup_uri_set_path(open_url, auth_path);

        guint port;
        if (gsignond_dictionary_get_uint32(session_data, "AuthPort", &port) != FALSE)
            soup_uri_set_port(open_url, port);

        GHashTable* query = g_hash_table_new((GHashFunc)g_str_hash,
                                             (GEqualFunc)g_str_equal);
        const gchar* auth_query_str = gsignond_dictionary_get_string(session_data, "AuthQuery");
        GHashTable *auth_query = NULL;
        if (auth_query_str != NULL) {
            auth_query = soup_form_decode(auth_query_str);
            if (auth_query)
                // insert all key/values in AuthQuery into final query
                // according to RFC6749 section 3.1
                g_hash_table_foreach(auth_query, _insert_key_value, query);
        }

        g_hash_table_insert(query, "response_type", (gchar*)response_type);
        g_hash_table_insert(query, "client_id", (gchar*)client_id);
        
        const gchar* redirect_uri = gsignond_dictionary_get_string(session_data, "RedirectUri");
        if (redirect_uri != NULL) {
            g_hash_table_insert(query, "redirect_uri", (gchar*)redirect_uri);
        }

        const gchar* scope_str = gsignond_dictionary_get_string(session_data, "Scope");
        if (scope_str != NULL) {
            g_hash_table_insert(query, "scope", (gchar*)scope_str);
        }
        
        gchar* state = gsignond_oauth_plugin_generate_random_data(20);
        g_hash_table_insert(query, "state", state);
        gsignond_dictionary_set_string(self->oauth2_request, "_Oauth2State", state);

        const gchar* username = gsignond_session_data_get_username(session_data);
        const gchar* secret = gsignond_session_data_get_secret(session_data);

        // login_hint is a google extension specified here:
        // https://developers.google.com/accounts/docs/OAuth2InstalledApp#formingtheurl
        gboolean use_login_hint = FALSE;
        if (gsignond_dictionary_get_boolean(session_data, 
            "UseLoginHint", &use_login_hint) && 
            use_login_hint && username != NULL)
            g_hash_table_insert(query, "login_hint", (gchar*)username);
        
        // display is a facebook extension specified here:
        // https://developers.facebook.com/docs/reference/dialogs/oauth/
        const gchar* display = gsignond_dictionary_get_string(session_data, "UseDisplay");
        if (display != NULL) {
            g_hash_table_insert(query, "display", (gchar*)display);
        }
        
        soup_uri_set_query_from_form(open_url, query);
        g_free(state);
        g_hash_table_unref(query);
        if (auth_query)
            g_hash_table_unref(auth_query);

        char* open_url_str = soup_uri_to_string(open_url, FALSE);
        soup_uri_free(open_url);
        
        GSignondSignonuiData* ui_request = gsignond_dictionary_new();
        gsignond_signonui_data_set_open_url(ui_request, open_url_str);
        free(open_url_str);
        
        if (redirect_uri != NULL)
            gsignond_signonui_data_set_final_url(ui_request, redirect_uri);
        
        /* add username and password, for fields initialization (the
         * decision on whether to actually use them is up to the signon UI */
        if (username != NULL)
            gsignond_signonui_data_set_username(ui_request, username);
        if (secret != NULL)
            gsignond_signonui_data_set_password(ui_request, secret);
        
        gsignond_plugin_user_action_required(GSIGNOND_PLUGIN(self), ui_request);
        gsignond_dictionary_unref(ui_request);
        
    } else if (grant_type != NULL &&
            (g_strcmp0(grant_type, "password") == 0)) {
        const gchar* username = gsignond_session_data_get_username(session_data);
        const gchar* secret = gsignond_session_data_get_secret(session_data);
        if (username == NULL || secret == NULL) {
            *error = g_error_new(GSIGNOND_ERROR,
                                 GSIGNOND_ERROR_MISSING_DATA,
                                 "username or password not set");
            return;
        }
        GHashTable* params = g_hash_table_new((GHashFunc)g_str_hash,
                                             (GEqualFunc)g_str_equal);
        g_hash_table_insert(params, "grant_type", "password");
        g_hash_table_insert(params, "username", (gchar*)username);
        g_hash_table_insert(params, "password", (gchar*)secret);
        _set_scope(params, session_data);
    
        _do_token_query(self, session_data, params, error);
        g_hash_table_unref(params);
    } else if (grant_type != NULL &&
            (g_strcmp0(grant_type, "client_credentials") == 0)) {
        GHashTable* params = g_hash_table_new((GHashFunc)g_str_hash,
                                             (GEqualFunc)g_str_equal);
        g_hash_table_insert(params, "grant_type", "client_credentials");
        _set_scope(params, session_data);
    
        _do_token_query(self, session_data, params, error);
        g_hash_table_unref(params);
    } else {
        *error = g_error_new(GSIGNOND_ERROR,
                             GSIGNOND_ERROR_MISSING_DATA,
                             "Unknown ResponseType or GrantType");
    }
}
Example #23
0
int
main (int argc, char **argv)
{
	SoupServer *server;
	SoupURI *server_uri;
	int ret;

	test_init (argc, argv, no_test_entry);

	server = soup_test_server_new (run_tests ? SOUP_TEST_SERVER_IN_THREAD : SOUP_TEST_SERVER_DEFAULT);
	soup_server_add_handler (server, "/xmlrpc-server.php",
				 server_callback, NULL, NULL);
	server_uri = soup_test_server_get_uri (server, "http", NULL);
	soup_uri_set_path (server_uri, "/xmlrpc-server.php");
	uri = soup_uri_to_string (server_uri, FALSE);

	if (run_tests) {
		char *out, **tests, *path;
		char *list_argv[4];
		GError *error = NULL;
		int i;

		list_argv[0] = NULL;
		list_argv[1] = "-S";
		list_argv[2] = "-l";
		list_argv[3] = NULL;

		if (!run_xmlrpc_test (list_argv, &out, NULL, &error)) {
			g_printerr ("'xmlrpc-test -l' failed: %s\n", error->message);
			g_error_free (error);
			return 1;
		}

		tests = g_strsplit (out, "\n", -1);
		g_free (out);

		for (i = 0; tests[i] && *tests[i]; i++) {
			g_assert_true (g_str_has_prefix (tests[i], "/xmlrpc/"));
			path = g_strdup_printf ("/xmlrpc-server/%s", tests[i] + strlen ("/xmlrpc/"));
			g_test_add_data_func (path, tests[i], do_one_xmlrpc_test);
			g_free (path);
		}

		ret = g_test_run ();

		g_strfreev (tests);
	} else {
		GMainLoop *loop;

		g_print ("Listening on port %d\n", soup_server_get_port (server));

		loop = g_main_loop_new (NULL, TRUE);
		g_main_loop_run (loop);
		g_main_loop_unref (loop);

		ret = 0;
	}

	soup_test_server_quit_unref (server);
	soup_uri_free (server_uri);
	g_free (uri);
	if (run_tests)
		test_cleanup ();
	return ret;
}
Example #24
0
static gboolean
cal_backend_http_load (ECalBackendHttp *backend,
                       const gchar *uri,
		       gchar **out_certificate_pem,
		       GTlsCertificateFlags *out_certificate_errors,
                       GCancellable *cancellable,
                       GError **error)
{
	ECalBackendHttpPrivate *priv = backend->priv;
	ETimezoneCache *timezone_cache;
	SoupMessage *soup_message;
	SoupSession *soup_session;
	icalcomponent *icalcomp, *subcomp;
	icalcomponent_kind kind;
	const gchar *newuri;
	SoupURI *uri_parsed;
	GHashTable *old_cache;
	GSList *comps_in_cache;
	ESource *source;
	guint status_code;
	gulong cancel_id = 0;

	struct {
		SoupSession *soup_session;
		SoupMessage *soup_message;
	} cancel_data;

	timezone_cache = E_TIMEZONE_CACHE (backend);

	soup_session = backend->priv->soup_session;
	soup_message = cal_backend_http_new_message (backend, uri);

	if (soup_message == NULL) {
		g_set_error (
			error, SOUP_HTTP_ERROR,
			SOUP_STATUS_MALFORMED,
			_("Malformed URI: %s"), uri);
		return FALSE;
	}

	if (G_IS_CANCELLABLE (cancellable)) {
		cancel_data.soup_session = soup_session;
		cancel_data.soup_message = soup_message;

		cancel_id = g_cancellable_connect (
			cancellable,
			G_CALLBACK (cal_backend_http_cancelled),
			&cancel_data, (GDestroyNotify) NULL);
	}

	source = e_backend_get_source (E_BACKEND (backend));

	e_soup_ssl_trust_connect (soup_message, source);

	e_source_set_connection_status (source, E_SOURCE_CONNECTION_STATUS_CONNECTING);

	status_code = soup_session_send_message (soup_session, soup_message);

	if (G_IS_CANCELLABLE (cancellable))
		g_cancellable_disconnect (cancellable, cancel_id);

	if (status_code == SOUP_STATUS_NOT_MODIFIED) {
		e_source_set_connection_status (source, E_SOURCE_CONNECTION_STATUS_CONNECTED);

		/* attempts with ETag can result in 304 status code */
		g_object_unref (soup_message);
		priv->opened = TRUE;
		return TRUE;
	}

	/* Handle redirection ourselves */
	if (SOUP_STATUS_IS_REDIRECTION (status_code)) {
		gboolean success;

		newuri = soup_message_headers_get_list (
			soup_message->response_headers, "Location");

		d (g_message ("Redirected from %s to %s\n", async_context->uri, newuri));

		if (newuri != NULL) {
			gchar *redirected_uri;

			if (newuri[0]=='/') {
				g_warning ("Hey! Relative URI returned! Working around...\n");

				uri_parsed = soup_uri_new (uri);
				soup_uri_set_path (uri_parsed, newuri);
				soup_uri_set_query (uri_parsed, NULL);
				/* g_free (newuri); */

				newuri = soup_uri_to_string (uri_parsed, FALSE);
				g_message ("Translated URI: %s\n", newuri);
				soup_uri_free (uri_parsed);
			}

			redirected_uri =
				webcal_to_http_method (newuri, FALSE);
			success = cal_backend_http_load (
				backend, redirected_uri, out_certificate_pem, out_certificate_errors, cancellable, error);
			g_free (redirected_uri);

		} else {
			g_set_error (
				error, SOUP_HTTP_ERROR,
				SOUP_STATUS_BAD_REQUEST,
				_("Redirected to Invalid URI"));
			success = FALSE;
		}

		if (success) {
			e_source_set_connection_status (source, E_SOURCE_CONNECTION_STATUS_CONNECTED);
		} else {
			e_source_set_connection_status (source, E_SOURCE_CONNECTION_STATUS_DISCONNECTED);
		}

		g_object_unref (soup_message);
		return success;
	}

	/* check status code */
	if (!SOUP_STATUS_IS_SUCCESSFUL (status_code)) {
		/* because evolution knows only G_IO_ERROR_CANCELLED */
		if (status_code == SOUP_STATUS_CANCELLED)
			g_set_error (
				error, G_IO_ERROR, G_IO_ERROR_CANCELLED,
				"%s", soup_message->reason_phrase);
		else
			g_set_error (
				error, SOUP_HTTP_ERROR, status_code,
				"%s", soup_message->reason_phrase);

		if (status_code == SOUP_STATUS_SSL_FAILED) {
			e_source_set_connection_status (source, E_SOURCE_CONNECTION_STATUS_SSL_FAILED);
			cal_backend_http_extract_ssl_failed_data (soup_message, out_certificate_pem, out_certificate_errors);
		} else {
			e_source_set_connection_status (source, E_SOURCE_CONNECTION_STATUS_DISCONNECTED);
		}

		g_object_unref (soup_message);
		empty_cache (backend);
		return FALSE;
	}

	e_source_set_connection_status (source, E_SOURCE_CONNECTION_STATUS_CONNECTED);

	if (priv->store) {
		const gchar *etag;

		etag = soup_message_headers_get_one (
			soup_message->response_headers, "ETag");

		if (etag != NULL && *etag == '\0')
			etag = NULL;

		e_cal_backend_store_put_key_value (priv->store, "ETag", etag);
	}

	/* get the calendar from the response */
	icalcomp = icalparser_parse_string (soup_message->response_body->data);

	if (!icalcomp) {
		g_set_error (
			error, SOUP_HTTP_ERROR,
			SOUP_STATUS_MALFORMED,
			_("Bad file format."));
		g_object_unref (soup_message);
		empty_cache (backend);
		return FALSE;
	}

	if (icalcomponent_isa (icalcomp) != ICAL_VCALENDAR_COMPONENT) {
		g_set_error (
			error, SOUP_HTTP_ERROR,
			SOUP_STATUS_MALFORMED,
			_("Not a calendar."));
		icalcomponent_free (icalcomp);
		g_object_unref (soup_message);
		empty_cache (backend);
		return FALSE;
	}

	g_object_unref (soup_message);
	soup_message = NULL;

	/* Update cache */
	old_cache = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);

	comps_in_cache = e_cal_backend_store_get_components (priv->store);
	while (comps_in_cache != NULL) {
		const gchar *uid;
		ECalComponent *comp = comps_in_cache->data;

		e_cal_component_get_uid (comp, &uid);
		g_hash_table_insert (old_cache, g_strdup (uid), e_cal_component_get_as_string (comp));

		comps_in_cache = g_slist_remove (comps_in_cache, comps_in_cache->data);
		g_object_unref (comp);
	}

	kind = e_cal_backend_get_kind (E_CAL_BACKEND (backend));
	subcomp = icalcomponent_get_first_component (icalcomp, ICAL_ANY_COMPONENT);
	e_cal_backend_store_freeze_changes (priv->store);
	while (subcomp) {
		ECalComponent *comp;
		icalcomponent_kind subcomp_kind;
		icalproperty *prop = NULL;

		subcomp_kind = icalcomponent_isa (subcomp);
		prop = icalcomponent_get_first_property (subcomp, ICAL_UID_PROPERTY);
		if (!prop && subcomp_kind == kind) {
			gchar *new_uid = e_cal_component_gen_uid ();
			icalcomponent_set_uid (subcomp, new_uid);
			g_free (new_uid);
		}

		if (subcomp_kind == kind) {
			comp = e_cal_component_new ();
			if (e_cal_component_set_icalcomponent (comp, icalcomponent_new_clone (subcomp))) {
				const gchar *uid;
				gpointer orig_key, orig_value;

				e_cal_component_get_uid (comp, &uid);

				if (!put_component_to_store (backend, comp)) {
					g_hash_table_remove (old_cache, uid);
				} else if (g_hash_table_lookup_extended (old_cache, uid, &orig_key, &orig_value)) {
					ECalComponent *orig_comp = e_cal_component_new_from_string (orig_value);

					e_cal_backend_notify_component_modified (E_CAL_BACKEND (backend), orig_comp, comp);

					g_hash_table_remove (old_cache, uid);
					if (orig_comp)
						g_object_unref (orig_comp);
				} else {
					e_cal_backend_notify_component_created (E_CAL_BACKEND (backend), comp);
				}
			}

			g_object_unref (comp);
		} else if (subcomp_kind == ICAL_VTIMEZONE_COMPONENT) {
			icaltimezone *zone;

			zone = icaltimezone_new ();
			icaltimezone_set_component (zone, icalcomponent_new_clone (subcomp));
			e_timezone_cache_add_timezone (timezone_cache, zone);

			icaltimezone_free (zone, 1);
		}

		subcomp = icalcomponent_get_next_component (icalcomp, ICAL_ANY_COMPONENT);
	}

	e_cal_backend_store_thaw_changes (priv->store);

	/* notify the removals */
	g_hash_table_foreach_remove (old_cache, (GHRFunc) notify_and_remove_from_cache, backend);
	g_hash_table_destroy (old_cache);

	/* free memory */
	icalcomponent_free (icalcomp);

	priv->opened = TRUE;

	return TRUE;
}
Example #25
0
static void
do_request_test (SoupSession *session, SoupURI *base_uri, int test)
{
	SoupURI *uri = base_uri;
	PutTestData ptd;
	SoupMessage *msg;
	const char *client_md5, *server_md5;
	GChecksum *check;
	int i, length;
	gboolean streaming = FALSE;

	switch (test) {
	case 0:
		debug_printf (1, "PUT\n");
		break;

	case 1:
		debug_printf (1, "PUT w/ streaming\n");
		streaming = TRUE;
		break;

	case 2:
		debug_printf (1, "PUT w/ streaming and restart\n");
		streaming = TRUE;
		uri = soup_uri_copy (base_uri);
		soup_uri_set_path (uri, "/redirect");
		break;
	}

	ptd.session = session;
	make_put_chunk (&ptd.chunks[0], "one\r\n");
	make_put_chunk (&ptd.chunks[1], "two\r\n");
	make_put_chunk (&ptd.chunks[2], "three\r\n");
	ptd.next = ptd.nwrote = ptd.nfreed = 0;
	ptd.streaming = streaming;

	check = g_checksum_new (G_CHECKSUM_MD5);
	length = 0;
	for (i = 0; i < 3; i++) {
		g_checksum_update (check, (guchar *)ptd.chunks[i]->data,
				   ptd.chunks[i]->length);
		length += ptd.chunks[i]->length;
	}
	client_md5 = g_checksum_get_string (check);

	msg = soup_message_new_from_uri ("PUT", uri);
	soup_message_headers_set_encoding (msg->request_headers, SOUP_ENCODING_CHUNKED);
	soup_message_body_set_accumulate (msg->request_body, FALSE);
	soup_message_set_chunk_allocator (msg, error_chunk_allocator, NULL, NULL);
	if (streaming) {
		g_signal_connect (msg, "wrote_chunk",
				  G_CALLBACK (write_next_chunk_streaming_hack), &ptd);
		g_signal_connect (msg, "restarted",
				  G_CALLBACK (restarted_streaming_hack), &ptd);
	} else {
		g_signal_connect (msg, "wrote_chunk",
				  G_CALLBACK (write_next_chunk), &ptd);
	}
	g_signal_connect (msg, "wrote_headers",
			  G_CALLBACK (write_next_chunk), &ptd);
	g_signal_connect (msg, "wrote_body_data",
			  G_CALLBACK (wrote_body_data), &ptd);
	soup_session_send_message (session, msg);

	if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code)) {
		debug_printf (1, "  message failed: %d %s\n",
			      msg->status_code, msg->reason_phrase);
		errors++;
	}

	if (msg->request_body->data) {
		debug_printf (1, "  msg->request_body set!\n");
		errors++;
	}
	if (msg->request_body->length != length || length != ptd.nwrote) {
		debug_printf (1, "  sent length mismatch: %d vs %d vs %d\n",
			      (int)msg->request_body->length, length, ptd.nwrote);
		errors++;
	}

	server_md5 = soup_message_headers_get_one (msg->response_headers,
						   "Content-MD5");
	if (!server_md5 || strcmp (client_md5, server_md5) != 0) {
		debug_printf (1, "  client/server data mismatch: %s vs %s\n",
			      client_md5, server_md5 ? server_md5 : "(null)");
		errors++;
	}

	g_object_unref (msg);
	g_checksum_free (check);

	if (uri != base_uri)
		soup_uri_free (uri);
}
static gboolean
do_one_attempt (gpointer user_data)
{
  GError *local_error = NULL;
  MinCloudAgentApp *self = user_data;
  gs_free char *uri_str = NULL;
  gs_unref_object SoupRequest *request = NULL;
  gs_unref_object GInputStream *instream = NULL;
  gs_unref_object GFileOutputStream *outstream = NULL;
  gs_unref_object GFile *authorized_keys_path = NULL;
  gs_unref_object SoupMessage *msg = NULL;
  SoupURI *uri = NULL;
  const int max_request_failures = 5;
  const char *state_description = NULL;

  /* Skip over already completed states */
 again:
  switch (self->state)
    {
    case MCA_STATE_USER_DATA:
      if (g_file_query_exists (self->userdata_done_stamp, NULL))
        {
          self->state++;
          goto again;
        }
      break;
    case MCA_STATE_OPENSSH_KEY:
      if (g_file_query_exists (self->authorized_keys_path, NULL))
        {
          self->state++;
          goto again;
        }
      break;
    case MCA_STATE_DONE:
      goto out;
    }

  uri = soup_uri_new (NULL);
  soup_uri_set_scheme (uri, "http");
  {
    gs_free char *addr_str = g_inet_address_to_string (self->addr);
    soup_uri_set_host (uri, addr_str);
  }
  soup_uri_set_port (uri, g_inet_socket_address_get_port (self->addr_port));
  switch (self->state)
    {
    case MCA_STATE_USER_DATA:
      soup_uri_set_path (uri, "/2009-04-04/user-data");
      state_description = "user-data";
      break;
    case MCA_STATE_OPENSSH_KEY:
      soup_uri_set_path (uri, "/2009-04-04/meta-data/public-keys/0/openssh-key");
      state_description = "openssh-key";
      break;
    case MCA_STATE_DONE:
      g_assert_not_reached ();
    }

  uri_str = soup_uri_to_string (uri, FALSE);
  g_print ("Requesting '%s'...\n", uri_str);

  request = soup_session_request_uri (self->session, uri, &local_error);
  soup_uri_free (uri);
  if (!request)
    goto out;

  instream = soup_request_send (request, NULL, &local_error);
  if (!instream)
    goto out;

  msg = soup_request_http_get_message ((SoupRequestHTTP*) request);
  if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code))
    {
      switch (msg->status_code)
        {
        case 404:
        case 410:
          {
            gs_log_structured_print_id_v (MCA_NOT_FOUND_ID, "No %s found", state_description);
            g_clear_error (&local_error);
            /* Note fallthrough to out, where we'll advance to the
               next state */
            goto out;
          }
        default:
          /* Don't actually set the error, we will just continue to
           * the next phase.
           */
          gs_log_structured_print_id_v (MCA_TIMEOUT_ID,
                                        "Error fetching %s: %u %s",
                                        uri_str,
                                        msg->status_code,
                                        soup_status_get_phrase (msg->status_code));
          goto out;
        }
    }

  switch (self->state)
    {
    case MCA_STATE_USER_DATA:
      if (!handle_userdata_script (self, instream, self->cancellable,
                                   &local_error))
        goto out;
      break;
    case MCA_STATE_OPENSSH_KEY:
      if (!handle_install_authorized_keys (self, instream, self->cancellable,
                                           &local_error))
        goto out;
      break;
    default:
      g_assert_not_reached ();
    }

  g_assert (self->state != MCA_STATE_DONE);
  self->state++;
  self->request_failure_count = 0;

 out:
  if (local_error)
    {
      self->request_failure_count++;
      if (self->request_failure_count >= max_request_failures)
        {
          g_error_free (local_error);
          gs_log_structured_print_id_v (MCA_TIMEOUT_ID,
                                        "Reached maximum failed attempts (%u) to fetch metadata",
                                        self->request_failure_count);
          self->do_one_attempt_id = 0;
          self->running = FALSE;
        }
      else
        {
          gs_log_structured_print_id_v (MCA_REQUEST_FAILED_ID,
                                        "Request failed (count: %u): %s", self->request_failure_count,
                                        local_error->message);
          g_error_free (local_error);
          self->do_one_attempt_id = g_timeout_add_seconds (self->request_failure_count,
                                                           do_one_attempt, self);
        }
    }
  else
    {
      /* If we advanced in state, schedule the next callback in an
       * idle so we're consistently scheduled out of an idle.
       */
      if (self->state != MCA_STATE_DONE)
        self->do_one_attempt_id = g_idle_add (do_one_attempt, self);
      else
        {
          self->do_one_attempt_id = 0;
          self->running = FALSE;
        }
    }

  return FALSE;
}