Remove build warning
[platform/upstream/libsoup.git] / libsoup / soup-session.c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3  * soup-session.c
4  *
5  * Copyright (C) 2000-2003, Ximian, Inc.
6  */
7
8 #ifdef HAVE_CONFIG_H
9 #include <config.h>
10 #endif
11
12 #include <glib/gi18n-lib.h>
13
14 #include "soup-session.h"
15 #include "soup.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"
24 #include "TIZEN.h"
25
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
30 #endif
31
32 #define MAX_STRING_LEN 256
33 #define HWCLOCK_LOG(s)  {const char *str=s; prctl(PR_TASK_PERF_USER_TRACE, str, strlen(str));}
34
35 static void prctl_with_url(const char *prestr, const char *url)
36 {
37         char s[MAX_STRING_LEN] = "";
38         int len_max = 120;
39         int len_pre = strlen(prestr);
40         int len_url = strlen(url);
41
42         strncpy(s, prestr, len_pre);
43         if(len_pre + len_url < len_max) {
44                 strncpy(s+len_pre, url, len_url);
45         }
46         else {
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);
51         }
52         prctl(PR_TASK_PERF_USER_TRACE, s, strlen(s));
53 }
54
55 static void prctl_with_url_and_free(const char *prestr, char *url)
56 {
57         prctl_with_url(prestr, url);
58         g_free(url);
59 }
60 #endif
61
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 */
65 #endif
66
67 /**
68  * SECTION:soup-session
69  * @short_description: Soup session state object
70  *
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.
76  *
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
84  * user.)
85  *
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
95  * #SoupSessionSync.)
96  **/
97
98 static void
99 soup_init (void)
100 {
101         bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
102 #ifdef HAVE_BIND_TEXTDOMAIN_CODESET
103         bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
104 #endif
105 }
106
107 typedef struct {
108         SoupURI     *uri;
109         SoupAddress *addr;
110
111         GSList      *connections;      /* CONTAINS: SoupConnection */
112         guint        num_conns;
113
114         guint        num_messages;
115
116         gboolean     ssl_fallback;
117
118         GSource     *keep_alive_src;
119         SoupSession *session;
120 } SoupSessionHost;
121 static guint soup_host_uri_hash (gconstpointer key);
122 static gboolean soup_host_uri_equal (gconstpointer v1, gconstpointer v2);
123
124 typedef struct {
125         SoupSession *session;
126         gboolean disposed;
127
128         GTlsDatabase *tlsdb;
129         char *ssl_ca_file;
130         gboolean ssl_strict;
131         gboolean tlsdb_use_default;
132
133         SoupMessageQueue *queue;
134
135         char *user_agent;
136         char *accept_language;
137         gboolean accept_language_auto;
138
139         GSList *features;
140         GHashTable *features_cache;
141
142         GHashTable *http_hosts, *https_hosts; /* char* -> SoupSessionHost */
143         GHashTable *conns; /* SoupConnection -> SoupSessionHost */
144         guint num_conns;
145         guint max_conns, max_conns_per_host;
146         guint io_timeout, idle_timeout;
147
148         SoupAddress *local_addr;
149
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.
156          */
157         GMutex conn_lock;
158         GCond conn_cond;
159
160         GMainContext *async_context;
161         gboolean use_thread_context;
162         GSList *run_queue_sources;
163
164         GResolver *resolver;
165         GProxyResolver *proxy_resolver;
166         gboolean proxy_use_default;
167         SoupURI *proxy_uri;
168
169         char **http_aliases, **https_aliases;
170 #if ENABLE(TIZEN_CERTIFICATE_FILE_SET)
171         GSource *tls_idle_timeout_src;
172         char *certificate_path;
173 #endif
174 #if ENABLE(TIZEN_TV_CLIENT_CERTIFICATE)
175         gboolean widget_engine;
176 #endif
177         GHashTable *request_types;
178 } SoupSessionPrivate;
179 #define SOUP_SESSION_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), SOUP_TYPE_SESSION, SoupSessionPrivate))
180
181 #define SOUP_IS_PLAIN_SESSION(o) (G_TYPE_FROM_INSTANCE (o) == SOUP_TYPE_SESSION)
182
183 static void free_host (SoupSessionHost *host);
184 static void connection_state_changed (GObject *object, GParamSpec *param,
185                                       gpointer user_data);
186 static void connection_disconnected (SoupConnection *conn, gpointer user_data);
187 static void drop_connection (SoupSession *session, SoupSessionHost *host,
188                              SoupConnection *conn);
189
190 static void auth_manager_authenticate (SoupAuthManager *manager,
191                                        SoupMessage *msg, SoupAuth *auth,
192                                        gboolean retrying, gpointer user_data);
193
194 static void async_run_queue (SoupSession *session);
195
196 static void async_send_request_running (SoupSession *session, SoupMessageQueueItem *item);
197
198 #define SOUP_SESSION_MAX_CONNS_DEFAULT 10
199 #define SOUP_SESSION_MAX_CONNS_PER_HOST_DEFAULT 2
200
201 #define SOUP_SESSION_MAX_RESEND_COUNT 20
202
203 #define SOUP_SESSION_USER_AGENT_BASE "libsoup/" PACKAGE_VERSION
204
205 G_DEFINE_TYPE_WITH_CODE (SoupSession, soup_session, G_TYPE_OBJECT,
206                          soup_init ();
207                          )
208
209 enum {
210         REQUEST_QUEUED,
211         REQUEST_STARTED,
212         REQUEST_UNQUEUED,
213         AUTHENTICATE,
214         CONNECTION_CREATED,
215         TUNNELING,
216         LAST_SIGNAL
217 };
218
219 static guint signals[LAST_SIGNAL] = { 0 };
220
221 enum {
222         PROP_0,
223
224         PROP_PROXY_URI,
225         PROP_PROXY_RESOLVER,
226         PROP_MAX_CONNS,
227         PROP_MAX_CONNS_PER_HOST,
228         PROP_USE_NTLM,
229         PROP_SSL_CA_FILE,
230         PROP_SSL_USE_SYSTEM_CA_FILE,
231         PROP_TLS_DATABASE,
232         PROP_SSL_STRICT,
233         PROP_ASYNC_CONTEXT,
234         PROP_USE_THREAD_CONTEXT,
235         PROP_TIMEOUT,
236         PROP_USER_AGENT,
237         PROP_ACCEPT_LANGUAGE,
238         PROP_ACCEPT_LANGUAGE_AUTO,
239         PROP_IDLE_TIMEOUT,
240         PROP_ADD_FEATURE,
241         PROP_ADD_FEATURE_BY_TYPE,
242         PROP_REMOVE_FEATURE_BY_TYPE,
243         PROP_HTTP_ALIASES,
244         PROP_HTTPS_ALIASES,
245         PROP_LOCAL_ADDRESS,
246 #if ENABLE(TIZEN_CERTIFICATE_FILE_SET)
247         PROP_CERTIFICATE_PATH,
248 #endif
249 #if ENABLE(TIZEN_TV_CLIENT_CERTIFICATE)
250         PROP_WIDGET_ENGINE,
251 #endif
252
253         LAST_PROP
254 };
255
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);
262 #endif
263
264 static void
265 soup_session_init (SoupSession *session)
266 {
267         SoupSessionPrivate *priv = SOUP_SESSION_GET_PRIVATE (session);
268         SoupAuthManager *auth_manager;
269
270         priv->session = session;
271
272         priv->queue = soup_message_queue_new (session);
273
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,
277                                                   soup_host_uri_equal,
278                                                   NULL, (GDestroyNotify)free_host);
279         priv->https_hosts = g_hash_table_new_full (soup_host_uri_hash,
280                                                    soup_host_uri_equal,
281                                                    NULL, (GDestroyNotify)free_host);
282         priv->conns = g_hash_table_new (NULL, NULL);
283
284         priv->max_conns = SOUP_SESSION_MAX_CONNS_DEFAULT;
285         priv->max_conns_per_host = SOUP_SESSION_MAX_CONNS_PER_HOST_DEFAULT;
286
287         priv->features_cache = g_hash_table_new (NULL, NULL);
288
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);
298
299         /* We'll be doing DNS continuously-ish while the session is active,
300          * so hold a ref on the default GResolver.
301          */
302         priv->resolver = g_resolver_get_default ();
303
304         priv->ssl_strict = TRUE;
305
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;
312 #endif
313
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);
319 }
320
321 static GObject *
322 soup_session_constructor (GType                  type,
323                           guint                  n_construct_properties,
324                           GObjectConstructParam *construct_params)
325 {
326         GObject *object;
327
328         object = G_OBJECT_CLASS (soup_session_parent_class)->constructor (type, n_construct_properties, construct_params);
329
330         /* If this is a "plain" SoupSession, fix up the default
331          * properties values, etc.
332          */
333         if (type == SOUP_TYPE_SESSION) {
334                 SoupSession *session = SOUP_SESSION (object);
335                 SoupSessionPrivate *priv = SOUP_SESSION_GET_PRIVATE (session);
336
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;
340
341                 priv->io_timeout = priv->idle_timeout = 60;
342
343                 priv->http_aliases[0] = NULL;
344
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.
348                  */
349                 priv->proxy_use_default = TRUE;
350                 priv->tlsdb_use_default = TRUE;
351
352                 soup_session_add_feature_by_type (session, SOUP_TYPE_CONTENT_DECODER);
353         }
354
355         return object;
356 }
357
358 static void
359 soup_session_dispose (GObject *object)
360 {
361         SoupSession *session = SOUP_SESSION (object);
362         SoupSessionPrivate *priv = SOUP_SESSION_GET_PRIVATE (session);
363         GSList *iter;
364
365         priv->disposed = TRUE;
366
367         for (iter = priv->run_queue_sources; iter; iter = iter->next) {
368                 g_source_destroy (iter->data);
369                 g_source_unref (iter->data);
370         }
371         g_clear_pointer (&priv->run_queue_sources, g_slist_free);
372
373         priv->disposed = TRUE;
374         soup_session_abort (session);
375         g_warn_if_fail (g_hash_table_size (priv->conns) == 0);
376
377         while (priv->features)
378                 soup_session_remove_feature (session, priv->features->data);
379
380         G_OBJECT_CLASS (soup_session_parent_class)->dispose (object);
381 }
382
383 static void
384 soup_session_finalize (GObject *object)
385 {
386         SoupSession *session = SOUP_SESSION (object);
387         SoupSessionPrivate *priv = SOUP_SESSION_GET_PRIVATE (session);
388
389         soup_message_queue_destroy (priv->queue);
390
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);
396
397         g_free (priv->user_agent);
398         g_free (priv->accept_language);
399
400         g_clear_object (&priv->tlsdb);
401         g_free (priv->ssl_ca_file);
402
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;
407 #endif
408         g_clear_pointer (&priv->async_context, g_main_context_unref);
409         g_clear_object (&priv->local_addr);
410
411         g_hash_table_destroy (priv->features_cache);
412
413         g_object_unref (priv->resolver);
414         g_clear_object (&priv->proxy_resolver);
415         g_clear_pointer (&priv->proxy_uri, soup_uri_free);
416
417         g_free (priv->http_aliases);
418         g_free (priv->https_aliases);
419
420         g_hash_table_destroy (priv->request_types);
421
422         G_OBJECT_CLASS (soup_session_parent_class)->finalize (object);
423 }
424
425 /* Converts a language in POSIX format and to be RFC2616 compliant    */
426 /* Based on code from epiphany-webkit (ephy_langs_append_languages()) */
427 static gchar *
428 posix_lang_to_rfc2616 (const gchar *language)
429 {
430         /* Don't include charset variants, etc */
431         if (strchr (language, '.') || strchr (language, '@'))
432                 return NULL;
433
434         /* Ignore "C" locale, which g_get_language_names() always
435          * includes as a fallback.
436          */
437         if (!strcmp (language, "C"))
438                 return NULL;
439
440         return g_strdelimit (g_ascii_strdown (language, -1), "_", '-');
441 }
442
443 /* Converts @quality from 0-100 to 0.0-1.0 and appends to @str */
444 static gchar *
445 add_quality_value (const gchar *str, int quality)
446 {
447         g_return_val_if_fail (str != NULL, NULL);
448
449         if (quality >= 0 && quality < 100) {
450                 /* We don't use %.02g because of "." vs "," locale issues */
451                 if (quality % 10)
452                         return g_strdup_printf ("%s;q=0.%02d", str, quality);
453                 else
454                         return g_strdup_printf ("%s;q=0.%d", str, quality / 10);
455         } else
456                 return g_strdup (str);
457 }
458
459 /* Returns a RFC2616 compliant languages list from system locales */
460 static gchar *
461 accept_languages_from_system (void)
462 {
463         const char * const * lang_names;
464         GPtrArray *langs = NULL;
465         char *lang, *langs_str;
466         int delta;
467         int i;
468
469         lang_names = g_get_language_names ();
470         g_return_val_if_fail (lang_names != NULL, NULL);
471
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]);
476                 if (lang)
477                         g_ptr_array_add (langs, lang);
478         }
479
480         /* Add quality values */
481         if (langs->len < 10)
482                 delta = 10;
483         else if (langs->len < 20)
484                 delta = 5;
485         else
486                 delta = 1;
487
488         for (i = 0; i < langs->len; i++) {
489                 lang = langs->pdata[i];
490                 langs->pdata[i] = add_quality_value (lang, 100 - i * delta);
491                 g_free (lang);
492         }
493
494         /* Fallback: add "en" if list is empty */
495         if (langs->len == 0)
496                 g_ptr_array_add (langs, g_strdup ("en"));
497
498         g_ptr_array_add (langs, NULL);
499         langs_str = g_strjoinv (", ", (char **)langs->pdata);
500         g_ptr_array_free (langs, TRUE);
501
502         return langs_str;
503 }
504
505 static void
506 set_tlsdb (SoupSession *session, GTlsDatabase *tlsdb)
507 {
508         SoupSessionPrivate *priv = SOUP_SESSION_GET_PRIVATE (session);
509         GTlsDatabase *system_default;
510
511         priv->tlsdb_use_default = FALSE;
512         if (tlsdb == priv->tlsdb)
513                 return;
514
515         g_object_freeze_notify (G_OBJECT (session));
516
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");
521                 }
522                 g_object_unref (system_default);
523         }
524
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");
529         }
530
531         if (priv->tlsdb)
532                 g_object_unref (priv->tlsdb);
533         priv->tlsdb = tlsdb;
534         if (priv->tlsdb)
535                 g_object_ref (priv->tlsdb);
536
537         g_object_notify (G_OBJECT (session), "tls-database");
538         g_object_thaw_notify (G_OBJECT (session));
539 }
540
541 static void
542 set_use_system_ca_file (SoupSession *session, gboolean use_system_ca_file)
543 {
544         SoupSessionPrivate *priv = SOUP_SESSION_GET_PRIVATE (session);
545         GTlsDatabase *system_default;
546
547         priv->tlsdb_use_default = FALSE;
548
549         system_default = g_tls_backend_get_default_database (g_tls_backend_get_default ());
550
551         if (use_system_ca_file)
552                 set_tlsdb (session, system_default);
553         else if (priv->tlsdb == system_default)
554                 set_tlsdb (session, NULL);
555
556         g_clear_object (&system_default);
557 }
558
559 static void
560 set_ssl_ca_file (SoupSession *session, const char *ssl_ca_file)
561 {
562         SoupSessionPrivate *priv = SOUP_SESSION_GET_PRIVATE (session);
563         GTlsDatabase *tlsdb;
564         GError *error = NULL;
565
566         priv->tlsdb_use_default = FALSE;
567         if (!g_strcmp0 (priv->ssl_ca_file, ssl_ca_file))
568                 return;
569
570         g_object_freeze_notify (G_OBJECT (session));
571
572         if (g_path_is_absolute (ssl_ca_file))
573                 tlsdb = g_tls_file_database_new (ssl_ca_file, &error);
574         else {
575                 char *path, *cwd;
576
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);
580                 g_free (path);
581                 g_free (cwd);
582         }
583
584         if (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);
588
589                         tlsdb = g_tls_file_database_new ("/dev/null", NULL);
590                 }
591                 g_error_free (error);
592         }
593
594         set_tlsdb (session, tlsdb);
595         if (tlsdb) {
596                 g_object_unref (tlsdb);
597
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");
603         }
604
605         g_object_thaw_notify (G_OBJECT (session));
606 }
607
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.
610  */
611 static void
612 set_aliases (char ***variable, char **value)
613 {
614         int len, i;
615
616         if (*variable)
617                 g_free (*variable);
618
619         if (!value) {
620                 *variable = NULL;
621                 return;
622         }
623
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;
629 }
630
631 static void
632 set_proxy_resolver (SoupSession *session, SoupURI *uri,
633                     SoupProxyURIResolver *soup_resolver,
634                     GProxyResolver *g_resolver)
635 {
636         SoupSessionPrivate *priv = SOUP_SESSION_GET_PRIVATE (session);
637
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;
644
645         if (uri) {
646                 char *uri_string;
647
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);
651                 g_free (uri_string);
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 ());
656                 else
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);
661 }
662
663 static void
664 soup_session_set_property (GObject *object, guint prop_id,
665                            const GValue *value, GParamSpec *pspec)
666 {
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;
672
673         switch (prop_id) {
674         case PROP_LOCAL_ADDRESS:
675                 priv->local_addr = g_value_dup_object (value);
676                 break;
677         case PROP_PROXY_URI:
678                 set_proxy_resolver (session, g_value_get_boxed (value),
679                                     NULL, NULL);
680                 soup_session_abort (session);
681                 break;
682         case PROP_PROXY_RESOLVER:
683                 set_proxy_resolver (session, NULL, NULL,
684                                     g_value_get_object (value));
685                 break;
686         case PROP_MAX_CONNS:
687                 priv->max_conns = g_value_get_int (value);
688                 break;
689         case PROP_MAX_CONNS_PER_HOST:
690                 priv->max_conns_per_host = g_value_get_int (value);
691                 break;
692         case PROP_USE_NTLM:
693                 g_return_if_fail (!SOUP_IS_PLAIN_SESSION (session));
694                 feature = soup_session_get_feature (session, SOUP_TYPE_AUTH_MANAGER);
695                 if (feature) {
696                         if (g_value_get_boolean (value))
697                                 soup_session_feature_add_feature (feature, SOUP_TYPE_AUTH_NTLM);
698                         else
699                                 soup_session_feature_remove_feature (feature, SOUP_TYPE_AUTH_NTLM);
700                 } else
701                         g_warning ("Trying to set use-ntlm on session with no auth-manager");
702                 break;
703         case PROP_SSL_CA_FILE:
704                 set_ssl_ca_file (session, g_value_get_string (value));
705                 break;
706         case PROP_SSL_USE_SYSTEM_CA_FILE:
707                 set_use_system_ca_file (session, g_value_get_boolean (value));
708                 break;
709         case PROP_TLS_DATABASE:
710                 set_tlsdb (session, g_value_get_object (value));
711                 break;
712         case PROP_SSL_STRICT:
713                 priv->ssl_strict = g_value_get_boolean (value);
714                 break;
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);
722                 break;
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);
733                 }
734                 break;
735         case PROP_TIMEOUT:
736                 priv->io_timeout = g_value_get_uint (value);
737                 break;
738         case PROP_USER_AGENT:
739                 g_free (priv->user_agent);
740                 user_agent = g_value_get_string (value);
741                 if (!user_agent)
742                         priv->user_agent = NULL;
743                 else if (!*user_agent) {
744                         priv->user_agent =
745                                 g_strdup (SOUP_SESSION_USER_AGENT_BASE);
746                 } else if (g_str_has_suffix (user_agent, " ")) {
747                         priv->user_agent =
748                                 g_strdup_printf ("%s%s", user_agent,
749                                                  SOUP_SESSION_USER_AGENT_BASE);
750                 } else
751                         priv->user_agent = g_strdup (user_agent);
752                 break;
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;
757                 break;
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;
763                 }
764
765                 /* Get languages from system if needed */
766                 if (priv->accept_language_auto)
767                         priv->accept_language = accept_languages_from_system ();
768                 break;
769         case PROP_IDLE_TIMEOUT:
770                 priv->idle_timeout = g_value_get_uint (value);
771                 break;
772         case PROP_ADD_FEATURE:
773                 soup_session_add_feature (session, g_value_get_object (value));
774                 break;
775         case PROP_ADD_FEATURE_BY_TYPE:
776                 soup_session_add_feature_by_type (session, g_value_get_gtype (value));
777                 break;
778         case PROP_REMOVE_FEATURE_BY_TYPE:
779                 soup_session_remove_feature_by_type (session, g_value_get_gtype (value));
780                 break;
781         case PROP_HTTP_ALIASES:
782                 set_aliases (&priv->http_aliases, g_value_get_boxed (value));
783                 break;
784         case PROP_HTTPS_ALIASES:
785                 set_aliases (&priv->https_aliases, g_value_get_boxed (value));
786                 break;
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;
792                 }
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);
798 #endif
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);
803 #else
804                         soup_session_tls_start_idle_timer(session, SET_TLS_CERT_FILE_TIMEOUT);
805 #endif
806                 break;
807 #endif
808 #if ENABLE(TIZEN_TV_CLIENT_CERTIFICATE)
809         case PROP_WIDGET_ENGINE:
810                 priv->widget_engine = g_value_get_boolean (value);
811                 break;
812 #endif
813         default:
814                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
815                 break;
816         }
817 }
818
819 static GProxyResolver *
820 get_proxy_resolver (SoupSession *session)
821 {
822         SoupSessionPrivate *priv = SOUP_SESSION_GET_PRIVATE (session);
823
824         if (priv->proxy_use_default) {
825                 priv->proxy_resolver = g_object_ref (g_proxy_resolver_get_default ());
826                 priv->proxy_use_default = FALSE;
827         }
828         return priv->proxy_resolver;
829 }
830
831 static GTlsDatabase *
832 get_tls_database (SoupSession *session)
833 {
834         SoupSessionPrivate *priv = SOUP_SESSION_GET_PRIVATE (session);
835
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;
839         }
840         return priv->tlsdb;
841 }
842
843 static void
844 soup_session_get_property (GObject *object, guint prop_id,
845                            GValue *value, GParamSpec *pspec)
846 {
847         SoupSession *session = SOUP_SESSION (object);
848         SoupSessionPrivate *priv = SOUP_SESSION_GET_PRIVATE (session);
849         SoupSessionFeature *feature;
850         GTlsDatabase *tlsdb;
851
852         switch (prop_id) {
853         case PROP_LOCAL_ADDRESS:
854                 g_value_set_object (value, priv->local_addr);
855                 break;
856         case PROP_PROXY_URI:
857                 g_value_set_boxed (value, priv->proxy_uri);
858                 break;
859         case PROP_PROXY_RESOLVER:
860                 g_value_set_object (value, get_proxy_resolver (session));
861                 break;
862         case PROP_MAX_CONNS:
863                 g_value_set_int (value, priv->max_conns);
864                 break;
865         case PROP_MAX_CONNS_PER_HOST:
866                 g_value_set_int (value, priv->max_conns_per_host);
867                 break;
868         case PROP_USE_NTLM:
869                 feature = soup_session_get_feature (session, SOUP_TYPE_AUTH_MANAGER);
870                 if (feature)
871                         g_value_set_boolean (value, soup_session_feature_has_feature (feature, SOUP_TYPE_AUTH_NTLM));
872                 else
873                         g_value_set_boolean (value, FALSE);
874                 break;
875         case PROP_SSL_CA_FILE:
876                 g_value_set_string (value, priv->ssl_ca_file);
877                 break;
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);
882                 break;
883         case PROP_TLS_DATABASE:
884                 g_value_set_object (value, get_tls_database (session));
885                 break;
886         case PROP_SSL_STRICT:
887                 g_value_set_boolean (value, priv->ssl_strict);
888                 break;
889         case PROP_ASYNC_CONTEXT:
890                 g_value_set_pointer (value, priv->async_context ? g_main_context_ref (priv->async_context) : NULL);
891                 break;
892         case PROP_USE_THREAD_CONTEXT:
893                 g_value_set_boolean (value, priv->use_thread_context);
894                 break;
895         case PROP_TIMEOUT:
896                 g_value_set_uint (value, priv->io_timeout);
897                 break;
898         case PROP_USER_AGENT:
899                 g_value_set_string (value, priv->user_agent);
900                 break;
901         case PROP_ACCEPT_LANGUAGE:
902                 g_value_set_string (value, priv->accept_language);
903                 break;
904         case PROP_ACCEPT_LANGUAGE_AUTO:
905                 g_value_set_boolean (value, priv->accept_language_auto);
906                 break;
907         case PROP_IDLE_TIMEOUT:
908                 g_value_set_uint (value, priv->idle_timeout);
909                 break;
910         case PROP_HTTP_ALIASES:
911                 g_value_set_boxed (value, priv->http_aliases);
912                 break;
913         case PROP_HTTPS_ALIASES:
914                 g_value_set_boxed (value, priv->https_aliases);
915                 break;
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");
920 #endif
921                 g_value_set_string (value, priv->certificate_path);
922                 break;
923 #endif
924 #if ENABLE(TIZEN_TV_CLIENT_CERTIFICATE)
925         case PROP_WIDGET_ENGINE:
926                 g_value_set_boolean (value, priv->widget_engine);
927                 break;
928 #endif
929         default:
930                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
931                 break;
932         }
933 }
934
935 /**
936  * soup_session_new:
937  *
938  * Creates a #SoupSession with the default options.
939  *
940  * Return value: the new session.
941  *
942  * Since: 2.42
943  */
944 SoupSession *
945 soup_session_new (void)
946 {
947         return g_object_new (SOUP_TYPE_SESSION, NULL);
948 }
949
950 /**
951  * soup_session_new_with_options:
952  * @optname1: name of first property to set
953  * @...: value of @optname1, followed by additional property/value pairs
954  *
955  * Creates a #SoupSession with the specified options.
956  *
957  * Return value: the new session.
958  *
959  * Since: 2.42
960  */
961 SoupSession *
962 soup_session_new_with_options (const char *optname1,
963                                ...)
964 {
965         SoupSession *session;
966         va_list ap;
967
968         va_start (ap, optname1);
969         session = (SoupSession *)g_object_new_valist (SOUP_TYPE_SESSION,
970                                                       optname1, ap);
971         va_end (ap);
972
973         return session;
974 }
975
976 /**
977  * soup_session_get_async_context:
978  * @session: a #SoupSession
979  *
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.
983  *
984  * For a modern #SoupSession, this will always just return the
985  * thread-default #GMainContext, and so is not especially useful.
986  *
987  * Return value: (transfer none): @session's #GMainContext, which may
988  * be %NULL
989  **/
990 GMainContext *
991 soup_session_get_async_context (SoupSession *session)
992 {
993         SoupSessionPrivate *priv;
994
995         g_return_val_if_fail (SOUP_IS_SESSION (session), NULL);
996         priv = SOUP_SESSION_GET_PRIVATE (session);
997
998         if (priv->use_thread_context)
999                 return g_main_context_get_thread_default ();
1000         else
1001                 return priv->async_context;
1002 }
1003
1004 /* Hosts */
1005
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.
1009  */
1010 static guint
1011 soup_host_uri_hash (gconstpointer key)
1012 {
1013         const SoupURI *uri = key;
1014
1015         g_return_val_if_fail (uri != NULL && uri->host != NULL, 0);
1016
1017         return uri->port + soup_str_case_hash (uri->host);
1018 }
1019
1020 static gboolean
1021 soup_host_uri_equal (gconstpointer v1, gconstpointer v2)
1022 {
1023         const SoupURI *one = v1;
1024         const SoupURI *two = v2;
1025
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);
1028
1029         if (one->port != two->port)
1030                 return FALSE;
1031
1032         return g_ascii_strcasecmp (one->host, two->host) == 0;
1033 }
1034
1035
1036 static SoupSessionHost *
1037 soup_session_host_new (SoupSession *session, SoupURI *uri)
1038 {
1039         SoupSessionHost *host;
1040
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);
1046
1047                 if (soup_uri_is_https (host->uri, priv->https_aliases))
1048                         host->uri->scheme = SOUP_URI_SCHEME_HTTPS;
1049                 else
1050                         host->uri->scheme = SOUP_URI_SCHEME_HTTP;
1051         }
1052
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,
1057                                    NULL);
1058         host->keep_alive_src = NULL;
1059         host->session = session;
1060
1061         return host;
1062 }
1063
1064 /* Requires conn_lock to be locked */
1065 static SoupSessionHost *
1066 get_host_for_uri (SoupSession *session, SoupURI *uri)
1067 {
1068         SoupSessionPrivate *priv = SOUP_SESSION_GET_PRIVATE (session);
1069         SoupSessionHost *host;
1070
1071         if (soup_uri_is_https (uri, priv->https_aliases))
1072                 host = g_hash_table_lookup (priv->https_hosts, uri);
1073         else
1074                 host = g_hash_table_lookup (priv->http_hosts, uri);
1075         if (host)
1076                 return host;
1077
1078         host = soup_session_host_new (session, uri);
1079
1080         if (soup_uri_is_https (uri, priv->https_aliases))
1081                 g_hash_table_insert (priv->https_hosts, host->uri, host);
1082         else
1083                 g_hash_table_insert (priv->http_hosts, host->uri, host);
1084
1085         return host;
1086 }
1087
1088 /* Requires conn_lock to be locked */
1089 static SoupSessionHost *
1090 get_host_for_message (SoupSession *session, SoupMessage *msg)
1091 {
1092         return get_host_for_uri (session, soup_message_get_uri (msg));
1093 }
1094
1095 static void
1096 free_host (SoupSessionHost *host)
1097 {
1098         g_warn_if_fail (host->connections == NULL);
1099
1100         if (host->keep_alive_src) {
1101                 g_source_destroy (host->keep_alive_src);
1102                 g_source_unref (host->keep_alive_src);
1103         }
1104
1105         soup_uri_free (host->uri);
1106         g_object_unref (host->addr);
1107         g_slice_free (SoupSessionHost, host);
1108 }
1109
1110 static void
1111 auth_manager_authenticate (SoupAuthManager *manager, SoupMessage *msg,
1112                            SoupAuth *auth, gboolean retrying,
1113                            gpointer session)
1114 {
1115 #if ENABLE(TIZEN_ON_AUTHENTICATION_REQUESTED)
1116         soup_message_authenticate(msg, auth, retrying);
1117 #endif
1118         g_signal_emit (session, signals[AUTHENTICATE], 0, msg, auth, retrying);
1119 }
1120
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))
1130 #else
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))
1137 #endif
1138
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))
1144
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)
1149 #endif
1150
1151 static inline SoupURI *
1152 redirection_uri (SoupMessage *msg)
1153 {
1154         const char *new_loc;
1155         SoupURI *new_uri;
1156
1157         new_loc = soup_message_headers_get_one (msg->response_headers,
1158                                                 "Location");
1159         if (!new_loc)
1160                 return NULL;
1161         new_uri = soup_uri_new_with_base (soup_message_get_uri (msg), new_loc);
1162         if (!new_uri || !new_uri->host) {
1163                 if (new_uri)
1164                         soup_uri_free (new_uri);
1165                 return NULL;
1166         }
1167
1168         return new_uri;
1169 }
1170
1171 /**
1172  * soup_session_would_redirect:
1173  * @session: a #SoupSession
1174  * @msg: a #SoupMessage that has response headers
1175  *
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).
1179  *
1180  * Return value: whether @msg would be redirected
1181  *
1182  * Since: 2.38
1183  */
1184 gboolean
1185 soup_session_would_redirect (SoupSession *session, SoupMessage *msg)
1186 {
1187         SoupSessionPrivate *priv = SOUP_SESSION_GET_PRIVATE (session);
1188         SoupURI *new_uri;
1189
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)
1195 #endif
1196         )
1197                 return FALSE;
1198
1199         /* and a Location header that parses to an http URI */
1200         if (!soup_message_headers_get_one (msg->response_headers, "Location"))
1201                 return FALSE;
1202         new_uri = redirection_uri (msg);
1203         if (!new_uri)
1204                 return FALSE;
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);
1209                 return FALSE;
1210         }
1211
1212         soup_uri_free (new_uri);
1213         return TRUE;
1214 }
1215
1216 /**
1217  * soup_session_redirect_message:
1218  * @session: the session
1219  * @msg: a #SoupMessage that has received a 3xx response
1220  *
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).
1227  *
1228  * If @msg's status code indicates that it should be retried as a GET
1229  * request, then @msg will be modified accordingly.
1230  *
1231  * If @msg has already been redirected too many times, this will
1232  * cause it to fail with %SOUP_STATUS_TOO_MANY_REDIRECTS.
1233  *
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
1236  * parsed).
1237  *
1238  * Since: 2.38
1239  */
1240 gboolean
1241 soup_session_redirect_message (SoupSession *session, SoupMessage *msg)
1242 {
1243         SoupURI *new_uri;
1244
1245         new_uri = redirection_uri (msg);
1246         if (!new_uri)
1247                 return FALSE;
1248
1249         if (SOUP_SESSION_WOULD_REDIRECT_AS_GET (session, msg)) {
1250                 if (msg->method != SOUP_METHOD_HEAD) {
1251                         g_object_set (msg,
1252                                       SOUP_MESSAGE_METHOD, SOUP_METHOD_GET,
1253                                       NULL);
1254                 }
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);
1259         }
1260
1261         soup_message_set_uri (msg, new_uri);
1262         soup_uri_free (new_uri);
1263
1264         soup_session_requeue_message (session, msg);
1265         return TRUE;
1266 }
1267
1268 static void
1269 redirect_handler (SoupMessage *msg, gpointer user_data)
1270 {
1271         SoupMessageQueueItem *item = user_data;
1272         SoupSession *session = item->session;
1273
1274         if (!soup_session_would_redirect (session, msg)) {
1275                 SoupURI *new_uri = redirection_uri (msg);
1276                 gboolean invalid = !new_uri || !new_uri->host;
1277
1278                 if (new_uri)
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");
1284                 }
1285                 return;
1286         }
1287
1288         soup_session_redirect_message (session, msg);
1289 }
1290
1291 static void
1292 re_emit_connection_event (SoupConnection      *conn,
1293                           GSocketClientEvent   event,
1294                           GIOStream           *connection,
1295                           gpointer             user_data)
1296 {
1297         SoupMessageQueueItem *item = user_data;
1298
1299         soup_message_network_event (item->msg, event, connection);
1300 }
1301
1302 #if ENABLE(TIZEN_TV_DYNAMIC_CERTIFICATE_LOADING)
1303 const char*
1304 re_emit_connection_dynamic_client_certificate (SoupConnection      *conn,
1305                                                const char* current_host,
1306                                                gpointer user_data)
1307 {
1308         SoupMessageQueueItem *item = user_data;
1309
1310         return soup_message_dynamic_client_certificate(item->msg, current_host);
1311 }
1312 #endif
1313
1314 #if ENABLE(TIZEN_TV_CERTIFICATE_HANDLING)
1315 gboolean
1316 re_emit_connection_accept_certificate (SoupConnection      *conn,
1317                                         GTlsCertificate* certificate,
1318                                         GTlsCertificateFlags errors,
1319                                         gpointer             user_data)
1320 {
1321         SoupMessageQueueItem *item = user_data;
1322
1323         return soup_message_accept_certificate(item->msg, certificate, errors);
1324 }
1325 #endif
1326
1327 static void
1328 soup_session_set_item_connection (SoupSession          *session,
1329                                   SoupMessageQueueItem *item,
1330                                   SoupConnection       *conn)
1331 {
1332         if (item->conn) {
1333                 g_signal_handlers_disconnect_by_func (item->conn, re_emit_connection_event, item);
1334                 g_object_unref (item->conn);
1335         }
1336
1337         item->conn = conn;
1338         soup_message_set_connection (item->msg, conn);
1339
1340         if (item->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);
1348 #endif
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);
1353 #endif
1354         }
1355 }
1356
1357 static void
1358 message_restarted (SoupMessage *msg, gpointer user_data)
1359 {
1360         SoupMessageQueueItem *item = user_data;
1361
1362         if (item->conn &&
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);
1368         }
1369
1370         soup_message_cleanup_response (msg);
1371 }
1372
1373 SoupMessageQueueItem *
1374 soup_session_append_queue_item (SoupSession *session, SoupMessage *msg,
1375                                 gboolean async, gboolean new_api,
1376                                 SoupSessionCallback callback, gpointer user_data)
1377 {
1378         SoupSessionPrivate *priv = SOUP_SESSION_GET_PRIVATE (session);
1379         SoupMessageQueueItem *item;
1380         SoupSessionHost *host;
1381
1382         soup_message_cleanup_response (msg);
1383
1384         item = soup_message_queue_append (priv->queue, msg, callback, user_data);
1385         item->async = async;
1386         item->new_api = new_api;
1387
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);
1392
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);
1397         }
1398         g_signal_connect (msg, "restarted",
1399                           G_CALLBACK (message_restarted), item);
1400
1401         g_signal_emit (session, signals[REQUEST_QUEUED], 0, msg);
1402
1403         soup_message_queue_item_ref (item);
1404         return item;
1405 }
1406
1407 static void
1408 soup_session_send_queue_item (SoupSession *session,
1409                               SoupMessageQueueItem *item,
1410                               SoupMessageCompletionFn completion_cb)
1411 {
1412         SoupSessionPrivate *priv = SOUP_SESSION_GET_PRIVATE (session);
1413         const char *conn_header;
1414
1415         if (priv->user_agent) {
1416                 soup_message_headers_replace (item->msg->request_headers,
1417                                               "User-Agent", priv->user_agent);
1418         }
1419
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,
1424                                              "Accept-Language",
1425                                              priv->accept_language);
1426         }
1427
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.
1432          */
1433         conn_header = soup_message_headers_get_list (item->msg->request_headers, "Connection");
1434         if (!conn_header ||
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");
1439
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);
1444 }
1445
1446 static gboolean
1447 soup_session_cleanup_connections (SoupSession *session,
1448                                   gboolean     cleanup_idle)
1449 {
1450         SoupSessionPrivate *priv = SOUP_SESSION_GET_PRIVATE (session);
1451         GSList *conns = NULL, *c;
1452         GHashTableIter iter;
1453         gpointer conn, host;
1454         SoupConnectionState state;
1455
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);
1465                 }
1466         }
1467         g_mutex_unlock (&priv->conn_lock);
1468
1469         if (!conns)
1470                 return FALSE;
1471
1472         for (c = conns; c; c = c->next) {
1473                 conn = c->data;
1474                 soup_connection_disconnect (conn);
1475                 g_object_unref (conn);
1476         }
1477         g_slist_free (conns);
1478
1479         return TRUE;
1480 }
1481
1482 static gboolean
1483 free_unused_host (gpointer user_data)
1484 {
1485         SoupSessionHost *host = (SoupSessionHost *) user_data;
1486         SoupSessionPrivate *priv = SOUP_SESSION_GET_PRIVATE (host->session);
1487
1488         g_mutex_lock (&priv->conn_lock);
1489
1490         /* In a multithreaded session, a connection might have been
1491          * added while we were waiting for conn_lock.
1492          */
1493         if (host->connections) {
1494                 g_mutex_unlock (&priv->conn_lock);
1495                 return FALSE;
1496         }
1497
1498         /* This will free the host in addition to removing it from the
1499          * hash table
1500          */
1501         if (host->uri->scheme == SOUP_URI_SCHEME_HTTPS)
1502                 g_hash_table_remove (priv->https_hosts, host->uri);
1503         else
1504                 g_hash_table_remove (priv->http_hosts, host->uri);
1505         g_mutex_unlock (&priv->conn_lock);
1506
1507         return FALSE;
1508 }
1509
1510 static void
1511 drop_connection (SoupSession *session, SoupSessionHost *host, SoupConnection *conn)
1512 {
1513         SoupSessionPrivate *priv = SOUP_SESSION_GET_PRIVATE (session);
1514
1515         /* Note: caller must hold conn_lock, and must remove @conn
1516          * from priv->conns itself.
1517          */
1518
1519         if (host) {
1520                 host->connections = g_slist_remove (host->connections, conn);
1521                 host->num_conns--;
1522
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.
1526                  */
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,
1530                                                                  HOST_KEEP_ALIVE,
1531                                                                  free_unused_host,
1532                                                                  host);
1533                         host->keep_alive_src = g_source_ref (host->keep_alive_src);
1534                 }
1535
1536                 if (soup_connection_get_ssl_fallback (conn))
1537                         host->ssl_fallback = TRUE;
1538         }
1539
1540         g_signal_handlers_disconnect_by_func (conn, connection_disconnected, session);
1541         g_signal_handlers_disconnect_by_func (conn, connection_state_changed, session);
1542         priv->num_conns--;
1543
1544         g_object_unref (conn);
1545 }
1546
1547 static void
1548 connection_disconnected (SoupConnection *conn, gpointer user_data)
1549 {
1550         SoupSession *session = user_data;
1551         SoupSessionPrivate *priv = SOUP_SESSION_GET_PRIVATE (session);
1552         SoupSessionHost *host;
1553
1554         g_mutex_lock (&priv->conn_lock);
1555
1556         host = g_hash_table_lookup (priv->conns, conn);
1557         if (host)
1558                 g_hash_table_remove (priv->conns, conn);
1559         drop_connection (session, host, conn);
1560
1561         g_mutex_unlock (&priv->conn_lock);
1562
1563         soup_session_kick_queue (session);
1564 }
1565
1566 static void
1567 connection_state_changed (GObject *object, GParamSpec *param, gpointer user_data)
1568 {
1569         SoupSession *session = user_data;
1570         SoupConnection *conn = SOUP_CONNECTION (object);
1571
1572         if (soup_connection_get_state (conn) == SOUP_CONNECTION_IDLE)
1573                 soup_session_kick_queue (session);
1574 }
1575
1576 SoupMessageQueue *
1577 soup_session_get_queue (SoupSession *session)
1578 {
1579         SoupSessionPrivate *priv = SOUP_SESSION_GET_PRIVATE (session);
1580
1581         return priv->queue;
1582 }
1583
1584 static void
1585 soup_session_unqueue_item (SoupSession          *session,
1586                            SoupMessageQueueItem *item)
1587 {
1588         SoupSessionPrivate *priv = SOUP_SESSION_GET_PRIVATE (session);
1589         SoupSessionHost *host;
1590
1591         if (item->conn) {
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);
1596         }
1597
1598         if (item->state != SOUP_MESSAGE_FINISHED) {
1599                 g_warning ("finished an item with state %d", item->state);
1600                 return;
1601         }
1602
1603         soup_message_queue_remove (priv->queue, item);
1604
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);
1610
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()
1614          */
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);
1619 }
1620
1621 static void
1622 soup_session_set_item_status (SoupSession          *session,
1623                               SoupMessageQueueItem *item,
1624                               guint                 status_code,
1625                               GError               *error)
1626 {
1627         SoupURI *uri = NULL;
1628
1629         switch (status_code) {
1630         case SOUP_STATUS_CANT_RESOLVE:
1631         case SOUP_STATUS_CANT_CONNECT:
1632                 uri = soup_message_get_uri (item->msg);
1633                 break;
1634
1635         case SOUP_STATUS_CANT_RESOLVE_PROXY:
1636         case SOUP_STATUS_CANT_CONNECT_PROXY:
1637                 if (item->conn)
1638                         uri = soup_connection_get_proxy_uri (item->conn);
1639                 break;
1640
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");
1645                         return;
1646                 }
1647                 break;
1648
1649         default:
1650                 break;
1651         }
1652
1653         if (error)
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),
1658                                              uri->host);
1659                 soup_message_set_status_full (item->msg, status_code, msg);
1660                 g_free (msg);
1661         } else
1662                 soup_message_set_status (item->msg, status_code);
1663 }
1664
1665
1666 static void
1667 message_completed (SoupMessage *msg, gpointer user_data)
1668 {
1669         SoupMessageQueueItem *item = user_data;
1670
1671         if (item->async)
1672                 soup_session_kick_queue (item->session);
1673
1674         if (item->state != SOUP_MESSAGE_RESTARTING) {
1675                 item->state = SOUP_MESSAGE_FINISHING;
1676
1677                 if (item->new_api && !item->async)
1678                         soup_session_process_queue_item (item->session, item, NULL, TRUE);
1679         }
1680 }
1681
1682 static guint
1683 status_from_connect_error (SoupMessageQueueItem *item, GError *error)
1684 {
1685         guint status;
1686
1687         if (!error)
1688                 return SOUP_STATUS_OK;
1689
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;
1693
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;
1699                 } else
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;
1718                 else
1719                         status = SOUP_STATUS_IO_ERROR;
1720         } else
1721                 status = SOUP_STATUS_IO_ERROR;
1722
1723         if (item->conn && soup_connection_is_via_proxy (item->conn))
1724                 return soup_status_proxify (status);
1725         else
1726                 return status;
1727 }
1728
1729 static void
1730 tunnel_complete (SoupMessageQueueItem *tunnel_item,
1731                  guint status, GError *error)
1732 {
1733         SoupMessageQueueItem *item = tunnel_item->related;
1734         SoupSession *session = tunnel_item->session;
1735
1736         soup_message_finished (tunnel_item->msg);
1737         soup_message_queue_item_unref (tunnel_item);
1738
1739         if (item->msg->status_code)
1740                 item->state = SOUP_MESSAGE_FINISHING;
1741         soup_message_set_https_status (item->msg, item->conn);
1742
1743         item->error = error;
1744         if (!status)
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);
1751         }
1752
1753         item->state = SOUP_MESSAGE_READY;
1754         if (item->async)
1755                 soup_session_kick_queue (session);
1756         soup_message_queue_item_unref (item);
1757 }
1758
1759 static void
1760 tunnel_handshake_complete (GObject      *object,
1761                            GAsyncResult *result,
1762                            gpointer      user_data)
1763 {
1764         SoupConnection *conn = SOUP_CONNECTION (object);
1765         SoupMessageQueueItem *tunnel_item = user_data;
1766         GError *error = NULL;
1767
1768         soup_connection_start_ssl_finish (conn, result, &error);
1769         tunnel_complete (tunnel_item, 0, error);
1770 }
1771
1772 static void
1773 tunnel_message_completed (SoupMessage *msg, gpointer user_data)
1774 {
1775         SoupMessageQueueItem *tunnel_item = user_data;
1776         SoupMessageQueueItem *item = tunnel_item->related;
1777         SoupSession *session = tunnel_item->session;
1778         guint status;
1779
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);
1786                         return;
1787                 }
1788
1789                 soup_message_set_status (msg, SOUP_STATUS_TRY_AGAIN);
1790         }
1791
1792         tunnel_item->state = SOUP_MESSAGE_FINISHED;
1793         soup_session_unqueue_item (session, tunnel_item);
1794
1795         status = tunnel_item->msg->status_code;
1796         if (!SOUP_STATUS_IS_SUCCESSFUL (status)) {
1797                 tunnel_complete (tunnel_item, status, NULL);
1798                 return;
1799         }
1800
1801         if (tunnel_item->async) {
1802                 soup_connection_start_ssl_async (item->conn, item->cancellable,
1803                                                  tunnel_handshake_complete,
1804                                                  tunnel_item);
1805         } else {
1806                 GError *error = NULL;
1807
1808                 soup_connection_start_ssl_sync (item->conn, item->cancellable, &error);
1809                 tunnel_complete (tunnel_item, 0, error);
1810         }
1811 }
1812
1813 static void
1814 tunnel_connect (SoupMessageQueueItem *item)
1815 {
1816         SoupSession *session = item->session;
1817         SoupMessageQueueItem *tunnel_item;
1818         SoupURI *uri;
1819         SoupMessage *msg;
1820
1821         item->state = SOUP_MESSAGE_TUNNELING;
1822
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);
1826
1827         tunnel_item = soup_session_append_queue_item (session, msg,
1828                                                       item->async, FALSE,
1829                                                       NULL, NULL);
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;
1835
1836         g_signal_emit (session, signals[TUNNELING], 0, tunnel_item->conn);
1837
1838         soup_session_send_queue_item (session, tunnel_item,
1839                                       tunnel_message_completed);
1840 }
1841
1842 static void
1843 connect_complete (SoupMessageQueueItem *item, SoupConnection *conn, GError *error)
1844 {
1845         SoupSession *session = item->session;
1846         guint status;
1847
1848         soup_message_set_https_status (item->msg, item->conn);
1849
1850         if (!error) {
1851                 item->state = SOUP_MESSAGE_CONNECTED;
1852                 return;
1853         }
1854
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;
1863         }
1864 }
1865
1866 static void
1867 connect_async_complete (GObject      *object,
1868                         GAsyncResult *result,
1869                         gpointer      user_data)
1870 {
1871         SoupConnection *conn = SOUP_CONNECTION (object);
1872         SoupMessageQueueItem *item = user_data;
1873         GError *error = NULL;
1874
1875         soup_connection_connect_finish (conn, result, &error);
1876         connect_complete (item, conn, error);
1877
1878         if (item->state == SOUP_MESSAGE_CONNECTED ||
1879             item->state == SOUP_MESSAGE_READY)
1880                 async_run_queue (item->session);
1881         else
1882                 soup_session_kick_queue (item->session);
1883
1884         soup_message_queue_item_unref (item);
1885 }
1886
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)
1894 {
1895         SoupSessionPrivate *priv = SOUP_SESSION_GET_PRIVATE (session);
1896         SoupConnection *conn;
1897         GSList *conns;
1898         int num_pending = 0;
1899         GProxyResolver *proxy_resolver;
1900         GTlsDatabase *tlsdb;
1901
1902         if (priv->disposed)
1903                 return FALSE;
1904
1905         if (item->conn) {
1906                 g_return_val_if_fail (soup_connection_get_state (item->conn) != SOUP_CONNECTION_DISCONNECTED, FALSE);
1907                 return item->conn;
1908         }
1909
1910         for (conns = host->connections; conns; conns = conns->next) {
1911                 conn = conns->data;
1912
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);
1916 #endif
1917                         soup_connection_set_state (conn, SOUP_CONNECTION_IN_USE);
1918                         return conn;
1919                 } else if (soup_connection_get_state (conn) == SOUP_CONNECTION_CONNECTING)
1920 #if ENABLE(TIZEN_TV_CREATE_IDLE_TCP_CONNECTION)
1921                 {
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);
1926                                 return item->conn;
1927                         } else {
1928 #endif
1929                         num_pending++;
1930 #if ENABLE(TIZEN_TV_CREATE_IDLE_TCP_CONNECTION)
1931                         }
1932                 }
1933 #endif
1934         }
1935
1936         /* Limit the number of pending connections; num_messages / 2
1937          * is somewhat arbitrary...
1938          */
1939 #if ENABLE(TIZEN_UNLIMITED_PENDING_CONNECTIONS)
1940         /* FIXME: What should we do here exactly? */
1941 #else
1942         if (num_pending > host->num_messages / 2)
1943                 return NULL;
1944 #endif
1945
1946         if (host->num_conns >= priv->max_conns_per_host) {
1947                 if (need_new_connection)
1948                         *try_cleanup = TRUE;
1949                 return NULL;
1950         }
1951
1952         if (priv->num_conns >= priv->max_conns) {
1953                 *try_cleanup = TRUE;
1954                 return NULL;
1955         }
1956
1957         proxy_resolver = get_proxy_resolver (session);
1958         tlsdb = get_tls_database (session);
1959
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,
1968 #endif
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,
1976                 NULL);
1977         g_signal_connect (conn, "disconnected",
1978                           G_CALLBACK (connection_disconnected),
1979                           session);
1980         g_signal_connect (conn, "notify::state",
1981                           G_CALLBACK (connection_state_changed),
1982                           session);
1983
1984         /* This is a debugging-related signal, and so can ignore the
1985          * usual rule about not emitting signals while holding
1986          * conn_lock.
1987          */
1988         g_signal_emit (session, signals[CONNECTION_CREATED], 0, conn);
1989
1990         g_hash_table_insert (priv->conns, conn, host);
1991
1992         priv->num_conns++;
1993         host->num_conns++;
1994         host->connections = g_slist_prepend (host->connections, conn);
1995
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;
2000         }
2001
2002 #if ENABLE(TIZEN_TV_CREATE_IDLE_TCP_CONNECTION)
2003         soup_connection_set_current_item (conn, item);
2004 #endif
2005         return conn;
2006 }
2007
2008 static gboolean
2009 get_connection (SoupMessageQueueItem *item, gboolean *should_cleanup)
2010 {
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;
2017
2018         soup_session_cleanup_connections (session, FALSE);
2019
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));
2024
2025         g_mutex_lock (&priv->conn_lock);
2026         host = get_host_for_message (session, item->msg);
2027         while (TRUE) {
2028                 conn = get_connection_for_host (session, item, host,
2029                                                 need_new_connection,
2030                                                 &my_should_cleanup);
2031                 if (conn || item->async)
2032                         break;
2033
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);
2038
2039                         my_should_cleanup = FALSE;
2040                         continue;
2041                 }
2042
2043                 g_cond_wait (&priv->conn_cond, &priv->conn_lock);
2044         }
2045         g_mutex_unlock (&priv->conn_lock);
2046
2047         if (!conn) {
2048                 if (should_cleanup)
2049                         *should_cleanup = my_should_cleanup;
2050                 return FALSE;
2051         }
2052
2053         soup_session_set_item_connection (session, item, conn);
2054
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);
2059                 return TRUE;
2060         }
2061 #endif
2062
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);
2066                 return TRUE;
2067         }
2068
2069         item->state = SOUP_MESSAGE_CONNECTING;
2070
2071         if (item->async) {
2072                 soup_message_queue_item_ref (item);
2073                 soup_connection_connect_async (item->conn, item->cancellable,
2074                                                connect_async_complete, item);
2075                 return FALSE;
2076         } else {
2077                 GError *error = NULL;
2078
2079                 soup_connection_connect_sync (item->conn, item->cancellable, &error);
2080                 connect_complete (item, conn, error);
2081
2082                 return TRUE;
2083         }
2084 }
2085
2086 void
2087 soup_session_process_queue_item (SoupSession          *session,
2088                                  SoupMessageQueueItem *item,
2089                                  gboolean             *should_cleanup,
2090                                  gboolean              loop)
2091 {
2092         g_assert (item->session == session);
2093
2094         do {
2095                 if (item->paused)
2096                         return;
2097
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);
2105                                 }
2106                         }
2107 #endif
2108                         if (!get_connection (item, should_cleanup))
2109                                 return;
2110                         break;
2111
2112                 case SOUP_MESSAGE_CONNECTED:
2113                         if (soup_connection_is_tunnelled (item->conn))
2114                                 tunnel_connect (item);
2115                         else
2116                                 item->state = SOUP_MESSAGE_READY;
2117                         break;
2118
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;
2124                                 } else
2125                                         item->state = SOUP_MESSAGE_FINISHING;
2126                                 break;
2127                         }
2128
2129                         item->state = SOUP_MESSAGE_RUNNING;
2130
2131                         soup_session_send_queue_item (session, item, message_completed);
2132
2133                         if (item->new_api) {
2134                                 if (item->async)
2135                                         async_send_request_running (session, item);
2136                                 return;
2137                         }
2138                         break;
2139
2140                 case SOUP_MESSAGE_RUNNING:
2141                         if (item->async)
2142                                 return;
2143
2144                         g_warn_if_fail (item->new_api);
2145                         item->state = SOUP_MESSAGE_FINISHING;
2146                         break;
2147
2148                 case SOUP_MESSAGE_CACHED:
2149                         /* Will be handled elsewhere */
2150                         return;
2151
2152                 case SOUP_MESSAGE_RESTARTING:
2153                         item->state = SOUP_MESSAGE_STARTING;
2154                         soup_message_restarted (item->msg);
2155                         break;
2156
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);
2162                                 break;
2163                         }
2164
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);
2170                         return;
2171
2172                 default:
2173                         /* Nothing to do with this message in any
2174                          * other state.
2175                          */
2176                         g_warn_if_fail (item->async);
2177                         return;
2178                 }
2179         } while (loop && item->state != SOUP_MESSAGE_FINISHED);
2180 }
2181
2182 static void
2183 async_run_queue (SoupSession *session)
2184 {
2185         SoupSessionPrivate *priv = SOUP_SESSION_GET_PRIVATE (session);
2186         SoupMessageQueueItem *item;
2187         SoupMessage *msg;
2188         gboolean try_cleanup = TRUE, should_cleanup = FALSE;
2189
2190         g_object_ref (session);
2191         soup_session_cleanup_connections (session, FALSE);
2192
2193  try_again:
2194         for (item = soup_message_queue_first (priv->queue);
2195              item;
2196              item = soup_message_queue_next (priv->queue, item)) {
2197                 msg = item->msg;
2198
2199                 /* CONNECT messages are handled specially */
2200                 if (msg->method == SOUP_METHOD_CONNECT)
2201                         continue;
2202
2203                 if (item->async_context != soup_session_get_async_context (session))
2204                         continue;
2205
2206                 soup_session_process_queue_item (session, item, &should_cleanup, TRUE);
2207         }
2208
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.
2213                  */
2214                 if (soup_session_cleanup_connections (session, TRUE)) {
2215                         try_cleanup = should_cleanup = FALSE;
2216                         goto try_again;
2217                 }
2218         }
2219
2220         g_object_unref (session);
2221 }
2222
2223 static gboolean
2224 idle_run_queue (gpointer user_data)
2225 {
2226         SoupSessionPrivate *priv = user_data;
2227         GSource *source;
2228
2229         if (priv->disposed)
2230                 return FALSE;
2231
2232         source = g_main_current_source ();
2233         priv->run_queue_sources = g_slist_remove (priv->run_queue_sources, source);
2234
2235         /* Ensure that the source is destroyed before running the queue */
2236         g_source_destroy (source);
2237         g_source_unref (source);
2238
2239         g_assert (priv->session);
2240         async_run_queue (priv->session);
2241         return FALSE;
2242 }
2243
2244 /**
2245  * SoupSessionCallback:
2246  * @session: the session
2247  * @msg: the message that has finished
2248  * @user_data: the data passed to soup_session_queue_message
2249  *
2250  * Prototype for the callback passed to soup_session_queue_message(),
2251  * qv.
2252  **/
2253
2254 static void
2255 soup_session_real_queue_message (SoupSession *session, SoupMessage *msg,
2256                                  SoupSessionCallback callback, gpointer user_data)
2257 {
2258         SoupMessageQueueItem *item;
2259
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);
2264 }
2265
2266 /**
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.
2273  * 
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.
2278  *
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.
2282  *
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.)
2289  *
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
2293  * #GInputStream.
2294  */
2295 void
2296 soup_session_queue_message (SoupSession *session, SoupMessage *msg,
2297                             SoupSessionCallback callback, gpointer user_data)
2298 {
2299         g_return_if_fail (SOUP_IS_SESSION (session));
2300         g_return_if_fail (SOUP_IS_MESSAGE (msg));
2301
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.
2306          */
2307         g_object_unref (msg);
2308 }
2309
2310 static void
2311 soup_session_real_requeue_message (SoupSession *session, SoupMessage *msg)
2312 {
2313         SoupSessionPrivate *priv = SOUP_SESSION_GET_PRIVATE (session);
2314         SoupMessageQueueItem *item;
2315
2316         item = soup_message_queue_lookup (priv->queue, msg);
2317         g_return_if_fail (item != NULL);
2318
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);
2322                 else
2323                         g_warning ("SoupMessage %p stuck in infinite loop?", msg);
2324         } else {
2325                 item->resend_count++;
2326                 item->state = SOUP_MESSAGE_RESTARTING;
2327         }
2328
2329         soup_message_queue_item_unref (item);
2330 }
2331
2332 /**
2333  * soup_session_requeue_message:
2334  * @session: a #SoupSession
2335  * @msg: the message to requeue
2336  *
2337  * This causes @msg to be placed back on the queue to be attempted
2338  * again.
2339  **/
2340 void
2341 soup_session_requeue_message (SoupSession *session, SoupMessage *msg)
2342 {
2343         g_return_if_fail (SOUP_IS_SESSION (session));
2344         g_return_if_fail (SOUP_IS_MESSAGE (msg));
2345
2346         SOUP_SESSION_GET_CLASS (session)->requeue_message (session, msg);
2347 }
2348
2349 static guint
2350 soup_session_real_send_message (SoupSession *session, SoupMessage *msg)
2351 {
2352         SoupMessageQueueItem *item;
2353         guint status;
2354
2355         item = soup_session_append_queue_item (session, msg, FALSE, FALSE,
2356                                                NULL, NULL);
2357         soup_session_process_queue_item (session, item, NULL, TRUE);
2358         status = msg->status_code;
2359         soup_message_queue_item_unref (item);
2360         return status;
2361 }
2362
2363 /**
2364  * soup_session_send_message:
2365  * @session: a #SoupSession
2366  * @msg: the message to send
2367  * 
2368  * Synchronously send @msg. This call will not return until the
2369  * transfer is finished successfully or there is an unrecoverable
2370  * error.
2371  *
2372  * Unlike with soup_session_queue_message(), @msg is not freed upon
2373  * return.
2374  *
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
2378  * processed.)
2379  *
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
2383  * #GInputStream.
2384  *
2385  * Return value: the HTTP status code of the response
2386  */
2387 guint
2388 soup_session_send_message (SoupSession *session, SoupMessage *msg)
2389 {
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);
2392
2393         return SOUP_SESSION_GET_CLASS (session)->send_message (session, msg);
2394 }
2395
2396
2397 /**
2398  * soup_session_pause_message:
2399  * @session: a #SoupSession
2400  * @msg: a #SoupMessage currently running on @session
2401  *
2402  * Pauses HTTP I/O on @msg. Call soup_session_unpause_message() to
2403  * resume I/O.
2404  *
2405  * This may only be called for asynchronous messages (those sent on a
2406  * #SoupSessionAsync or using soup_session_queue_message()).
2407  **/
2408 void
2409 soup_session_pause_message (SoupSession *session,
2410                             SoupMessage *msg)
2411 {
2412         SoupSessionPrivate *priv;
2413         SoupMessageQueueItem *item;
2414
2415         g_return_if_fail (SOUP_IS_SESSION (session));
2416         g_return_if_fail (SOUP_IS_MESSAGE (msg));
2417
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);
2422
2423         item->paused = TRUE;
2424         if (item->state == SOUP_MESSAGE_RUNNING)
2425                 soup_message_io_pause (msg);
2426         soup_message_queue_item_unref (item);
2427 }
2428
2429 static void
2430 soup_session_real_kick_queue (SoupSession *session)
2431 {
2432         SoupSessionPrivate *priv = SOUP_SESSION_GET_PRIVATE (session);
2433         SoupMessageQueueItem *item;
2434         gboolean have_sync_items = FALSE;
2435
2436         if (priv->disposed)
2437                 return;
2438
2439         for (item = soup_message_queue_first (priv->queue);
2440              item;
2441              item = soup_message_queue_next (priv->queue, item)) {
2442                 if (item->async) {
2443                         GSource *source;
2444
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.
2449                          */
2450                         source = g_main_context_find_source_by_user_data (item->async_context, priv);
2451                         if (!source) {
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,
2455                                                                            source);
2456                         }
2457                 } else
2458                         have_sync_items = TRUE;
2459         }
2460
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);
2465         }
2466 }
2467
2468 void
2469 soup_session_kick_queue (SoupSession *session)
2470 {
2471         SOUP_SESSION_GET_CLASS (session)->kick (session);
2472 }
2473
2474 /**
2475  * soup_session_unpause_message:
2476  * @session: a #SoupSession
2477  * @msg: a #SoupMessage currently running on @session
2478  *
2479  * Resumes HTTP I/O on @msg. Use this to resume after calling
2480  * soup_session_pause_message().
2481  *
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.
2485  *
2486  * This may only be called for asynchronous messages (those sent on a
2487  * #SoupSessionAsync or using soup_session_queue_message()).
2488  **/
2489 void
2490 soup_session_unpause_message (SoupSession *session,
2491                               SoupMessage *msg)
2492 {
2493         SoupSessionPrivate *priv;
2494         SoupMessageQueueItem *item;
2495
2496         g_return_if_fail (SOUP_IS_SESSION (session));
2497         g_return_if_fail (SOUP_IS_MESSAGE (msg));
2498
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);
2503
2504         item->paused = FALSE;
2505         if (item->state == SOUP_MESSAGE_RUNNING)
2506                 soup_message_io_unpause (msg);
2507         soup_message_queue_item_unref (item);
2508
2509         soup_session_kick_queue (session);
2510 }
2511
2512
2513 static void
2514 soup_session_real_cancel_message (SoupSession *session, SoupMessage *msg, guint status_code)
2515 {
2516         SoupSessionPrivate *priv = SOUP_SESSION_GET_PRIVATE (session);
2517         SoupMessageQueueItem *item;
2518
2519         item = soup_message_queue_lookup (priv->queue, msg);
2520         g_return_if_fail (item != NULL);
2521
2522         item->paused = FALSE;
2523         soup_message_set_status (msg, status_code);
2524         g_cancellable_cancel (item->cancellable);
2525
2526         soup_session_kick_queue (item->session);
2527         soup_message_queue_item_unref (item);
2528 }
2529
2530 /**
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)
2536  *
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.
2547  *
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.
2552  *
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.
2559  **/
2560 void
2561 soup_session_cancel_message (SoupSession *session, SoupMessage *msg,
2562                              guint status_code)
2563 {
2564         SoupSessionPrivate *priv;
2565         SoupMessageQueueItem *item;
2566
2567         g_return_if_fail (SOUP_IS_SESSION (session));
2568         g_return_if_fail (SOUP_IS_MESSAGE (msg));
2569
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 */
2573         if (!item)
2574                 return;
2575         if (item->state == SOUP_MESSAGE_FINISHED) {
2576                 soup_message_queue_item_unref (item);
2577                 return;
2578         }
2579
2580         SOUP_SESSION_GET_CLASS (session)->cancel_message (session, msg, status_code);
2581         soup_message_queue_item_unref (item);
2582 }
2583
2584 static void
2585 soup_session_real_flush_queue (SoupSession *session)
2586 {
2587         SoupSessionPrivate *priv = SOUP_SESSION_GET_PRIVATE (session);
2588         SoupMessageQueueItem *item;
2589         GHashTable *current = NULL;
2590         gboolean done = FALSE;
2591
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);
2596                      item;
2597                      item = soup_message_queue_next (priv->queue, item))
2598                         g_hash_table_insert (current, item, item);
2599         }
2600
2601         /* Cancel everything */
2602         for (item = soup_message_queue_first (priv->queue);
2603              item;
2604              item = soup_message_queue_next (priv->queue, item)) {
2605                 soup_session_cancel_message (session, item->msg,
2606                                              SOUP_STATUS_CANCELLED);
2607         }
2608
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.)
2617                  */
2618                 g_mutex_lock (&priv->conn_lock);
2619                 do {
2620                         done = TRUE;
2621                         for (item = soup_message_queue_first (priv->queue);
2622                              item;
2623                              item = soup_message_queue_next (priv->queue, item)) {
2624                                 if (g_hash_table_lookup (current, item))
2625                                         done = FALSE;
2626                         }
2627
2628                         if (!done)
2629                                 g_cond_wait (&priv->conn_cond, &priv->conn_lock);
2630                 } while (!done);
2631                 g_mutex_unlock (&priv->conn_lock);
2632
2633                 g_hash_table_destroy (current);
2634         }
2635 }
2636
2637 /**
2638  * soup_session_abort:
2639  * @session: the session
2640  *
2641  * Cancels all pending requests in @session and closes all idle
2642  * persistent connections.
2643  *
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
2648  * not.
2649  **/
2650 void
2651 soup_session_abort (SoupSession *session)
2652 {
2653         SoupSessionPrivate *priv;
2654         GSList *conns, *c;
2655         GHashTableIter iter;
2656         gpointer conn, host;
2657
2658         g_return_if_fail (SOUP_IS_SESSION (session));
2659         priv = SOUP_SESSION_GET_PRIVATE (session);
2660
2661         SOUP_SESSION_GET_CLASS (session)->flush_queue (session);
2662
2663         /* Close all connections */
2664         g_mutex_lock (&priv->conn_lock);
2665         conns = NULL;
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);
2671         }
2672         g_mutex_unlock (&priv->conn_lock);
2673
2674         for (c = conns; c; c = c->next) {
2675                 soup_connection_disconnect (c->data);
2676                 g_object_unref (c->data);
2677         }
2678
2679         g_slist_free (conns);
2680 }
2681
2682 static void
2683 prefetch_uri (SoupSession *session, SoupURI *uri,
2684               GCancellable *cancellable,
2685               SoupAddressCallback callback, gpointer user_data)
2686 {
2687         SoupSessionPrivate *priv;
2688         SoupSessionHost *host;
2689         SoupAddress *addr;
2690
2691         priv = SOUP_SESSION_GET_PRIVATE (session);
2692
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);
2697
2698         soup_address_resolve_async (addr,
2699                                     soup_session_get_async_context (session),
2700                                     cancellable, callback, user_data);
2701         g_object_unref (addr);
2702 }
2703
2704 /**
2705  * soup_session_prepare_for_uri:
2706  * @session: a #SoupSession
2707  * @uri: a #SoupURI which may be required
2708  *
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.
2713  *
2714  * Since: 2.30
2715  *
2716  * Deprecated: 2.38: use soup_session_prefetch_dns() instead
2717  **/
2718 void
2719 soup_session_prepare_for_uri (SoupSession *session, SoupURI *uri)
2720 {
2721         g_return_if_fail (SOUP_IS_SESSION (session));
2722         g_return_if_fail (uri != NULL);
2723
2724         if (!uri->host)
2725                 return;
2726
2727         prefetch_uri (session, uri, NULL, NULL, NULL);
2728 }
2729
2730 /**
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
2736 *     result, or %NULL
2737 * @user_data: data for @callback
2738 *
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.
2743 *
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.
2747 *
2748 * Since: 2.38
2749 **/
2750 void
2751 soup_session_prefetch_dns (SoupSession *session, const char *hostname,
2752                            GCancellable *cancellable,
2753                            SoupAddressCallback callback, gpointer user_data)
2754 {
2755         SoupURI *uri;
2756
2757         g_return_if_fail (SOUP_IS_SESSION (session));
2758         g_return_if_fail (hostname != NULL);
2759
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, "");
2765
2766         prefetch_uri (session, uri, cancellable, callback, user_data);
2767         soup_uri_free (uri);
2768 }
2769
2770 /**
2771  * soup_session_add_feature:
2772  * @session: a #SoupSession
2773  * @feature: an object that implements #SoupSessionFeature
2774  *
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.
2778  *
2779  * Note that a #SoupContentDecoder is added to the session by default
2780  * (unless you are using one of the deprecated session subclasses).
2781  *
2782  * Since: 2.24
2783  **/
2784 void
2785 soup_session_add_feature (SoupSession *session, SoupSessionFeature *feature)
2786 {
2787         SoupSessionPrivate *priv;
2788
2789         g_return_if_fail (SOUP_IS_SESSION (session));
2790         g_return_if_fail (SOUP_IS_SESSION_FEATURE (feature));
2791
2792         priv = SOUP_SESSION_GET_PRIVATE (session);
2793
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),
2798                                     NULL);
2799         }
2800         G_GNUC_END_IGNORE_DEPRECATIONS;
2801
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);
2805 }
2806
2807 /**
2808  * soup_session_add_feature_by_type:
2809  * @session: a #SoupSession
2810  * @feature_type: a #GType
2811  *
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.
2816  *
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.
2821  *
2822  * You can also add a feature to the session at construct time by
2823  * using the %SOUP_SESSION_ADD_FEATURE_BY_TYPE property.
2824  *
2825  * Note that a #SoupContentDecoder is added to the session by default
2826  * (unless you are using one of the deprecated session subclasses).
2827  *
2828  * Since: 2.24
2829  **/
2830 void
2831 soup_session_add_feature_by_type (SoupSession *session, GType feature_type)
2832 {
2833         SoupSessionPrivate *priv;
2834
2835         g_return_if_fail (SOUP_IS_SESSION (session));
2836
2837         priv = SOUP_SESSION_GET_PRIVATE (session);
2838
2839         if (g_type_is_a (feature_type, SOUP_TYPE_SESSION_FEATURE)) {
2840                 SoupSessionFeature *feature;
2841
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;
2847                 int i;
2848
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));
2854                 }
2855         } else {
2856                 GSList *f;
2857
2858                 for (f = priv->features; f; f = f->next) {
2859                         if (soup_session_feature_add_feature (f->data, feature_type))
2860                                 return;
2861                 }
2862                 g_warning ("No feature manager for feature of type '%s'", g_type_name (feature_type));
2863         }
2864 }
2865
2866 /**
2867  * soup_session_remove_feature:
2868  * @session: a #SoupSession
2869  * @feature: a feature that has previously been added to @session
2870  *
2871  * Removes @feature's functionality from @session.
2872  *
2873  * Since: 2.24
2874  **/
2875 void
2876 soup_session_remove_feature (SoupSession *session, SoupSessionFeature *feature)
2877 {
2878         SoupSessionPrivate *priv;
2879
2880         g_return_if_fail (SOUP_IS_SESSION (session));
2881
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);
2887
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);
2893                 }
2894                 G_GNUC_END_IGNORE_DEPRECATIONS;
2895
2896                 g_object_unref (feature);
2897         }
2898 }
2899
2900 /**
2901  * soup_session_remove_feature_by_type:
2902  * @session: a #SoupSession
2903  * @feature_type: a #GType
2904  *
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.
2909  *
2910  * Since: 2.24
2911  **/
2912 void
2913 soup_session_remove_feature_by_type (SoupSession *session, GType feature_type)
2914 {
2915         SoupSessionPrivate *priv;
2916         GSList *f;
2917
2918         g_return_if_fail (SOUP_IS_SESSION (session));
2919
2920         priv = SOUP_SESSION_GET_PRIVATE (session);
2921
2922         if (g_type_is_a (feature_type, SOUP_TYPE_SESSION_FEATURE)) {
2923         restart:
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);
2927                                 goto restart;
2928                         }
2929                 }
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;
2936                 int i;
2937
2938                 request_class = g_type_class_peek (feature_type);
2939                 if (!request_class)
2940                         return;
2941                 for (i = 0; request_class->schemes[i]; i++) {
2942                         g_hash_table_remove (priv->request_types,
2943                                              request_class->schemes[i]);
2944                 }
2945         } else {
2946                 for (f = priv->features; f; f = f->next) {
2947                         if (soup_session_feature_remove_feature (f->data, feature_type))
2948                                 return;
2949                 }
2950                 g_warning ("No feature manager for feature of type '%s'", g_type_name (feature_type));
2951         }
2952 }
2953
2954 /**
2955  * soup_session_has_feature:
2956  * @session: a #SoupSession
2957  * @feature_type: the #GType of the class of features to check for
2958  *
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
2962  * #SoupRequest).
2963  *
2964  * Return value: %TRUE or %FALSE
2965  *
2966  * Since: 2.42
2967  **/
2968 gboolean
2969 soup_session_has_feature (SoupSession *session,
2970                           GType        feature_type)
2971 {
2972         SoupSessionPrivate *priv;
2973         GSList *f;
2974
2975         g_return_val_if_fail (SOUP_IS_SESSION (session), FALSE);
2976
2977         priv = SOUP_SESSION_GET_PRIVATE (session);
2978
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))
2982                                 return TRUE;
2983                 }
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;
2987         } else {
2988                 for (f = priv->features; f; f = f->next) {
2989                         if (soup_session_feature_has_feature (f->data, feature_type))
2990                                 return TRUE;
2991                 }
2992         }
2993
2994         return FALSE;
2995 }
2996
2997 /**
2998  * soup_session_get_features:
2999  * @session: a #SoupSession
3000  * @feature_type: the #GType of the class of features to get
3001  *
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.)
3005  *
3006  * Return value: (transfer container) (element-type Soup.SessionFeature):
3007  * a list of features. You must free the list, but not its contents
3008  *
3009  * Since: 2.26
3010  **/
3011 GSList *
3012 soup_session_get_features (SoupSession *session, GType feature_type)
3013 {
3014         SoupSessionPrivate *priv;
3015         GSList *f, *ret;
3016
3017         g_return_val_if_fail (SOUP_IS_SESSION (session), NULL);
3018
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);
3023         }
3024         return g_slist_reverse (ret);
3025 }
3026
3027 /**
3028  * soup_session_get_feature:
3029  * @session: a #SoupSession
3030  * @feature_type: the #GType of the feature to get
3031  *
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().
3035  *
3036  * Return value: (transfer none): a #SoupSessionFeature, or %NULL. The
3037  * feature is owned by @session.
3038  *
3039  * Since: 2.26
3040  **/
3041 SoupSessionFeature *
3042 soup_session_get_feature (SoupSession *session, GType feature_type)
3043 {
3044         SoupSessionPrivate *priv;
3045         SoupSessionFeature *feature;
3046         GSList *f;
3047
3048         g_return_val_if_fail (SOUP_IS_SESSION (session), NULL);
3049
3050         priv = SOUP_SESSION_GET_PRIVATE (session);
3051
3052         feature = g_hash_table_lookup (priv->features_cache,
3053                                        GSIZE_TO_POINTER (feature_type));
3054         if (feature)
3055                 return feature;
3056
3057         for (f = priv->features; f; f = f->next) {
3058                 feature = f->data;
3059                 if (G_TYPE_CHECK_INSTANCE_TYPE (feature, feature_type)) {
3060                         g_hash_table_insert (priv->features_cache,
3061                                              GSIZE_TO_POINTER (feature_type),
3062                                              feature);
3063                         return feature;
3064                 }
3065         }
3066         return NULL;
3067 }
3068
3069 /**
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
3074  *
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.
3082  *
3083  * Return value: (transfer none): a #SoupSessionFeature, or %NULL. The
3084  * feature is owned by @session.
3085  *
3086  * Since: 2.28
3087  **/
3088 SoupSessionFeature *
3089 soup_session_get_feature_for_message (SoupSession *session, GType feature_type,
3090                                       SoupMessage *msg)
3091 {
3092         SoupSessionFeature *feature;
3093
3094         feature = soup_session_get_feature (session, feature_type);
3095         if (feature && soup_message_disables_feature (msg, feature))
3096                 return NULL;
3097         return feature;
3098 }
3099
3100 #if ENABLE(TIZEN_CERTIFICATE_FILE_SET)
3101
3102 #if ENABLE(TIZEN_TV_FORCE_PRELOAD_TLSDB)
3103 /**
3104  * TLS database preloader thread.
3105  **/
3106 static gpointer
3107 _preload_tlsdb_thread (gpointer p)
3108 {
3109         GError* error = NULL;
3110
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);
3116
3117         return NULL;
3118 }
3119
3120 /**
3121  * Launch the TLS database preloader thread for a specified path.
3122  * This is a one-time function.
3123  **/
3124 static void
3125 soup_preload_tls_database (const gchar *path)
3126 {
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);
3132                 if (_gTlsDB_path)
3133                         g_thread_new ("TLS Preloader", _preload_tlsdb_thread, NULL);
3134         }
3135         g_mutex_unlock (&_gTlsDB_lock);
3136 }
3137 #endif
3138
3139 void soup_session_set_certificate_file(SoupSession *session)
3140 {
3141         SoupSessionPrivate *priv = SOUP_SESSION_GET_PRIVATE (session);
3142
3143         TIZEN_LOGI ("");
3144
3145         if (!priv->certificate_path) {
3146                 TIZEN_LOGI("priv->certificate_path is NULL, return!!");
3147                 return;
3148         }
3149
3150         if (!priv->tlsdb) {
3151
3152                 GError* error = NULL;
3153                 GTlsDatabase* tlsdb = NULL;
3154
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.
3162                         _gTlsDB = NULL;
3163                 } else {
3164                         tlsdb = g_tls_file_database_new (priv->certificate_path, &error);
3165                 }
3166                 g_mutex_unlock (&_gTlsDB_lock);
3167 #else
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);
3172 #endif
3173
3174                 if (!error && tlsdb) {
3175 #if ENABLE(TIZEN_DLOG)
3176                         TIZEN_LOGI ("g_tls_file_database_new() is success. no error call set_tlsdb().");
3177 #endif
3178                         set_tlsdb (session, tlsdb);
3179                 }
3180
3181                 if (tlsdb)
3182                         g_object_unref (tlsdb);
3183                 if (priv->certificate_path) {
3184                         g_free (priv->certificate_path);
3185                         priv->certificate_path = NULL;
3186                 }
3187        }
3188 }
3189 #endif
3190
3191 static void
3192 soup_session_class_init (SoupSessionClass *session_class)
3193 {
3194         GObjectClass *object_class = G_OBJECT_CLASS (session_class);
3195
3196         g_type_class_add_private (session_class, sizeof (SoupSessionPrivate));
3197
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;
3205
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;
3212
3213         /* signals */
3214
3215         /**
3216          * SoupSession::request-queued:
3217          * @session: the session
3218          * @msg: the request that was queued
3219          *
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
3223          * as well.)
3224          *
3225          * When sending a request, first #SoupSession::request_queued
3226          * is emitted, indicating that the session has become aware of
3227          * the request.
3228          *
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.
3236          *
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.
3244          *
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
3248          * with the message.
3249          *
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.
3255          *
3256          * Since: 2.24
3257          **/
3258         signals[REQUEST_QUEUED] =
3259                 g_signal_new ("request-queued",
3260                               G_OBJECT_CLASS_TYPE (object_class),
3261                               G_SIGNAL_RUN_FIRST,
3262                               0, /* FIXME? */
3263                               NULL, NULL,
3264                               NULL,
3265                               G_TYPE_NONE, 1,
3266                               SOUP_TYPE_MESSAGE);
3267
3268         /**
3269          * SoupSession::request-started:
3270          * @session: the session
3271          * @msg: the request being sent
3272          * @socket: the socket the request is being sent on
3273          *
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.
3277          **/
3278         signals[REQUEST_STARTED] =
3279                 g_signal_new ("request-started",
3280                               G_OBJECT_CLASS_TYPE (object_class),
3281                               G_SIGNAL_RUN_FIRST,
3282                               G_STRUCT_OFFSET (SoupSessionClass, request_started),
3283                               NULL, NULL,
3284                               NULL,
3285                               G_TYPE_NONE, 2,
3286                               SOUP_TYPE_MESSAGE,
3287                               SOUP_TYPE_SOCKET);
3288
3289         /**
3290          * SoupSession::request-unqueued:
3291          * @session: the session
3292          * @msg: the request that was unqueued
3293          *
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.
3298          *
3299          * Since: 2.24
3300          **/
3301         signals[REQUEST_UNQUEUED] =
3302                 g_signal_new ("request-unqueued",
3303                               G_OBJECT_CLASS_TYPE (object_class),
3304                               G_SIGNAL_RUN_FIRST,
3305                               0, /* FIXME? */
3306                               NULL, NULL,
3307                               NULL,
3308                               G_TYPE_NONE, 1,
3309                               SOUP_TYPE_MESSAGE);
3310
3311         /**
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
3317          *
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.
3324          *
3325          * Note that this may be emitted before @msg's body has been
3326          * fully read.
3327          *
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.
3333          **/
3334         signals[AUTHENTICATE] =
3335                 g_signal_new ("authenticate",
3336                               G_OBJECT_CLASS_TYPE (object_class),
3337                               G_SIGNAL_RUN_FIRST,
3338                               G_STRUCT_OFFSET (SoupSessionClass, authenticate),
3339                               NULL, NULL,
3340                               NULL,
3341                               G_TYPE_NONE, 3,
3342                               SOUP_TYPE_MESSAGE,
3343                               SOUP_TYPE_AUTH,
3344                               G_TYPE_BOOLEAN);
3345
3346         /**
3347          * SoupSession::connection-created:
3348          * @session: the #SoupSession
3349          * @connection: the connection
3350          *
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.
3354          *
3355          * Since: 2.30
3356          */
3357         signals[CONNECTION_CREATED] =
3358                 g_signal_new ("connection-created",
3359                               G_OBJECT_CLASS_TYPE (object_class),
3360                               G_SIGNAL_RUN_FIRST,
3361                               0,
3362                               NULL, NULL,
3363                               NULL,
3364                               G_TYPE_NONE, 1,
3365                               /* SoupConnection is private, so we can't use
3366                                * SOUP_TYPE_CONNECTION here.
3367                                */
3368                               G_TYPE_OBJECT);
3369
3370         /**
3371          * SoupSession::tunneling:
3372          * @session: the #SoupSession
3373          * @connection: the connection
3374          *
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.
3378          *
3379          * Since: 2.30
3380          */
3381         signals[TUNNELING] =
3382                 g_signal_new ("tunneling",
3383                               G_OBJECT_CLASS_TYPE (object_class),
3384                               G_SIGNAL_RUN_FIRST,
3385                               0,
3386                               NULL, NULL,
3387                               NULL,
3388                               G_TYPE_NONE, 1,
3389                               /* SoupConnection is private, so we can't use
3390                                * SOUP_TYPE_CONNECTION here.
3391                                */
3392                               G_TYPE_OBJECT);
3393
3394
3395         /* properties */
3396         /**
3397          * SoupSession:proxy-uri:
3398          *
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.
3405          *
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.
3410          *
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.
3416          */
3417         /**
3418          * SOUP_SESSION_PROXY_URI:
3419          *
3420          * Alias for the #SoupSession:proxy-uri property, qv.
3421          **/
3422         g_object_class_install_property (
3423                 object_class, PROP_PROXY_URI,
3424                 g_param_spec_boxed (SOUP_SESSION_PROXY_URI,
3425                                     "Proxy URI",
3426                                     "The HTTP Proxy to use for this session",
3427                                     SOUP_TYPE_URI,
3428                                     G_PARAM_READWRITE));
3429         /**
3430          * SoupSession:proxy-resolver:
3431          *
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.
3436          *
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
3441          * used.
3442          *
3443          * Since: 2.42
3444          */
3445         /**
3446          * SOUP_SESSION_PROXY_RESOLVER:
3447          *
3448          * Alias for the #SoupSession:proxy-resolver property, qv.
3449          **/
3450         g_object_class_install_property (
3451                 object_class, PROP_PROXY_RESOLVER,
3452                 g_param_spec_object (SOUP_SESSION_PROXY_RESOLVER,
3453                                      "Proxy Resolver",
3454                                      "The GProxyResolver to use for this session",
3455                                      G_TYPE_PROXY_RESOLVER,
3456                                      G_PARAM_READWRITE));
3457         /**
3458          * SOUP_SESSION_MAX_CONNS:
3459          *
3460          * Alias for the #SoupSession:max-conns property, qv.
3461          **/
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",
3467                                   1,
3468                                   G_MAXINT,
3469                                   SOUP_SESSION_MAX_CONNS_DEFAULT,
3470                                   G_PARAM_READWRITE));
3471         /**
3472          * SOUP_SESSION_MAX_CONNS_PER_HOST:
3473          *
3474          * Alias for the #SoupSession:max-conns-per-host property, qv.
3475          **/
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",
3481                                   1,
3482                                   G_MAXINT,
3483                                   SOUP_SESSION_MAX_CONNS_PER_HOST_DEFAULT,
3484                                   G_PARAM_READWRITE));
3485         /**
3486          * SoupSession:idle-timeout:
3487          *
3488          * Connection lifetime (in seconds) when idle. Any connection
3489          * left idle longer than this will be closed.
3490          *
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.
3496          *
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).
3501          *
3502          * Since: 2.24
3503          **/
3504         /**
3505          * SOUP_SESSION_IDLE_TIMEOUT:
3506          *
3507          * Alias for the #SoupSession:idle-timeout property, qv.
3508          *
3509          * Since: 2.24
3510          **/
3511         g_object_class_install_property (
3512                 object_class, PROP_IDLE_TIMEOUT,
3513                 g_param_spec_uint (SOUP_SESSION_IDLE_TIMEOUT,
3514                                    "Idle Timeout",
3515                                    "Connection lifetime when idle",
3516                                    0, G_MAXUINT, 60,
3517                                    G_PARAM_READWRITE));
3518         /**
3519          * SoupSession:use-ntlm:
3520          *
3521          * Whether or not to use NTLM authentication.
3522          *
3523          * Deprecated: use soup_session_add_feature_by_type() with
3524          * #SOUP_TYPE_AUTH_NTLM.
3525          **/
3526         /**
3527          * SOUP_SESSION_USE_NTLM:
3528          *
3529          * Alias for the #SoupSession:use-ntlm property, qv.
3530          **/
3531         g_object_class_install_property (
3532                 object_class, PROP_USE_NTLM,
3533                 g_param_spec_boolean (SOUP_SESSION_USE_NTLM,
3534                                       "Use NTLM",
3535                                       "Whether or not to use NTLM authentication",
3536                                       FALSE,
3537                                       G_PARAM_READWRITE | G_PARAM_DEPRECATED));
3538         /**
3539          * SoupSession:ssl-ca-file:
3540          *
3541          * File containing SSL CA certificates.
3542          *
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.
3547          *
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).
3551          **/
3552         /**
3553          * SOUP_SESSION_SSL_CA_FILE:
3554          *
3555          * Alias for the #SoupSession:ssl-ca-file property, qv.
3556          **/
3557         g_object_class_install_property (
3558                 object_class, PROP_SSL_CA_FILE,
3559                 g_param_spec_string (SOUP_SESSION_SSL_CA_FILE,
3560                                      "SSL CA file",
3561                                      "File containing SSL CA certificates",
3562                                      NULL,
3563                                      G_PARAM_READWRITE | G_PARAM_DEPRECATED));
3564         /**
3565          * SOUP_SESSION_SSL_USE_SYSTEM_CA_FILE:
3566          *
3567          * Alias for the #SoupSession:ssl-use-system-ca-file property,
3568          * qv.
3569          *
3570          * Since: 2.38
3571          **/
3572         /**
3573          * SoupSession:ssl-use-system-ca-file:
3574          *
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
3579          * become %TRUE).
3580          *
3581          * Setting this to %FALSE (when it was previously %TRUE) will
3582          * clear the #SoupSession:tls-database field.
3583          *
3584          * See #SoupSession:ssl-strict for more information on how
3585          * https certificate validation is handled.
3586          *
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
3590          * compatibility.
3591          *
3592          * Since: 2.38
3593          **/
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",
3599                                       TRUE,
3600                                       G_PARAM_READWRITE));
3601         /**
3602          * SOUP_SESSION_TLS_DATABASE:
3603          *
3604          * Alias for the #SoupSession:tls-database property, qv.
3605          *
3606          * Since: 2.38
3607          **/
3608         /**
3609          * SoupSession:tls-database:
3610          *
3611          * Sets the #GTlsDatabase to use for validating SSL/TLS
3612          * certificates.
3613          *
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.
3618          *
3619          * See #SoupSession:ssl-strict for more information on how
3620          * https certificate validation is handled.
3621          *
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.
3627          *
3628          * Since: 2.38
3629          **/
3630         g_object_class_install_property (
3631                 object_class, PROP_TLS_DATABASE,
3632                 g_param_spec_object (SOUP_SESSION_TLS_DATABASE,
3633                                      "TLS Database",
3634                                      "TLS database to use",
3635                                      G_TYPE_TLS_DATABASE,
3636                                      G_PARAM_READWRITE));
3637         /**
3638          * SOUP_SESSION_SSL_STRICT:
3639          *
3640          * Alias for the #SoupSession:ssl-strict property, qv.
3641          *
3642          * Since: 2.30
3643          **/
3644         /**
3645          * SoupSession:ssl-strict:
3646          *
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.
3654          *
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
3660          * warning.)
3661          *
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.
3669          *
3670          * Since: 2.30
3671          */
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",
3677                                       TRUE,
3678                                       G_PARAM_READWRITE));
3679         /**
3680          * SoupSession:async-context:
3681          *
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
3685          * context.)
3686          *
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.
3692          *
3693          * If #SoupSession:use-thread-context is %FALSE, this context
3694          * will also be used for asynchronous HTTP I/O.
3695          */
3696         /**
3697          * SOUP_SESSION_ASYNC_CONTEXT:
3698          *
3699          * Alias for the #SoupSession:async-context property, qv.
3700          */
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));
3707         /**
3708          * SOUP_SESSION_USE_THREAD_CONTEXT:
3709          *
3710          * Alias for the #SoupSession:use-thread-context property, qv.
3711          *
3712          * Since: 2.38
3713          */
3714         /**
3715          * SoupSession:use-thread-context:
3716          *
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.
3722          *
3723          * Since: 2.38
3724          */
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",
3730                                       FALSE,
3731                                       G_PARAM_READWRITE));
3732         /**
3733          * SoupSession:timeout:
3734          *
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).
3738          *
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.
3744          *
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).
3749          *
3750          * Not to be confused with #SoupSession:idle-timeout (which is
3751          * the length of time that idle persistent connections will be
3752          * kept open).
3753          */
3754         /**
3755          * SOUP_SESSION_TIMEOUT:
3756          *
3757          * Alias for the #SoupSession:timeout property, qv.
3758          **/
3759         g_object_class_install_property (
3760                 object_class, PROP_TIMEOUT,
3761                 g_param_spec_uint (SOUP_SESSION_TIMEOUT,
3762                                    "Timeout value",
3763                                    "Value in seconds to timeout a blocking I/O",
3764                                    0, G_MAXUINT, 0,
3765                                    G_PARAM_READWRITE));
3766
3767         /**
3768          * SoupSession:user-agent:
3769          *
3770          * If non-%NULL, the value to use for the "User-Agent" header
3771          * on #SoupMessage<!-- -->s sent from this session.
3772          *
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."
3780          *
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.
3788          *
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
3792          * header for you.
3793          **/
3794         /**
3795          * SOUP_SESSION_USER_AGENT:
3796          *
3797          * Alias for the #SoupSession:user-agent property, qv.
3798          **/
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",
3804                                      NULL,
3805                                      G_PARAM_READWRITE));
3806
3807         /**
3808          * SoupSession:accept-language:
3809          *
3810          * If non-%NULL, the value to use for the "Accept-Language" header
3811          * on #SoupMessage<!-- -->s sent from this session.
3812          *
3813          * Setting this will disable
3814          * #SoupSession:accept-language-auto.
3815          *
3816          * Since: 2.30
3817          **/
3818         /**
3819          * SOUP_SESSION_ACCEPT_LANGUAGE:
3820          *
3821          * Alias for the #SoupSession:accept-language property, qv.
3822          *
3823          * Since: 2.30
3824          **/
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",
3830                                      NULL,
3831                                      G_PARAM_READWRITE));
3832
3833         /**
3834          * SoupSession:accept-language-auto:
3835          *
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().
3839          *
3840          * Setting this will override any previous value of
3841          * #SoupSession:accept-language.
3842          *
3843          * Since: 2.30
3844          **/
3845         /**
3846          * SOUP_SESSION_ACCEPT_LANGUAGE_AUTO:
3847          *
3848          * Alias for the #SoupSession:accept-language-auto property, qv.
3849          *
3850          * Since: 2.30
3851          **/
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",
3857                                       FALSE,
3858                                       G_PARAM_READWRITE));
3859
3860         /**
3861          * SoupSession:add-feature: (skip)
3862          *
3863          * Add a feature object to the session. (Shortcut for calling
3864          * soup_session_add_feature().)
3865          *
3866          * Since: 2.24
3867          **/
3868         /**
3869          * SOUP_SESSION_ADD_FEATURE: (skip)
3870          *
3871          * Alias for the #SoupSession:add-feature property, qv.
3872          *
3873          * Since: 2.24
3874          **/
3875         g_object_class_install_property (
3876                 object_class, PROP_ADD_FEATURE,
3877                 g_param_spec_object (SOUP_SESSION_ADD_FEATURE,
3878                                      "Add Feature",
3879                                      "Add a feature object to the session",
3880                                      SOUP_TYPE_SESSION_FEATURE,
3881                                      G_PARAM_READWRITE));
3882         /**
3883          * SoupSession:add-feature-by-type: (skip)
3884          *
3885          * Add a feature object of the given type to the session.
3886          * (Shortcut for calling soup_session_add_feature_by_type().)
3887          *
3888          * Since: 2.24
3889          **/
3890         /**
3891          * SOUP_SESSION_ADD_FEATURE_BY_TYPE: (skip)
3892          *
3893          * Alias for the #SoupSession:add-feature-by-type property, qv.
3894          *
3895          * Since: 2.24
3896          **/
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",
3902                                     G_TYPE_OBJECT,
3903                                     G_PARAM_READWRITE));
3904         /**
3905          * SoupSession:remove-feature-by-type: (skip)
3906          *
3907          * Remove feature objects from the session. (Shortcut for
3908          * calling soup_session_remove_feature_by_type().)
3909          *
3910          * Since: 2.24
3911          **/
3912         /**
3913          * SOUP_SESSION_REMOVE_FEATURE_BY_TYPE: (skip)
3914          *
3915          * Alias for the #SoupSession:remove-feature-by-type property,
3916          * qv.
3917          *
3918          * Since: 2.24
3919          **/
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",
3925                                     G_TYPE_OBJECT,
3926                                     G_PARAM_READWRITE));
3927         /**
3928          * SoupSession:http-aliases:
3929          *
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>.
3935          *
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".
3943          *
3944          * See also #SoupSession:https-aliases.
3945          *
3946          * Since: 2.38
3947          */
3948         /**
3949          * SOUP_SESSION_HTTP_ALIASES:
3950          *
3951          * Alias for the #SoupSession:http-aliases property, qv.
3952          *
3953          * Since: 2.38
3954          */
3955         g_object_class_install_property (
3956                 object_class, PROP_HTTP_ALIASES,
3957                 g_param_spec_boxed (SOUP_SESSION_HTTP_ALIASES,
3958                                     "http aliases",
3959                                     "URI schemes that are considered aliases for 'http'",
3960                                     G_TYPE_STRV,
3961                                     G_PARAM_READWRITE));
3962         /**
3963          * SoupSession:https-aliases:
3964          *
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.
3968          *
3969          * The default value is %NULL, meaning that no URI schemes
3970          * are considered aliases for "https".
3971          *
3972          * Since: 2.38
3973          */
3974         /**
3975          * SOUP_SESSION_HTTPS_ALIASES:
3976          *
3977          * Alias for the #SoupSession:https-aliases property, qv.
3978          *
3979          * Since: 2.38
3980          **/
3981         g_object_class_install_property (
3982                 object_class, PROP_HTTPS_ALIASES,
3983                 g_param_spec_boxed (SOUP_SESSION_HTTPS_ALIASES,
3984                                     "https aliases",
3985                                     "URI schemes that are considered aliases for 'https'",
3986                                     G_TYPE_STRV,
3987                                     G_PARAM_READWRITE));
3988
3989         /**
3990          * SOUP_SESSION_LOCAL_ADDRESS:
3991          *
3992          * Alias for the #SoupSession:local-address property, qv.
3993          *
3994          * Since: 2.42
3995          **/
3996         /**
3997          * SoupSession:local-address:
3998          *
3999          * Sets the #SoupAddress to use for the client side of
4000          * the connection.
4001          *
4002          * Use this property if you want for instance to bind the
4003          * local socket to a specific IP address.
4004          *
4005          * Since: 2.42
4006          **/
4007         g_object_class_install_property (
4008                 object_class, PROP_LOCAL_ADDRESS,
4009                 g_param_spec_object (SOUP_SESSION_LOCAL_ADDRESS,
4010                                      "Local address",
4011                                      "Address of local end of socket",
4012                                      SOUP_TYPE_ADDRESS,
4013                                      G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
4014
4015 #if ENABLE(TIZEN_CERTIFICATE_FILE_SET)
4016         /**
4017          * SOUP_SESSION_CERTIFICATE_PATH
4018          * SoupSession:certificate-path:
4019          *
4020          * Set the certificate path for soup session
4021          *
4022          */
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",
4028                                      NULL,
4029                                      G_PARAM_READWRITE));
4030 #endif
4031
4032 #if ENABLE(TIZEN_TV_CLIENT_CERTIFICATE)
4033         /**
4034         * SOUP_SESSION_USE_WIDGETENGINE:
4035         *
4036         * Alias for the #SoupSession:widget-engine property.
4037         *
4038         **/
4039
4040         g_object_class_install_property (
4041                 object_class, PROP_WIDGET_ENGINE,
4042                 g_param_spec_boolean (SOUP_SESSION_WIDGET_ENGINE,
4043                                 "widget engine",
4044                                 "Whether or not to be running Widget Engine",
4045                                 FALSE,
4046                                 G_PARAM_READWRITE));
4047
4048
4049 #endif
4050 }
4051
4052
4053 static gboolean
4054 expected_to_be_requeued (SoupSession *session, SoupMessage *msg)
4055 {
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);
4061         }
4062
4063         if (!(soup_message_get_flags (msg) & SOUP_MESSAGE_NO_REDIRECT))
4064                 return soup_session_would_redirect (session, msg);
4065
4066         return FALSE;
4067 }
4068
4069 /* send_request_async */
4070
4071 static void
4072 async_send_request_return_result (SoupMessageQueueItem *item,
4073                                   gpointer stream, GError *error)
4074 {
4075         GTask *task;
4076
4077         g_return_if_fail (item->task != NULL);
4078
4079         g_signal_handlers_disconnect_matched (item->msg, G_SIGNAL_MATCH_DATA,
4080                                               0, 0, NULL, NULL, item);
4081
4082         task = item->task;
4083         item->task = NULL;
4084
4085         if (item->io_source) {
4086                 g_source_destroy (item->io_source);
4087                 g_clear_pointer (&item->io_source, g_source_unref);
4088         }
4089
4090         if (error)
4091                 g_task_return_error (task, error);
4092         else if (item->error) {
4093                 if (stream)
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)) {
4097                 if (stream)
4098                         g_object_unref (stream);
4099                 g_task_return_new_error (task, SOUP_HTTP_ERROR,
4100                                          item->msg->status_code,
4101                                          "%s",
4102                                          item->msg->reason_phrase);
4103         } else
4104                 g_task_return_pointer (task, stream, g_object_unref);
4105         g_object_unref (task);
4106 }
4107
4108 static void
4109 async_send_request_restarted (SoupMessage *msg, gpointer user_data)
4110 {
4111         SoupMessageQueueItem *item = user_data;
4112
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;
4116 }
4117
4118 static void
4119 async_send_request_finished (SoupMessage *msg, gpointer user_data)
4120 {
4121         SoupMessageQueueItem *item = user_data;
4122         GMemoryOutputStream *mostream;
4123         GInputStream *istream = NULL;
4124         GError *error = NULL;
4125
4126         if (!item->task) {
4127                 /* Something else already took care of it. */
4128                 return;
4129         }
4130
4131         mostream = g_object_get_data (G_OBJECT (item->task), "SoupSession:ostream");
4132         if (mostream) {
4133                 gpointer data;
4134                 gssize size;
4135
4136                 /* We thought it would be requeued, but it wasn't, so
4137                  * return the original body.
4138                  */
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()
4146                  * after we return;
4147                  */
4148                 return;
4149         } else {
4150                 /* The message finished before even being started;
4151                  * probably a tunnel connect failure.
4152                  */
4153                 istream = g_memory_input_stream_new ();
4154         }
4155
4156         async_send_request_return_result (item, istream, error);
4157 }
4158
4159 static void
4160 send_async_spliced (GObject *source, GAsyncResult *result, gpointer user_data)
4161 {
4162         SoupMessageQueueItem *item = user_data;
4163         GInputStream *istream = g_object_get_data (source, "istream");
4164         GError *error = NULL;
4165
4166         /* It should be safe to call the sync close() method here since
4167          * the message body has already been written.
4168          */
4169         g_input_stream_close (istream, NULL, NULL);
4170         g_object_unref (istream);
4171
4172         /* If the message was cancelled, it will be completed via other means */
4173         if (g_cancellable_is_cancelled (item->cancellable) ||
4174             !item->task) {
4175                 soup_message_queue_item_unref (item);
4176                 return;
4177         }
4178
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);
4183                 return;
4184         }
4185
4186         /* Otherwise either restarted or finished will eventually be called. */
4187         soup_session_kick_queue (item->session);
4188         soup_message_queue_item_unref (item);
4189 }
4190
4191 static void
4192 send_async_maybe_complete (SoupMessageQueueItem *item,
4193                            GInputStream         *stream)
4194 {
4195         if (expected_to_be_requeued (item->session, item->msg)) {
4196                 GOutputStream *ostream;
4197
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);
4202
4203                 g_object_set_data (G_OBJECT (ostream), "istream", stream);
4204
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.
4209                  */
4210                 g_output_stream_splice_async (ostream, stream,
4211                                               G_OUTPUT_STREAM_SPLICE_CLOSE_TARGET,
4212                                               G_PRIORITY_DEFAULT,
4213                                               item->cancellable,
4214                                               send_async_spliced, item);
4215                 return;
4216         }
4217
4218         async_send_request_return_result (item, stream, NULL);
4219 }
4220
4221 static void try_run_until_read (SoupMessageQueueItem *item);
4222
4223 static gboolean
4224 read_ready_cb (SoupMessage *msg, gpointer user_data)
4225 {
4226         SoupMessageQueueItem *item = user_data;
4227
4228         g_clear_pointer (&item->io_source, g_source_unref);
4229         try_run_until_read (item);
4230         return FALSE;
4231 }
4232
4233 static void
4234 try_run_until_read (SoupMessageQueueItem *item)
4235 {
4236         GError *error = NULL;
4237         GInputStream *stream = NULL;
4238
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);
4241         if (stream) {
4242                 send_async_maybe_complete (item, stream);
4243                 return;
4244         }
4245
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);
4250                 return;
4251         }
4252
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);
4259                 }
4260                 async_send_request_return_result (item, NULL, error);
4261                 return;
4262         }
4263
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));
4268 }
4269
4270 static void
4271 async_send_request_running (SoupSession *session, SoupMessageQueueItem *item)
4272 {
4273         item->io_started = TRUE;
4274         try_run_until_read (item);
4275 }
4276
4277 static void
4278 async_return_from_cache (SoupMessageQueueItem *item,
4279                          GInputStream         *stream)
4280 {
4281         const char *content_type;
4282         GHashTable *params = NULL;
4283
4284         soup_message_got_headers (item->msg);
4285
4286         content_type = soup_message_headers_get_content_type (item->msg->response_headers, &params);
4287         if (content_type) {
4288                 soup_message_content_sniffed (item->msg, content_type, params);
4289                 g_hash_table_unref (params);
4290         }
4291
4292         item->state = SOUP_MESSAGE_FINISHING;
4293         async_send_request_return_result (item, g_object_ref (stream), NULL);
4294 }
4295
4296 typedef struct {
4297         SoupCache *cache;
4298         SoupMessage *conditional_msg;
4299 } AsyncCacheCancelData;
4300
4301
4302 static void
4303 free_async_cache_cancel_data (AsyncCacheCancelData *data)
4304 {
4305         g_object_unref (data->conditional_msg);
4306         g_object_unref (data->cache);
4307         g_slice_free (AsyncCacheCancelData, data);
4308 }
4309
4310 static void
4311 cancel_cache_response (SoupMessageQueueItem *item)
4312 {
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);
4317 }
4318
4319 static void
4320 conditional_request_cancelled_cb (GCancellable *cancellable, AsyncCacheCancelData *data)
4321 {
4322         soup_cache_cancel_conditional_request (data->cache, data->conditional_msg);
4323 }
4324
4325 static void
4326 conditional_get_ready_cb (SoupSession *session, SoupMessage *msg, gpointer user_data)
4327 {
4328         SoupMessageQueueItem *item = user_data;
4329         GInputStream *stream;
4330         SoupCache *cache;
4331
4332         if (g_cancellable_is_cancelled (item->cancellable)) {
4333                 cancel_cache_response (item);
4334                 return;
4335         } else {
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);
4338         }
4339
4340         cache = (SoupCache *)soup_session_get_feature (session, SOUP_TYPE_CACHE);
4341         soup_cache_update_from_conditional_request (cache, msg);
4342
4343         if (msg->status_code == SOUP_STATUS_NOT_MODIFIED) {
4344                 stream = soup_cache_send_response (cache, item->msg);
4345                 if (stream) {
4346                         async_return_from_cache (item, stream);
4347                         g_object_unref (stream);
4348                         return;
4349                 }
4350         }
4351
4352         /* The resource was modified or the server returned a 200
4353          * OK. Either way we reload it. FIXME.
4354          */
4355         item->state = SOUP_MESSAGE_STARTING;
4356         soup_session_kick_queue (session);
4357 }
4358
4359 static gboolean
4360 idle_return_from_cache_cb (gpointer data)
4361 {
4362         GTask *task = data;
4363         SoupMessageQueueItem *item = g_task_get_task_data (task);
4364         GInputStream *istream;
4365
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.
4370                  */
4371                 return FALSE;
4372         } else if (g_cancellable_is_cancelled (item->cancellable)) {
4373                 /* Cancel original msg after g_cancellable_cancel(). */
4374                 cancel_cache_response (item);
4375                 return FALSE;
4376         }
4377
4378         istream = g_object_get_data (G_OBJECT (task), "SoupSession:istream");
4379         async_return_from_cache (item, istream);
4380
4381         return FALSE;
4382 }
4383
4384
4385 static gboolean
4386 async_respond_from_cache (SoupSession          *session,
4387                           SoupMessageQueueItem *item)
4388 {
4389         SoupCache *cache;
4390         SoupCacheResponse response;
4391
4392         cache = (SoupCache *)soup_session_get_feature (session, SOUP_TYPE_CACHE);
4393         if (!cache)
4394                 return FALSE;
4395
4396         response = soup_cache_has_response (cache, item->msg);
4397         if (response == SOUP_CACHE_RESPONSE_FRESH) {
4398                 GInputStream *stream;
4399                 GSource *source;
4400
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));
4403 #endif
4404                 stream = soup_cache_send_response (cache, item->msg);
4405                 if (!stream) {
4406                         /* Cached file was deleted? */
4407                         return FALSE;
4408                 }
4409                 g_object_set_data_full (G_OBJECT (item->task), "SoupSession:istream",
4410                                         stream, g_object_unref);
4411
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);
4416                 return TRUE;
4417         } else if (response == SOUP_CACHE_RESPONSE_NEEDS_VALIDATION) {
4418                 SoupMessage *conditional_msg;
4419                 AsyncCacheCancelData *data;
4420                 gulong handler_id;
4421
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));
4424 #endif
4425                 conditional_msg = soup_cache_generate_conditional_request (cache, item->msg);
4426                 if (!conditional_msg)
4427                         return FALSE;
4428
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);
4435
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,
4440                                             item);
4441
4442
4443                 return TRUE;
4444         } else {
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));
4447 #endif
4448                 return FALSE;
4449         }
4450 }
4451
4452 /**
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
4459  *
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.
4465  *
4466  * See soup_session_send() for more details on the general semantics.
4467  *
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.
4471  *
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.)
4476  *
4477  * Since: 2.42
4478  */
4479 void
4480 soup_session_send_async (SoupSession         *session,
4481                          SoupMessage         *msg,
4482                          GCancellable        *cancellable,
4483                          GAsyncReadyCallback  callback,
4484                          gpointer             user_data)
4485 {
4486         SoupMessageQueueItem *item;
4487         gboolean use_thread_context;
4488 #if ENABLE(TIZEN_TV_IMMEDIATE_REQUESTING)
4489         gboolean should_prune = FALSE;
4490 #endif
4491
4492         g_return_if_fail (SOUP_IS_SESSION (session));
4493         g_return_if_fail (!SOUP_IS_SESSION_SYNC (session));
4494
4495         g_object_get (G_OBJECT (session),
4496                       SOUP_SESSION_USE_THREAD_CONTEXT, &use_thread_context,
4497                       NULL);
4498         g_return_if_fail (use_thread_context);
4499
4500         item = soup_session_append_queue_item (session, msg, TRUE, TRUE,
4501                                                NULL, NULL);
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);
4506
4507         if (cancellable) {
4508                 g_object_unref (item->cancellable);
4509                 item->cancellable = g_object_ref (cancellable);
4510         }
4511
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);
4515
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)).
4521          */
4522         g_task_set_check_cancellable (item->task, FALSE);
4523
4524         if (async_respond_from_cache (session, item))
4525                 item->state = SOUP_MESSAGE_CACHED;
4526         else
4527 #if ENABLE(TIZEN_TV_IMMEDIATE_REQUESTING)
4528         {
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);
4532                 }
4533 #endif
4534                 soup_session_kick_queue (session);
4535 #if ENABLE(TIZEN_TV_IMMEDIATE_REQUESTING)
4536         }
4537 #endif
4538 }
4539
4540 /**
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
4545  *
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
4548  * response body.
4549  *
4550  * Return value: (transfer full): a #GInputStream for reading the
4551  *   response body, or %NULL on error.
4552  *
4553  * Since: 2.42
4554  */
4555 GInputStream *
4556 soup_session_send_finish (SoupSession   *session,
4557                           GAsyncResult  *result,
4558                           GError       **error)
4559 {
4560         GTask *task;
4561
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);
4565
4566         task = G_TASK (result);
4567         if (g_task_had_error (task)) {
4568                 SoupMessageQueueItem *item = g_task_get_task_data (task);
4569
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;
4574
4575                 if (item->state != SOUP_MESSAGE_FINISHED)
4576                         soup_session_process_queue_item (session, item, NULL, FALSE);
4577         }
4578
4579         return g_task_propagate_pointer (task, error);
4580 }
4581
4582 /**
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
4588  *
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.)
4594  *
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.
4602  *
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
4606  * received.
4607  *
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.
4611  *
4612  * (Note that this method cannot be called on the deprecated
4613  * #SoupSessionAsync subclass.)
4614  *
4615  * Return value: (transfer full): a #GInputStream for reading the
4616  *   response body, or %NULL on error.
4617  *
4618  * Since: 2.42
4619  */
4620 GInputStream *
4621 soup_session_send (SoupSession   *session,
4622                    SoupMessage   *msg,
4623                    GCancellable  *cancellable,
4624                    GError       **error)
4625 {
4626         SoupMessageQueueItem *item;
4627         GInputStream *stream = NULL;
4628         GOutputStream *ostream;
4629         GMemoryOutputStream *mostream;
4630         gssize size;
4631         GError *my_error = NULL;
4632
4633         g_return_val_if_fail (SOUP_IS_SESSION (session), NULL);
4634         g_return_val_if_fail (!SOUP_IS_SESSION_ASYNC (session), NULL);
4635
4636         item = soup_session_append_queue_item (session, msg, FALSE, TRUE,
4637                                                NULL, NULL);
4638
4639         item->new_api = TRUE;
4640         if (cancellable) {
4641                 g_object_unref (item->cancellable);
4642                 item->cancellable = g_object_ref (cancellable);
4643         }
4644
4645         while (!stream) {
4646                 /* Get a connection, etc */
4647                 soup_session_process_queue_item (session, item, NULL, TRUE);
4648                 if (item->state != SOUP_MESSAGE_RUNNING)
4649                         break;
4650
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);
4657                                 continue;
4658                         } else
4659                                 break;
4660                 }
4661
4662                 stream = soup_message_io_get_response_istream (msg, &my_error);
4663                 if (!stream)
4664                         break;
4665
4666                 if (!expected_to_be_requeued (session, msg))
4667                         break;
4668
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);
4677                         stream = NULL;
4678                         break;
4679                 }
4680                 g_object_unref (stream);
4681                 stream = NULL;
4682
4683                 /* If the message was requeued, loop */
4684                 if (item->state == SOUP_MESSAGE_RESTARTING) {
4685                         g_object_unref (ostream);
4686                         continue;
4687                 }
4688
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 ();
4693                 if (size) {
4694                         g_memory_input_stream_add_data (G_MEMORY_INPUT_STREAM (stream),
4695                                                         g_memory_output_stream_steal_data (mostream),
4696                                                         size, g_free);
4697                 }
4698                 g_object_unref (ostream);
4699         }
4700
4701         if (my_error)
4702                 g_propagate_error (error, my_error);
4703         else if (item->error) {
4704                 g_clear_object (&stream);
4705                 if (error)
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);
4711         } else if (!stream)
4712                 stream = g_memory_input_stream_new ();
4713
4714         if (!stream) {
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;
4719
4720                 if (item->state != SOUP_MESSAGE_FINISHED)
4721                         soup_session_process_queue_item (session, item, NULL, TRUE);
4722         }
4723
4724         soup_message_queue_item_unref (item);
4725         return stream;
4726 }
4727
4728 /**
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
4733  *
4734  * Creates a #SoupRequest for retrieving @uri_string.
4735  *
4736  * Return value: (transfer full): a new #SoupRequest, or
4737  *   %NULL on error.
4738  *
4739  * Since: 2.42
4740  */
4741 SoupRequest *
4742 soup_session_request (SoupSession *session, const char *uri_string,
4743                       GError **error)
4744 {
4745         SoupURI *uri;
4746         SoupRequest *req;
4747
4748         uri = soup_uri_new (uri_string);
4749         if (!uri) {
4750                 g_set_error (error, SOUP_REQUEST_ERROR,
4751                              SOUP_REQUEST_ERROR_BAD_URI,
4752                              _("Could not parse URI '%s'"), uri_string);
4753                 return NULL;
4754         }
4755
4756         req = soup_session_request_uri (session, uri, error);
4757         soup_uri_free (uri);
4758         return req;
4759 }
4760
4761 /**
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
4766  *
4767  * Creates a #SoupRequest for retrieving @uri.
4768  *
4769  * Return value: (transfer full): a new #SoupRequest, or
4770  *   %NULL on error.
4771  *
4772  * Since: 2.42
4773  */
4774 SoupRequest *
4775 soup_session_request_uri (SoupSession *session, SoupURI *uri,
4776                           GError **error)
4777 {
4778         SoupSessionPrivate *priv;
4779         GType request_type;
4780
4781         g_return_val_if_fail (SOUP_IS_SESSION (session), NULL);
4782
4783         priv = SOUP_SESSION_GET_PRIVATE (session);
4784
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);
4790                 return NULL;
4791         }
4792
4793         return g_initable_new (request_type, NULL, error,
4794                                "uri", uri,
4795                                "session", session,
4796                                NULL);
4797 }
4798
4799 static SoupRequestHTTP *
4800 initialize_http_request (SoupRequest  *req,
4801                          const char   *method,
4802                          GError      **error)
4803 {
4804         SoupRequestHTTP *http;
4805         SoupMessage *msg;
4806
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"));
4812                 return NULL;
4813         }
4814
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,
4819                       NULL);
4820         g_object_unref (msg);
4821
4822         return http;
4823 }
4824
4825 /**
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
4831  *
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).
4835  *
4836  * Return value: (transfer full): a new #SoupRequestHTTP, or
4837  *   %NULL on error.
4838  *
4839  * Since: 2.42
4840  */
4841 SoupRequestHTTP *
4842 soup_session_request_http (SoupSession  *session,
4843                            const char   *method,
4844                            const char   *uri_string,
4845                            GError      **error)
4846 {
4847         SoupRequest *req;
4848
4849         req = soup_session_request (session, uri_string, error);
4850         if (!req)
4851                 return NULL;
4852
4853         return initialize_http_request (req, method, error);
4854 }
4855
4856 /**
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
4862  *
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).
4866  *
4867  * Return value: (transfer full): a new #SoupRequestHTTP, or
4868  *   %NULL on error.
4869  *
4870  * Since: 2.42
4871  */
4872 SoupRequestHTTP *
4873 soup_session_request_http_uri (SoupSession  *session,
4874                                const char   *method,
4875                                SoupURI      *uri,
4876                                GError      **error)
4877 {
4878         SoupRequest *req;
4879
4880         req = soup_session_request_uri (session, uri, error);
4881         if (!req)
4882                 return NULL;
4883
4884         return initialize_http_request (req, method, error);
4885 }
4886
4887 /**
4888  * SOUP_REQUEST_ERROR:
4889  *
4890  * A #GError domain for #SoupRequest<!-- -->-related errors. Used with
4891  * #SoupRequestError.
4892  *
4893  * Since: 2.42
4894  */
4895 /**
4896  * 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
4901  *   be parsed
4902  * @SOUP_REQUEST_ERROR_ENCODING: the server's response was in an
4903  *   unsupported format
4904  *
4905  * A #SoupRequest error.
4906  *
4907  * Since: 2.42
4908  */
4909
4910 GQuark
4911 soup_request_error_quark (void)
4912 {
4913         static GQuark error;
4914         if (!error)
4915                 error = g_quark_from_static_string ("soup_request_error_quark");
4916         return error;
4917 }
4918
4919 #if ENABLE(TIZEN_CERTIFICATE_FILE_SET)
4920 static gboolean
4921 set_tls_certificate_file (gpointer session)
4922 {
4923         TIZEN_LOGI("");
4924         soup_session_set_certificate_file(session);
4925
4926         return FALSE;
4927 }
4928
4929 void
4930 soup_session_tls_start_idle_timer (SoupSession *session, guint idle_timeout)
4931 {
4932         SoupSessionPrivate *priv = SOUP_SESSION_GET_PRIVATE (session);
4933
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,
4938                                           idle_timeout,
4939                                           set_tls_certificate_file, session);
4940         }
4941 }
4942
4943 void
4944 soup_session_tls_stop_idle_timer (SoupSession *session)
4945 {
4946         SoupSessionPrivate *priv = SOUP_SESSION_GET_PRIVATE (session);
4947
4948         TIZEN_LOGI ("");
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);
4957                 }
4958                 priv->tls_idle_timeout_src = NULL;
4959         }
4960 }
4961
4962 gboolean
4963 soup_session_is_tls_db_initialized (SoupSession *session)
4964 {
4965         SoupSessionPrivate *priv = SOUP_SESSION_GET_PRIVATE (session);
4966         if (priv && priv->tlsdb)
4967                 return TRUE;
4968         return FALSE;
4969 }
4970 #endif
4971
4972 #if ENABLE(TIZEN_TV_CREATE_IDLE_TCP_CONNECTION)
4973
4974 static SoupConnection *
4975 get_pre_connection_with_uri (SoupSession *session, SoupURI *uri)
4976 {
4977         SoupSessionPrivate *priv = SOUP_SESSION_GET_PRIVATE (session);
4978         SoupConnection *conn = NULL;
4979         SoupSessionHost *host = NULL;
4980
4981         if (!priv)
4982                 return NULL;
4983
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);
4988                 return NULL;
4989         }
4990
4991         if (priv->num_conns >= priv->max_conns) {
4992                 g_mutex_unlock (&priv->conn_lock);
4993                 return NULL;
4994         }
4995
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,
5010                 NULL);
5011
5012         g_signal_connect (conn, "disconnected",
5013                         G_CALLBACK (connection_disconnected),
5014                         session);
5015         g_signal_emit (session, signals[CONNECTION_CREATED], 0, conn);
5016         priv->num_conns++;
5017         host->num_conns++;
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;
5022         }
5023         g_mutex_unlock (&priv->conn_lock);
5024         return g_object_ref (conn);
5025 }
5026
5027 static void
5028 got_pre_connection (GObject *object, GAsyncResult *result, gpointer user_data)
5029 {
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;
5037
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;
5042                 g_object_get (sock,
5043                               SOUP_SOCKET_TLS_ERRORS,
5044                               &errors,
5045                               NULL);
5046         }
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,
5052                               &uri,
5053                               NULL);
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);
5057                 soup_uri_free(uri);
5058                 g_mutex_unlock (&priv->conn_lock);
5059         } else
5060                 soup_connection_disconnect (conn);
5061
5062 }
5063 static gboolean
5064 pre_connection_accept_certificate (SoupConnection      *conn,
5065                           GTlsCertificate* certificate,
5066                           GTlsCertificateFlags errors,
5067                           gpointer             user_data)
5068 {
5069     SoupSession* session = (SoupSession*)user_data;
5070     SoupSessionPrivate *priv = SOUP_SESSION_GET_PRIVATE (session);
5071
5072         if (!priv)
5073                 return FALSE;
5074
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;
5077
5078         return TRUE;
5079 }
5080
5081 void soup_session_create_idle_connection(SoupSession *session, SoupURI* pre_uri)
5082 {
5083         SoupConnection * pre_conn = NULL;
5084         pre_conn = get_pre_connection_with_uri(session, pre_uri);
5085
5086         if (pre_conn) {
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);
5090         }
5091 }
5092 #endif