[evolution-data-server/wip/offline-cache] Add ESoupSession - hides some common parts into a descendant of SoupSession
- From: Milan Crha <mcrha src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [evolution-data-server/wip/offline-cache] Add ESoupSession - hides some common parts into a descendant of SoupSession
- Date: Thu, 23 Mar 2017 14:31:28 +0000 (UTC)
commit 51474c1fdf3d0131004453a7839049ca9ce4b9ca
Author: Milan Crha <mcrha redhat com>
Date: Thu Mar 23 15:30:25 2017 +0100
Add ESoupSession - hides some common parts into a descendant of SoupSession
src/calendar/backends/http/e-cal-backend-http.c | 140 ++-----
src/libedataserver/CMakeLists.txt | 4 +
src/libedataserver/e-soup-session.c | 574 +++++++++++++++++++++++
src/libedataserver/e-soup-session.h | 101 ++++
src/libedataserver/e-webdav-session.c | 74 +++
src/libedataserver/e-webdav-session.h | 83 ++++
src/libedataserver/libedataserver.h | 2 +
7 files changed, 868 insertions(+), 110 deletions(-)
---
diff --git a/src/calendar/backends/http/e-cal-backend-http.c b/src/calendar/backends/http/e-cal-backend-http.c
index 57d1087..3e85504 100644
--- a/src/calendar/backends/http/e-cal-backend-http.c
+++ b/src/calendar/backends/http/e-cal-backend-http.c
@@ -34,17 +34,13 @@
G_DEFINE_TYPE (ECalBackendHttp, e_cal_backend_http, E_TYPE_CAL_META_BACKEND)
struct _ECalBackendHttpPrivate {
- SoupSession *soup_session;
+ ESoupSession *session;
SoupRequestHTTP *request;
GInputStream *input_stream;
GHashTable *components; /* gchar *uid ~> icalcomponent * */
-
- ENamedParameters *credentials;
};
-#define d(x)
-
static gchar *
ecb_http_webcal_to_http_method (const gchar *webcal_str,
gboolean secure)
@@ -95,66 +91,6 @@ ecb_http_dup_uri (ECalBackendHttp *cbhttp)
return uri;
}
-static void
-ecb_http_extract_ssl_failed_data (SoupMessage *msg,
- gchar **out_certificate_pem,
- GTlsCertificateFlags *out_certificate_errors)
-{
- GTlsCertificate *certificate = NULL;
-
- g_return_if_fail (SOUP_IS_MESSAGE (msg));
-
- if (!out_certificate_pem || !out_certificate_errors)
- return;
-
- g_object_get (G_OBJECT (msg),
- "tls-certificate", &certificate,
- "tls-errors", out_certificate_errors,
- NULL);
-
- if (certificate) {
- g_object_get (certificate, "certificate-pem", out_certificate_pem, NULL);
- g_object_unref (certificate);
- }
-}
-
-static void
-ecb_http_soup_authenticate (SoupSession *session,
- SoupMessage *msg,
- SoupAuth *auth,
- gboolean retrying,
- gpointer user_data)
-{
- ECalBackendHttp *cbhttp;
- const gchar *username;
- gchar *auth_user = NULL;
-
- if (retrying)
- return;
-
- cbhttp = E_CAL_BACKEND_HTTP (user_data);
-
- username = cbhttp->priv->credentials ? e_named_parameters_get (cbhttp->priv->credentials,
E_SOURCE_CREDENTIAL_USERNAME) : NULL;
- if (!username || !*username) {
- ESourceAuthentication *auth_extension;
- ESource *source;
-
- source = e_backend_get_source (E_BACKEND (cbhttp));
- auth_extension = e_source_get_extension (source, E_SOURCE_EXTENSION_AUTHENTICATION);
- auth_user = e_source_authentication_dup_user (auth_extension);
-
- username = auth_user;
- }
-
- if (!username || !*username || !cbhttp->priv->credentials ||
- !e_named_parameters_exists (cbhttp->priv->credentials, E_SOURCE_CREDENTIAL_PASSWORD))
- soup_message_set_status (msg, SOUP_STATUS_FORBIDDEN);
- else
- soup_auth_authenticate (auth, username, e_named_parameters_get (cbhttp->priv->credentials,
E_SOURCE_CREDENTIAL_PASSWORD));
-
- g_free (auth_user);
-}
-
static gboolean
ecb_http_connect_sync (ECalMetaBackend *meta_backend,
const ENamedParameters *credentials,
@@ -196,10 +132,9 @@ ecb_http_connect_sync (ECalMetaBackend *meta_backend,
e_source_set_connection_status (source, E_SOURCE_CONNECTION_STATUS_CONNECTING);
- e_named_parameters_free (cbhttp->priv->credentials);
- cbhttp->priv->credentials = credentials ? e_named_parameters_new_clone (credentials) : NULL;
+ e_soup_session_set_credentials (cbhttp->priv->session, credentials);
- request = soup_session_request_http (cbhttp->priv->soup_session, SOUP_METHOD_GET, uri, &local_error);
+ request = soup_session_request_http (SOUP_SESSION (cbhttp->priv->session), SOUP_METHOD_GET, uri,
&local_error);
success = request != NULL;
if (success) {
@@ -211,7 +146,7 @@ ecb_http_connect_sync (ECalMetaBackend *meta_backend,
soup_message_headers_append (message->request_headers, "Connection", "close");
}
- input_stream = soup_request_send (SOUP_REQUEST (request), cancellable, &local_error);
+ input_stream = e_soup_session_send_request_sync (cbhttp->priv->session, SOUP_REQUEST
(request), cancellable, &local_error);
success = input_stream != NULL;
@@ -251,8 +186,7 @@ ecb_http_connect_sync (ECalMetaBackend *meta_backend,
*out_auth_result = E_SOURCE_AUTHENTICATION_ERROR_SSL_FAILED;
e_source_set_connection_status (source,
E_SOURCE_CONNECTION_STATUS_SSL_FAILED);
- if (message)
- ecb_http_extract_ssl_failed_data (message, out_certificate_pem,
out_certificate_errors);
+ e_soup_session_get_ssl_error_details (cbhttp->priv->session,
out_certificate_pem, out_certificate_errors);
} else {
e_source_set_connection_status (source,
E_SOURCE_CONNECTION_STATUS_DISCONNECTED);
}
@@ -294,8 +228,8 @@ ecb_http_disconnect_sync (ECalMetaBackend *meta_backend,
cbhttp = E_CAL_BACKEND_HTTP (meta_backend);
- if (cbhttp->priv->soup_session)
- soup_session_abort (cbhttp->priv->soup_session);
+ if (cbhttp->priv->session)
+ soup_session_abort (SOUP_SESSION (cbhttp->priv->session));
g_clear_object (&cbhttp->priv->input_stream);
g_clear_object (&cbhttp->priv->request);
@@ -642,6 +576,24 @@ ecb_http_load_component_sync (ECalMetaBackend *meta_backend,
}
static void
+e_cal_backend_http_constructed (GObject *object)
+{
+ ECalBackendHttp *cbhttp = E_CAL_BACKEND_HTTP (object);
+
+ /* Chain up to parent's method. */
+ G_OBJECT_CLASS (e_cal_backend_http_parent_class)->constructed (object);
+
+ cbhttp->priv->session = e_soup_session_new (e_backend_get_source (E_BACKEND (cbhttp)));
+
+ e_soup_session_setup_logging (cbhttp->priv->session, g_getenv ("WEBCAL_DEBUG"));
+
+ e_binding_bind_property (
+ cbhttp, "proxy-resolver",
+ cbhttp->priv->session, "proxy-resolver",
+ G_BINDING_SYNC_CREATE);
+}
+
+static void
e_cal_backend_http_dispose (GObject *object)
{
ECalBackendHttp *cbhttp;
@@ -651,9 +603,9 @@ e_cal_backend_http_dispose (GObject *object)
g_clear_object (&cbhttp->priv->request);
g_clear_object (&cbhttp->priv->input_stream);
- if (cbhttp->priv->soup_session) {
- soup_session_abort (cbhttp->priv->soup_session);
- g_clear_object (&cbhttp->priv->soup_session);
+ if (cbhttp->priv->session) {
+ soup_session_abort (SOUP_SESSION (cbhttp->priv->session));
+ g_clear_object (&cbhttp->priv->session);
}
if (cbhttp->priv->components) {
@@ -670,8 +622,7 @@ e_cal_backend_http_finalize (GObject *object)
{
ECalBackendHttp *cbhttp = E_CAL_BACKEND_HTTP (object);
- e_named_parameters_free (cbhttp->priv->credentials);
- cbhttp->priv->credentials = NULL;
+ g_clear_object (&cbhttp->priv->session);
/* Chain up to parent's method. */
G_OBJECT_CLASS (e_cal_backend_http_parent_class)->finalize (object);
@@ -680,41 +631,9 @@ e_cal_backend_http_finalize (GObject *object)
static void
e_cal_backend_http_init (ECalBackendHttp *cbhttp)
{
- SoupSession *soup_session;
-
cbhttp->priv = G_TYPE_INSTANCE_GET_PRIVATE (cbhttp, E_TYPE_CAL_BACKEND_HTTP, ECalBackendHttpPrivate);
e_cal_backend_set_writable (E_CAL_BACKEND (cbhttp), FALSE);
-
- soup_session = soup_session_new ();
- g_object_set (
- soup_session,
- SOUP_SESSION_TIMEOUT, 90,
- SOUP_SESSION_SSL_STRICT, TRUE,
- SOUP_SESSION_SSL_USE_SYSTEM_CA_FILE, TRUE,
- SOUP_SESSION_ACCEPT_LANGUAGE_AUTO, TRUE,
- NULL);
-
- if (g_getenv ("WEBCAL_DEBUG") != NULL) {
- SoupLogger *logger;
-
- logger = soup_logger_new (SOUP_LOGGER_LOG_BODY, 1024 * 1024);
- soup_session_add_feature (soup_session, SOUP_SESSION_FEATURE (logger));
- g_object_unref (logger);
- }
-
- cbhttp->priv->soup_session = soup_session;
- cbhttp->priv->request = NULL;
- cbhttp->priv->input_stream = NULL;
-
- e_binding_bind_property (
- cbhttp, "proxy-resolver",
- cbhttp->priv->soup_session, "proxy-resolver",
- G_BINDING_SYNC_CREATE);
-
- g_signal_connect (
- cbhttp->priv->soup_session, "authenticate",
- G_CALLBACK (ecb_http_soup_authenticate), cbhttp);
}
static void
@@ -741,6 +660,7 @@ e_cal_backend_http_class_init (ECalBackendHttpClass *klass)
cal_backend_sync_class->remove_objects_sync = NULL;
object_class = G_OBJECT_CLASS (klass);
+ object_class->constructed = e_cal_backend_http_constructed;
object_class->dispose = e_cal_backend_http_dispose;
object_class->finalize = e_cal_backend_http_finalize;
}
diff --git a/src/libedataserver/CMakeLists.txt b/src/libedataserver/CMakeLists.txt
index 8e26b83..33a0eb4 100644
--- a/src/libedataserver/CMakeLists.txt
+++ b/src/libedataserver/CMakeLists.txt
@@ -69,6 +69,7 @@ set(SOURCES
e-secret-store.c
e-sexp.c
e-soup-auth-bearer.c
+ e-soup-session.c
e-soup-ssl-trust.c
e-source.c
e-source-extension.c
@@ -117,6 +118,7 @@ set(SOURCES
e-uid.c
e-url.c
e-webdav-discover.c
+ e-webdav-session.c
e-data-server-util.c
e-xml-utils.c
e-xml-hash-utils.c
@@ -148,6 +150,7 @@ set(HEADERS
e-secret-store.h
e-sexp.h
e-soup-auth-bearer.h
+ e-soup-session.h
e-soup-ssl-trust.h
e-source.h
e-source-address-book.h
@@ -196,6 +199,7 @@ set(HEADERS
e-uid.h
e-url.h
e-webdav-discover.h
+ e-webdav-session.h
e-data-server-util.h
e-xml-utils.h
e-xml-hash-utils.h
diff --git a/src/libedataserver/e-soup-session.c b/src/libedataserver/e-soup-session.c
new file mode 100644
index 0000000..69edeeb
--- /dev/null
+++ b/src/libedataserver/e-soup-session.c
@@ -0,0 +1,574 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2017 Red Hat, Inc. (www.redhat.com)
+ *
+ * This library is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * SECTION: e-soup-session
+ * @include: libedataserver/libedataserver.h
+ * @short_description: A SoupSession descendant
+ *
+ * The #ESoupSession is a #SoupSession descendant, which hides common
+ * tasks related to the way evolution-data-server works.
+ **/
+
+#include "evolution-data-server-config.h"
+
+#include "e-soup-ssl-trust.h"
+#include "e-source-authentication.h"
+#include "e-source-webdav.h"
+
+#include "e-soup-session.h"
+
+struct _ESoupSessionPrivate {
+ GMutex property_lock;
+ ESource *source;
+ ENamedParameters *credentials;
+
+ gboolean ssl_info_set;
+ gchar *ssl_certificate_pem;
+ GTlsCertificateFlags ssl_certificate_errors;
+};
+
+enum {
+ PROP_0,
+ PROP_SOURCE,
+ PROP_CREDENTIALS
+};
+
+G_DEFINE_TYPE (ESoupSession, e_soup_session, SOUP_TYPE_SESSION)
+
+static void
+e_soup_session_authenticate_cb (SoupSession *soup_session,
+ SoupMessage *message,
+ SoupAuth *auth,
+ gboolean retrying,
+ gpointer user_data)
+{
+ ESoupSession *session;
+ const gchar *username;
+ ENamedParameters *credentials;
+ gchar *auth_user = NULL;
+
+ g_return_if_fail (E_IS_SOUP_SESSION (soup_session));
+
+ if (retrying)
+ return;
+
+ session = E_SOUP_SESSION (soup_session);
+
+ credentials = e_soup_session_dup_credentials (session);
+
+ username = credentials ? e_named_parameters_get (credentials, E_SOURCE_CREDENTIAL_USERNAME) : NULL;
+ if ((!username || !*username) &&
+ e_source_has_extension (session->priv->source, E_SOURCE_EXTENSION_AUTHENTICATION)) {
+ ESourceAuthentication *auth_extension;
+
+ auth_extension = e_source_get_extension (session->priv->source,
E_SOURCE_EXTENSION_AUTHENTICATION);
+ auth_user = e_source_authentication_dup_user (auth_extension);
+
+ username = auth_user;
+ }
+
+ if (!username || !*username || !credentials ||
+ !e_named_parameters_exists (credentials, E_SOURCE_CREDENTIAL_PASSWORD))
+ soup_message_set_status (message, SOUP_STATUS_FORBIDDEN);
+ else
+ soup_auth_authenticate (auth, username, e_named_parameters_get (credentials,
E_SOURCE_CREDENTIAL_PASSWORD));
+
+ e_named_parameters_free (credentials);
+ g_free (auth_user);
+}
+
+static void
+e_soup_session_set_source (ESoupSession *session,
+ ESource *source)
+{
+ g_return_if_fail (E_IS_SOUP_SESSION (session));
+ g_return_if_fail (E_IS_SOURCE (source));
+ g_return_if_fail (!session->priv->source);
+
+ session->priv->source = g_object_ref (source);
+}
+
+static void
+e_soup_session_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_SOURCE:
+ e_soup_session_set_source (
+ E_SOUP_SESSION (object),
+ g_value_get_object (value));
+ return;
+
+ case PROP_CREDENTIALS:
+ e_soup_session_set_credentials (
+ E_SOUP_SESSION (object),
+ g_value_get_boxed (value));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+e_soup_session_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_SOURCE:
+ g_value_set_object (
+ value,
+ e_soup_session_get_source (
+ E_SOUP_SESSION (object)));
+ return;
+
+ case PROP_CREDENTIALS:
+ g_value_take_boxed (
+ value,
+ e_soup_session_dup_credentials (
+ E_SOUP_SESSION (object)));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+e_soup_session_finalize (GObject *object)
+{
+ ESoupSession *session = E_SOUP_SESSION (object);
+
+ g_clear_object (&session->priv->source);
+ g_clear_pointer (&session->priv->credentials, e_named_parameters_free);
+ g_clear_pointer (&session->priv->ssl_certificate_pem, g_free);
+
+ g_mutex_clear (&session->priv->property_lock);
+
+ /* Chain up to parent's method. */
+ G_OBJECT_CLASS (e_soup_session_parent_class)->finalize (object);
+}
+
+static void
+e_soup_session_class_init (ESoupSessionClass *klass)
+{
+ GObjectClass *object_class;
+
+ g_type_class_add_private (klass, sizeof (ESoupSessionPrivate));
+
+ object_class = G_OBJECT_CLASS (klass);
+ object_class->set_property = e_soup_session_set_property;
+ object_class->get_property = e_soup_session_get_property;
+ object_class->finalize = e_soup_session_finalize;
+
+ /**
+ * ESoupSession:source:
+ *
+ * The #ESource being used for this soup session.
+ *
+ * Since: 3.26
+ **/
+ g_object_class_install_property (
+ object_class,
+ PROP_SOURCE,
+ g_param_spec_object (
+ "source",
+ "Source",
+ NULL,
+ E_TYPE_SOURCE,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS));
+
+ /**
+ * ESoupSession:credentials:
+ *
+ * The #ENamedParameters containing login credentials.
+ *
+ * Since: 3.26
+ **/
+ g_object_class_install_property (
+ object_class,
+ PROP_CREDENTIALS,
+ g_param_spec_boxed (
+ "credentials",
+ "Credentials",
+ NULL,
+ E_TYPE_NAMED_PARAMETERS,
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_STRINGS));
+}
+
+static void
+e_soup_session_init (ESoupSession *session)
+{
+ session->priv = G_TYPE_INSTANCE_GET_PRIVATE (session, E_TYPE_SOUP_SESSION, ESoupSessionPrivate);
+ session->priv->ssl_info_set = FALSE;
+
+ g_mutex_init (&session->priv->property_lock);
+
+ g_object_set (
+ G_OBJECT (session),
+ SOUP_SESSION_TIMEOUT, 90,
+ SOUP_SESSION_SSL_STRICT, TRUE,
+ SOUP_SESSION_SSL_USE_SYSTEM_CA_FILE, TRUE,
+ SOUP_SESSION_ACCEPT_LANGUAGE_AUTO, TRUE,
+ NULL);
+
+ g_signal_connect (session, "authenticate",
+ G_CALLBACK (e_soup_session_authenticate_cb), NULL);
+}
+
+/**
+ * e_soup_session_new:
+ * @source: an #ESource
+ *
+ * Creates a new #ESoupSession associated with given @source.
+ * The @source can be used to store and read SSL trust settings, but only if
+ * it already contains an #ESourceWebdav extension. Otherwise the SSL trust
+ * settings are ignored.
+ *
+ * Returns: (transfer full): a new #ESoupSession; free it with g_object_unref(),
+ * when no longer needed.
+ *
+ * Since: 3.26
+ **/
+ESoupSession *
+e_soup_session_new (ESource *source)
+{
+ g_return_val_if_fail (E_IS_SOURCE (source), NULL);
+
+ return g_object_new (E_TYPE_SOUP_SESSION,
+ "source", source,
+ NULL);
+}
+
+/**
+ * e_soup_session_setup_logging:
+ * @session: an #ESoupSession
+ * @logging_level: (nullable): logging level to setup, or %NULL
+ *
+ * Setups logging for the @session. The @logging_level can be one of:
+ * "all" - log whole raw communication;
+ * "body" - the same as "all";
+ * "headers" - log the headers only;
+ * "min" - minimal logging;
+ * "1" - the same as "all".
+ * Any other value, including %NULL, disables logging.
+ *
+ * Since: 3.26
+ **/
+void
+e_soup_session_setup_logging (ESoupSession *session,
+ const gchar *logging_level)
+{
+ SoupLogger *logger;
+ SoupLoggerLogLevel level;
+
+ g_return_if_fail (E_IS_SOUP_SESSION (session));
+
+ soup_session_remove_feature_by_type (SOUP_SESSION (session), SOUP_TYPE_LOGGER);
+
+ if (!logging_level)
+ return;
+
+ if (g_ascii_strcasecmp (logging_level, "all") == 0 ||
+ g_ascii_strcasecmp (logging_level, "body") == 0 ||
+ g_ascii_strcasecmp (logging_level, "1") == 0)
+ level = SOUP_LOGGER_LOG_BODY;
+ else if (g_ascii_strcasecmp (logging_level, "headers") == 0)
+ level = SOUP_LOGGER_LOG_HEADERS;
+ else if (g_ascii_strcasecmp (logging_level, "min") == 0)
+ level = SOUP_LOGGER_LOG_MINIMAL;
+ else
+ return;
+
+ logger = soup_logger_new (level, 10 * 1024 * 1024);
+ soup_session_add_feature (SOUP_SESSION (session), SOUP_SESSION_FEATURE (logger));
+ g_object_unref (logger);
+}
+
+/**
+ * e_soup_session_get_source:
+ * @session: an #ESoupSession
+ *
+ * Returns: (transfer none): Associated #ESource with the @session.
+ *
+ * Since: 3.26
+ **/
+ESource *
+e_soup_session_get_source (ESoupSession *session)
+{
+ g_return_val_if_fail (E_IS_SOUP_SESSION (session), NULL);
+
+ return session->priv->source;
+}
+
+/**
+ * e_soup_session_set_credentials:
+ * @session: an #ESoupSession
+ * @credentials: (nullable): an #ENamedParameters with credentials to use, or %NULL
+ *
+ * Sets credentials to use for connection. Using %NULL for @credentials
+ * unsets previous value.
+ *
+ * Since: 3.26
+ **/
+void
+e_soup_session_set_credentials (ESoupSession *session,
+ const ENamedParameters *credentials)
+{
+ g_return_if_fail (E_IS_SOUP_SESSION (session));
+
+ g_mutex_lock (&session->priv->property_lock);
+
+ if (credentials == session->priv->credentials) {
+ g_mutex_unlock (&session->priv->property_lock);
+ return;
+ }
+
+ e_named_parameters_free (session->priv->credentials);
+ if (credentials)
+ session->priv->credentials = e_named_parameters_new_clone (credentials);
+ else
+ session->priv->credentials = NULL;
+
+ g_mutex_unlock (&session->priv->property_lock);
+
+ g_object_notify (G_OBJECT (session), "credentials");
+}
+
+/**
+ * e_soup_session_dup_credentials:
+ * @session: an #ESoupSession
+ *
+ * Returns: (nullable) (transfer full): A copy of the credentials being
+ * previously set with e_soup_session_set_credentials(), or %NULL when
+ * none are set. Free the returned pointer with e_named_parameters_free(),
+ * when no longer needed.
+ *
+ * Since: 3.26
+ **/
+ENamedParameters *
+e_soup_session_dup_credentials (ESoupSession *session)
+{
+ ENamedParameters *credentials;
+
+ g_return_val_if_fail (E_IS_SOUP_SESSION (session), NULL);
+
+ g_mutex_lock (&session->priv->property_lock);
+
+ if (session->priv->credentials)
+ credentials = e_named_parameters_new_clone (session->priv->credentials);
+ else
+ credentials = NULL;
+
+ g_mutex_unlock (&session->priv->property_lock);
+
+ return credentials;
+}
+
+/**
+ * e_soup_session_get_ssl_error_details:
+ * @session: an #ESoupSession
+ * @out_certificate_pem: (out): return location for a server TLS/SSL certificate
+ * in PEM format, when the last operation failed with a TLS/SSL error
+ * @out_certificate_errors: (out): return location for a #GTlsCertificateFlags,
+ * with certificate error flags when the the operation failed with a TLS/SSL error
+ *
+ * Populates @out_certificate_pem and @out_certificate_errors with the last values
+ * returned on #SOUP_STATUS_SSL_FAILED error.
+ *
+ * Returns: Whether the information was available and set to the out parameters.
+ *
+ * Since: 3.26
+ **/
+gboolean
+e_soup_session_get_ssl_error_details (ESoupSession *session,
+ gchar **out_certificate_pem,
+ GTlsCertificateFlags *out_certificate_errors)
+{
+ g_return_val_if_fail (E_IS_SOUP_SESSION (session), FALSE);
+ g_return_val_if_fail (out_certificate_pem != NULL, FALSE);
+ g_return_val_if_fail (out_certificate_errors != NULL, FALSE);
+
+ g_mutex_lock (&session->priv->property_lock);
+ if (!session->priv->ssl_info_set) {
+ g_mutex_unlock (&session->priv->property_lock);
+ return FALSE;
+ }
+
+ *out_certificate_pem = g_strdup (session->priv->ssl_certificate_pem);
+ *out_certificate_errors = session->priv->ssl_certificate_errors;
+
+ g_mutex_unlock (&session->priv->property_lock);
+
+ return TRUE;
+}
+
+/**
+ * e_soup_session_send_request_sync:
+ * @session: an #ESoupSession
+ * @request: a #SoupRequest to send
+ * @cancellable: optional #GCancellable object, or %NULL
+ * @error: return location for a #GError, or %NULL
+ *
+ * Synchronously sends prepared request and returns #GInputStream
+ * that can be used to read its contents.
+ *
+ * This calls soup_request_send() internally, but it also setups
+ * the request according to #ESoupSession:source authentication
+ * settings. It also extracts information about used certificate,
+ * in case of SOUP_STATUS_SSL_FAILED error and keeps it for later use
+ * by e_soup_session_get_ssl_error_details().
+ *
+ * Use e_soup_session_send_request_simple_sync() to read whole
+ * content into a #GByteArray.
+ *
+ * Returns: (transfer full): A newly allocated #GInputStream,
+ * that can be used to read from the URI pointed to by @request.
+ * Free it with g_object_unref(), when no longer needed.
+ *
+ * Since: 3.26
+ **/
+GInputStream *
+e_soup_session_send_request_sync (ESoupSession *session,
+ SoupRequest *request,
+ GCancellable *cancellable,
+ GError **error)
+{
+ GInputStream *input_stream;
+ GError *local_error = NULL;
+
+ g_return_val_if_fail (E_IS_SOUP_SESSION (session), NULL);
+ g_return_val_if_fail (SOUP_IS_REQUEST (request), NULL);
+
+ g_mutex_lock (&session->priv->property_lock);
+ g_clear_pointer (&session->priv->ssl_certificate_pem, g_free);
+ session->priv->ssl_certificate_errors = 0;
+ session->priv->ssl_info_set = FALSE;
+ g_mutex_unlock (&session->priv->property_lock);
+
+ if (session->priv->source &&
+ e_source_has_extension (session->priv->source, E_SOURCE_EXTENSION_WEBDAV_BACKEND) &&
+ SOUP_IS_REQUEST_HTTP (request)) {
+ SoupMessage *message;
+
+ message = soup_request_http_get_message (SOUP_REQUEST_HTTP (request));
+
+ e_soup_ssl_trust_connect (message, session->priv->source);
+
+ g_clear_object (&message);
+ }
+
+ input_stream = soup_request_send (request, cancellable, &local_error);
+ if (input_stream)
+ return input_stream;
+
+ if (g_error_matches (local_error, SOUP_HTTP_ERROR, SOUP_STATUS_SSL_FAILED)) {
+ GTlsCertificate *certificate = NULL;
+ SoupMessage *message;
+
+ message = soup_request_http_get_message (SOUP_REQUEST_HTTP (request));
+
+ g_mutex_lock (&session->priv->property_lock);
+
+ g_object_get (G_OBJECT (message),
+ "tls-certificate", &certificate,
+ "tls-errors", &session->priv->ssl_certificate_errors,
+ NULL);
+
+ if (certificate) {
+ g_object_get (certificate, "certificate-pem", &session->priv->ssl_certificate_pem,
NULL);
+ session->priv->ssl_info_set = TRUE;
+
+ g_object_unref (certificate);
+ }
+
+ g_mutex_unlock (&session->priv->property_lock);
+ g_clear_object (&message);
+ }
+
+ if (local_error)
+ g_propagate_error (error, local_error);
+
+ return NULL;
+}
+
+/**
+ * e_soup_session_send_request_simple_sync:
+ * @session: an #ESoupSession
+ * @request: a #SoupRequest to send
+ * @cancellable: optional #GCancellable object, or %NULL
+ * @error: return location for a #GError, or %NULL
+ *
+ * Similar to e_soup_session_send_request_sync(), except it reads
+ * whole response content into memory and returns it as a #GByteArray.
+ * Use e_soup_session_send_request_sync() when you want to have
+ * more control on the content read.
+ *
+ * Returns: (transfer full): A newly allocated #GByteArray,
+ * which contains whole content from the URI pointed to by @request.
+ *
+ * Since: 3.26
+ **/
+GByteArray *
+e_soup_session_send_request_simple_sync (ESoupSession *session,
+ SoupRequest *request,
+ GCancellable *cancellable,
+ GError **error)
+{
+ GInputStream *input_stream;
+ GByteArray *bytes;
+ gint expected_length;
+ void *buffer;
+ gsize nread = 0;
+ gboolean success = FALSE;
+
+ g_return_val_if_fail (E_IS_SOUP_SESSION (session), NULL);
+ g_return_val_if_fail (SOUP_IS_REQUEST (request), NULL);
+
+ input_stream = e_soup_session_send_request_sync (session, request, cancellable, error);
+ if (!input_stream)
+ return NULL;
+
+ expected_length = soup_request_get_content_length (request);
+ if (expected_length > 0)
+ bytes = g_byte_array_sized_new (expected_length);
+ else
+ bytes = g_byte_array_new ();
+
+ buffer = g_malloc (16384);
+
+ while (success = g_input_stream_read_all (input_stream, buffer, 16384, &nread, cancellable, error),
+ success && nread > 0) {
+ g_byte_array_append (bytes, buffer, nread);
+ }
+
+ g_free (buffer);
+ g_object_unref (input_stream);
+
+ if (!success) {
+ g_byte_array_free (bytes, TRUE);
+ bytes = NULL;
+ }
+
+ return bytes;
+}
diff --git a/src/libedataserver/e-soup-session.h b/src/libedataserver/e-soup-session.h
new file mode 100644
index 0000000..09784e8
--- /dev/null
+++ b/src/libedataserver/e-soup-session.h
@@ -0,0 +1,101 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2017 Red Hat, Inc. (www.redhat.com)
+ *
+ * This library is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#if !defined (__LIBEDATASERVER_H_INSIDE__) && !defined (LIBEDATASERVER_COMPILATION)
+#error "Only <libedataserver/libedataserver.h> should be included directly."
+#endif
+
+#ifndef E_SOUP_SESSION_H
+#define E_SOUP_SESSION_H
+
+#include <glib.h>
+#include <libsoup/soup.h>
+
+#include <libedataserver/e-data-server-util.h>
+#include <libedataserver/e-source.h>
+
+/* Standard GObject macros */
+#define E_TYPE_SOUP_SESSION \
+ (e_soup_session_get_type ())
+#define E_SOUP_SESSION(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), E_TYPE_SOUP_SESSION, ESoupSession))
+#define E_SOUP_SESSION_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), E_TYPE_SOUP_SESSION, ESoupSessionClass))
+#define E_IS_SOUP_SESSION(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), E_TYPE_SOUP_SESSION))
+#define E_IS_SOUP_SESSION_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((cls), E_TYPE_SOUP_SESSION))
+#define E_SOUP_SESSION_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS \
+ ((obj), E_TYPE_SOUP_SESSION, ESoupSessionClass))
+
+G_BEGIN_DECLS
+
+typedef struct _ESoupSession ESoupSession;
+typedef struct _ESoupSessionClass ESoupSessionClass;
+typedef struct _ESoupSessionPrivate ESoupSessionPrivate;
+
+/**
+ * ESoupSession:
+ *
+ * Contains only private data that should be read and manipulated using the
+ * functions below.
+ *
+ * Since: 3.26
+ **/
+struct _ESoupSession {
+ /*< private >*/
+ SoupSession parent;
+ ESoupSessionPrivate *priv;
+};
+
+struct _ESoupSessionClass {
+ SoupSessionClass parent_class;
+
+ /* Padding for future expansion */
+ gpointer reserved[10];
+};
+
+GType e_soup_session_get_type (void) G_GNUC_CONST;
+
+ESoupSession * e_soup_session_new (ESource *source);
+void e_soup_session_setup_logging (ESoupSession *session,
+ const gchar *logging_level);
+ESource * e_soup_session_get_source (ESoupSession *session);
+void e_soup_session_set_credentials (ESoupSession *session,
+ const ENamedParameters *credentials);
+ENamedParameters *
+ e_soup_session_dup_credentials (ESoupSession *session);
+gboolean e_soup_session_get_ssl_error_details (ESoupSession *session,
+ gchar **out_certificate_pem,
+ GTlsCertificateFlags *out_certificate_errors);
+GInputStream * e_soup_session_send_request_sync (ESoupSession *session,
+ SoupRequest *request,
+ GCancellable *cancellable,
+ GError **error);
+GByteArray * e_soup_session_send_request_simple_sync (ESoupSession *session,
+ SoupRequest *request,
+ GCancellable *cancellable,
+ GError **error);
+
+G_END_DECLS
+
+#endif /* E_SOUP_SESSION_H */
diff --git a/src/libedataserver/e-webdav-session.c b/src/libedataserver/e-webdav-session.c
new file mode 100644
index 0000000..246c36a
--- /dev/null
+++ b/src/libedataserver/e-webdav-session.c
@@ -0,0 +1,74 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2017 Red Hat, Inc. (www.redhat.com)
+ *
+ * This library is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * SECTION: e-webdav-session
+ * @include: libedataserver/libedataserver.h
+ * @short_description: A WebDAV, CalDAV and CardDAV session
+ *
+ * The #EWebDAVSession is a class to work with WebDAV (RFC 4918),
+ * CalDAV (RFC 4791) or CardDAV (RFC 6352) servers, providing API
+ * for common requests/responses, on top of an #ESoupSession.
+ **/
+
+#include "evolution-data-server-config.h"
+
+#include "e-source-webdav.h"
+
+#include "e-webdav-session.h"
+
+struct _EWebDAVSessionPrivate {
+ gboolean dummy;
+};
+
+G_DEFINE_TYPE (EWebDAVSession, e_webdav_session, E_TYPE_SOUP_SESSION)
+
+static void
+e_webdav_session_class_init (EWebDAVSessionClass *klass)
+{
+ g_type_class_add_private (klass, sizeof (EWebDAVSessionPrivate));
+}
+
+static void
+e_webdav_session_init (EWebDAVSession *webdav)
+{
+ webdav->priv = G_TYPE_INSTANCE_GET_PRIVATE (webdav, E_TYPE_WEBDAV_SESSION, EWebDAVSessionPrivate);
+}
+
+/**
+ * e_webdav_session_new:
+ * @source: an #ESource
+ *
+ * Creates a new #EWebDAVSession associated with given @source. It's
+ * a user's error to try to create the #EWebDAVSession for a source
+ * which doesn't have #ESourceWebdav extension properly defined.
+ *
+ * Returns: (transfer full): a new #EWebDAVSession; free it with g_object_unref(),
+ * when no longer needed.
+ *
+ * Since: 3.26
+ **/
+EWebDAVSession *
+e_webdav_session_new (ESource *source)
+{
+ g_return_val_if_fail (E_IS_SOURCE (source), NULL);
+ g_return_val_if_fail (e_source_has_extension (source, E_SOURCE_EXTENSION_WEBDAV_BACKEND), NULL);
+
+ return g_object_new (E_TYPE_WEBDAV_SESSION,
+ "source", source,
+ NULL);
+}
diff --git a/src/libedataserver/e-webdav-session.h b/src/libedataserver/e-webdav-session.h
new file mode 100644
index 0000000..280ab72
--- /dev/null
+++ b/src/libedataserver/e-webdav-session.h
@@ -0,0 +1,83 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2017 Red Hat, Inc. (www.redhat.com)
+ *
+ * This library is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#if !defined (__LIBEDATASERVER_H_INSIDE__) && !defined (LIBEDATASERVER_COMPILATION)
+#error "Only <libedataserver/libedataserver.h> should be included directly."
+#endif
+
+#ifndef E_WEBDAV_SESSION_H
+#define E_WEBDAV_SESSION_H
+
+#include <glib.h>
+
+#include <libedataserver/e-data-server-util.h>
+#include <libedataserver/e-soup-session.h>
+#include <libedataserver/e-source.h>
+
+/* Standard GObject macros */
+#define E_TYPE_WEBDAV_SESSION \
+ (e_webdav_session_get_type ())
+#define E_WEBDAV_SESSION(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), E_TYPE_WEBDAV_SESSION, EWebDAVSession))
+#define E_WEBDAV_SESSION_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), E_TYPE_WEBDAV_SESSION, EWebDAVSessionClass))
+#define E_IS_WEBDAV_SESSION(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), E_TYPE_WEBDAV_SESSION))
+#define E_IS_WEBDAV_SESSION_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((cls), E_TYPE_WEBDAV_SESSION))
+#define E_WEBDAV_SESSION_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS \
+ ((obj), E_TYPE_WEBDAV_SESSION, EWebDAVSessionClass))
+
+G_BEGIN_DECLS
+
+typedef struct _EWebDAVSession EWebDAVSession;
+typedef struct _EWebDAVSessionClass EWebDAVSessionClass;
+typedef struct _EWebDAVSessionPrivate EWebDAVSessionPrivate;
+
+/**
+ * EWebDAVSession:
+ *
+ * Contains only private data that should be read and manipulated using the
+ * functions below.
+ *
+ * Since: 3.26
+ **/
+struct _EWebDAVSession {
+ /*< private >*/
+ ESoupSession parent;
+ EWebDAVSessionPrivate *priv;
+};
+
+struct _EWebDAVSessionClass {
+ ESoupSessionClass parent_class;
+
+ /* Padding for future expansion */
+ gpointer reserved[10];
+};
+
+GType e_webdav_session_get_type (void) G_GNUC_CONST;
+
+EWebDAVSession *e_webdav_session_new (ESource *source);
+
+G_END_DECLS
+
+#endif /* E_WEBDAV_SESSION_H */
diff --git a/src/libedataserver/libedataserver.h b/src/libedataserver/libedataserver.h
index 47b6304..437cb02 100644
--- a/src/libedataserver/libedataserver.h
+++ b/src/libedataserver/libedataserver.h
@@ -43,6 +43,7 @@
#include <libedataserver/e-secret-store.h>
#include <libedataserver/e-sexp.h>
#include <libedataserver/e-soup-auth-bearer.h>
+#include <libedataserver/e-soup-session.h>
#include <libedataserver/e-soup-ssl-trust.h>
#include <libedataserver/e-source-address-book.h>
#include <libedataserver/e-source-alarms.h>
@@ -91,6 +92,7 @@
#include <libedataserver/e-uid.h>
#include <libedataserver/e-url.h>
#include <libedataserver/e-webdav-discover.h>
+#include <libedataserver/e-webdav-session.h>
#include <libedataserver/e-xml-hash-utils.h>
#include <libedataserver/e-xml-utils.h>
#include <libedataserver/eds-version.h>
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]