1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
5 * Copyright (C) 2000-2003, Ximian, Inc.
12 #include <glib/gi18n-lib.h>
14 #include "soup-session.h"
16 #include "soup-auth-manager.h"
17 #include "soup-cache-private.h"
18 #include "soup-connection.h"
19 #include "soup-message-private.h"
20 #include "soup-misc-private.h"
21 #include "soup-message-queue.h"
22 #include "soup-proxy-resolver-wrapper.h"
23 #include "soup-session-private.h"
26 #if ENABLE(TIZEN_PERFORMANCE_TEST_LOG)
27 #include <sys/prctl.h>
28 #ifndef PR_TASK_PERF_USER_TRACE
29 #define PR_TASK_PERF_USER_TRACE 666
32 #define MAX_STRING_LEN 256
33 #define HWCLOCK_LOG(s) {const char *str=s; prctl(PR_TASK_PERF_USER_TRACE, str, strlen(str));}
35 static void prctl_with_url(const char *prestr, const char *url)
37 char s[MAX_STRING_LEN] = "";
39 int len_pre = strlen(prestr);
40 int len_url = strlen(url);
42 strncpy(s, prestr, len_pre);
43 if(len_pre + len_url < len_max) {
44 strncpy(s+len_pre, url, len_url);
47 int len_part = len_max - len_pre - 10;
48 strncpy(s+len_pre, url, len_part );
49 strncpy(s+len_pre+len_part, "...", MAX_STRING_LEN-len_pre-len_part-1);
50 strncpy(s+len_pre+len_part+3, url+len_url-7, 7);
52 prctl(PR_TASK_PERF_USER_TRACE, s, strlen(s));
55 static void prctl_with_url_and_free(const char *prestr, char *url)
57 prctl_with_url(prestr, url);
62 #define HOST_KEEP_ALIVE 5 * 60 * 1000 /* 5 min in msecs */
63 #if ENABLE(TIZEN_CERTIFICATE_FILE_SET)
64 #define SET_TLS_CERT_FILE_TIMEOUT 7 * 1000 /* msecs */
68 * SECTION:soup-session
69 * @short_description: Soup session state object
71 * #SoupSession is the object that controls client-side HTTP. A
72 * #SoupSession encapsulates all of the state that libsoup is keeping
73 * on behalf of your program; cached HTTP connections, authentication
74 * information, etc. It also keeps track of various global options
75 * and features that you are using.
77 * Most applications will only need a single #SoupSession; the primary
78 * reason you might need multiple sessions is if you need to have
79 * multiple independent authentication contexts. (Eg, you are
80 * connecting to a server and authenticating as two different users at
81 * different times; the easiest way to ensure that each #SoupMessage
82 * is sent with the authentication information you intended is to use
83 * one session for the first user, and a second session for the other
86 * In the past, #SoupSession was an abstract class, and users needed
87 * to choose between #SoupSessionAsync (which always uses
88 * #GMainLoop<!-- -->-based I/O), or #SoupSessionSync (which always uses
89 * blocking I/O and can be used from multiple threads simultaneously).
90 * This is no longer necessary; you can (and should) use a plain
91 * #SoupSession, which supports both synchronous and asynchronous use.
92 * (When using a plain #SoupSession, soup_session_queue_message()
93 * behaves like it traditionally did on a #SoupSessionAsync, and
94 * soup_session_send_message() behaves like it traditionally did on a
101 bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
102 #ifdef HAVE_BIND_TEXTDOMAIN_CODESET
103 bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
111 GSList *connections; /* CONTAINS: SoupConnection */
116 gboolean ssl_fallback;
118 GSource *keep_alive_src;
119 SoupSession *session;
121 static guint soup_host_uri_hash (gconstpointer key);
122 static gboolean soup_host_uri_equal (gconstpointer v1, gconstpointer v2);
125 SoupSession *session;
131 gboolean tlsdb_use_default;
133 SoupMessageQueue *queue;
136 char *accept_language;
137 gboolean accept_language_auto;
140 GHashTable *features_cache;
142 GHashTable *http_hosts, *https_hosts; /* char* -> SoupSessionHost */
143 GHashTable *conns; /* SoupConnection -> SoupSessionHost */
145 guint max_conns, max_conns_per_host;
146 guint io_timeout, idle_timeout;
148 SoupAddress *local_addr;
150 /* Must hold the conn_lock before potentially creating a new
151 * SoupSessionHost, adding/removing a connection,
152 * disconnecting a connection, or moving a connection from
153 * IDLE to IN_USE. Must not emit signals or destroy objects
154 * while holding it. conn_cond is signaled when it may be
155 * possible for a previously-blocked message to continue.
160 GMainContext *async_context;
161 gboolean use_thread_context;
162 GSList *run_queue_sources;
165 GProxyResolver *proxy_resolver;
166 gboolean proxy_use_default;
169 char **http_aliases, **https_aliases;
170 #if ENABLE(TIZEN_CERTIFICATE_FILE_SET)
171 GSource *tls_idle_timeout_src;
172 char *certificate_path;
174 #if ENABLE(TIZEN_TV_CLIENT_CERTIFICATE)
175 gboolean widget_engine;
177 GHashTable *request_types;
178 } SoupSessionPrivate;
179 #define SOUP_SESSION_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), SOUP_TYPE_SESSION, SoupSessionPrivate))
181 #define SOUP_IS_PLAIN_SESSION(o) (G_TYPE_FROM_INSTANCE (o) == SOUP_TYPE_SESSION)
183 static void free_host (SoupSessionHost *host);
184 static void connection_state_changed (GObject *object, GParamSpec *param,
186 static void connection_disconnected (SoupConnection *conn, gpointer user_data);
187 static void drop_connection (SoupSession *session, SoupSessionHost *host,
188 SoupConnection *conn);
190 static void auth_manager_authenticate (SoupAuthManager *manager,
191 SoupMessage *msg, SoupAuth *auth,
192 gboolean retrying, gpointer user_data);
194 static void async_run_queue (SoupSession *session);
196 static void async_send_request_running (SoupSession *session, SoupMessageQueueItem *item);
198 #define SOUP_SESSION_MAX_CONNS_DEFAULT 10
199 #define SOUP_SESSION_MAX_CONNS_PER_HOST_DEFAULT 2
201 #define SOUP_SESSION_MAX_RESEND_COUNT 20
203 #define SOUP_SESSION_USER_AGENT_BASE "libsoup/" PACKAGE_VERSION
205 G_DEFINE_TYPE_WITH_CODE (SoupSession, soup_session, G_TYPE_OBJECT,
219 static guint signals[LAST_SIGNAL] = { 0 };
227 PROP_MAX_CONNS_PER_HOST,
230 PROP_SSL_USE_SYSTEM_CA_FILE,
234 PROP_USE_THREAD_CONTEXT,
237 PROP_ACCEPT_LANGUAGE,
238 PROP_ACCEPT_LANGUAGE_AUTO,
241 PROP_ADD_FEATURE_BY_TYPE,
242 PROP_REMOVE_FEATURE_BY_TYPE,
246 #if ENABLE(TIZEN_CERTIFICATE_FILE_SET)
247 PROP_CERTIFICATE_PATH,
249 #if ENABLE(TIZEN_TV_CLIENT_CERTIFICATE)
256 #if ENABLE(TIZEN_TV_FORCE_PRELOAD_TLSDB)
257 // Preload TLS database. Allow to load the TLS database in background.
258 static GTlsDatabase *_gTlsDB = NULL;
259 static gchar *_gTlsDB_path = NULL;
260 static GMutex _gTlsDB_lock;
261 static void soup_preload_tls_database (const gchar *path);
265 soup_session_init (SoupSession *session)
267 SoupSessionPrivate *priv = SOUP_SESSION_GET_PRIVATE (session);
268 SoupAuthManager *auth_manager;
270 priv->session = session;
272 priv->queue = soup_message_queue_new (session);
274 g_mutex_init (&priv->conn_lock);
275 g_cond_init (&priv->conn_cond);
276 priv->http_hosts = g_hash_table_new_full (soup_host_uri_hash,
278 NULL, (GDestroyNotify)free_host);
279 priv->https_hosts = g_hash_table_new_full (soup_host_uri_hash,
281 NULL, (GDestroyNotify)free_host);
282 priv->conns = g_hash_table_new (NULL, NULL);
284 priv->max_conns = SOUP_SESSION_MAX_CONNS_DEFAULT;
285 priv->max_conns_per_host = SOUP_SESSION_MAX_CONNS_PER_HOST_DEFAULT;
287 priv->features_cache = g_hash_table_new (NULL, NULL);
289 auth_manager = g_object_new (SOUP_TYPE_AUTH_MANAGER, NULL);
290 g_signal_connect (auth_manager, "authenticate",
291 G_CALLBACK (auth_manager_authenticate), session);
292 soup_session_feature_add_feature (SOUP_SESSION_FEATURE (auth_manager),
293 SOUP_TYPE_AUTH_BASIC);
294 soup_session_feature_add_feature (SOUP_SESSION_FEATURE (auth_manager),
295 SOUP_TYPE_AUTH_DIGEST);
296 soup_session_add_feature (session, SOUP_SESSION_FEATURE (auth_manager));
297 g_object_unref (auth_manager);
299 /* We'll be doing DNS continuously-ish while the session is active,
300 * so hold a ref on the default GResolver.
302 priv->resolver = g_resolver_get_default ();
304 priv->ssl_strict = TRUE;
306 priv->http_aliases = g_new (char *, 2);
307 priv->http_aliases[0] = (char *)g_intern_string ("*");
308 priv->http_aliases[1] = NULL;
309 #if ENABLE(TIZEN_CERTIFICATE_FILE_SET)
310 priv->tls_idle_timeout_src = NULL;
311 priv->certificate_path = NULL;
314 priv->request_types = g_hash_table_new (soup_str_case_hash,
315 soup_str_case_equal);
316 soup_session_add_feature_by_type (session, SOUP_TYPE_REQUEST_HTTP);
317 soup_session_add_feature_by_type (session, SOUP_TYPE_REQUEST_FILE);
318 soup_session_add_feature_by_type (session, SOUP_TYPE_REQUEST_DATA);
322 soup_session_constructor (GType type,
323 guint n_construct_properties,
324 GObjectConstructParam *construct_params)
328 object = G_OBJECT_CLASS (soup_session_parent_class)->constructor (type, n_construct_properties, construct_params);
330 /* If this is a "plain" SoupSession, fix up the default
331 * properties values, etc.
333 if (type == SOUP_TYPE_SESSION) {
334 SoupSession *session = SOUP_SESSION (object);
335 SoupSessionPrivate *priv = SOUP_SESSION_GET_PRIVATE (session);
337 g_clear_pointer (&priv->async_context, g_main_context_unref);
338 priv->async_context = g_main_context_ref_thread_default ();
339 priv->use_thread_context = TRUE;
341 priv->io_timeout = priv->idle_timeout = 60;
343 priv->http_aliases[0] = NULL;
345 /* If the user overrides the proxy or tlsdb during construction,
346 * we don't want to needlessly resolve the extension point. So
347 * we just set flags saying to do it later.
349 priv->proxy_use_default = TRUE;
350 priv->tlsdb_use_default = TRUE;
352 soup_session_add_feature_by_type (session, SOUP_TYPE_CONTENT_DECODER);
359 soup_session_dispose (GObject *object)
361 SoupSession *session = SOUP_SESSION (object);
362 SoupSessionPrivate *priv = SOUP_SESSION_GET_PRIVATE (session);
365 priv->disposed = TRUE;
367 for (iter = priv->run_queue_sources; iter; iter = iter->next) {
368 g_source_destroy (iter->data);
369 g_source_unref (iter->data);
371 g_clear_pointer (&priv->run_queue_sources, g_slist_free);
373 priv->disposed = TRUE;
374 soup_session_abort (session);
375 g_warn_if_fail (g_hash_table_size (priv->conns) == 0);
377 while (priv->features)
378 soup_session_remove_feature (session, priv->features->data);
380 G_OBJECT_CLASS (soup_session_parent_class)->dispose (object);
384 soup_session_finalize (GObject *object)
386 SoupSession *session = SOUP_SESSION (object);
387 SoupSessionPrivate *priv = SOUP_SESSION_GET_PRIVATE (session);
389 soup_message_queue_destroy (priv->queue);
391 g_mutex_clear (&priv->conn_lock);
392 g_cond_clear (&priv->conn_cond);
393 g_hash_table_destroy (priv->http_hosts);
394 g_hash_table_destroy (priv->https_hosts);
395 g_hash_table_destroy (priv->conns);
397 g_free (priv->user_agent);
398 g_free (priv->accept_language);
400 g_clear_object (&priv->tlsdb);
401 g_free (priv->ssl_ca_file);
403 #if ENABLE(TIZEN_CERTIFICATE_FILE_SET)
404 soup_session_tls_stop_idle_timer (session);
405 g_free (priv->certificate_path);
406 priv->certificate_path = NULL;
408 g_clear_pointer (&priv->async_context, g_main_context_unref);
409 g_clear_object (&priv->local_addr);
411 g_hash_table_destroy (priv->features_cache);
413 g_object_unref (priv->resolver);
414 g_clear_object (&priv->proxy_resolver);
415 g_clear_pointer (&priv->proxy_uri, soup_uri_free);
417 g_free (priv->http_aliases);
418 g_free (priv->https_aliases);
420 g_hash_table_destroy (priv->request_types);
422 G_OBJECT_CLASS (soup_session_parent_class)->finalize (object);
425 /* Converts a language in POSIX format and to be RFC2616 compliant */
426 /* Based on code from epiphany-webkit (ephy_langs_append_languages()) */
428 posix_lang_to_rfc2616 (const gchar *language)
430 /* Don't include charset variants, etc */
431 if (strchr (language, '.') || strchr (language, '@'))
434 /* Ignore "C" locale, which g_get_language_names() always
435 * includes as a fallback.
437 if (!strcmp (language, "C"))
440 return g_strdelimit (g_ascii_strdown (language, -1), "_", '-');
443 /* Converts @quality from 0-100 to 0.0-1.0 and appends to @str */
445 add_quality_value (const gchar *str, int quality)
447 g_return_val_if_fail (str != NULL, NULL);
449 if (quality >= 0 && quality < 100) {
450 /* We don't use %.02g because of "." vs "," locale issues */
452 return g_strdup_printf ("%s;q=0.%02d", str, quality);
454 return g_strdup_printf ("%s;q=0.%d", str, quality / 10);
456 return g_strdup (str);
459 /* Returns a RFC2616 compliant languages list from system locales */
461 accept_languages_from_system (void)
463 const char * const * lang_names;
464 GPtrArray *langs = NULL;
465 char *lang, *langs_str;
469 lang_names = g_get_language_names ();
470 g_return_val_if_fail (lang_names != NULL, NULL);
472 /* Build the array of languages */
473 langs = g_ptr_array_new_with_free_func (g_free);
474 for (i = 0; lang_names[i] != NULL; i++) {
475 lang = posix_lang_to_rfc2616 (lang_names[i]);
477 g_ptr_array_add (langs, lang);
480 /* Add quality values */
483 else if (langs->len < 20)
488 for (i = 0; i < langs->len; i++) {
489 lang = langs->pdata[i];
490 langs->pdata[i] = add_quality_value (lang, 100 - i * delta);
494 /* Fallback: add "en" if list is empty */
496 g_ptr_array_add (langs, g_strdup ("en"));
498 g_ptr_array_add (langs, NULL);
499 langs_str = g_strjoinv (", ", (char **)langs->pdata);
500 g_ptr_array_free (langs, TRUE);
506 set_tlsdb (SoupSession *session, GTlsDatabase *tlsdb)
508 SoupSessionPrivate *priv = SOUP_SESSION_GET_PRIVATE (session);
509 GTlsDatabase *system_default;
511 priv->tlsdb_use_default = FALSE;
512 if (tlsdb == priv->tlsdb)
515 g_object_freeze_notify (G_OBJECT (session));
517 system_default = g_tls_backend_get_default_database (g_tls_backend_get_default ());
518 if (system_default) {
519 if (priv->tlsdb == system_default || tlsdb == system_default) {
520 g_object_notify (G_OBJECT (session), "ssl-use-system-ca-file");
522 g_object_unref (system_default);
525 if (priv->ssl_ca_file) {
526 g_free (priv->ssl_ca_file);
527 priv->ssl_ca_file = NULL;
528 g_object_notify (G_OBJECT (session), "ssl-ca-file");
532 g_object_unref (priv->tlsdb);
535 g_object_ref (priv->tlsdb);
537 g_object_notify (G_OBJECT (session), "tls-database");
538 g_object_thaw_notify (G_OBJECT (session));
542 set_use_system_ca_file (SoupSession *session, gboolean use_system_ca_file)
544 SoupSessionPrivate *priv = SOUP_SESSION_GET_PRIVATE (session);
545 GTlsDatabase *system_default;
547 priv->tlsdb_use_default = FALSE;
549 system_default = g_tls_backend_get_default_database (g_tls_backend_get_default ());
551 if (use_system_ca_file)
552 set_tlsdb (session, system_default);
553 else if (priv->tlsdb == system_default)
554 set_tlsdb (session, NULL);
556 g_clear_object (&system_default);
560 set_ssl_ca_file (SoupSession *session, const char *ssl_ca_file)
562 SoupSessionPrivate *priv = SOUP_SESSION_GET_PRIVATE (session);
564 GError *error = NULL;
566 priv->tlsdb_use_default = FALSE;
567 if (!g_strcmp0 (priv->ssl_ca_file, ssl_ca_file))
570 g_object_freeze_notify (G_OBJECT (session));
572 if (g_path_is_absolute (ssl_ca_file))
573 tlsdb = g_tls_file_database_new (ssl_ca_file, &error);
577 cwd = g_get_current_dir ();
578 path = g_build_filename (cwd, ssl_ca_file, NULL);
579 tlsdb = g_tls_file_database_new (path, &error);
585 if (!g_error_matches (error, G_TLS_ERROR, G_TLS_ERROR_UNAVAILABLE)) {
586 g_warning ("Could not set SSL credentials from '%s': %s",
587 ssl_ca_file, error->message);
589 tlsdb = g_tls_file_database_new ("/dev/null", NULL);
591 g_error_free (error);
594 set_tlsdb (session, tlsdb);
596 g_object_unref (tlsdb);
598 priv->ssl_ca_file = g_strdup (ssl_ca_file);
599 g_object_notify (G_OBJECT (session), "ssl-ca-file");
600 } else if (priv->ssl_ca_file) {
601 g_clear_pointer (&priv->ssl_ca_file, g_free);
602 g_object_notify (G_OBJECT (session), "ssl-ca-file");
605 g_object_thaw_notify (G_OBJECT (session));
608 /* priv->http_aliases and priv->https_aliases are stored as arrays of
609 * *interned* strings, so we can't just use g_strdupv() to set them.
612 set_aliases (char ***variable, char **value)
624 len = g_strv_length (value);
625 *variable = g_new (char *, len + 1);
626 for (i = 0; i < len; i++)
627 (*variable)[i] = (char *)g_intern_string (value[i]);
628 (*variable)[i] = NULL;
632 set_proxy_resolver (SoupSession *session, SoupURI *uri,
633 SoupProxyURIResolver *soup_resolver,
634 GProxyResolver *g_resolver)
636 SoupSessionPrivate *priv = SOUP_SESSION_GET_PRIVATE (session);
638 G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
639 soup_session_remove_feature_by_type (session, SOUP_TYPE_PROXY_URI_RESOLVER);
640 G_GNUC_END_IGNORE_DEPRECATIONS;
641 g_clear_object (&priv->proxy_resolver);
642 g_clear_pointer (&priv->proxy_uri, soup_uri_free);
643 priv->proxy_use_default = FALSE;
648 priv->proxy_uri = soup_uri_copy (uri);
649 uri_string = soup_uri_to_string_internal (uri, FALSE, TRUE);
650 priv->proxy_resolver = g_simple_proxy_resolver_new (uri_string, NULL);
652 } else if (soup_resolver) {
653 G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
654 if (SOUP_IS_PROXY_RESOLVER_DEFAULT (soup_resolver))
655 priv->proxy_resolver = g_object_ref (g_proxy_resolver_get_default ());
657 priv->proxy_resolver = soup_proxy_resolver_wrapper_new (soup_resolver);
658 G_GNUC_END_IGNORE_DEPRECATIONS;
659 } else if (g_resolver)
660 priv->proxy_resolver = g_object_ref (g_resolver);
664 soup_session_set_property (GObject *object, guint prop_id,
665 const GValue *value, GParamSpec *pspec)
667 SoupSession *session = SOUP_SESSION (object);
668 SoupSessionPrivate *priv = SOUP_SESSION_GET_PRIVATE (session);
669 const char *user_agent;
670 SoupSessionFeature *feature;
671 GMainContext *async_context;
674 case PROP_LOCAL_ADDRESS:
675 priv->local_addr = g_value_dup_object (value);
678 set_proxy_resolver (session, g_value_get_boxed (value),
680 soup_session_abort (session);
682 case PROP_PROXY_RESOLVER:
683 set_proxy_resolver (session, NULL, NULL,
684 g_value_get_object (value));
687 priv->max_conns = g_value_get_int (value);
689 case PROP_MAX_CONNS_PER_HOST:
690 priv->max_conns_per_host = g_value_get_int (value);
693 g_return_if_fail (!SOUP_IS_PLAIN_SESSION (session));
694 feature = soup_session_get_feature (session, SOUP_TYPE_AUTH_MANAGER);
696 if (g_value_get_boolean (value))
697 soup_session_feature_add_feature (feature, SOUP_TYPE_AUTH_NTLM);
699 soup_session_feature_remove_feature (feature, SOUP_TYPE_AUTH_NTLM);
701 g_warning ("Trying to set use-ntlm on session with no auth-manager");
703 case PROP_SSL_CA_FILE:
704 set_ssl_ca_file (session, g_value_get_string (value));
706 case PROP_SSL_USE_SYSTEM_CA_FILE:
707 set_use_system_ca_file (session, g_value_get_boolean (value));
709 case PROP_TLS_DATABASE:
710 set_tlsdb (session, g_value_get_object (value));
712 case PROP_SSL_STRICT:
713 priv->ssl_strict = g_value_get_boolean (value);
715 case PROP_ASYNC_CONTEXT:
716 async_context = g_value_get_pointer (value);
717 if (async_context && async_context != g_main_context_get_thread_default ())
718 g_return_if_fail (!SOUP_IS_PLAIN_SESSION (session));
719 priv->async_context = async_context;
720 if (priv->async_context)
721 g_main_context_ref (priv->async_context);
723 case PROP_USE_THREAD_CONTEXT:
724 if (!g_value_get_boolean (value))
725 g_return_if_fail (!SOUP_IS_PLAIN_SESSION (session));
726 priv->use_thread_context = g_value_get_boolean (value);
727 if (priv->use_thread_context) {
728 if (priv->async_context)
729 g_main_context_unref (priv->async_context);
730 priv->async_context = g_main_context_get_thread_default ();
731 if (priv->async_context)
732 g_main_context_ref (priv->async_context);
736 priv->io_timeout = g_value_get_uint (value);
738 case PROP_USER_AGENT:
739 g_free (priv->user_agent);
740 user_agent = g_value_get_string (value);
742 priv->user_agent = NULL;
743 else if (!*user_agent) {
745 g_strdup (SOUP_SESSION_USER_AGENT_BASE);
746 } else if (g_str_has_suffix (user_agent, " ")) {
748 g_strdup_printf ("%s%s", user_agent,
749 SOUP_SESSION_USER_AGENT_BASE);
751 priv->user_agent = g_strdup (user_agent);
753 case PROP_ACCEPT_LANGUAGE:
754 g_free (priv->accept_language);
755 priv->accept_language = g_strdup (g_value_get_string (value));
756 priv->accept_language_auto = FALSE;
758 case PROP_ACCEPT_LANGUAGE_AUTO:
759 priv->accept_language_auto = g_value_get_boolean (value);
760 if (priv->accept_language) {
761 g_free (priv->accept_language);
762 priv->accept_language = NULL;
765 /* Get languages from system if needed */
766 if (priv->accept_language_auto)
767 priv->accept_language = accept_languages_from_system ();
769 case PROP_IDLE_TIMEOUT:
770 priv->idle_timeout = g_value_get_uint (value);
772 case PROP_ADD_FEATURE:
773 soup_session_add_feature (session, g_value_get_object (value));
775 case PROP_ADD_FEATURE_BY_TYPE:
776 soup_session_add_feature_by_type (session, g_value_get_gtype (value));
778 case PROP_REMOVE_FEATURE_BY_TYPE:
779 soup_session_remove_feature_by_type (session, g_value_get_gtype (value));
781 case PROP_HTTP_ALIASES:
782 set_aliases (&priv->http_aliases, g_value_get_boxed (value));
784 case PROP_HTTPS_ALIASES:
785 set_aliases (&priv->https_aliases, g_value_get_boxed (value));
787 #if ENABLE(TIZEN_CERTIFICATE_FILE_SET)
788 case PROP_CERTIFICATE_PATH:
789 if (priv->certificate_path) {
790 g_free (priv->certificate_path);
791 priv->certificate_path = NULL;
793 if (g_value_get_string (value) && strlen (g_value_get_string (value)))
794 priv->certificate_path = g_strdup (g_value_get_string (value));
795 #if ENABLE(TIZEN_DLOG)
796 TIZEN_LOGI ("set_property() PROP_CERTIFICATE_PATH priv->certificate_path is set");
797 TIZEN_LOGI ("set_property() PROP_CERTIFICATE_PATH priv->certificate_path is set [%s]", priv->certificate_path);
799 if (priv->certificate_path)
800 #if ENABLE(TIZEN_TV_FORCE_PRELOAD_TLSDB)
801 //Trigger loading of the TLS database. The load is done in a thread.
802 soup_preload_tls_database(priv->certificate_path);
804 soup_session_tls_start_idle_timer(session, SET_TLS_CERT_FILE_TIMEOUT);
808 #if ENABLE(TIZEN_TV_CLIENT_CERTIFICATE)
809 case PROP_WIDGET_ENGINE:
810 priv->widget_engine = g_value_get_boolean (value);
814 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
819 static GProxyResolver *
820 get_proxy_resolver (SoupSession *session)
822 SoupSessionPrivate *priv = SOUP_SESSION_GET_PRIVATE (session);
824 if (priv->proxy_use_default) {
825 priv->proxy_resolver = g_object_ref (g_proxy_resolver_get_default ());
826 priv->proxy_use_default = FALSE;
828 return priv->proxy_resolver;
831 static GTlsDatabase *
832 get_tls_database (SoupSession *session)
834 SoupSessionPrivate *priv = SOUP_SESSION_GET_PRIVATE (session);
836 if (priv->tlsdb_use_default) {
837 priv->tlsdb = g_tls_backend_get_default_database (g_tls_backend_get_default ());
838 priv->tlsdb_use_default = FALSE;
844 soup_session_get_property (GObject *object, guint prop_id,
845 GValue *value, GParamSpec *pspec)
847 SoupSession *session = SOUP_SESSION (object);
848 SoupSessionPrivate *priv = SOUP_SESSION_GET_PRIVATE (session);
849 SoupSessionFeature *feature;
853 case PROP_LOCAL_ADDRESS:
854 g_value_set_object (value, priv->local_addr);
857 g_value_set_boxed (value, priv->proxy_uri);
859 case PROP_PROXY_RESOLVER:
860 g_value_set_object (value, get_proxy_resolver (session));
863 g_value_set_int (value, priv->max_conns);
865 case PROP_MAX_CONNS_PER_HOST:
866 g_value_set_int (value, priv->max_conns_per_host);
869 feature = soup_session_get_feature (session, SOUP_TYPE_AUTH_MANAGER);
871 g_value_set_boolean (value, soup_session_feature_has_feature (feature, SOUP_TYPE_AUTH_NTLM));
873 g_value_set_boolean (value, FALSE);
875 case PROP_SSL_CA_FILE:
876 g_value_set_string (value, priv->ssl_ca_file);
878 case PROP_SSL_USE_SYSTEM_CA_FILE:
879 tlsdb = g_tls_backend_get_default_database (g_tls_backend_get_default ());
880 g_value_set_boolean (value, get_tls_database (session) == tlsdb);
881 g_clear_object (&tlsdb);
883 case PROP_TLS_DATABASE:
884 g_value_set_object (value, get_tls_database (session));
886 case PROP_SSL_STRICT:
887 g_value_set_boolean (value, priv->ssl_strict);
889 case PROP_ASYNC_CONTEXT:
890 g_value_set_pointer (value, priv->async_context ? g_main_context_ref (priv->async_context) : NULL);
892 case PROP_USE_THREAD_CONTEXT:
893 g_value_set_boolean (value, priv->use_thread_context);
896 g_value_set_uint (value, priv->io_timeout);
898 case PROP_USER_AGENT:
899 g_value_set_string (value, priv->user_agent);
901 case PROP_ACCEPT_LANGUAGE:
902 g_value_set_string (value, priv->accept_language);
904 case PROP_ACCEPT_LANGUAGE_AUTO:
905 g_value_set_boolean (value, priv->accept_language_auto);
907 case PROP_IDLE_TIMEOUT:
908 g_value_set_uint (value, priv->idle_timeout);
910 case PROP_HTTP_ALIASES:
911 g_value_set_boxed (value, priv->http_aliases);
913 case PROP_HTTPS_ALIASES:
914 g_value_set_boxed (value, priv->https_aliases);
916 #if ENABLE(TIZEN_CERTIFICATE_FILE_SET)
917 case PROP_CERTIFICATE_PATH:
918 #if ENABLE(TIZEN_DLOG)
919 TIZEN_LOGI ("get_property() PROP_CERTIFICATE_PATH");
921 g_value_set_string (value, priv->certificate_path);
924 #if ENABLE(TIZEN_TV_CLIENT_CERTIFICATE)
925 case PROP_WIDGET_ENGINE:
926 g_value_set_boolean (value, priv->widget_engine);
930 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
938 * Creates a #SoupSession with the default options.
940 * Return value: the new session.
945 soup_session_new (void)
947 return g_object_new (SOUP_TYPE_SESSION, NULL);
951 * soup_session_new_with_options:
952 * @optname1: name of first property to set
953 * @...: value of @optname1, followed by additional property/value pairs
955 * Creates a #SoupSession with the specified options.
957 * Return value: the new session.
962 soup_session_new_with_options (const char *optname1,
965 SoupSession *session;
968 va_start (ap, optname1);
969 session = (SoupSession *)g_object_new_valist (SOUP_TYPE_SESSION,
977 * soup_session_get_async_context:
978 * @session: a #SoupSession
980 * Gets @session's #SoupSession:async-context. This does not add a ref
981 * to the context, so you will need to ref it yourself if you want it
982 * to outlive its session.
984 * For a modern #SoupSession, this will always just return the
985 * thread-default #GMainContext, and so is not especially useful.
987 * Return value: (transfer none): @session's #GMainContext, which may
991 soup_session_get_async_context (SoupSession *session)
993 SoupSessionPrivate *priv;
995 g_return_val_if_fail (SOUP_IS_SESSION (session), NULL);
996 priv = SOUP_SESSION_GET_PRIVATE (session);
998 if (priv->use_thread_context)
999 return g_main_context_get_thread_default ();
1001 return priv->async_context;
1006 /* Note that we can't use soup_uri_host_hash() and soup_uri_host_equal()
1007 * because we want to ignore the protocol; http://example.com and
1008 * webcal://example.com are the same host.
1011 soup_host_uri_hash (gconstpointer key)
1013 const SoupURI *uri = key;
1015 g_return_val_if_fail (uri != NULL && uri->host != NULL, 0);
1017 return uri->port + soup_str_case_hash (uri->host);
1021 soup_host_uri_equal (gconstpointer v1, gconstpointer v2)
1023 const SoupURI *one = v1;
1024 const SoupURI *two = v2;
1026 g_return_val_if_fail (one != NULL && two != NULL, one == two);
1027 g_return_val_if_fail (one->host != NULL && two->host != NULL, one->host == two->host);
1029 if (one->port != two->port)
1032 return g_ascii_strcasecmp (one->host, two->host) == 0;
1036 static SoupSessionHost *
1037 soup_session_host_new (SoupSession *session, SoupURI *uri)
1039 SoupSessionHost *host;
1041 host = g_slice_new0 (SoupSessionHost);
1042 host->uri = soup_uri_copy_host (uri);
1043 if (host->uri->scheme != SOUP_URI_SCHEME_HTTP &&
1044 host->uri->scheme != SOUP_URI_SCHEME_HTTPS) {
1045 SoupSessionPrivate *priv = SOUP_SESSION_GET_PRIVATE (session);
1047 if (soup_uri_is_https (host->uri, priv->https_aliases))
1048 host->uri->scheme = SOUP_URI_SCHEME_HTTPS;
1050 host->uri->scheme = SOUP_URI_SCHEME_HTTP;
1053 host->addr = g_object_new (SOUP_TYPE_ADDRESS,
1054 SOUP_ADDRESS_NAME, host->uri->host,
1055 SOUP_ADDRESS_PORT, host->uri->port,
1056 SOUP_ADDRESS_PROTOCOL, host->uri->scheme,
1058 host->keep_alive_src = NULL;
1059 host->session = session;
1064 /* Requires conn_lock to be locked */
1065 static SoupSessionHost *
1066 get_host_for_uri (SoupSession *session, SoupURI *uri)
1068 SoupSessionPrivate *priv = SOUP_SESSION_GET_PRIVATE (session);
1069 SoupSessionHost *host;
1071 if (soup_uri_is_https (uri, priv->https_aliases))
1072 host = g_hash_table_lookup (priv->https_hosts, uri);
1074 host = g_hash_table_lookup (priv->http_hosts, uri);
1078 host = soup_session_host_new (session, uri);
1080 if (soup_uri_is_https (uri, priv->https_aliases))
1081 g_hash_table_insert (priv->https_hosts, host->uri, host);
1083 g_hash_table_insert (priv->http_hosts, host->uri, host);
1088 /* Requires conn_lock to be locked */
1089 static SoupSessionHost *
1090 get_host_for_message (SoupSession *session, SoupMessage *msg)
1092 return get_host_for_uri (session, soup_message_get_uri (msg));
1096 free_host (SoupSessionHost *host)
1098 g_warn_if_fail (host->connections == NULL);
1100 if (host->keep_alive_src) {
1101 g_source_destroy (host->keep_alive_src);
1102 g_source_unref (host->keep_alive_src);
1105 soup_uri_free (host->uri);
1106 g_object_unref (host->addr);
1107 g_slice_free (SoupSessionHost, host);
1111 auth_manager_authenticate (SoupAuthManager *manager, SoupMessage *msg,
1112 SoupAuth *auth, gboolean retrying,
1115 #if ENABLE(TIZEN_ON_AUTHENTICATION_REQUESTED)
1116 soup_message_authenticate(msg, auth, retrying);
1118 g_signal_emit (session, signals[AUTHENTICATE], 0, msg, auth, retrying);
1121 #if ENABLE(TIZEN_HANDLING_307_REDIRECTION)
1122 #define SOUP_SESSION_WOULD_REDIRECT_AS_GET(session, msg) \
1123 ((msg)->status_code == SOUP_STATUS_SEE_OTHER || \
1124 ((msg)->status_code == SOUP_STATUS_FOUND && \
1125 !SOUP_METHOD_IS_SAFE ((msg)->method)) || \
1126 ((msg)->status_code == SOUP_STATUS_TEMPORARY_REDIRECT && \
1127 (msg)->method == SOUP_METHOD_GET) || \
1128 ((msg)->status_code == SOUP_STATUS_MOVED_PERMANENTLY && \
1129 (msg)->method == SOUP_METHOD_POST))
1131 #define SOUP_SESSION_WOULD_REDIRECT_AS_GET(session, msg) \
1132 ((msg)->status_code == SOUP_STATUS_SEE_OTHER || \
1133 ((msg)->status_code == SOUP_STATUS_FOUND && \
1134 !SOUP_METHOD_IS_SAFE ((msg)->method)) || \
1135 ((msg)->status_code == SOUP_STATUS_MOVED_PERMANENTLY && \
1136 (msg)->method == SOUP_METHOD_POST))
1139 #define SOUP_SESSION_WOULD_REDIRECT_AS_SAFE(session, msg) \
1140 (((msg)->status_code == SOUP_STATUS_MOVED_PERMANENTLY || \
1141 (msg)->status_code == SOUP_STATUS_TEMPORARY_REDIRECT || \
1142 (msg)->status_code == SOUP_STATUS_FOUND) && \
1143 SOUP_METHOD_IS_SAFE ((msg)->method))
1145 #if ENABLE(TIZEN_HANDLING_307_REDIRECTION)
1146 #define SOUP_SESSION_WOULD_REDIRECT_AS_POST(session, msg) \
1147 ((msg)->status_code == SOUP_STATUS_TEMPORARY_REDIRECT && \
1148 (msg)->method == SOUP_METHOD_POST)
1151 static inline SoupURI *
1152 redirection_uri (SoupMessage *msg)
1154 const char *new_loc;
1157 new_loc = soup_message_headers_get_one (msg->response_headers,
1161 new_uri = soup_uri_new_with_base (soup_message_get_uri (msg), new_loc);
1162 if (!new_uri || !new_uri->host) {
1164 soup_uri_free (new_uri);
1172 * soup_session_would_redirect:
1173 * @session: a #SoupSession
1174 * @msg: a #SoupMessage that has response headers
1176 * Checks if @msg contains a response that would cause @session to
1177 * redirect it to a new URL (ignoring @msg's %SOUP_MESSAGE_NO_REDIRECT
1178 * flag, and the number of times it has already been redirected).
1180 * Return value: whether @msg would be redirected
1185 soup_session_would_redirect (SoupSession *session, SoupMessage *msg)
1187 SoupSessionPrivate *priv = SOUP_SESSION_GET_PRIVATE (session);
1190 /* It must have an appropriate status code and method */
1191 if (!SOUP_SESSION_WOULD_REDIRECT_AS_GET (session, msg) &&
1192 !SOUP_SESSION_WOULD_REDIRECT_AS_SAFE (session, msg)
1193 #if ENABLE(TIZEN_HANDLING_307_REDIRECTION)
1194 && !SOUP_SESSION_WOULD_REDIRECT_AS_POST (session, msg)
1199 /* and a Location header that parses to an http URI */
1200 if (!soup_message_headers_get_one (msg->response_headers, "Location"))
1202 new_uri = redirection_uri (msg);
1205 if (!new_uri->host || !*new_uri->host ||
1206 (!soup_uri_is_http (new_uri, priv->http_aliases) &&
1207 !soup_uri_is_https (new_uri, priv->https_aliases))) {
1208 soup_uri_free (new_uri);
1212 soup_uri_free (new_uri);
1217 * soup_session_redirect_message:
1218 * @session: the session
1219 * @msg: a #SoupMessage that has received a 3xx response
1221 * Updates @msg's URI according to its status code and "Location"
1222 * header, and requeues it on @session. Use this when you have set
1223 * %SOUP_MESSAGE_NO_REDIRECT on a message, but have decided to allow a
1224 * particular redirection to occur, or if you want to allow a
1225 * redirection that #SoupSession will not perform automatically (eg,
1226 * redirecting a non-safe method such as DELETE).
1228 * If @msg's status code indicates that it should be retried as a GET
1229 * request, then @msg will be modified accordingly.
1231 * If @msg has already been redirected too many times, this will
1232 * cause it to fail with %SOUP_STATUS_TOO_MANY_REDIRECTS.
1234 * Return value: %TRUE if a redirection was applied, %FALSE if not
1235 * (eg, because there was no Location header, or it could not be
1241 soup_session_redirect_message (SoupSession *session, SoupMessage *msg)
1245 new_uri = redirection_uri (msg);
1249 if (SOUP_SESSION_WOULD_REDIRECT_AS_GET (session, msg)) {
1250 if (msg->method != SOUP_METHOD_HEAD) {
1252 SOUP_MESSAGE_METHOD, SOUP_METHOD_GET,
1255 soup_message_set_request (msg, NULL,
1256 SOUP_MEMORY_STATIC, NULL, 0);
1257 soup_message_headers_set_encoding (msg->request_headers,
1258 SOUP_ENCODING_NONE);
1261 soup_message_set_uri (msg, new_uri);
1262 soup_uri_free (new_uri);
1264 soup_session_requeue_message (session, msg);
1269 redirect_handler (SoupMessage *msg, gpointer user_data)
1271 SoupMessageQueueItem *item = user_data;
1272 SoupSession *session = item->session;
1274 if (!soup_session_would_redirect (session, msg)) {
1275 SoupURI *new_uri = redirection_uri (msg);
1276 gboolean invalid = !new_uri || !new_uri->host;
1279 soup_uri_free (new_uri);
1280 if (invalid && !item->new_api) {
1281 soup_message_set_status_full (msg,
1282 SOUP_STATUS_MALFORMED,
1283 "Invalid Redirect URL");
1288 soup_session_redirect_message (session, msg);
1292 re_emit_connection_event (SoupConnection *conn,
1293 GSocketClientEvent event,
1294 GIOStream *connection,
1297 SoupMessageQueueItem *item = user_data;
1299 soup_message_network_event (item->msg, event, connection);
1302 #if ENABLE(TIZEN_TV_DYNAMIC_CERTIFICATE_LOADING)
1304 re_emit_connection_dynamic_client_certificate (SoupConnection *conn,
1305 const char* current_host,
1308 SoupMessageQueueItem *item = user_data;
1310 return soup_message_dynamic_client_certificate(item->msg, current_host);
1314 #if ENABLE(TIZEN_TV_CERTIFICATE_HANDLING)
1316 re_emit_connection_accept_certificate (SoupConnection *conn,
1317 GTlsCertificate* certificate,
1318 GTlsCertificateFlags errors,
1321 SoupMessageQueueItem *item = user_data;
1323 return soup_message_accept_certificate(item->msg, certificate, errors);
1328 soup_session_set_item_connection (SoupSession *session,
1329 SoupMessageQueueItem *item,
1330 SoupConnection *conn)
1333 g_signal_handlers_disconnect_by_func (item->conn, re_emit_connection_event, item);
1334 g_object_unref (item->conn);
1338 soup_message_set_connection (item->msg, conn);
1341 g_object_ref (item->conn);
1342 g_signal_connect (item->conn, "event",
1343 G_CALLBACK (re_emit_connection_event), item);
1344 #if ENABLE(TIZEN_TV_DYNAMIC_CERTIFICATE_LOADING)
1345 if (item->msg->method != SOUP_METHOD_CONNECT)
1346 g_signal_connect (item->conn, "dynamic-certificatePath",
1347 G_CALLBACK (re_emit_connection_dynamic_client_certificate), item);
1349 #if ENABLE(TIZEN_TV_CERTIFICATE_HANDLING)
1350 if (item->msg->method != SOUP_METHOD_CONNECT)
1351 g_signal_connect (item->conn, "accept-certificate",
1352 G_CALLBACK (re_emit_connection_accept_certificate), item);
1358 message_restarted (SoupMessage *msg, gpointer user_data)
1360 SoupMessageQueueItem *item = user_data;
1363 (!soup_message_is_keepalive (msg) ||
1364 SOUP_STATUS_IS_REDIRECTION (msg->status_code))) {
1365 if (soup_connection_get_state (item->conn) == SOUP_CONNECTION_IN_USE)
1366 soup_connection_set_state (item->conn, SOUP_CONNECTION_IDLE);
1367 soup_session_set_item_connection (item->session, item, NULL);
1370 soup_message_cleanup_response (msg);
1373 SoupMessageQueueItem *
1374 soup_session_append_queue_item (SoupSession *session, SoupMessage *msg,
1375 gboolean async, gboolean new_api,
1376 SoupSessionCallback callback, gpointer user_data)
1378 SoupSessionPrivate *priv = SOUP_SESSION_GET_PRIVATE (session);
1379 SoupMessageQueueItem *item;
1380 SoupSessionHost *host;
1382 soup_message_cleanup_response (msg);
1384 item = soup_message_queue_append (priv->queue, msg, callback, user_data);
1385 item->async = async;
1386 item->new_api = new_api;
1388 g_mutex_lock (&priv->conn_lock);
1389 host = get_host_for_message (session, item->msg);
1390 host->num_messages++;
1391 g_mutex_unlock (&priv->conn_lock);
1393 if (!(soup_message_get_flags (msg) & SOUP_MESSAGE_NO_REDIRECT)) {
1394 soup_message_add_header_handler (
1395 msg, "got_body", "Location",
1396 G_CALLBACK (redirect_handler), item);
1398 g_signal_connect (msg, "restarted",
1399 G_CALLBACK (message_restarted), item);
1401 g_signal_emit (session, signals[REQUEST_QUEUED], 0, msg);
1403 soup_message_queue_item_ref (item);
1408 soup_session_send_queue_item (SoupSession *session,
1409 SoupMessageQueueItem *item,
1410 SoupMessageCompletionFn completion_cb)
1412 SoupSessionPrivate *priv = SOUP_SESSION_GET_PRIVATE (session);
1413 const char *conn_header;
1415 if (priv->user_agent) {
1416 soup_message_headers_replace (item->msg->request_headers,
1417 "User-Agent", priv->user_agent);
1420 if (priv->accept_language &&
1421 !soup_message_headers_get_list (item->msg->request_headers,
1422 "Accept-Language")) {
1423 soup_message_headers_append (item->msg->request_headers,
1425 priv->accept_language);
1428 /* Force keep alive connections for HTTP 1.0. Performance will
1429 * improve when issuing multiple requests to the same host in
1430 * a short period of time, as we wouldn't need to establish
1431 * new connections. Keep alive is implicit for HTTP 1.1.
1433 conn_header = soup_message_headers_get_list (item->msg->request_headers, "Connection");
1435 (!soup_header_contains (conn_header, "Keep-Alive") &&
1436 !soup_header_contains (conn_header, "close")))
1437 soup_message_headers_append (item->msg->request_headers,
1438 "Connection", "Keep-Alive");
1440 g_signal_emit (session, signals[REQUEST_STARTED], 0,
1441 item->msg, soup_connection_get_socket (item->conn));
1442 if (item->state == SOUP_MESSAGE_RUNNING)
1443 soup_connection_send_request (item->conn, item, completion_cb, item);
1447 soup_session_cleanup_connections (SoupSession *session,
1448 gboolean cleanup_idle)
1450 SoupSessionPrivate *priv = SOUP_SESSION_GET_PRIVATE (session);
1451 GSList *conns = NULL, *c;
1452 GHashTableIter iter;
1453 gpointer conn, host;
1454 SoupConnectionState state;
1456 g_mutex_lock (&priv->conn_lock);
1457 g_hash_table_iter_init (&iter, priv->conns);
1458 while (g_hash_table_iter_next (&iter, &conn, &host)) {
1459 state = soup_connection_get_state (conn);
1460 if (state == SOUP_CONNECTION_REMOTE_DISCONNECTED ||
1461 (cleanup_idle && state == SOUP_CONNECTION_IDLE)) {
1462 conns = g_slist_prepend (conns, g_object_ref (conn));
1463 g_hash_table_iter_remove (&iter);
1464 drop_connection (session, host, conn);
1467 g_mutex_unlock (&priv->conn_lock);
1472 for (c = conns; c; c = c->next) {
1474 soup_connection_disconnect (conn);
1475 g_object_unref (conn);
1477 g_slist_free (conns);
1483 free_unused_host (gpointer user_data)
1485 SoupSessionHost *host = (SoupSessionHost *) user_data;
1486 SoupSessionPrivate *priv = SOUP_SESSION_GET_PRIVATE (host->session);
1488 g_mutex_lock (&priv->conn_lock);
1490 /* In a multithreaded session, a connection might have been
1491 * added while we were waiting for conn_lock.
1493 if (host->connections) {
1494 g_mutex_unlock (&priv->conn_lock);
1498 /* This will free the host in addition to removing it from the
1501 if (host->uri->scheme == SOUP_URI_SCHEME_HTTPS)
1502 g_hash_table_remove (priv->https_hosts, host->uri);
1504 g_hash_table_remove (priv->http_hosts, host->uri);
1505 g_mutex_unlock (&priv->conn_lock);
1511 drop_connection (SoupSession *session, SoupSessionHost *host, SoupConnection *conn)
1513 SoupSessionPrivate *priv = SOUP_SESSION_GET_PRIVATE (session);
1515 /* Note: caller must hold conn_lock, and must remove @conn
1516 * from priv->conns itself.
1520 host->connections = g_slist_remove (host->connections, conn);
1523 /* Free the SoupHost (and its SoupAddress) if there
1524 * has not been any new connection to the host during
1525 * the last HOST_KEEP_ALIVE msecs.
1527 if (host->num_conns == 0) {
1528 g_assert (host->keep_alive_src == NULL);
1529 host->keep_alive_src = soup_add_timeout (priv->async_context,
1533 host->keep_alive_src = g_source_ref (host->keep_alive_src);
1536 if (soup_connection_get_ssl_fallback (conn))
1537 host->ssl_fallback = TRUE;
1540 g_signal_handlers_disconnect_by_func (conn, connection_disconnected, session);
1541 g_signal_handlers_disconnect_by_func (conn, connection_state_changed, session);
1544 g_object_unref (conn);
1548 connection_disconnected (SoupConnection *conn, gpointer user_data)
1550 SoupSession *session = user_data;
1551 SoupSessionPrivate *priv = SOUP_SESSION_GET_PRIVATE (session);
1552 SoupSessionHost *host;
1554 g_mutex_lock (&priv->conn_lock);
1556 host = g_hash_table_lookup (priv->conns, conn);
1558 g_hash_table_remove (priv->conns, conn);
1559 drop_connection (session, host, conn);
1561 g_mutex_unlock (&priv->conn_lock);
1563 soup_session_kick_queue (session);
1567 connection_state_changed (GObject *object, GParamSpec *param, gpointer user_data)
1569 SoupSession *session = user_data;
1570 SoupConnection *conn = SOUP_CONNECTION (object);
1572 if (soup_connection_get_state (conn) == SOUP_CONNECTION_IDLE)
1573 soup_session_kick_queue (session);
1577 soup_session_get_queue (SoupSession *session)
1579 SoupSessionPrivate *priv = SOUP_SESSION_GET_PRIVATE (session);
1585 soup_session_unqueue_item (SoupSession *session,
1586 SoupMessageQueueItem *item)
1588 SoupSessionPrivate *priv = SOUP_SESSION_GET_PRIVATE (session);
1589 SoupSessionHost *host;
1592 if (item->msg->method != SOUP_METHOD_CONNECT ||
1593 !SOUP_STATUS_IS_SUCCESSFUL (item->msg->status_code))
1594 soup_connection_set_state (item->conn, SOUP_CONNECTION_IDLE);
1595 soup_session_set_item_connection (session, item, NULL);
1598 if (item->state != SOUP_MESSAGE_FINISHED) {
1599 g_warning ("finished an item with state %d", item->state);
1603 soup_message_queue_remove (priv->queue, item);
1605 g_mutex_lock (&priv->conn_lock);
1606 host = get_host_for_message (session, item->msg);
1607 host->num_messages--;
1608 g_cond_broadcast (&priv->conn_cond);
1609 g_mutex_unlock (&priv->conn_lock);
1611 /* g_signal_handlers_disconnect_by_func doesn't work if you
1612 * have a metamarshal, meaning it doesn't work with
1613 * soup_message_add_header_handler()
1615 g_signal_handlers_disconnect_matched (item->msg, G_SIGNAL_MATCH_DATA,
1616 0, 0, NULL, NULL, item);
1617 g_signal_emit (session, signals[REQUEST_UNQUEUED], 0, item->msg);
1618 soup_message_queue_item_unref (item);
1622 soup_session_set_item_status (SoupSession *session,
1623 SoupMessageQueueItem *item,
1627 SoupURI *uri = NULL;
1629 switch (status_code) {
1630 case SOUP_STATUS_CANT_RESOLVE:
1631 case SOUP_STATUS_CANT_CONNECT:
1632 uri = soup_message_get_uri (item->msg);
1635 case SOUP_STATUS_CANT_RESOLVE_PROXY:
1636 case SOUP_STATUS_CANT_CONNECT_PROXY:
1638 uri = soup_connection_get_proxy_uri (item->conn);
1641 case SOUP_STATUS_SSL_FAILED:
1642 if (!g_tls_backend_supports_tls (g_tls_backend_get_default ())) {
1643 soup_message_set_status_full (item->msg, status_code,
1644 "TLS/SSL support not available; install glib-networking");
1654 soup_message_set_status_full (item->msg, status_code, error->message);
1655 else if (uri && uri->host) {
1656 char *msg = g_strdup_printf ("%s (%s)",
1657 soup_status_get_phrase (status_code),
1659 soup_message_set_status_full (item->msg, status_code, msg);
1662 soup_message_set_status (item->msg, status_code);
1667 message_completed (SoupMessage *msg, gpointer user_data)
1669 SoupMessageQueueItem *item = user_data;
1672 soup_session_kick_queue (item->session);
1674 if (item->state != SOUP_MESSAGE_RESTARTING) {
1675 item->state = SOUP_MESSAGE_FINISHING;
1677 if (item->new_api && !item->async)
1678 soup_session_process_queue_item (item->session, item, NULL, TRUE);
1683 status_from_connect_error (SoupMessageQueueItem *item, GError *error)
1688 return SOUP_STATUS_OK;
1690 if (g_error_matches (error, G_TLS_ERROR, G_TLS_ERROR_NOT_TLS)) {
1691 SoupSessionPrivate *priv = SOUP_SESSION_GET_PRIVATE (item->session);
1692 SoupSessionHost *host;
1694 g_mutex_lock (&priv->conn_lock);
1695 host = get_host_for_message (item->session, item->msg);
1696 if (!host->ssl_fallback) {
1697 host->ssl_fallback = TRUE;
1698 status = SOUP_STATUS_TRY_AGAIN;
1700 status = SOUP_STATUS_SSL_FAILED;
1701 g_mutex_unlock (&priv->conn_lock);
1702 } else if (error->domain == G_TLS_ERROR)
1703 status = SOUP_STATUS_SSL_FAILED;
1704 else if (error->domain == G_RESOLVER_ERROR)
1705 status = SOUP_STATUS_CANT_RESOLVE;
1706 else if (error->domain == G_IO_ERROR) {
1707 if (error->code == G_IO_ERROR_CANCELLED)
1708 status = SOUP_STATUS_CANCELLED;
1709 else if (error->code == G_IO_ERROR_HOST_UNREACHABLE ||
1710 error->code == G_IO_ERROR_NETWORK_UNREACHABLE ||
1711 error->code == G_IO_ERROR_CONNECTION_REFUSED)
1712 status = SOUP_STATUS_CANT_CONNECT;
1713 else if (error->code == G_IO_ERROR_PROXY_FAILED ||
1714 error->code == G_IO_ERROR_PROXY_AUTH_FAILED ||
1715 error->code == G_IO_ERROR_PROXY_NEED_AUTH ||
1716 error->code == G_IO_ERROR_PROXY_NOT_ALLOWED)
1717 status = SOUP_STATUS_CANT_CONNECT_PROXY;
1719 status = SOUP_STATUS_IO_ERROR;
1721 status = SOUP_STATUS_IO_ERROR;
1723 if (item->conn && soup_connection_is_via_proxy (item->conn))
1724 return soup_status_proxify (status);
1730 tunnel_complete (SoupMessageQueueItem *tunnel_item,
1731 guint status, GError *error)
1733 SoupMessageQueueItem *item = tunnel_item->related;
1734 SoupSession *session = tunnel_item->session;
1736 soup_message_finished (tunnel_item->msg);
1737 soup_message_queue_item_unref (tunnel_item);
1739 if (item->msg->status_code)
1740 item->state = SOUP_MESSAGE_FINISHING;
1741 soup_message_set_https_status (item->msg, item->conn);
1743 item->error = error;
1745 status = status_from_connect_error (item, error);
1746 if (!SOUP_STATUS_IS_SUCCESSFUL (status)) {
1747 soup_connection_disconnect (item->conn);
1748 soup_session_set_item_connection (session, item, NULL);
1749 if (!item->new_api || item->msg->status_code == 0)
1750 soup_session_set_item_status (session, item, status, error);
1753 item->state = SOUP_MESSAGE_READY;
1755 soup_session_kick_queue (session);
1756 soup_message_queue_item_unref (item);
1760 tunnel_handshake_complete (GObject *object,
1761 GAsyncResult *result,
1764 SoupConnection *conn = SOUP_CONNECTION (object);
1765 SoupMessageQueueItem *tunnel_item = user_data;
1766 GError *error = NULL;
1768 soup_connection_start_ssl_finish (conn, result, &error);
1769 tunnel_complete (tunnel_item, 0, error);
1773 tunnel_message_completed (SoupMessage *msg, gpointer user_data)
1775 SoupMessageQueueItem *tunnel_item = user_data;
1776 SoupMessageQueueItem *item = tunnel_item->related;
1777 SoupSession *session = tunnel_item->session;
1780 if (tunnel_item->state == SOUP_MESSAGE_RESTARTING) {
1781 soup_message_restarted (msg);
1782 if (tunnel_item->conn) {
1783 tunnel_item->state = SOUP_MESSAGE_RUNNING;
1784 soup_session_send_queue_item (session, tunnel_item,
1785 tunnel_message_completed);
1789 soup_message_set_status (msg, SOUP_STATUS_TRY_AGAIN);
1792 tunnel_item->state = SOUP_MESSAGE_FINISHED;
1793 soup_session_unqueue_item (session, tunnel_item);
1795 status = tunnel_item->msg->status_code;
1796 if (!SOUP_STATUS_IS_SUCCESSFUL (status)) {
1797 tunnel_complete (tunnel_item, status, NULL);
1801 if (tunnel_item->async) {
1802 soup_connection_start_ssl_async (item->conn, item->cancellable,
1803 tunnel_handshake_complete,
1806 GError *error = NULL;
1808 soup_connection_start_ssl_sync (item->conn, item->cancellable, &error);
1809 tunnel_complete (tunnel_item, 0, error);
1814 tunnel_connect (SoupMessageQueueItem *item)
1816 SoupSession *session = item->session;
1817 SoupMessageQueueItem *tunnel_item;
1821 item->state = SOUP_MESSAGE_TUNNELING;
1823 uri = soup_connection_get_remote_uri (item->conn);
1824 msg = soup_message_new_from_uri (SOUP_METHOD_CONNECT, uri);
1825 soup_message_set_flags (msg, SOUP_MESSAGE_NO_REDIRECT);
1827 tunnel_item = soup_session_append_queue_item (session, msg,
1830 g_object_unref (msg);
1831 tunnel_item->related = item;
1832 soup_message_queue_item_ref (item);
1833 soup_session_set_item_connection (session, tunnel_item, item->conn);
1834 tunnel_item->state = SOUP_MESSAGE_RUNNING;
1836 g_signal_emit (session, signals[TUNNELING], 0, tunnel_item->conn);
1838 soup_session_send_queue_item (session, tunnel_item,
1839 tunnel_message_completed);
1843 connect_complete (SoupMessageQueueItem *item, SoupConnection *conn, GError *error)
1845 SoupSession *session = item->session;
1848 soup_message_set_https_status (item->msg, item->conn);
1851 item->state = SOUP_MESSAGE_CONNECTED;
1855 item->error = error;
1856 status = status_from_connect_error (item, error);
1857 soup_connection_disconnect (conn);
1858 if (item->state == SOUP_MESSAGE_CONNECTING) {
1859 if (!item->new_api || item->msg->status_code == 0)
1860 soup_session_set_item_status (session, item, status, error);
1861 soup_session_set_item_connection (session, item, NULL);
1862 item->state = SOUP_MESSAGE_READY;
1867 connect_async_complete (GObject *object,
1868 GAsyncResult *result,
1871 SoupConnection *conn = SOUP_CONNECTION (object);
1872 SoupMessageQueueItem *item = user_data;
1873 GError *error = NULL;
1875 soup_connection_connect_finish (conn, result, &error);
1876 connect_complete (item, conn, error);
1878 if (item->state == SOUP_MESSAGE_CONNECTED ||
1879 item->state == SOUP_MESSAGE_READY)
1880 async_run_queue (item->session);
1882 soup_session_kick_queue (item->session);
1884 soup_message_queue_item_unref (item);
1887 /* requires conn_lock */
1888 static SoupConnection *
1889 get_connection_for_host (SoupSession *session,
1890 SoupMessageQueueItem *item,
1891 SoupSessionHost *host,
1892 gboolean need_new_connection,
1893 gboolean *try_cleanup)
1895 SoupSessionPrivate *priv = SOUP_SESSION_GET_PRIVATE (session);
1896 SoupConnection *conn;
1898 int num_pending = 0;
1899 GProxyResolver *proxy_resolver;
1900 GTlsDatabase *tlsdb;
1906 g_return_val_if_fail (soup_connection_get_state (item->conn) != SOUP_CONNECTION_DISCONNECTED, FALSE);
1910 for (conns = host->connections; conns; conns = conns->next) {
1913 if (!need_new_connection && soup_connection_get_state (conn) == SOUP_CONNECTION_IDLE) {
1914 #if ENABLE(TIZEN_TV_CREATE_IDLE_TCP_CONNECTION)
1915 soup_connection_set_current_item (conns->data, item);
1917 soup_connection_set_state (conn, SOUP_CONNECTION_IN_USE);
1919 } else if (soup_connection_get_state (conn) == SOUP_CONNECTION_CONNECTING)
1920 #if ENABLE(TIZEN_TV_CREATE_IDLE_TCP_CONNECTION)
1922 if (!soup_connection_has_current_item (conns->data)) {
1923 soup_connection_set_current_item (conns->data, item);
1924 g_mutex_unlock (&priv->conn_lock);
1925 item->conn = g_object_ref (conns->data);
1930 #if ENABLE(TIZEN_TV_CREATE_IDLE_TCP_CONNECTION)
1936 /* Limit the number of pending connections; num_messages / 2
1937 * is somewhat arbitrary...
1939 #if ENABLE(TIZEN_UNLIMITED_PENDING_CONNECTIONS)
1940 /* FIXME: What should we do here exactly? */
1942 if (num_pending > host->num_messages / 2)
1946 if (host->num_conns >= priv->max_conns_per_host) {
1947 if (need_new_connection)
1948 *try_cleanup = TRUE;
1952 if (priv->num_conns >= priv->max_conns) {
1953 *try_cleanup = TRUE;
1957 proxy_resolver = get_proxy_resolver (session);
1958 tlsdb = get_tls_database (session);
1960 conn = g_object_new (
1961 SOUP_TYPE_CONNECTION,
1962 SOUP_CONNECTION_REMOTE_URI, host->uri,
1963 SOUP_CONNECTION_PROXY_RESOLVER, proxy_resolver,
1964 SOUP_CONNECTION_SSL, soup_uri_is_https (soup_message_get_uri (item->msg), priv->https_aliases),
1965 SOUP_CONNECTION_SSL_CREDENTIALS, tlsdb,
1966 #if ENABLE(TIZEN_TV_CLIENT_CERTIFICATE)
1967 SOUP_CONNECTION_WIDGET_ENGINE, priv->widget_engine,
1969 SOUP_CONNECTION_SSL_STRICT, priv->ssl_strict && (tlsdb != NULL || SOUP_IS_PLAIN_SESSION (session)),
1970 SOUP_CONNECTION_ASYNC_CONTEXT, priv->async_context,
1971 SOUP_CONNECTION_USE_THREAD_CONTEXT, priv->use_thread_context,
1972 SOUP_CONNECTION_TIMEOUT, priv->io_timeout,
1973 SOUP_CONNECTION_IDLE_TIMEOUT, priv->idle_timeout,
1974 SOUP_CONNECTION_SSL_FALLBACK, host->ssl_fallback,
1975 SOUP_CONNECTION_LOCAL_ADDRESS, priv->local_addr,
1977 g_signal_connect (conn, "disconnected",
1978 G_CALLBACK (connection_disconnected),
1980 g_signal_connect (conn, "notify::state",
1981 G_CALLBACK (connection_state_changed),
1984 /* This is a debugging-related signal, and so can ignore the
1985 * usual rule about not emitting signals while holding
1988 g_signal_emit (session, signals[CONNECTION_CREATED], 0, conn);
1990 g_hash_table_insert (priv->conns, conn, host);
1994 host->connections = g_slist_prepend (host->connections, conn);
1996 if (host->keep_alive_src) {
1997 g_source_destroy (host->keep_alive_src);
1998 g_source_unref (host->keep_alive_src);
1999 host->keep_alive_src = NULL;
2002 #if ENABLE(TIZEN_TV_CREATE_IDLE_TCP_CONNECTION)
2003 soup_connection_set_current_item (conn, item);
2009 get_connection (SoupMessageQueueItem *item, gboolean *should_cleanup)
2011 SoupSession *session = item->session;
2012 SoupSessionPrivate *priv = SOUP_SESSION_GET_PRIVATE (session);
2013 SoupSessionHost *host;
2014 SoupConnection *conn = NULL;
2015 gboolean my_should_cleanup = FALSE;
2016 gboolean need_new_connection;
2018 soup_session_cleanup_connections (session, FALSE);
2020 need_new_connection =
2021 (soup_message_get_flags (item->msg) & SOUP_MESSAGE_NEW_CONNECTION) ||
2022 (!(soup_message_get_flags (item->msg) & SOUP_MESSAGE_IDEMPOTENT) &&
2023 !SOUP_METHOD_IS_IDEMPOTENT (item->msg->method));
2025 g_mutex_lock (&priv->conn_lock);
2026 host = get_host_for_message (session, item->msg);
2028 conn = get_connection_for_host (session, item, host,
2029 need_new_connection,
2030 &my_should_cleanup);
2031 if (conn || item->async)
2034 if (my_should_cleanup) {
2035 g_mutex_unlock (&priv->conn_lock);
2036 soup_session_cleanup_connections (session, TRUE);
2037 g_mutex_lock (&priv->conn_lock);
2039 my_should_cleanup = FALSE;
2043 g_cond_wait (&priv->conn_cond, &priv->conn_lock);
2045 g_mutex_unlock (&priv->conn_lock);
2049 *should_cleanup = my_should_cleanup;
2053 soup_session_set_item_connection (session, item, conn);
2055 #if ENABLE(TIZEN_TV_CREATE_IDLE_TCP_CONNECTION)
2056 if (soup_connection_get_state (item->conn) == SOUP_CONNECTION_CONNECTING) {
2057 item->state = SOUP_MESSAGE_CONNECTING;
2058 soup_message_queue_item_ref (item);
2063 if (soup_connection_get_state (item->conn) != SOUP_CONNECTION_NEW) {
2064 item->state = SOUP_MESSAGE_READY;
2065 soup_message_set_https_status (item->msg, item->conn);
2069 item->state = SOUP_MESSAGE_CONNECTING;
2072 soup_message_queue_item_ref (item);
2073 soup_connection_connect_async (item->conn, item->cancellable,
2074 connect_async_complete, item);
2077 GError *error = NULL;
2079 soup_connection_connect_sync (item->conn, item->cancellable, &error);
2080 connect_complete (item, conn, error);
2087 soup_session_process_queue_item (SoupSession *session,
2088 SoupMessageQueueItem *item,
2089 gboolean *should_cleanup,
2092 g_assert (item->session == session);
2098 switch (item->state) {
2099 case SOUP_MESSAGE_STARTING:
2100 #if ENABLE(TIZEN_CERTIFICATE_FILE_SET)
2101 if(soup_uri_get_scheme(soup_message_get_uri(item->msg)) == SOUP_URI_SCHEME_HTTPS){
2102 if (!soup_session_is_tls_db_initialized (session) && !soup_message_is_from_session_restore (item->msg)) {
2103 soup_session_tls_stop_idle_timer(session);
2104 soup_session_set_certificate_file(session);
2108 if (!get_connection (item, should_cleanup))
2112 case SOUP_MESSAGE_CONNECTED:
2113 if (soup_connection_is_tunnelled (item->conn))
2114 tunnel_connect (item);
2116 item->state = SOUP_MESSAGE_READY;
2119 case SOUP_MESSAGE_READY:
2120 if (item->msg->status_code) {
2121 if (item->msg->status_code == SOUP_STATUS_TRY_AGAIN) {
2122 soup_message_cleanup_response (item->msg);
2123 item->state = SOUP_MESSAGE_STARTING;
2125 item->state = SOUP_MESSAGE_FINISHING;
2129 item->state = SOUP_MESSAGE_RUNNING;
2131 soup_session_send_queue_item (session, item, message_completed);
2133 if (item->new_api) {
2135 async_send_request_running (session, item);
2140 case SOUP_MESSAGE_RUNNING:
2144 g_warn_if_fail (item->new_api);
2145 item->state = SOUP_MESSAGE_FINISHING;
2148 case SOUP_MESSAGE_CACHED:
2149 /* Will be handled elsewhere */
2152 case SOUP_MESSAGE_RESTARTING:
2153 item->state = SOUP_MESSAGE_STARTING;
2154 soup_message_restarted (item->msg);
2157 case SOUP_MESSAGE_FINISHING:
2158 item->state = SOUP_MESSAGE_FINISHED;
2159 soup_message_finished (item->msg);
2160 if (item->state != SOUP_MESSAGE_FINISHED) {
2161 g_return_if_fail (!item->new_api);
2165 soup_message_queue_item_ref (item);
2166 soup_session_unqueue_item (session, item);
2167 if (item->async && item->callback)
2168 item->callback (session, item->msg, item->callback_data);
2169 soup_message_queue_item_unref (item);
2173 /* Nothing to do with this message in any
2176 g_warn_if_fail (item->async);
2179 } while (loop && item->state != SOUP_MESSAGE_FINISHED);
2183 async_run_queue (SoupSession *session)
2185 SoupSessionPrivate *priv = SOUP_SESSION_GET_PRIVATE (session);
2186 SoupMessageQueueItem *item;
2188 gboolean try_cleanup = TRUE, should_cleanup = FALSE;
2190 g_object_ref (session);
2191 soup_session_cleanup_connections (session, FALSE);
2194 for (item = soup_message_queue_first (priv->queue);
2196 item = soup_message_queue_next (priv->queue, item)) {
2199 /* CONNECT messages are handled specially */
2200 if (msg->method == SOUP_METHOD_CONNECT)
2203 if (item->async_context != soup_session_get_async_context (session))
2206 soup_session_process_queue_item (session, item, &should_cleanup, TRUE);
2209 if (try_cleanup && should_cleanup) {
2210 /* There is at least one message in the queue that
2211 * could be sent if we cleanupd an idle connection from
2212 * some other server.
2214 if (soup_session_cleanup_connections (session, TRUE)) {
2215 try_cleanup = should_cleanup = FALSE;
2220 g_object_unref (session);
2224 idle_run_queue (gpointer user_data)
2226 SoupSessionPrivate *priv = user_data;
2232 source = g_main_current_source ();
2233 priv->run_queue_sources = g_slist_remove (priv->run_queue_sources, source);
2235 /* Ensure that the source is destroyed before running the queue */
2236 g_source_destroy (source);
2237 g_source_unref (source);
2239 g_assert (priv->session);
2240 async_run_queue (priv->session);
2245 * SoupSessionCallback:
2246 * @session: the session
2247 * @msg: the message that has finished
2248 * @user_data: the data passed to soup_session_queue_message
2250 * Prototype for the callback passed to soup_session_queue_message(),
2255 soup_session_real_queue_message (SoupSession *session, SoupMessage *msg,
2256 SoupSessionCallback callback, gpointer user_data)
2258 SoupMessageQueueItem *item;
2260 item = soup_session_append_queue_item (session, msg, TRUE, FALSE,
2261 callback, user_data);
2262 soup_session_kick_queue (session);
2263 soup_message_queue_item_unref (item);
2267 * soup_session_queue_message:
2268 * @session: a #SoupSession
2269 * @msg: (transfer full): the message to queue
2270 * @callback: (allow-none) (scope async): a #SoupSessionCallback which will
2271 * be called after the message completes or when an unrecoverable error occurs.
2272 * @user_data: (allow-none): a pointer passed to @callback.
2274 * Queues the message @msg for asynchronously sending the request and
2275 * receiving a response in the current thread-default #GMainContext.
2276 * If @msg has been processed before, any resources related to the
2277 * time it was last sent are freed.
2279 * Upon message completion, the callback specified in @callback will
2280 * be invoked. If after returning from this callback the message has not
2281 * been requeued, @msg will be unreffed.
2283 * (The behavior above applies to a plain #SoupSession; if you are
2284 * using #SoupSessionAsync or #SoupSessionSync, then the #GMainContext
2285 * that is used depends on the settings of #SoupSession:async-context
2286 * and #SoupSession:use-thread-context, and for #SoupSessionSync, the
2287 * message will actually be sent and processed in another thread, with
2288 * only the final callback occurring in the indicated #GMainContext.)
2290 * Contrast this method with soup_session_send_async(), which also
2291 * asynchronously sends a message, but returns before reading the
2292 * response body, and allows you to read the response via a
2296 soup_session_queue_message (SoupSession *session, SoupMessage *msg,
2297 SoupSessionCallback callback, gpointer user_data)
2299 g_return_if_fail (SOUP_IS_SESSION (session));
2300 g_return_if_fail (SOUP_IS_MESSAGE (msg));
2302 SOUP_SESSION_GET_CLASS (session)->queue_message (session, msg,
2303 callback, user_data);
2304 /* The SoupMessageQueueItem will hold a ref on @msg until it is
2305 * finished, so we can drop the ref adopted from the caller now.
2307 g_object_unref (msg);
2311 soup_session_real_requeue_message (SoupSession *session, SoupMessage *msg)
2313 SoupSessionPrivate *priv = SOUP_SESSION_GET_PRIVATE (session);
2314 SoupMessageQueueItem *item;
2316 item = soup_message_queue_lookup (priv->queue, msg);
2317 g_return_if_fail (item != NULL);
2319 if (item->resend_count >= SOUP_SESSION_MAX_RESEND_COUNT) {
2320 if (SOUP_STATUS_IS_REDIRECTION (msg->status_code))
2321 soup_message_set_status (msg, SOUP_STATUS_TOO_MANY_REDIRECTS);
2323 g_warning ("SoupMessage %p stuck in infinite loop?", msg);
2325 item->resend_count++;
2326 item->state = SOUP_MESSAGE_RESTARTING;
2329 soup_message_queue_item_unref (item);
2333 * soup_session_requeue_message:
2334 * @session: a #SoupSession
2335 * @msg: the message to requeue
2337 * This causes @msg to be placed back on the queue to be attempted
2341 soup_session_requeue_message (SoupSession *session, SoupMessage *msg)
2343 g_return_if_fail (SOUP_IS_SESSION (session));
2344 g_return_if_fail (SOUP_IS_MESSAGE (msg));
2346 SOUP_SESSION_GET_CLASS (session)->requeue_message (session, msg);
2350 soup_session_real_send_message (SoupSession *session, SoupMessage *msg)
2352 SoupMessageQueueItem *item;
2355 item = soup_session_append_queue_item (session, msg, FALSE, FALSE,
2357 soup_session_process_queue_item (session, item, NULL, TRUE);
2358 status = msg->status_code;
2359 soup_message_queue_item_unref (item);
2364 * soup_session_send_message:
2365 * @session: a #SoupSession
2366 * @msg: the message to send
2368 * Synchronously send @msg. This call will not return until the
2369 * transfer is finished successfully or there is an unrecoverable
2372 * Unlike with soup_session_queue_message(), @msg is not freed upon
2375 * (Note that if you call this method on a #SoupSessionAsync, it will
2376 * still use asynchronous I/O internally, running the glib main loop
2377 * to process the message, which may also cause other events to be
2380 * Contrast this method with soup_session_send(), which also
2381 * synchronously sends a message, but returns before reading the
2382 * response body, and allows you to read the response via a
2385 * Return value: the HTTP status code of the response
2388 soup_session_send_message (SoupSession *session, SoupMessage *msg)
2390 g_return_val_if_fail (SOUP_IS_SESSION (session), SOUP_STATUS_MALFORMED);
2391 g_return_val_if_fail (SOUP_IS_MESSAGE (msg), SOUP_STATUS_MALFORMED);
2393 return SOUP_SESSION_GET_CLASS (session)->send_message (session, msg);
2398 * soup_session_pause_message:
2399 * @session: a #SoupSession
2400 * @msg: a #SoupMessage currently running on @session
2402 * Pauses HTTP I/O on @msg. Call soup_session_unpause_message() to
2405 * This may only be called for asynchronous messages (those sent on a
2406 * #SoupSessionAsync or using soup_session_queue_message()).
2409 soup_session_pause_message (SoupSession *session,
2412 SoupSessionPrivate *priv;
2413 SoupMessageQueueItem *item;
2415 g_return_if_fail (SOUP_IS_SESSION (session));
2416 g_return_if_fail (SOUP_IS_MESSAGE (msg));
2418 priv = SOUP_SESSION_GET_PRIVATE (session);
2419 item = soup_message_queue_lookup (priv->queue, msg);
2420 g_return_if_fail (item != NULL);
2421 g_return_if_fail (item->async);
2423 item->paused = TRUE;
2424 if (item->state == SOUP_MESSAGE_RUNNING)
2425 soup_message_io_pause (msg);
2426 soup_message_queue_item_unref (item);
2430 soup_session_real_kick_queue (SoupSession *session)
2432 SoupSessionPrivate *priv = SOUP_SESSION_GET_PRIVATE (session);
2433 SoupMessageQueueItem *item;
2434 gboolean have_sync_items = FALSE;
2439 for (item = soup_message_queue_first (priv->queue);
2441 item = soup_message_queue_next (priv->queue, item)) {
2445 /* We use priv rather than session as the
2446 * source data, because other parts of libsoup
2447 * (or the calling app) may have sources using
2448 * the session as the source data.
2450 source = g_main_context_find_source_by_user_data (item->async_context, priv);
2452 source = soup_add_completion_reffed (item->async_context,
2453 idle_run_queue, priv);
2454 priv->run_queue_sources = g_slist_prepend (priv->run_queue_sources,
2458 have_sync_items = TRUE;
2461 if (have_sync_items) {
2462 g_mutex_lock (&priv->conn_lock);
2463 g_cond_broadcast (&priv->conn_cond);
2464 g_mutex_unlock (&priv->conn_lock);
2469 soup_session_kick_queue (SoupSession *session)
2471 SOUP_SESSION_GET_CLASS (session)->kick (session);
2475 * soup_session_unpause_message:
2476 * @session: a #SoupSession
2477 * @msg: a #SoupMessage currently running on @session
2479 * Resumes HTTP I/O on @msg. Use this to resume after calling
2480 * soup_session_pause_message().
2482 * If @msg is being sent via blocking I/O, this will resume reading or
2483 * writing immediately. If @msg is using non-blocking I/O, then
2484 * reading or writing won't resume until you return to the main loop.
2486 * This may only be called for asynchronous messages (those sent on a
2487 * #SoupSessionAsync or using soup_session_queue_message()).
2490 soup_session_unpause_message (SoupSession *session,
2493 SoupSessionPrivate *priv;
2494 SoupMessageQueueItem *item;
2496 g_return_if_fail (SOUP_IS_SESSION (session));
2497 g_return_if_fail (SOUP_IS_MESSAGE (msg));
2499 priv = SOUP_SESSION_GET_PRIVATE (session);
2500 item = soup_message_queue_lookup (priv->queue, msg);
2501 g_return_if_fail (item != NULL);
2502 g_return_if_fail (item->async);
2504 item->paused = FALSE;
2505 if (item->state == SOUP_MESSAGE_RUNNING)
2506 soup_message_io_unpause (msg);
2507 soup_message_queue_item_unref (item);
2509 soup_session_kick_queue (session);
2514 soup_session_real_cancel_message (SoupSession *session, SoupMessage *msg, guint status_code)
2516 SoupSessionPrivate *priv = SOUP_SESSION_GET_PRIVATE (session);
2517 SoupMessageQueueItem *item;
2519 item = soup_message_queue_lookup (priv->queue, msg);
2520 g_return_if_fail (item != NULL);
2522 item->paused = FALSE;
2523 soup_message_set_status (msg, status_code);
2524 g_cancellable_cancel (item->cancellable);
2526 soup_session_kick_queue (item->session);
2527 soup_message_queue_item_unref (item);
2531 * soup_session_cancel_message:
2532 * @session: a #SoupSession
2533 * @msg: the message to cancel
2534 * @status_code: status code to set on @msg (generally
2535 * %SOUP_STATUS_CANCELLED)
2537 * Causes @session to immediately finish processing @msg (regardless
2538 * of its current state) with a final status_code of @status_code. You
2539 * may call this at any time after handing @msg off to @session; if
2540 * @session has started sending the request but has not yet received
2541 * the complete response, then it will close the request's connection.
2542 * Note that with requests that have side effects (eg,
2543 * <literal>POST</literal>, <literal>PUT</literal>,
2544 * <literal>DELETE</literal>) it is possible that you might cancel the
2545 * request after the server acts on it, but before it returns a
2546 * response, leaving the remote resource in an unknown state.
2548 * If the message is cancelled while its response body is being read,
2549 * then the response body in @msg will be left partially-filled-in.
2550 * The response headers, on the other hand, will always be either
2551 * empty or complete.
2553 * Beware that with the deprecated #SoupSessionAsync, messages queued
2554 * with soup_session_queue_message() will have their callbacks invoked
2555 * before soup_session_cancel_message() returns. The plain
2556 * #SoupSession does not have this behavior; cancelling an
2557 * asynchronous message will merely queue its callback to be run after
2558 * returning to the main loop.
2561 soup_session_cancel_message (SoupSession *session, SoupMessage *msg,
2564 SoupSessionPrivate *priv;
2565 SoupMessageQueueItem *item;
2567 g_return_if_fail (SOUP_IS_SESSION (session));
2568 g_return_if_fail (SOUP_IS_MESSAGE (msg));
2570 priv = SOUP_SESSION_GET_PRIVATE (session);
2571 item = soup_message_queue_lookup (priv->queue, msg);
2572 /* If the message is already ending, don't do anything */
2575 if (item->state == SOUP_MESSAGE_FINISHED) {
2576 soup_message_queue_item_unref (item);
2580 SOUP_SESSION_GET_CLASS (session)->cancel_message (session, msg, status_code);
2581 soup_message_queue_item_unref (item);
2585 soup_session_real_flush_queue (SoupSession *session)
2587 SoupSessionPrivate *priv = SOUP_SESSION_GET_PRIVATE (session);
2588 SoupMessageQueueItem *item;
2589 GHashTable *current = NULL;
2590 gboolean done = FALSE;
2592 if (SOUP_IS_SESSION_SYNC (session)) {
2593 /* Record the current contents of the queue */
2594 current = g_hash_table_new (NULL, NULL);
2595 for (item = soup_message_queue_first (priv->queue);
2597 item = soup_message_queue_next (priv->queue, item))
2598 g_hash_table_insert (current, item, item);
2601 /* Cancel everything */
2602 for (item = soup_message_queue_first (priv->queue);
2604 item = soup_message_queue_next (priv->queue, item)) {
2605 soup_session_cancel_message (session, item->msg,
2606 SOUP_STATUS_CANCELLED);
2609 if (SOUP_IS_SESSION_SYNC (session)) {
2610 /* Wait until all of the items in @current have been
2611 * removed from the queue. (This is not the same as
2612 * "wait for the queue to be empty", because the app
2613 * may queue new requests in response to the
2614 * cancellation of the old ones. We don't try to
2615 * cancel those requests as well, since we'd likely
2616 * just end up looping forever.)
2618 g_mutex_lock (&priv->conn_lock);
2621 for (item = soup_message_queue_first (priv->queue);
2623 item = soup_message_queue_next (priv->queue, item)) {
2624 if (g_hash_table_lookup (current, item))
2629 g_cond_wait (&priv->conn_cond, &priv->conn_lock);
2631 g_mutex_unlock (&priv->conn_lock);
2633 g_hash_table_destroy (current);
2638 * soup_session_abort:
2639 * @session: the session
2641 * Cancels all pending requests in @session and closes all idle
2642 * persistent connections.
2644 * The message cancellation has the same semantics as with
2645 * soup_session_cancel_message(); asynchronous requests on a
2646 * #SoupSessionAsync will have their callback called before
2647 * soup_session_abort() returns. Requests on a plain #SoupSession will
2651 soup_session_abort (SoupSession *session)
2653 SoupSessionPrivate *priv;
2655 GHashTableIter iter;
2656 gpointer conn, host;
2658 g_return_if_fail (SOUP_IS_SESSION (session));
2659 priv = SOUP_SESSION_GET_PRIVATE (session);
2661 SOUP_SESSION_GET_CLASS (session)->flush_queue (session);
2663 /* Close all connections */
2664 g_mutex_lock (&priv->conn_lock);
2666 g_hash_table_iter_init (&iter, priv->conns);
2667 while (g_hash_table_iter_next (&iter, &conn, &host)) {
2668 conns = g_slist_prepend (conns, g_object_ref (conn));
2669 g_hash_table_iter_remove (&iter);
2670 drop_connection (session, host, conn);
2672 g_mutex_unlock (&priv->conn_lock);
2674 for (c = conns; c; c = c->next) {
2675 soup_connection_disconnect (c->data);
2676 g_object_unref (c->data);
2679 g_slist_free (conns);
2683 prefetch_uri (SoupSession *session, SoupURI *uri,
2684 GCancellable *cancellable,
2685 SoupAddressCallback callback, gpointer user_data)
2687 SoupSessionPrivate *priv;
2688 SoupSessionHost *host;
2691 priv = SOUP_SESSION_GET_PRIVATE (session);
2693 g_mutex_lock (&priv->conn_lock);
2694 host = get_host_for_uri (session, uri);
2695 addr = g_object_ref (host->addr);
2696 g_mutex_unlock (&priv->conn_lock);
2698 soup_address_resolve_async (addr,
2699 soup_session_get_async_context (session),
2700 cancellable, callback, user_data);
2701 g_object_unref (addr);
2705 * soup_session_prepare_for_uri:
2706 * @session: a #SoupSession
2707 * @uri: a #SoupURI which may be required
2709 * Tells @session that @uri may be requested shortly, and so the
2710 * session can try to prepare (resolving the domain name, obtaining
2711 * proxy address, etc.) in order to work more quickly once the URI is
2712 * actually requested.
2716 * Deprecated: 2.38: use soup_session_prefetch_dns() instead
2719 soup_session_prepare_for_uri (SoupSession *session, SoupURI *uri)
2721 g_return_if_fail (SOUP_IS_SESSION (session));
2722 g_return_if_fail (uri != NULL);
2727 prefetch_uri (session, uri, NULL, NULL, NULL);
2731 * soup_session_prefetch_dns:
2732 * @session: a #SoupSession
2733 * @hostname: a hostname to be resolved
2734 * @cancellable: (allow-none): a #GCancellable object, or %NULL
2735 * @callback: (scope async) (allow-none): callback to call with the
2737 * @user_data: data for @callback
2739 * Tells @session that an URI from the given @hostname may be requested
2740 * shortly, and so the session can try to prepare by resolving the
2741 * domain name in advance, in order to work more quickly once the URI
2742 * is actually requested.
2744 * If @cancellable is non-%NULL, it can be used to cancel the
2745 * resolution. @callback will still be invoked in this case, with a
2746 * status of %SOUP_STATUS_CANCELLED.
2751 soup_session_prefetch_dns (SoupSession *session, const char *hostname,
2752 GCancellable *cancellable,
2753 SoupAddressCallback callback, gpointer user_data)
2757 g_return_if_fail (SOUP_IS_SESSION (session));
2758 g_return_if_fail (hostname != NULL);
2760 /* FIXME: Prefetching should work for both HTTP and HTTPS */
2761 uri = soup_uri_new (NULL);
2762 soup_uri_set_scheme (uri, SOUP_URI_SCHEME_HTTP);
2763 soup_uri_set_host (uri, hostname);
2764 soup_uri_set_path (uri, "");
2766 prefetch_uri (session, uri, cancellable, callback, user_data);
2767 soup_uri_free (uri);
2771 * soup_session_add_feature:
2772 * @session: a #SoupSession
2773 * @feature: an object that implements #SoupSessionFeature
2775 * Adds @feature's functionality to @session. You can also add a
2776 * feature to the session at construct time by using the
2777 * %SOUP_SESSION_ADD_FEATURE property.
2779 * Note that a #SoupContentDecoder is added to the session by default
2780 * (unless you are using one of the deprecated session subclasses).
2785 soup_session_add_feature (SoupSession *session, SoupSessionFeature *feature)
2787 SoupSessionPrivate *priv;
2789 g_return_if_fail (SOUP_IS_SESSION (session));
2790 g_return_if_fail (SOUP_IS_SESSION_FEATURE (feature));
2792 priv = SOUP_SESSION_GET_PRIVATE (session);
2794 G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
2795 if (SOUP_IS_PROXY_URI_RESOLVER (feature)) {
2796 set_proxy_resolver (session, NULL,
2797 SOUP_PROXY_URI_RESOLVER (feature),
2800 G_GNUC_END_IGNORE_DEPRECATIONS;
2802 priv->features = g_slist_prepend (priv->features, g_object_ref (feature));
2803 g_hash_table_remove_all (priv->features_cache);
2804 soup_session_feature_attach (feature, session);
2808 * soup_session_add_feature_by_type:
2809 * @session: a #SoupSession
2810 * @feature_type: a #GType
2812 * If @feature_type is the type of a class that implements
2813 * #SoupSessionFeature, this creates a new feature of that type and
2814 * adds it to @session as with soup_session_add_feature(). You can use
2815 * this when you don't need to customize the new feature in any way.
2817 * If @feature_type is not a #SoupSessionFeature type, this gives each
2818 * existing feature on @session the chance to accept @feature_type as
2819 * a "subfeature". This can be used to add new #SoupAuth or
2820 * #SoupRequest types, for instance.
2822 * You can also add a feature to the session at construct time by
2823 * using the %SOUP_SESSION_ADD_FEATURE_BY_TYPE property.
2825 * Note that a #SoupContentDecoder is added to the session by default
2826 * (unless you are using one of the deprecated session subclasses).
2831 soup_session_add_feature_by_type (SoupSession *session, GType feature_type)
2833 SoupSessionPrivate *priv;
2835 g_return_if_fail (SOUP_IS_SESSION (session));
2837 priv = SOUP_SESSION_GET_PRIVATE (session);
2839 if (g_type_is_a (feature_type, SOUP_TYPE_SESSION_FEATURE)) {
2840 SoupSessionFeature *feature;
2842 feature = g_object_new (feature_type, NULL);
2843 soup_session_add_feature (session, feature);
2844 g_object_unref (feature);
2845 } else if (g_type_is_a (feature_type, SOUP_TYPE_REQUEST)) {
2846 SoupRequestClass *request_class;
2849 request_class = g_type_class_ref (feature_type);
2850 for (i = 0; request_class->schemes[i]; i++) {
2851 g_hash_table_insert (priv->request_types,
2852 (char *)request_class->schemes[i],
2853 GSIZE_TO_POINTER (feature_type));
2858 for (f = priv->features; f; f = f->next) {
2859 if (soup_session_feature_add_feature (f->data, feature_type))
2862 g_warning ("No feature manager for feature of type '%s'", g_type_name (feature_type));
2867 * soup_session_remove_feature:
2868 * @session: a #SoupSession
2869 * @feature: a feature that has previously been added to @session
2871 * Removes @feature's functionality from @session.
2876 soup_session_remove_feature (SoupSession *session, SoupSessionFeature *feature)
2878 SoupSessionPrivate *priv;
2880 g_return_if_fail (SOUP_IS_SESSION (session));
2882 priv = SOUP_SESSION_GET_PRIVATE (session);
2883 if (g_slist_find (priv->features, feature)) {
2884 priv->features = g_slist_remove (priv->features, feature);
2885 g_hash_table_remove_all (priv->features_cache);
2886 soup_session_feature_detach (feature, session);
2888 G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
2889 if (SOUP_IS_PROXY_URI_RESOLVER (feature)) {
2890 if (SOUP_IS_PROXY_RESOLVER_WRAPPER (priv->proxy_resolver) &&
2891 SOUP_PROXY_RESOLVER_WRAPPER (priv->proxy_resolver)->soup_resolver == SOUP_PROXY_URI_RESOLVER (feature))
2892 g_clear_object (&priv->proxy_resolver);
2894 G_GNUC_END_IGNORE_DEPRECATIONS;
2896 g_object_unref (feature);
2901 * soup_session_remove_feature_by_type:
2902 * @session: a #SoupSession
2903 * @feature_type: a #GType
2905 * Removes all features of type @feature_type (or any subclass of
2906 * @feature_type) from @session. You can also remove standard features
2907 * from the session at construct time by using the
2908 * %SOUP_SESSION_REMOVE_FEATURE_BY_TYPE property.
2913 soup_session_remove_feature_by_type (SoupSession *session, GType feature_type)
2915 SoupSessionPrivate *priv;
2918 g_return_if_fail (SOUP_IS_SESSION (session));
2920 priv = SOUP_SESSION_GET_PRIVATE (session);
2922 if (g_type_is_a (feature_type, SOUP_TYPE_SESSION_FEATURE)) {
2924 for (f = priv->features; f; f = f->next) {
2925 if (G_TYPE_CHECK_INSTANCE_TYPE (f->data, feature_type)) {
2926 soup_session_remove_feature (session, f->data);
2930 G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
2931 if (g_type_is_a (feature_type, SOUP_TYPE_PROXY_URI_RESOLVER))
2932 priv->proxy_use_default = FALSE;
2933 G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
2934 } else if (g_type_is_a (feature_type, SOUP_TYPE_REQUEST)) {
2935 SoupRequestClass *request_class;
2938 request_class = g_type_class_peek (feature_type);
2941 for (i = 0; request_class->schemes[i]; i++) {
2942 g_hash_table_remove (priv->request_types,
2943 request_class->schemes[i]);
2946 for (f = priv->features; f; f = f->next) {
2947 if (soup_session_feature_remove_feature (f->data, feature_type))
2950 g_warning ("No feature manager for feature of type '%s'", g_type_name (feature_type));
2955 * soup_session_has_feature:
2956 * @session: a #SoupSession
2957 * @feature_type: the #GType of the class of features to check for
2959 * Tests if @session has at a feature of type @feature_type (which can
2960 * be the type of either a #SoupSessionFeature, or else a subtype of
2961 * some class managed by another feature, such as #SoupAuth or
2964 * Return value: %TRUE or %FALSE
2969 soup_session_has_feature (SoupSession *session,
2972 SoupSessionPrivate *priv;
2975 g_return_val_if_fail (SOUP_IS_SESSION (session), FALSE);
2977 priv = SOUP_SESSION_GET_PRIVATE (session);
2979 if (g_type_is_a (feature_type, SOUP_TYPE_SESSION_FEATURE)) {
2980 for (f = priv->features; f; f = f->next) {
2981 if (G_TYPE_CHECK_INSTANCE_TYPE (f->data, feature_type))
2984 } else if (g_type_is_a (feature_type, SOUP_TYPE_REQUEST)) {
2985 return g_hash_table_lookup (priv->request_types,
2986 GSIZE_TO_POINTER (feature_type)) != NULL;
2988 for (f = priv->features; f; f = f->next) {
2989 if (soup_session_feature_has_feature (f->data, feature_type))
2998 * soup_session_get_features:
2999 * @session: a #SoupSession
3000 * @feature_type: the #GType of the class of features to get
3002 * Generates a list of @session's features of type @feature_type. (If
3003 * you want to see all features, you can pass %SOUP_TYPE_SESSION_FEATURE
3004 * for @feature_type.)
3006 * Return value: (transfer container) (element-type Soup.SessionFeature):
3007 * a list of features. You must free the list, but not its contents
3012 soup_session_get_features (SoupSession *session, GType feature_type)
3014 SoupSessionPrivate *priv;
3017 g_return_val_if_fail (SOUP_IS_SESSION (session), NULL);
3019 priv = SOUP_SESSION_GET_PRIVATE (session);
3020 for (f = priv->features, ret = NULL; f; f = f->next) {
3021 if (G_TYPE_CHECK_INSTANCE_TYPE (f->data, feature_type))
3022 ret = g_slist_prepend (ret, f->data);
3024 return g_slist_reverse (ret);
3028 * soup_session_get_feature:
3029 * @session: a #SoupSession
3030 * @feature_type: the #GType of the feature to get
3032 * Gets the first feature in @session of type @feature_type. For
3033 * features where there may be more than one feature of a given type,
3034 * use soup_session_get_features().
3036 * Return value: (transfer none): a #SoupSessionFeature, or %NULL. The
3037 * feature is owned by @session.
3041 SoupSessionFeature *
3042 soup_session_get_feature (SoupSession *session, GType feature_type)
3044 SoupSessionPrivate *priv;
3045 SoupSessionFeature *feature;
3048 g_return_val_if_fail (SOUP_IS_SESSION (session), NULL);
3050 priv = SOUP_SESSION_GET_PRIVATE (session);
3052 feature = g_hash_table_lookup (priv->features_cache,
3053 GSIZE_TO_POINTER (feature_type));
3057 for (f = priv->features; f; f = f->next) {
3059 if (G_TYPE_CHECK_INSTANCE_TYPE (feature, feature_type)) {
3060 g_hash_table_insert (priv->features_cache,
3061 GSIZE_TO_POINTER (feature_type),
3070 * soup_session_get_feature_for_message:
3071 * @session: a #SoupSession
3072 * @feature_type: the #GType of the feature to get
3073 * @msg: a #SoupMessage
3075 * Gets the first feature in @session of type @feature_type, provided
3076 * that it is not disabled for @msg. As with
3077 * soup_session_get_feature(), this should only be used for features
3078 * where @feature_type is only expected to match a single feature. In
3079 * particular, if there are two matching features, and the first is
3080 * disabled on @msg, and the second is not, then this will return
3081 * %NULL, not the second feature.
3083 * Return value: (transfer none): a #SoupSessionFeature, or %NULL. The
3084 * feature is owned by @session.
3088 SoupSessionFeature *
3089 soup_session_get_feature_for_message (SoupSession *session, GType feature_type,
3092 SoupSessionFeature *feature;
3094 feature = soup_session_get_feature (session, feature_type);
3095 if (feature && soup_message_disables_feature (msg, feature))
3100 #if ENABLE(TIZEN_CERTIFICATE_FILE_SET)
3102 #if ENABLE(TIZEN_TV_FORCE_PRELOAD_TLSDB)
3104 * TLS database preloader thread.
3107 _preload_tlsdb_thread (gpointer p)
3109 GError* error = NULL;
3111 g_mutex_lock (&_gTlsDB_lock);
3112 TIZEN_LOGI("Create new tls database by using thread.");
3113 g_assert (_gTlsDB_path);
3114 _gTlsDB = g_tls_file_database_new (_gTlsDB_path, &error);
3115 g_mutex_unlock (&_gTlsDB_lock);
3121 * Launch the TLS database preloader thread for a specified path.
3122 * This is a one-time function.
3125 soup_preload_tls_database (const gchar *path)
3127 g_mutex_lock (&_gTlsDB_lock);
3128 //_gTlsDB_path is set only once. It prevent to create thread repeatedly.
3129 //So keep the value of _gTlsDB_path.
3130 if (!_gTlsDB_path) {
3131 _gTlsDB_path = g_strdup (path);
3133 g_thread_new ("TLS Preloader", _preload_tlsdb_thread, NULL);
3135 g_mutex_unlock (&_gTlsDB_lock);
3139 void soup_session_set_certificate_file(SoupSession *session)
3141 SoupSessionPrivate *priv = SOUP_SESSION_GET_PRIVATE (session);
3145 if (!priv->certificate_path) {
3146 TIZEN_LOGI("priv->certificate_path is NULL, return!!");
3152 GError* error = NULL;
3153 GTlsDatabase* tlsdb = NULL;
3155 #if ENABLE(TIZEN_TV_FORCE_PRELOAD_TLSDB)
3156 TIZEN_LOGI("Begin to handle TLS database.");
3157 g_mutex_lock (&_gTlsDB_lock);
3158 //Check whether certificate_path is the same as the path used by pre-load TLS DB.
3159 if ((_gTlsDB) && (!g_strcmp0(_gTlsDB_path, priv->certificate_path))) {
3160 TIZEN_LOGI("Use tls database which is created by thread.");
3161 tlsdb = g_object_ref(_gTlsDB); // Take a reference to the global DB.
3164 tlsdb = g_tls_file_database_new (priv->certificate_path, &error);
3166 g_mutex_unlock (&_gTlsDB_lock);
3168 TIZEN_LOGI ("g_tls_file_database_new() is called. START");
3169 tlsdb = g_tls_file_database_new(priv->certificate_path, &error);
3170 TIZEN_LOGI ("g_tls_file_database_new() is called. END");
3171 TIZEN_LOGI ("g_tls_file_database_new() is called. [%s]", priv->certificate_path);
3174 if (!error && tlsdb) {
3175 #if ENABLE(TIZEN_DLOG)
3176 TIZEN_LOGI ("g_tls_file_database_new() is success. no error call set_tlsdb().");
3178 set_tlsdb (session, tlsdb);
3182 g_object_unref (tlsdb);
3183 if (priv->certificate_path) {
3184 g_free (priv->certificate_path);
3185 priv->certificate_path = NULL;
3192 soup_session_class_init (SoupSessionClass *session_class)
3194 GObjectClass *object_class = G_OBJECT_CLASS (session_class);
3196 g_type_class_add_private (session_class, sizeof (SoupSessionPrivate));
3198 /* virtual method definition */
3199 session_class->queue_message = soup_session_real_queue_message;
3200 session_class->send_message = soup_session_real_send_message;
3201 session_class->requeue_message = soup_session_real_requeue_message;
3202 session_class->cancel_message = soup_session_real_cancel_message;
3203 session_class->flush_queue = soup_session_real_flush_queue;
3204 session_class->kick = soup_session_real_kick_queue;
3206 /* virtual method override */
3207 object_class->constructor = soup_session_constructor;
3208 object_class->dispose = soup_session_dispose;
3209 object_class->finalize = soup_session_finalize;
3210 object_class->set_property = soup_session_set_property;
3211 object_class->get_property = soup_session_get_property;
3216 * SoupSession::request-queued:
3217 * @session: the session
3218 * @msg: the request that was queued
3220 * Emitted when a request is queued on @session. (Note that
3221 * "queued" doesn't just mean soup_session_queue_message();
3222 * soup_session_send_message() implicitly queues the message
3225 * When sending a request, first #SoupSession::request_queued
3226 * is emitted, indicating that the session has become aware of
3229 * Once a connection is available to send the request on, the
3230 * session emits #SoupSession::request_started. Then, various
3231 * #SoupMessage signals are emitted as the message is
3232 * processed. If the message is requeued, it will emit
3233 * #SoupMessage::restarted, which will then be followed by
3234 * another #SoupSession::request_started and another set of
3235 * #SoupMessage signals when the message is re-sent.
3237 * Eventually, the message will emit #SoupMessage::finished.
3238 * Normally, this signals the completion of message
3239 * processing. However, it is possible that the application
3240 * will requeue the message from the "finished" handler (or
3241 * equivalently, from the soup_session_queue_message()
3242 * callback). In that case, the process will loop back to
3243 * #SoupSession::request_started.
3245 * Eventually, a message will reach "finished" and not be
3246 * requeued. At that point, the session will emit
3247 * #SoupSession::request_unqueued to indicate that it is done
3250 * To sum up: #SoupSession::request_queued and
3251 * #SoupSession::request_unqueued are guaranteed to be emitted
3252 * exactly once, but #SoupSession::request_started and
3253 * #SoupMessage::finished (and all of the other #SoupMessage
3254 * signals) may be invoked multiple times for a given message.
3258 signals[REQUEST_QUEUED] =
3259 g_signal_new ("request-queued",
3260 G_OBJECT_CLASS_TYPE (object_class),
3269 * SoupSession::request-started:
3270 * @session: the session
3271 * @msg: the request being sent
3272 * @socket: the socket the request is being sent on
3274 * Emitted just before a request is sent. See
3275 * #SoupSession::request_queued for a detailed description of
3276 * the message lifecycle within a session.
3278 signals[REQUEST_STARTED] =
3279 g_signal_new ("request-started",
3280 G_OBJECT_CLASS_TYPE (object_class),
3282 G_STRUCT_OFFSET (SoupSessionClass, request_started),
3290 * SoupSession::request-unqueued:
3291 * @session: the session
3292 * @msg: the request that was unqueued
3294 * Emitted when a request is removed from @session's queue,
3295 * indicating that @session is done with it. See
3296 * #SoupSession::request_queued for a detailed description of the
3297 * message lifecycle within a session.
3301 signals[REQUEST_UNQUEUED] =
3302 g_signal_new ("request-unqueued",
3303 G_OBJECT_CLASS_TYPE (object_class),
3312 * SoupSession::authenticate:
3313 * @session: the session
3314 * @msg: the #SoupMessage being sent
3315 * @auth: the #SoupAuth to authenticate
3316 * @retrying: %TRUE if this is the second (or later) attempt
3318 * Emitted when the session requires authentication. If
3319 * credentials are available call soup_auth_authenticate() on
3320 * @auth. If these credentials fail, the signal will be
3321 * emitted again, with @retrying set to %TRUE, which will
3322 * continue until you return without calling
3323 * soup_auth_authenticate() on @auth.
3325 * Note that this may be emitted before @msg's body has been
3328 * If you call soup_session_pause_message() on @msg before
3329 * returning, then you can authenticate @auth asynchronously
3330 * (as long as you g_object_ref() it to make sure it doesn't
3331 * get destroyed), and then unpause @msg when you are ready
3332 * for it to continue.
3334 signals[AUTHENTICATE] =
3335 g_signal_new ("authenticate",
3336 G_OBJECT_CLASS_TYPE (object_class),
3338 G_STRUCT_OFFSET (SoupSessionClass, authenticate),
3347 * SoupSession::connection-created:
3348 * @session: the #SoupSession
3349 * @connection: the connection
3351 * Emitted when a new connection is created. This is an
3352 * internal signal intended only to be used for debugging
3353 * purposes, and may go away in the future.
3357 signals[CONNECTION_CREATED] =
3358 g_signal_new ("connection-created",
3359 G_OBJECT_CLASS_TYPE (object_class),
3365 /* SoupConnection is private, so we can't use
3366 * SOUP_TYPE_CONNECTION here.
3371 * SoupSession::tunneling:
3372 * @session: the #SoupSession
3373 * @connection: the connection
3375 * Emitted when an SSL tunnel is being created on a proxy
3376 * connection. This is an internal signal intended only to be
3377 * used for debugging purposes, and may go away in the future.
3381 signals[TUNNELING] =
3382 g_signal_new ("tunneling",
3383 G_OBJECT_CLASS_TYPE (object_class),
3389 /* SoupConnection is private, so we can't use
3390 * SOUP_TYPE_CONNECTION here.
3397 * SoupSession:proxy-uri:
3399 * A proxy to use for all http and https requests in this
3400 * session. Setting this will clear the
3401 * #SoupSession:proxy-resolver property, and remove any
3402 * <type>SoupProxyURIResolver</type> features that have been
3403 * added to the session. Setting this property will also
3404 * cancel all currently pending messages.
3406 * Note that #SoupSession will normally handle looking up the
3407 * user's proxy settings for you; you should only use
3408 * #SoupSession:proxy-uri if you need to override the user's
3409 * normal proxy settings.
3411 * Also note that this proxy will be used for
3412 * <emphasis>all</emphasis> requests; even requests to
3413 * <literal>localhost</literal>. If you need more control over
3414 * proxies, you can create a #GSimpleProxyResolver and set the
3415 * #SoupSession:proxy-resolver property.
3418 * SOUP_SESSION_PROXY_URI:
3420 * Alias for the #SoupSession:proxy-uri property, qv.
3422 g_object_class_install_property (
3423 object_class, PROP_PROXY_URI,
3424 g_param_spec_boxed (SOUP_SESSION_PROXY_URI,
3426 "The HTTP Proxy to use for this session",
3428 G_PARAM_READWRITE));
3430 * SoupSession:proxy-resolver:
3432 * A #GProxyResolver to use with this session. Setting this
3433 * will clear the #SoupSession:proxy-uri property, and remove
3434 * any <type>SoupProxyURIResolver</type> features that have
3435 * been added to the session.
3437 * By default, in a plain #SoupSession, this is set to the
3438 * default #GProxyResolver, but you can set it to %NULL if you
3439 * don't want to use proxies, or set it to your own
3440 * #GProxyResolver if you want to control what proxies get
3446 * SOUP_SESSION_PROXY_RESOLVER:
3448 * Alias for the #SoupSession:proxy-resolver property, qv.
3450 g_object_class_install_property (
3451 object_class, PROP_PROXY_RESOLVER,
3452 g_param_spec_object (SOUP_SESSION_PROXY_RESOLVER,
3454 "The GProxyResolver to use for this session",
3455 G_TYPE_PROXY_RESOLVER,
3456 G_PARAM_READWRITE));
3458 * SOUP_SESSION_MAX_CONNS:
3460 * Alias for the #SoupSession:max-conns property, qv.
3462 g_object_class_install_property (
3463 object_class, PROP_MAX_CONNS,
3464 g_param_spec_int (SOUP_SESSION_MAX_CONNS,
3465 "Max Connection Count",
3466 "The maximum number of connections that the session can open at once",
3469 SOUP_SESSION_MAX_CONNS_DEFAULT,
3470 G_PARAM_READWRITE));
3472 * SOUP_SESSION_MAX_CONNS_PER_HOST:
3474 * Alias for the #SoupSession:max-conns-per-host property, qv.
3476 g_object_class_install_property (
3477 object_class, PROP_MAX_CONNS_PER_HOST,
3478 g_param_spec_int (SOUP_SESSION_MAX_CONNS_PER_HOST,
3479 "Max Per-Host Connection Count",
3480 "The maximum number of connections that the session can open at once to a given host",
3483 SOUP_SESSION_MAX_CONNS_PER_HOST_DEFAULT,
3484 G_PARAM_READWRITE));
3486 * SoupSession:idle-timeout:
3488 * Connection lifetime (in seconds) when idle. Any connection
3489 * left idle longer than this will be closed.
3491 * Although you can change this property at any time, it will
3492 * only affect newly-created connections, not currently-open
3493 * ones. You can call soup_session_abort() after setting this
3494 * if you want to ensure that all future connections will have
3495 * this timeout value.
3497 * Note that the default value of 60 seconds only applies to
3498 * plain #SoupSessions. If you are using #SoupSessionAsync or
3499 * #SoupSessionSync, the default value is 0 (meaning idle
3500 * connections will never time out).
3505 * SOUP_SESSION_IDLE_TIMEOUT:
3507 * Alias for the #SoupSession:idle-timeout property, qv.
3511 g_object_class_install_property (
3512 object_class, PROP_IDLE_TIMEOUT,
3513 g_param_spec_uint (SOUP_SESSION_IDLE_TIMEOUT,
3515 "Connection lifetime when idle",
3517 G_PARAM_READWRITE));
3519 * SoupSession:use-ntlm:
3521 * Whether or not to use NTLM authentication.
3523 * Deprecated: use soup_session_add_feature_by_type() with
3524 * #SOUP_TYPE_AUTH_NTLM.
3527 * SOUP_SESSION_USE_NTLM:
3529 * Alias for the #SoupSession:use-ntlm property, qv.
3531 g_object_class_install_property (
3532 object_class, PROP_USE_NTLM,
3533 g_param_spec_boolean (SOUP_SESSION_USE_NTLM,
3535 "Whether or not to use NTLM authentication",
3537 G_PARAM_READWRITE | G_PARAM_DEPRECATED));
3539 * SoupSession:ssl-ca-file:
3541 * File containing SSL CA certificates.
3543 * If the specified file does not exist or cannot be read,
3544 * then libsoup will print a warning, and then behave as
3545 * though it had read in a empty CA file, meaning that all SSL
3546 * certificates will be considered invalid.
3548 * Deprecated: use #SoupSession:ssl-use-system-ca-file, or
3549 * else #SoupSession:tls-database with a #GTlsFileDatabase
3550 * (which allows you to do explicit error handling).
3553 * SOUP_SESSION_SSL_CA_FILE:
3555 * Alias for the #SoupSession:ssl-ca-file property, qv.
3557 g_object_class_install_property (
3558 object_class, PROP_SSL_CA_FILE,
3559 g_param_spec_string (SOUP_SESSION_SSL_CA_FILE,
3561 "File containing SSL CA certificates",
3563 G_PARAM_READWRITE | G_PARAM_DEPRECATED));
3565 * SOUP_SESSION_SSL_USE_SYSTEM_CA_FILE:
3567 * Alias for the #SoupSession:ssl-use-system-ca-file property,
3573 * SoupSession:ssl-use-system-ca-file:
3575 * Setting this to %TRUE is equivalent to setting
3576 * #SoupSession:tls-database to the default system CA database.
3577 * (and likewise, setting #SoupSession:tls-database to the
3578 * default database by hand will cause this property to
3581 * Setting this to %FALSE (when it was previously %TRUE) will
3582 * clear the #SoupSession:tls-database field.
3584 * See #SoupSession:ssl-strict for more information on how
3585 * https certificate validation is handled.
3587 * Note that the default value of %TRUE only applies to plain
3588 * #SoupSessions. If you are using #SoupSessionAsync or
3589 * #SoupSessionSync, the default value is %FALSE, for backward
3594 g_object_class_install_property (
3595 object_class, PROP_SSL_USE_SYSTEM_CA_FILE,
3596 g_param_spec_boolean (SOUP_SESSION_SSL_USE_SYSTEM_CA_FILE,
3597 "Use system CA file",
3598 "Use the system certificate database",
3600 G_PARAM_READWRITE));
3602 * SOUP_SESSION_TLS_DATABASE:
3604 * Alias for the #SoupSession:tls-database property, qv.
3609 * SoupSession:tls-database:
3611 * Sets the #GTlsDatabase to use for validating SSL/TLS
3614 * Note that setting the #SoupSession:ssl-ca-file or
3615 * #SoupSession:ssl-use-system-ca-file property will cause
3616 * this property to be set to a #GTlsDatabase corresponding to
3617 * the indicated file or system default.
3619 * See #SoupSession:ssl-strict for more information on how
3620 * https certificate validation is handled.
3622 * If you are using a plain #SoupSession then
3623 * #SoupSession:ssl-use-system-ca-file will be %TRUE by
3624 * default, and so this property will be a copy of the system
3625 * CA database. If you are using #SoupSessionAsync or
3626 * #SoupSessionSync, this property will be %NULL by default.
3630 g_object_class_install_property (
3631 object_class, PROP_TLS_DATABASE,
3632 g_param_spec_object (SOUP_SESSION_TLS_DATABASE,
3634 "TLS database to use",
3635 G_TYPE_TLS_DATABASE,
3636 G_PARAM_READWRITE));
3638 * SOUP_SESSION_SSL_STRICT:
3640 * Alias for the #SoupSession:ssl-strict property, qv.
3645 * SoupSession:ssl-strict:
3647 * Normally, if #SoupSession:tls-database is set (including if
3648 * it was set via #SoupSession:ssl-use-system-ca-file or
3649 * #SoupSession:ssl-ca-file), then libsoup will reject any
3650 * certificate that is invalid (ie, expired) or that is not
3651 * signed by one of the given CA certificates, and the
3652 * #SoupMessage will fail with the status
3653 * %SOUP_STATUS_SSL_FAILED.
3655 * If you set #SoupSession:ssl-strict to %FALSE, then all
3656 * certificates will be accepted, and you will need to call
3657 * soup_message_get_https_status() to distinguish valid from
3658 * invalid certificates. (This can be used, eg, if you want to
3659 * accept invalid certificates after giving some sort of
3662 * For a plain #SoupSession, if the session has no CA file or
3663 * TLS database, and this property is %TRUE, then all
3664 * certificates will be rejected. However, beware that the
3665 * deprecated #SoupSession subclasses (#SoupSessionAsync and
3666 * #SoupSessionSync) have the opposite behavior: if there is
3667 * no CA file or TLS database, then all certificates are always
3668 * accepted, and this property has no effect.
3672 g_object_class_install_property (
3673 object_class, PROP_SSL_STRICT,
3674 g_param_spec_boolean (SOUP_SESSION_SSL_STRICT,
3675 "Strictly validate SSL certificates",
3676 "Whether certificate errors should be considered a connection error",
3678 G_PARAM_READWRITE));
3680 * SoupSession:async-context:
3682 * The #GMainContext that miscellaneous session-related
3683 * asynchronous callbacks are invoked on. (Eg, setting
3684 * #SoupSession:idle-timeout will add a timeout source on this
3687 * For a plain #SoupSession, this property is always set to
3688 * the #GMainContext that is the thread-default at the time
3689 * the session was created, and cannot be overridden. For the
3690 * deprecated #SoupSession subclasses, the default value is
3691 * %NULL, meaning to use the global default #GMainContext.
3693 * If #SoupSession:use-thread-context is %FALSE, this context
3694 * will also be used for asynchronous HTTP I/O.
3697 * SOUP_SESSION_ASYNC_CONTEXT:
3699 * Alias for the #SoupSession:async-context property, qv.
3701 g_object_class_install_property (
3702 object_class, PROP_ASYNC_CONTEXT,
3703 g_param_spec_pointer (SOUP_SESSION_ASYNC_CONTEXT,
3704 "Async GMainContext",
3705 "The GMainContext to dispatch async I/O in",
3706 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
3708 * SOUP_SESSION_USE_THREAD_CONTEXT:
3710 * Alias for the #SoupSession:use-thread-context property, qv.
3715 * SoupSession:use-thread-context:
3717 * If %TRUE (which it always is on a plain #SoupSession),
3718 * asynchronous HTTP requests in this session will run in
3719 * whatever the thread-default #GMainContext is at the time
3720 * they are started, rather than always occurring in
3721 * #SoupSession:async-context.
3725 g_object_class_install_property (
3726 object_class, PROP_USE_THREAD_CONTEXT,
3727 g_param_spec_boolean (SOUP_SESSION_USE_THREAD_CONTEXT,
3728 "Use thread-default GMainContext",
3729 "Whether to use thread-default main contexts",
3731 G_PARAM_READWRITE));
3733 * SoupSession:timeout:
3735 * The timeout (in seconds) for socket I/O operations
3736 * (including connecting to a server, and waiting for a reply
3737 * to an HTTP request).
3739 * Although you can change this property at any time, it will
3740 * only affect newly-created connections, not currently-open
3741 * ones. You can call soup_session_abort() after setting this
3742 * if you want to ensure that all future connections will have
3743 * this timeout value.
3745 * Note that the default value of 60 seconds only applies to
3746 * plain #SoupSessions. If you are using #SoupSessionAsync or
3747 * #SoupSessionSync, the default value is 0 (meaning socket I/O
3748 * will not time out).
3750 * Not to be confused with #SoupSession:idle-timeout (which is
3751 * the length of time that idle persistent connections will be
3755 * SOUP_SESSION_TIMEOUT:
3757 * Alias for the #SoupSession:timeout property, qv.
3759 g_object_class_install_property (
3760 object_class, PROP_TIMEOUT,
3761 g_param_spec_uint (SOUP_SESSION_TIMEOUT,
3763 "Value in seconds to timeout a blocking I/O",
3765 G_PARAM_READWRITE));
3768 * SoupSession:user-agent:
3770 * If non-%NULL, the value to use for the "User-Agent" header
3771 * on #SoupMessage<!-- -->s sent from this session.
3773 * RFC 2616 says: "The User-Agent request-header field
3774 * contains information about the user agent originating the
3775 * request. This is for statistical purposes, the tracing of
3776 * protocol violations, and automated recognition of user
3777 * agents for the sake of tailoring responses to avoid
3778 * particular user agent limitations. User agents SHOULD
3779 * include this field with requests."
3781 * The User-Agent header contains a list of one or more
3782 * product tokens, separated by whitespace, with the most
3783 * significant product token coming first. The tokens must be
3784 * brief, ASCII, and mostly alphanumeric (although "-", "_",
3785 * and "." are also allowed), and may optionally include a "/"
3786 * followed by a version string. You may also put comments,
3787 * enclosed in parentheses, between or after the tokens.
3789 * If you set a #SoupSession:user_agent property that has trailing
3790 * whitespace, #SoupSession will append its own product token
3791 * (eg, "<literal>libsoup/2.3.2</literal>") to the end of the
3795 * SOUP_SESSION_USER_AGENT:
3797 * Alias for the #SoupSession:user-agent property, qv.
3799 g_object_class_install_property (
3800 object_class, PROP_USER_AGENT,
3801 g_param_spec_string (SOUP_SESSION_USER_AGENT,
3802 "User-Agent string",
3803 "User-Agent string",
3805 G_PARAM_READWRITE));
3808 * SoupSession:accept-language:
3810 * If non-%NULL, the value to use for the "Accept-Language" header
3811 * on #SoupMessage<!-- -->s sent from this session.
3813 * Setting this will disable
3814 * #SoupSession:accept-language-auto.
3819 * SOUP_SESSION_ACCEPT_LANGUAGE:
3821 * Alias for the #SoupSession:accept-language property, qv.
3825 g_object_class_install_property (
3826 object_class, PROP_ACCEPT_LANGUAGE,
3827 g_param_spec_string (SOUP_SESSION_ACCEPT_LANGUAGE,
3828 "Accept-Language string",
3829 "Accept-Language string",
3831 G_PARAM_READWRITE));
3834 * SoupSession:accept-language-auto:
3836 * If %TRUE, #SoupSession will automatically set the string
3837 * for the "Accept-Language" header on every #SoupMessage
3838 * sent, based on the return value of g_get_language_names().
3840 * Setting this will override any previous value of
3841 * #SoupSession:accept-language.
3846 * SOUP_SESSION_ACCEPT_LANGUAGE_AUTO:
3848 * Alias for the #SoupSession:accept-language-auto property, qv.
3852 g_object_class_install_property (
3853 object_class, PROP_ACCEPT_LANGUAGE_AUTO,
3854 g_param_spec_boolean (SOUP_SESSION_ACCEPT_LANGUAGE_AUTO,
3855 "Accept-Language automatic mode",
3856 "Accept-Language automatic mode",
3858 G_PARAM_READWRITE));
3861 * SoupSession:add-feature: (skip)
3863 * Add a feature object to the session. (Shortcut for calling
3864 * soup_session_add_feature().)
3869 * SOUP_SESSION_ADD_FEATURE: (skip)
3871 * Alias for the #SoupSession:add-feature property, qv.
3875 g_object_class_install_property (
3876 object_class, PROP_ADD_FEATURE,
3877 g_param_spec_object (SOUP_SESSION_ADD_FEATURE,
3879 "Add a feature object to the session",
3880 SOUP_TYPE_SESSION_FEATURE,
3881 G_PARAM_READWRITE));
3883 * SoupSession:add-feature-by-type: (skip)
3885 * Add a feature object of the given type to the session.
3886 * (Shortcut for calling soup_session_add_feature_by_type().)
3891 * SOUP_SESSION_ADD_FEATURE_BY_TYPE: (skip)
3893 * Alias for the #SoupSession:add-feature-by-type property, qv.
3897 g_object_class_install_property (
3898 object_class, PROP_ADD_FEATURE_BY_TYPE,
3899 g_param_spec_gtype (SOUP_SESSION_ADD_FEATURE_BY_TYPE,
3900 "Add Feature By Type",
3901 "Add a feature object of the given type to the session",
3903 G_PARAM_READWRITE));
3905 * SoupSession:remove-feature-by-type: (skip)
3907 * Remove feature objects from the session. (Shortcut for
3908 * calling soup_session_remove_feature_by_type().)
3913 * SOUP_SESSION_REMOVE_FEATURE_BY_TYPE: (skip)
3915 * Alias for the #SoupSession:remove-feature-by-type property,
3920 g_object_class_install_property (
3921 object_class, PROP_REMOVE_FEATURE_BY_TYPE,
3922 g_param_spec_gtype (SOUP_SESSION_REMOVE_FEATURE_BY_TYPE,
3923 "Remove Feature By Type",
3924 "Remove features of the given type from the session",
3926 G_PARAM_READWRITE));
3928 * SoupSession:http-aliases:
3930 * A %NULL-terminated array of URI schemes that should be
3931 * considered to be aliases for "http". Eg, if this included
3932 * <literal>"dav"</literal>, than a URI of
3933 * <literal>dav://example.com/path</literal> would be treated
3934 * identically to <literal>http://example.com/path</literal>.
3936 * In a plain #SoupSession, the default value is %NULL,
3937 * meaning that only "http" is recognized as meaning "http".
3938 * In #SoupSessionAsync and #SoupSessionSync, for backward
3939 * compatibility, the default value is an array containing the
3940 * single element <literal>"*"</literal>, a special value
3941 * which means that any scheme except "https" is considered to
3942 * be an alias for "http".
3944 * See also #SoupSession:https-aliases.
3949 * SOUP_SESSION_HTTP_ALIASES:
3951 * Alias for the #SoupSession:http-aliases property, qv.
3955 g_object_class_install_property (
3956 object_class, PROP_HTTP_ALIASES,
3957 g_param_spec_boxed (SOUP_SESSION_HTTP_ALIASES,
3959 "URI schemes that are considered aliases for 'http'",
3961 G_PARAM_READWRITE));
3963 * SoupSession:https-aliases:
3965 * A comma-delimited list of URI schemes that should be
3966 * considered to be aliases for "https". See
3967 * #SoupSession:http-aliases for more information.
3969 * The default value is %NULL, meaning that no URI schemes
3970 * are considered aliases for "https".
3975 * SOUP_SESSION_HTTPS_ALIASES:
3977 * Alias for the #SoupSession:https-aliases property, qv.
3981 g_object_class_install_property (
3982 object_class, PROP_HTTPS_ALIASES,
3983 g_param_spec_boxed (SOUP_SESSION_HTTPS_ALIASES,
3985 "URI schemes that are considered aliases for 'https'",
3987 G_PARAM_READWRITE));
3990 * SOUP_SESSION_LOCAL_ADDRESS:
3992 * Alias for the #SoupSession:local-address property, qv.
3997 * SoupSession:local-address:
3999 * Sets the #SoupAddress to use for the client side of
4002 * Use this property if you want for instance to bind the
4003 * local socket to a specific IP address.
4007 g_object_class_install_property (
4008 object_class, PROP_LOCAL_ADDRESS,
4009 g_param_spec_object (SOUP_SESSION_LOCAL_ADDRESS,
4011 "Address of local end of socket",
4013 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
4015 #if ENABLE(TIZEN_CERTIFICATE_FILE_SET)
4017 * SOUP_SESSION_CERTIFICATE_PATH
4018 * SoupSession:certificate-path:
4020 * Set the certificate path for soup session
4023 g_object_class_install_property (
4024 object_class, PROP_CERTIFICATE_PATH,
4025 g_param_spec_string (SOUP_SESSION_CERTIFICATE_PATH,
4026 "certificate file path",
4027 "Set the ca-certificate.crt file path",
4029 G_PARAM_READWRITE));
4032 #if ENABLE(TIZEN_TV_CLIENT_CERTIFICATE)
4034 * SOUP_SESSION_USE_WIDGETENGINE:
4036 * Alias for the #SoupSession:widget-engine property.
4040 g_object_class_install_property (
4041 object_class, PROP_WIDGET_ENGINE,
4042 g_param_spec_boolean (SOUP_SESSION_WIDGET_ENGINE,
4044 "Whether or not to be running Widget Engine",
4046 G_PARAM_READWRITE));
4054 expected_to_be_requeued (SoupSession *session, SoupMessage *msg)
4056 if (msg->status_code == SOUP_STATUS_UNAUTHORIZED ||
4057 msg->status_code == SOUP_STATUS_PROXY_UNAUTHORIZED) {
4058 SoupSessionFeature *feature =
4059 soup_session_get_feature (session, SOUP_TYPE_AUTH_MANAGER);
4060 return !feature || !soup_message_disables_feature (msg, feature);
4063 if (!(soup_message_get_flags (msg) & SOUP_MESSAGE_NO_REDIRECT))
4064 return soup_session_would_redirect (session, msg);
4069 /* send_request_async */
4072 async_send_request_return_result (SoupMessageQueueItem *item,
4073 gpointer stream, GError *error)
4077 g_return_if_fail (item->task != NULL);
4079 g_signal_handlers_disconnect_matched (item->msg, G_SIGNAL_MATCH_DATA,
4080 0, 0, NULL, NULL, item);
4085 if (item->io_source) {
4086 g_source_destroy (item->io_source);
4087 g_clear_pointer (&item->io_source, g_source_unref);
4091 g_task_return_error (task, error);
4092 else if (item->error) {
4094 g_object_unref (stream);
4095 g_task_return_error (task, g_error_copy (item->error));
4096 } else if (SOUP_STATUS_IS_TRANSPORT_ERROR (item->msg->status_code)) {
4098 g_object_unref (stream);
4099 g_task_return_new_error (task, SOUP_HTTP_ERROR,
4100 item->msg->status_code,
4102 item->msg->reason_phrase);
4104 g_task_return_pointer (task, stream, g_object_unref);
4105 g_object_unref (task);
4109 async_send_request_restarted (SoupMessage *msg, gpointer user_data)
4111 SoupMessageQueueItem *item = user_data;
4113 /* We won't be needing this, then. */
4114 g_object_set_data (G_OBJECT (item->msg), "SoupSession:ostream", NULL);
4115 item->io_started = FALSE;
4119 async_send_request_finished (SoupMessage *msg, gpointer user_data)
4121 SoupMessageQueueItem *item = user_data;
4122 GMemoryOutputStream *mostream;
4123 GInputStream *istream = NULL;
4124 GError *error = NULL;
4127 /* Something else already took care of it. */
4131 mostream = g_object_get_data (G_OBJECT (item->task), "SoupSession:ostream");
4136 /* We thought it would be requeued, but it wasn't, so
4137 * return the original body.
4139 size = g_memory_output_stream_get_data_size (mostream);
4140 data = size ? g_memory_output_stream_steal_data (mostream) : g_strdup ("");
4141 istream = g_memory_input_stream_new_from_data (data, size, g_free);
4142 } else if (item->io_started) {
4143 /* The message finished before becoming readable. This
4144 * will happen, eg, if it's cancelled from got-headers.
4145 * Do nothing; the op will complete via read_ready_cb()
4150 /* The message finished before even being started;
4151 * probably a tunnel connect failure.
4153 istream = g_memory_input_stream_new ();
4156 async_send_request_return_result (item, istream, error);
4160 send_async_spliced (GObject *source, GAsyncResult *result, gpointer user_data)
4162 SoupMessageQueueItem *item = user_data;
4163 GInputStream *istream = g_object_get_data (source, "istream");
4164 GError *error = NULL;
4166 /* It should be safe to call the sync close() method here since
4167 * the message body has already been written.
4169 g_input_stream_close (istream, NULL, NULL);
4170 g_object_unref (istream);
4172 /* If the message was cancelled, it will be completed via other means */
4173 if (g_cancellable_is_cancelled (item->cancellable) ||
4175 soup_message_queue_item_unref (item);
4179 if (g_output_stream_splice_finish (G_OUTPUT_STREAM (source),
4180 result, &error) == -1) {
4181 async_send_request_return_result (item, NULL, error);
4182 soup_message_queue_item_unref (item);
4186 /* Otherwise either restarted or finished will eventually be called. */
4187 soup_session_kick_queue (item->session);
4188 soup_message_queue_item_unref (item);
4192 send_async_maybe_complete (SoupMessageQueueItem *item,
4193 GInputStream *stream)
4195 if (expected_to_be_requeued (item->session, item->msg)) {
4196 GOutputStream *ostream;
4198 /* Gather the current message body... */
4199 ostream = g_memory_output_stream_new (NULL, 0, g_realloc, g_free);
4200 g_object_set_data_full (G_OBJECT (item->task), "SoupSession:ostream",
4201 ostream, g_object_unref);
4203 g_object_set_data (G_OBJECT (ostream), "istream", stream);
4205 /* Give the splice op its own ref on item */
4206 soup_message_queue_item_ref (item);
4207 /* We don't use CLOSE_SOURCE because we need to control when the
4208 * side effects of closing the SoupClientInputStream happen.
4210 g_output_stream_splice_async (ostream, stream,
4211 G_OUTPUT_STREAM_SPLICE_CLOSE_TARGET,
4214 send_async_spliced, item);
4218 async_send_request_return_result (item, stream, NULL);
4221 static void try_run_until_read (SoupMessageQueueItem *item);
4224 read_ready_cb (SoupMessage *msg, gpointer user_data)
4226 SoupMessageQueueItem *item = user_data;
4228 g_clear_pointer (&item->io_source, g_source_unref);
4229 try_run_until_read (item);
4234 try_run_until_read (SoupMessageQueueItem *item)
4236 GError *error = NULL;
4237 GInputStream *stream = NULL;
4239 if (soup_message_io_run_until_read (item->msg, FALSE, item->cancellable, &error))
4240 stream = soup_message_io_get_response_istream (item->msg, &error);
4242 send_async_maybe_complete (item, stream);
4246 if (g_error_matches (error, SOUP_HTTP_ERROR, SOUP_STATUS_TRY_AGAIN)) {
4247 item->state = SOUP_MESSAGE_RESTARTING;
4248 soup_message_io_finished (item->msg);
4249 g_error_free (error);
4253 if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK)) {
4254 if (item->state != SOUP_MESSAGE_FINISHED) {
4255 if (soup_message_io_in_progress (item->msg))
4256 soup_message_io_finished (item->msg);
4257 item->state = SOUP_MESSAGE_FINISHING;
4258 soup_session_process_queue_item (item->session, item, NULL, FALSE);
4260 async_send_request_return_result (item, NULL, error);
4264 g_clear_error (&error);
4265 item->io_source = soup_message_io_get_source (item->msg, item->cancellable,
4266 read_ready_cb, item);
4267 g_source_attach (item->io_source, soup_session_get_async_context (item->session));
4271 async_send_request_running (SoupSession *session, SoupMessageQueueItem *item)
4273 item->io_started = TRUE;
4274 try_run_until_read (item);
4278 async_return_from_cache (SoupMessageQueueItem *item,
4279 GInputStream *stream)
4281 const char *content_type;
4282 GHashTable *params = NULL;
4284 soup_message_got_headers (item->msg);
4286 content_type = soup_message_headers_get_content_type (item->msg->response_headers, ¶ms);
4288 soup_message_content_sniffed (item->msg, content_type, params);
4289 g_hash_table_unref (params);
4292 item->state = SOUP_MESSAGE_FINISHING;
4293 async_send_request_return_result (item, g_object_ref (stream), NULL);
4298 SoupMessage *conditional_msg;
4299 } AsyncCacheCancelData;
4303 free_async_cache_cancel_data (AsyncCacheCancelData *data)
4305 g_object_unref (data->conditional_msg);
4306 g_object_unref (data->cache);
4307 g_slice_free (AsyncCacheCancelData, data);
4311 cancel_cache_response (SoupMessageQueueItem *item)
4313 item->paused = FALSE;
4314 item->state = SOUP_MESSAGE_FINISHING;
4315 soup_message_set_status (item->msg, SOUP_STATUS_CANCELLED);
4316 soup_session_kick_queue (item->session);
4320 conditional_request_cancelled_cb (GCancellable *cancellable, AsyncCacheCancelData *data)
4322 soup_cache_cancel_conditional_request (data->cache, data->conditional_msg);
4326 conditional_get_ready_cb (SoupSession *session, SoupMessage *msg, gpointer user_data)
4328 SoupMessageQueueItem *item = user_data;
4329 GInputStream *stream;
4332 if (g_cancellable_is_cancelled (item->cancellable)) {
4333 cancel_cache_response (item);
4336 gulong handler_id = GPOINTER_TO_SIZE (g_object_get_data (G_OBJECT (msg), "SoupSession:handler-id"));
4337 g_cancellable_disconnect (item->cancellable, handler_id);
4340 cache = (SoupCache *)soup_session_get_feature (session, SOUP_TYPE_CACHE);
4341 soup_cache_update_from_conditional_request (cache, msg);
4343 if (msg->status_code == SOUP_STATUS_NOT_MODIFIED) {
4344 stream = soup_cache_send_response (cache, item->msg);
4346 async_return_from_cache (item, stream);
4347 g_object_unref (stream);
4352 /* The resource was modified or the server returned a 200
4353 * OK. Either way we reload it. FIXME.
4355 item->state = SOUP_MESSAGE_STARTING;
4356 soup_session_kick_queue (session);
4360 idle_return_from_cache_cb (gpointer data)
4363 SoupMessageQueueItem *item = g_task_get_task_data (task);
4364 GInputStream *istream;
4366 if (item->state == SOUP_MESSAGE_FINISHED) {
4367 /* The original request was cancelled using
4368 * soup_session_cancel_message () so it has been
4369 * already handled by the cancellation code path.
4372 } else if (g_cancellable_is_cancelled (item->cancellable)) {
4373 /* Cancel original msg after g_cancellable_cancel(). */
4374 cancel_cache_response (item);
4378 istream = g_object_get_data (G_OBJECT (task), "SoupSession:istream");
4379 async_return_from_cache (item, istream);
4386 async_respond_from_cache (SoupSession *session,
4387 SoupMessageQueueItem *item)
4390 SoupCacheResponse response;
4392 cache = (SoupCache *)soup_session_get_feature (session, SOUP_TYPE_CACHE);
4396 response = soup_cache_has_response (cache, item->msg);
4397 if (response == SOUP_CACHE_RESPONSE_FRESH) {
4398 GInputStream *stream;
4401 #if ENABLE(TIZEN_PERFORMANCE_TEST_LOG)
4402 prctl_with_url_and_free("[EVT] soup_use_cache1 (file cache) : ", soup_uri_to_string(soup_message_get_uri(item->msg), TRUE));
4404 stream = soup_cache_send_response (cache, item->msg);
4406 /* Cached file was deleted? */
4409 g_object_set_data_full (G_OBJECT (item->task), "SoupSession:istream",
4410 stream, g_object_unref);
4412 source = g_timeout_source_new (0);
4413 g_task_attach_source (item->task, source,
4414 (GSourceFunc) idle_return_from_cache_cb);
4415 g_source_unref (source);
4417 } else if (response == SOUP_CACHE_RESPONSE_NEEDS_VALIDATION) {
4418 SoupMessage *conditional_msg;
4419 AsyncCacheCancelData *data;
4422 #if ENABLE(TIZEN_PERFORMANCE_TEST_LOG)
4423 prctl_with_url_and_free("[EVT] soup_use_cache2-1 (conditional) : ", soup_uri_to_string(soup_message_get_uri(item->msg), TRUE));
4425 conditional_msg = soup_cache_generate_conditional_request (cache, item->msg);
4426 if (!conditional_msg)
4429 /* Detect any quick cancellation before the cache is able to return data. */
4430 data = g_slice_new0 (AsyncCacheCancelData);
4431 data->cache = g_object_ref (cache);
4432 data->conditional_msg = g_object_ref (conditional_msg);
4433 handler_id = g_cancellable_connect (item->cancellable, G_CALLBACK (conditional_request_cancelled_cb),
4434 data, (GDestroyNotify) free_async_cache_cancel_data);
4436 g_object_set_data (G_OBJECT (conditional_msg), "SoupSession:handler-id",
4437 GSIZE_TO_POINTER (handler_id));
4438 soup_session_queue_message (session, conditional_msg,
4439 conditional_get_ready_cb,
4445 #if ENABLE(TIZEN_PERFORMANCE_TEST_LOG)
4446 prctl_with_url_and_free("[EVT] soup_cache_stale : ", soup_uri_to_string(soup_message_get_uri(item->msg), TRUE));
4453 * soup_session_send_async:
4454 * @session: a #SoupSession
4455 * @msg: a #SoupMessage
4456 * @cancellable: a #GCancellable
4457 * @callback: the callback to invoke
4458 * @user_data: data for @callback
4460 * Asynchronously sends @msg and waits for the beginning of a
4461 * response. When @callback is called, then either @msg has been sent,
4462 * and its response headers received, or else an error has occurred.
4463 * Call soup_session_send_finish() to get a #GInputStream for reading
4464 * the response body.
4466 * See soup_session_send() for more details on the general semantics.
4468 * Contrast this method with soup_session_queue_message(), which also
4469 * asynchronously sends a #SoupMessage, but doesn't invoke its
4470 * callback until the response has been completely read.
4472 * (Note that this method cannot be called on the deprecated
4473 * #SoupSessionSync subclass, and can only be called on
4474 * #SoupSessionAsync if you have set the
4475 * #SoupSession:use-thread-context property.)
4480 soup_session_send_async (SoupSession *session,
4482 GCancellable *cancellable,
4483 GAsyncReadyCallback callback,
4486 SoupMessageQueueItem *item;
4487 gboolean use_thread_context;
4488 #if ENABLE(TIZEN_TV_IMMEDIATE_REQUESTING)
4489 gboolean should_prune = FALSE;
4492 g_return_if_fail (SOUP_IS_SESSION (session));
4493 g_return_if_fail (!SOUP_IS_SESSION_SYNC (session));
4495 g_object_get (G_OBJECT (session),
4496 SOUP_SESSION_USE_THREAD_CONTEXT, &use_thread_context,
4498 g_return_if_fail (use_thread_context);
4500 item = soup_session_append_queue_item (session, msg, TRUE, TRUE,
4502 g_signal_connect (msg, "restarted",
4503 G_CALLBACK (async_send_request_restarted), item);
4504 g_signal_connect (msg, "finished",
4505 G_CALLBACK (async_send_request_finished), item);
4508 g_object_unref (item->cancellable);
4509 item->cancellable = g_object_ref (cancellable);
4512 item->new_api = TRUE;
4513 item->task = g_task_new (session, item->cancellable, callback, user_data);
4514 g_task_set_task_data (item->task, item, (GDestroyNotify) soup_message_queue_item_unref);
4516 /* Do not check for cancellations as we do not want to
4517 * overwrite custom error messages set during cancellations
4518 * (for example SOUP_HTTP_ERROR is set for cancelled messages
4519 * in async_send_request_return_result() (status_code==1
4520 * means CANCEL and is considered a TRANSPORT_ERROR)).
4522 g_task_set_check_cancellable (item->task, FALSE);
4524 if (async_respond_from_cache (session, item))
4525 item->state = SOUP_MESSAGE_CACHED;
4527 #if ENABLE(TIZEN_TV_IMMEDIATE_REQUESTING)
4529 /* CONNECT messages are handled specially */
4530 if (item->msg->method != SOUP_METHOD_CONNECT) {
4531 soup_session_process_queue_item (session, item, &should_prune, TRUE);
4534 soup_session_kick_queue (session);
4535 #if ENABLE(TIZEN_TV_IMMEDIATE_REQUESTING)
4541 * soup_session_send_finish:
4542 * @session: a #SoupSession
4543 * @result: the #GAsyncResult passed to your callback
4544 * @error: return location for a #GError, or %NULL
4546 * Gets the response to a soup_session_send_async() call and (if
4547 * successful), returns a #GInputStream that can be used to read the
4550 * Return value: (transfer full): a #GInputStream for reading the
4551 * response body, or %NULL on error.
4556 soup_session_send_finish (SoupSession *session,
4557 GAsyncResult *result,
4562 g_return_val_if_fail (SOUP_IS_SESSION (session), NULL);
4563 g_return_val_if_fail (!SOUP_IS_SESSION_SYNC (session), NULL);
4564 g_return_val_if_fail (g_task_is_valid (result, session), NULL);
4566 task = G_TASK (result);
4567 if (g_task_had_error (task)) {
4568 SoupMessageQueueItem *item = g_task_get_task_data (task);
4570 if (soup_message_io_in_progress (item->msg))
4571 soup_message_io_finished (item->msg);
4572 else if (item->state != SOUP_MESSAGE_FINISHED)
4573 item->state = SOUP_MESSAGE_FINISHING;
4575 if (item->state != SOUP_MESSAGE_FINISHED)
4576 soup_session_process_queue_item (session, item, NULL, FALSE);
4579 return g_task_propagate_pointer (task, error);
4583 * soup_session_send:
4584 * @session: a #SoupSession
4585 * @msg: a #SoupMessage
4586 * @cancellable: a #GCancellable
4587 * @error: return location for a #GError, or %NULL
4589 * Synchronously sends @msg and waits for the beginning of a response.
4590 * On success, a #GInputStream will be returned which you can use to
4591 * read the response body. ("Success" here means only that an HTTP
4592 * response was received and understood; it does not necessarily mean
4593 * that a 2xx class status code was received.)
4595 * If non-%NULL, @cancellable can be used to cancel the request;
4596 * soup_session_send() will return a %G_IO_ERROR_CANCELLED error. Note
4597 * that with requests that have side effects (eg,
4598 * <literal>POST</literal>, <literal>PUT</literal>,
4599 * <literal>DELETE</literal>) it is possible that you might cancel the
4600 * request after the server acts on it, but before it returns a
4601 * response, leaving the remote resource in an unknown state.
4603 * If @msg is requeued due to a redirect or authentication, the
4604 * initial (3xx/401/407) response body will be suppressed, and
4605 * soup_session_send() will only return once a final response has been
4608 * Contrast this method with soup_session_send_message(), which also
4609 * synchronously sends a #SoupMessage, but doesn't return until the
4610 * response has been completely read.
4612 * (Note that this method cannot be called on the deprecated
4613 * #SoupSessionAsync subclass.)
4615 * Return value: (transfer full): a #GInputStream for reading the
4616 * response body, or %NULL on error.
4621 soup_session_send (SoupSession *session,
4623 GCancellable *cancellable,
4626 SoupMessageQueueItem *item;
4627 GInputStream *stream = NULL;
4628 GOutputStream *ostream;
4629 GMemoryOutputStream *mostream;
4631 GError *my_error = NULL;
4633 g_return_val_if_fail (SOUP_IS_SESSION (session), NULL);
4634 g_return_val_if_fail (!SOUP_IS_SESSION_ASYNC (session), NULL);
4636 item = soup_session_append_queue_item (session, msg, FALSE, TRUE,
4639 item->new_api = TRUE;
4641 g_object_unref (item->cancellable);
4642 item->cancellable = g_object_ref (cancellable);
4646 /* Get a connection, etc */
4647 soup_session_process_queue_item (session, item, NULL, TRUE);
4648 if (item->state != SOUP_MESSAGE_RUNNING)
4651 /* Send request, read headers */
4652 if (!soup_message_io_run_until_read (msg, TRUE, item->cancellable, &my_error)) {
4653 if (g_error_matches (my_error, SOUP_HTTP_ERROR, SOUP_STATUS_TRY_AGAIN)) {
4654 item->state = SOUP_MESSAGE_RESTARTING;
4655 soup_message_io_finished (item->msg);
4656 g_clear_error (&my_error);
4662 stream = soup_message_io_get_response_istream (msg, &my_error);
4666 if (!expected_to_be_requeued (session, msg))
4669 /* Gather the current message body... */
4670 ostream = g_memory_output_stream_new (NULL, 0, g_realloc, g_free);
4671 if (g_output_stream_splice (ostream, stream,
4672 G_OUTPUT_STREAM_SPLICE_CLOSE_SOURCE |
4673 G_OUTPUT_STREAM_SPLICE_CLOSE_TARGET,
4674 item->cancellable, &my_error) == -1) {
4675 g_object_unref (stream);
4676 g_object_unref (ostream);
4680 g_object_unref (stream);
4683 /* If the message was requeued, loop */
4684 if (item->state == SOUP_MESSAGE_RESTARTING) {
4685 g_object_unref (ostream);
4689 /* Not requeued, so return the original body */
4690 mostream = G_MEMORY_OUTPUT_STREAM (ostream);
4691 size = g_memory_output_stream_get_data_size (mostream);
4692 stream = g_memory_input_stream_new ();
4694 g_memory_input_stream_add_data (G_MEMORY_INPUT_STREAM (stream),
4695 g_memory_output_stream_steal_data (mostream),
4698 g_object_unref (ostream);
4702 g_propagate_error (error, my_error);
4703 else if (item->error) {
4704 g_clear_object (&stream);
4706 *error = g_error_copy (item->error);
4707 } else if (SOUP_STATUS_IS_TRANSPORT_ERROR (msg->status_code)) {
4708 g_clear_object (&stream);
4709 g_set_error_literal (error, SOUP_HTTP_ERROR, msg->status_code,
4710 msg->reason_phrase);
4712 stream = g_memory_input_stream_new ();
4715 if (soup_message_io_in_progress (msg))
4716 soup_message_io_finished (msg);
4717 else if (item->state != SOUP_MESSAGE_FINISHED)
4718 item->state = SOUP_MESSAGE_FINISHING;
4720 if (item->state != SOUP_MESSAGE_FINISHED)
4721 soup_session_process_queue_item (session, item, NULL, TRUE);
4724 soup_message_queue_item_unref (item);
4729 * soup_session_request:
4730 * @session: a #SoupSession
4731 * @uri_string: a URI, in string form
4732 * @error: return location for a #GError, or %NULL
4734 * Creates a #SoupRequest for retrieving @uri_string.
4736 * Return value: (transfer full): a new #SoupRequest, or
4742 soup_session_request (SoupSession *session, const char *uri_string,
4748 uri = soup_uri_new (uri_string);
4750 g_set_error (error, SOUP_REQUEST_ERROR,
4751 SOUP_REQUEST_ERROR_BAD_URI,
4752 _("Could not parse URI '%s'"), uri_string);
4756 req = soup_session_request_uri (session, uri, error);
4757 soup_uri_free (uri);
4762 * soup_session_request_uri:
4763 * @session: a #SoupSession
4764 * @uri: a #SoupURI representing the URI to retrieve
4765 * @error: return location for a #GError, or %NULL
4767 * Creates a #SoupRequest for retrieving @uri.
4769 * Return value: (transfer full): a new #SoupRequest, or
4775 soup_session_request_uri (SoupSession *session, SoupURI *uri,
4778 SoupSessionPrivate *priv;
4781 g_return_val_if_fail (SOUP_IS_SESSION (session), NULL);
4783 priv = SOUP_SESSION_GET_PRIVATE (session);
4785 request_type = (GType)GPOINTER_TO_SIZE (g_hash_table_lookup (priv->request_types, uri->scheme));
4786 if (!request_type) {
4787 g_set_error (error, SOUP_REQUEST_ERROR,
4788 SOUP_REQUEST_ERROR_UNSUPPORTED_URI_SCHEME,
4789 _("Unsupported URI scheme '%s'"), uri->scheme);
4793 return g_initable_new (request_type, NULL, error,
4799 static SoupRequestHTTP *
4800 initialize_http_request (SoupRequest *req,
4804 SoupRequestHTTP *http;
4807 if (!SOUP_IS_REQUEST_HTTP (req)) {
4808 g_object_unref (req);
4809 g_set_error (error, SOUP_REQUEST_ERROR,
4810 SOUP_REQUEST_ERROR_BAD_URI,
4811 _("Not an HTTP URI"));
4815 http = SOUP_REQUEST_HTTP (req);
4816 msg = soup_request_http_get_message (http);
4817 g_object_set (G_OBJECT (msg),
4818 SOUP_MESSAGE_METHOD, method,
4820 g_object_unref (msg);
4826 * soup_session_request_http:
4827 * @session: a #SoupSession
4828 * @method: an HTTP method
4829 * @uri_string: a URI, in string form
4830 * @error: return location for a #GError, or %NULL
4832 * Creates a #SoupRequest for retrieving @uri_string, which must be an
4833 * "http" or "https" URI (or another protocol listed in @session's
4834 * #SoupSession:http-aliases or #SoupSession:https-aliases).
4836 * Return value: (transfer full): a new #SoupRequestHTTP, or
4842 soup_session_request_http (SoupSession *session,
4844 const char *uri_string,
4849 req = soup_session_request (session, uri_string, error);
4853 return initialize_http_request (req, method, error);
4857 * soup_session_request_http_uri:
4858 * @session: a #SoupSession
4859 * @method: an HTTP method
4860 * @uri: a #SoupURI representing the URI to retrieve
4861 * @error: return location for a #GError, or %NULL
4863 * Creates a #SoupRequest for retrieving @uri, which must be an
4864 * "http" or "https" URI (or another protocol listed in @session's
4865 * #SoupSession:http-aliases or #SoupSession:https-aliases).
4867 * Return value: (transfer full): a new #SoupRequestHTTP, or
4873 soup_session_request_http_uri (SoupSession *session,
4880 req = soup_session_request_uri (session, uri, error);
4884 return initialize_http_request (req, method, error);
4888 * SOUP_REQUEST_ERROR:
4890 * A #GError domain for #SoupRequest<!-- -->-related errors. Used with
4891 * #SoupRequestError.
4897 * @SOUP_REQUEST_ERROR_BAD_URI: the URI could not be parsed
4898 * @SOUP_REQUEST_ERROR_UNSUPPORTED_URI_SCHEME: the URI scheme is not
4899 * supported by this #SoupSession
4900 * @SOUP_REQUEST_ERROR_PARSING: the server's response could not
4902 * @SOUP_REQUEST_ERROR_ENCODING: the server's response was in an
4903 * unsupported format
4905 * A #SoupRequest error.
4911 soup_request_error_quark (void)
4913 static GQuark error;
4915 error = g_quark_from_static_string ("soup_request_error_quark");
4919 #if ENABLE(TIZEN_CERTIFICATE_FILE_SET)
4921 set_tls_certificate_file (gpointer session)
4924 soup_session_set_certificate_file(session);
4930 soup_session_tls_start_idle_timer (SoupSession *session, guint idle_timeout)
4932 SoupSessionPrivate *priv = SOUP_SESSION_GET_PRIVATE (session);
4934 TIZEN_LOGI ("timeout[%d]", idle_timeout);
4935 if (priv && idle_timeout > 0 && !priv->tls_idle_timeout_src) {
4936 priv->tls_idle_timeout_src =
4937 soup_add_timeout (priv->async_context,
4939 set_tls_certificate_file, session);
4944 soup_session_tls_stop_idle_timer (SoupSession *session)
4946 SoupSessionPrivate *priv = SOUP_SESSION_GET_PRIVATE (session);
4949 if (priv && priv->tls_idle_timeout_src) {
4950 if (!g_source_is_destroyed (priv->tls_idle_timeout_src)) {
4951 TIZEN_LOGI("g_source isn't NULL.");
4952 /* Adding log to cross check if MainContext exists */
4953 TIZEN_LOGE("GMainContext of priv->tls_idle_timeout_src"
4954 " is %p", priv->async_context);
4955 if(priv->async_context)
4956 g_source_destroy (priv->tls_idle_timeout_src);
4958 priv->tls_idle_timeout_src = NULL;
4963 soup_session_is_tls_db_initialized (SoupSession *session)
4965 SoupSessionPrivate *priv = SOUP_SESSION_GET_PRIVATE (session);
4966 if (priv && priv->tlsdb)
4972 #if ENABLE(TIZEN_TV_CREATE_IDLE_TCP_CONNECTION)
4974 static SoupConnection *
4975 get_pre_connection_with_uri (SoupSession *session, SoupURI *uri)
4977 SoupSessionPrivate *priv = SOUP_SESSION_GET_PRIVATE (session);
4978 SoupConnection *conn = NULL;
4979 SoupSessionHost *host = NULL;
4984 g_mutex_lock (&priv->conn_lock);
4985 host = get_host_for_uri (session, uri);
4986 if (host->num_conns >= priv->max_conns_per_host) {
4987 g_mutex_unlock (&priv->conn_lock);
4991 if (priv->num_conns >= priv->max_conns) {
4992 g_mutex_unlock (&priv->conn_lock);
4996 conn = g_object_new (
4997 SOUP_TYPE_CONNECTION,
4998 SOUP_CONNECTION_REMOTE_URI, host->uri,
4999 SOUP_CONNECTION_PROXY_RESOLVER, get_proxy_resolver (session),
5000 SOUP_CONNECTION_SSL, soup_uri_is_https (uri, priv->https_aliases),
5001 SOUP_CONNECTION_SSL_CREDENTIALS, get_tls_database (session),
5002 SOUP_CONNECTION_WIDGET_ENGINE, priv->widget_engine,
5003 SOUP_CONNECTION_SSL_STRICT, priv->ssl_strict && (priv->tlsdb != NULL || SOUP_IS_PLAIN_SESSION (session)),
5004 SOUP_CONNECTION_ASYNC_CONTEXT, priv->async_context,
5005 SOUP_CONNECTION_USE_THREAD_CONTEXT, priv->use_thread_context,
5006 SOUP_CONNECTION_TIMEOUT, priv->io_timeout,
5007 SOUP_CONNECTION_IDLE_TIMEOUT, priv->idle_timeout,
5008 SOUP_CONNECTION_SSL_FALLBACK, host->ssl_fallback,
5009 SOUP_CONNECTION_LOCAL_ADDRESS, priv->local_addr,
5012 g_signal_connect (conn, "disconnected",
5013 G_CALLBACK (connection_disconnected),
5015 g_signal_emit (session, signals[CONNECTION_CREATED], 0, conn);
5018 if (host->keep_alive_src) {
5019 g_source_destroy (host->keep_alive_src);
5020 g_source_unref (host->keep_alive_src);
5021 host->keep_alive_src = NULL;
5023 g_mutex_unlock (&priv->conn_lock);
5024 return g_object_ref (conn);
5028 got_pre_connection (GObject *object, GAsyncResult *result, gpointer user_data)
5030 SoupConnection *conn = SOUP_CONNECTION (object);
5031 SoupSession *session = user_data;
5032 SoupSessionPrivate *priv = SOUP_SESSION_GET_PRIVATE (session);
5033 GError *error = NULL;
5034 SoupSocket *sock = NULL;
5035 SoupURI *uri = NULL;
5036 SoupSessionHost *host = NULL;
5038 soup_connection_connect_finish (conn, result, &error);
5039 sock = soup_connection_get_socket (conn);
5040 if (sock && soup_socket_is_ssl (sock)) {
5041 GTlsCertificateFlags errors;
5043 SOUP_SOCKET_TLS_ERRORS,
5047 if (!error && priv) {
5048 g_mutex_lock (&priv->conn_lock);
5049 soup_connection_set_pre_connect_idle (conn);
5050 g_object_get (G_OBJECT (conn),
5051 SOUP_CONNECTION_REMOTE_URI,
5054 host = get_host_for_uri (session, uri);
5055 g_hash_table_insert (priv->conns, conn, host);
5056 host->connections = g_slist_prepend (host->connections, conn);
5058 g_mutex_unlock (&priv->conn_lock);
5060 soup_connection_disconnect (conn);
5064 pre_connection_accept_certificate (SoupConnection *conn,
5065 GTlsCertificate* certificate,
5066 GTlsCertificateFlags errors,
5069 SoupSession* session = (SoupSession*)user_data;
5070 SoupSessionPrivate *priv = SOUP_SESSION_GET_PRIVATE (session);
5075 if (priv->widget_engine)
5076 return (errors & (G_TLS_CERTIFICATE_UNKNOWN_CA | G_TLS_CERTIFICATE_BAD_IDENTITY | G_TLS_CERTIFICATE_REVOKED | G_TLS_CERTIFICATE_INSECURE | G_TLS_CERTIFICATE_GENERIC_ERROR)) ? FALSE : TRUE;
5081 void soup_session_create_idle_connection(SoupSession *session, SoupURI* pre_uri)
5083 SoupConnection * pre_conn = NULL;
5084 pre_conn = get_pre_connection_with_uri(session, pre_uri);
5087 g_signal_connect (pre_conn, "accept-certificate",
5088 G_CALLBACK (pre_connection_accept_certificate), session);
5089 soup_connection_connect_async(pre_conn, NULL, got_pre_connection, session);