1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3 * soup-connection.c: A single HTTP/HTTPS connection
5 * Copyright (C) 2000-2003, Ximian, Inc.
12 #include "soup-connection.h"
14 #include "soup-message-queue.h"
15 #include "soup-misc-private.h"
19 #if ENABLE(TIZEN_PERFORMANCE_TEST_LOG)
20 #include <sys/prctl.h>
21 #ifndef PR_TASK_PERF_USER_TRACE
22 #define PR_TASK_PERF_USER_TRACE 666
24 #define MAX_STRING_LEN 256
26 static void prctl_with_url(const char *prestr, const char *url)
28 char s[MAX_STRING_LEN] = "";
30 int len_pre = strlen(prestr);
31 int len_url = strlen(url);
33 strncpy(s, prestr, len_pre);
34 if(len_pre + len_url < len_max) {
35 strncpy(s+len_pre, url, len_url);
38 int len_part = len_max - len_pre - 10;
39 strncpy(s+len_pre, url, len_part);
40 strncpy(s+len_pre+len_part, "...", MAX_STRING_LEN-len_pre-len_part-1);
41 strncpy(s+len_pre+len_part+3, url+len_url-7, 7);
43 prctl(PR_TASK_PERF_USER_TRACE, s, strlen(s));
46 static void prctl_with_url_and_free(const char *prestr, char *url)
48 prctl_with_url(prestr, url);
56 SoupAddress *local_addr;
57 SoupURI *remote_uri, *proxy_uri;
58 GProxyResolver *proxy_resolver;
60 gboolean ssl, ssl_strict, ssl_fallback;
62 GMainContext *async_context;
63 gboolean use_thread_context;
65 SoupMessage *current_msg;
66 SoupConnectionState state;
67 time_t unused_timeout;
68 guint io_timeout, idle_timeout;
69 GSource *idle_timeout_src;
71 #if ENABLE(TIZEN_TV_CREATE_IDLE_TCP_CONNECTION)
72 SoupMessageQueueItem *cur_item;
75 #if ENABLE(TIZEN_TV_CLIENT_CERTIFICATE)
76 gboolean widget_engine;
78 } SoupConnectionPrivate;
79 #define SOUP_CONNECTION_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), SOUP_TYPE_CONNECTION, SoupConnectionPrivate))
81 G_DEFINE_TYPE (SoupConnection, soup_connection, G_TYPE_OBJECT)
86 #if ENABLE(TIZEN_TV_DYNAMIC_CERTIFICATE_LOADING)
87 DYNAMIC_CERTIFICATEPATH,
89 #if ENABLE(TIZEN_TV_CERTIFICATE_HANDLING)
95 static guint signals[LAST_SIGNAL] = { 0 };
108 PROP_USE_THREAD_CONTEXT,
112 #if ENABLE(TIZEN_TV_CLIENT_CERTIFICATE)
119 static void stop_idle_timer (SoupConnectionPrivate *priv);
121 #if ENABLE(TIZEN_TV_CREATE_IDLE_TCP_CONNECTION)
122 static void clear_current_item (SoupConnection *conn);
125 /* Number of seconds after which we close a connection that hasn't yet
128 #define SOUP_CONNECTION_UNUSED_TIMEOUT 3
131 soup_connection_init (SoupConnection *conn)
136 soup_connection_finalize (GObject *object)
138 SoupConnectionPrivate *priv = SOUP_CONNECTION_GET_PRIVATE (object);
140 g_clear_pointer (&priv->remote_uri, soup_uri_free);
141 g_clear_pointer (&priv->proxy_uri, soup_uri_free);
142 g_clear_object (&priv->tlsdb);
143 g_clear_object (&priv->proxy_resolver);
144 g_clear_object (&priv->local_addr);
145 g_clear_pointer (&priv->async_context, g_main_context_unref);
147 G_OBJECT_CLASS (soup_connection_parent_class)->finalize (object);
151 soup_connection_dispose (GObject *object)
153 SoupConnection *conn = SOUP_CONNECTION (object);
154 SoupConnectionPrivate *priv = SOUP_CONNECTION_GET_PRIVATE (conn);
156 stop_idle_timer (priv);
158 #if ENABLE(TIZEN_TV_CREATE_IDLE_TCP_CONNECTION)
159 if (priv->cur_item) {
160 clear_current_item (conn);
164 g_warning ("Disposing connection while connected");
165 soup_connection_disconnect (conn);
168 G_OBJECT_CLASS (soup_connection_parent_class)->dispose (object);
172 soup_connection_set_property (GObject *object, guint prop_id,
173 const GValue *value, GParamSpec *pspec)
175 SoupConnectionPrivate *priv = SOUP_CONNECTION_GET_PRIVATE (object);
178 case PROP_LOCAL_ADDRESS:
179 priv->local_addr = g_value_dup_object (value);
181 case PROP_REMOTE_URI:
182 priv->remote_uri = g_value_dup_boxed (value);
184 case PROP_PROXY_RESOLVER:
185 priv->proxy_resolver = g_value_dup_object (value);
188 priv->ssl = g_value_get_boolean (value);
192 g_object_unref (priv->tlsdb);
193 priv->tlsdb = g_value_dup_object (value);
195 case PROP_SSL_STRICT:
196 priv->ssl_strict = g_value_get_boolean (value);
198 case PROP_SSL_FALLBACK:
199 priv->ssl_fallback = g_value_get_boolean (value);
201 case PROP_ASYNC_CONTEXT:
202 priv->async_context = g_value_get_pointer (value);
203 if (priv->async_context)
204 g_main_context_ref (priv->async_context);
206 case PROP_USE_THREAD_CONTEXT:
207 priv->use_thread_context = g_value_get_boolean (value);
210 priv->io_timeout = g_value_get_uint (value);
212 case PROP_IDLE_TIMEOUT:
213 priv->idle_timeout = g_value_get_uint (value);
216 soup_connection_set_state (SOUP_CONNECTION (object), g_value_get_uint (value));
218 #if ENABLE(TIZEN_TV_CLIENT_CERTIFICATE)
219 case PROP_WIDGET_ENGINE:
220 priv->widget_engine = g_value_get_boolean (value);
224 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
230 soup_connection_get_property (GObject *object, guint prop_id,
231 GValue *value, GParamSpec *pspec)
233 SoupConnectionPrivate *priv = SOUP_CONNECTION_GET_PRIVATE (object);
236 case PROP_LOCAL_ADDRESS:
237 g_value_set_object (value, priv->local_addr);
239 case PROP_REMOTE_URI:
240 g_value_set_boxed (value, priv->remote_uri);
243 g_value_set_boolean (value, priv->ssl);
246 g_value_set_object (value, priv->tlsdb);
248 case PROP_SSL_STRICT:
249 g_value_set_boolean (value, priv->ssl_strict);
251 case PROP_SSL_FALLBACK:
252 g_value_set_boolean (value, priv->ssl_fallback);
254 case PROP_ASYNC_CONTEXT:
255 g_value_set_pointer (value, priv->async_context ? g_main_context_ref (priv->async_context) : NULL);
257 case PROP_USE_THREAD_CONTEXT:
258 g_value_set_boolean (value, priv->use_thread_context);
261 g_value_set_uint (value, priv->io_timeout);
263 case PROP_IDLE_TIMEOUT:
264 g_value_set_uint (value, priv->idle_timeout);
267 g_value_set_enum (value, priv->state);
269 #if ENABLE(TIZEN_TV_CLIENT_CERTIFICATE)
270 case PROP_WIDGET_ENGINE:
271 g_value_set_boolean (value, priv->widget_engine);
275 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
281 soup_connection_class_init (SoupConnectionClass *connection_class)
283 GObjectClass *object_class = G_OBJECT_CLASS (connection_class);
285 g_type_class_add_private (connection_class, sizeof (SoupConnectionPrivate));
287 /* virtual method override */
288 object_class->dispose = soup_connection_dispose;
289 object_class->finalize = soup_connection_finalize;
290 object_class->set_property = soup_connection_set_property;
291 object_class->get_property = soup_connection_get_property;
295 g_signal_new ("event",
296 G_OBJECT_CLASS_TYPE (object_class),
302 G_TYPE_SOCKET_CLIENT_EVENT,
304 signals[DISCONNECTED] =
305 g_signal_new ("disconnected",
306 G_OBJECT_CLASS_TYPE (object_class),
308 G_STRUCT_OFFSET (SoupConnectionClass, disconnected),
312 #if ENABLE(TIZEN_TV_CERTIFICATE_HANDLING)
313 signals[ACCEPT_CERTIFICATE] =
314 g_signal_new ("accept-certificate",
315 G_OBJECT_CLASS_TYPE (object_class),
321 G_TYPE_TLS_CERTIFICATE,
322 G_TYPE_TLS_CERTIFICATE_FLAGS);
325 #if ENABLE(TIZEN_TV_DYNAMIC_CERTIFICATE_LOADING)
326 signals[DYNAMIC_CERTIFICATEPATH] =
327 g_signal_new ("dynamic-certificatePath",
328 G_OBJECT_CLASS_TYPE (object_class),
338 g_object_class_install_property (
339 object_class, PROP_LOCAL_ADDRESS,
340 g_param_spec_object (SOUP_CONNECTION_LOCAL_ADDRESS,
342 "Address of local end of socket",
344 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
345 g_object_class_install_property (
346 object_class, PROP_REMOTE_URI,
347 g_param_spec_boxed (SOUP_CONNECTION_REMOTE_URI,
349 "The URI of the HTTP server",
351 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
352 g_object_class_install_property (
353 object_class, PROP_PROXY_RESOLVER,
354 g_param_spec_object (SOUP_CONNECTION_PROXY_RESOLVER,
356 "GProxyResolver to use",
357 G_TYPE_PROXY_RESOLVER,
358 G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));
359 g_object_class_install_property (
360 object_class, PROP_SSL,
361 g_param_spec_boolean (SOUP_CONNECTION_SSL,
363 "Whether this is an SSL connection",
365 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
366 g_object_class_install_property (
367 object_class, PROP_SSL_CREDS,
368 g_param_spec_object (SOUP_CONNECTION_SSL_CREDENTIALS,
370 "SSL credentials for this connection",
372 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
373 g_object_class_install_property (
374 object_class, PROP_SSL_STRICT,
375 g_param_spec_boolean (SOUP_CONNECTION_SSL_STRICT,
376 "Strictly validate SSL certificates",
377 "Whether certificate errors should be considered a connection error",
379 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
380 g_object_class_install_property (
381 object_class, PROP_SSL_FALLBACK,
382 g_param_spec_boolean (SOUP_CONNECTION_SSL_FALLBACK,
384 "Use SSLv3 instead of TLS",
386 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
387 g_object_class_install_property (
388 object_class, PROP_ASYNC_CONTEXT,
389 g_param_spec_pointer (SOUP_CONNECTION_ASYNC_CONTEXT,
390 "Async GMainContext",
391 "GMainContext to dispatch this connection's async I/O in",
392 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
393 g_object_class_install_property (
394 object_class, PROP_USE_THREAD_CONTEXT,
395 g_param_spec_boolean (SOUP_CONNECTION_USE_THREAD_CONTEXT,
396 "Use thread context",
397 "Use g_main_context_get_thread_default",
399 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
400 g_object_class_install_property (
401 object_class, PROP_TIMEOUT,
402 g_param_spec_uint (SOUP_CONNECTION_TIMEOUT,
404 "Value in seconds to timeout a blocking I/O",
407 g_object_class_install_property (
408 object_class, PROP_IDLE_TIMEOUT,
409 g_param_spec_uint (SOUP_CONNECTION_IDLE_TIMEOUT,
411 "Connection lifetime when idle",
413 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
414 g_object_class_install_property (
415 object_class, PROP_STATE,
416 g_param_spec_enum (SOUP_CONNECTION_STATE,
418 "Current state of connection",
419 SOUP_TYPE_CONNECTION_STATE, SOUP_CONNECTION_NEW,
421 #if ENABLE(TIZEN_TV_CLIENT_CERTIFICATE)
422 g_object_class_install_property (
423 object_class, PROP_WIDGET_ENGINE,
424 g_param_spec_boolean (SOUP_CONNECTION_WIDGET_ENGINE,
426 "Whether or not to be running Widget Engine",
428 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
433 soup_connection_event (SoupConnection *conn,
434 GSocketClientEvent event,
435 GIOStream *connection)
437 SoupConnectionPrivate *priv = SOUP_CONNECTION_GET_PRIVATE (conn);
439 if (!connection && priv->socket)
440 connection = soup_socket_get_connection (priv->socket);
442 g_signal_emit (conn, signals[EVENT], 0,
446 #if ENABLE(TIZEN_TV_DYNAMIC_CERTIFICATE_LOADING)
448 soup_connection_dynamic_client_certificate (SoupSocket *sock,
449 const char* current_host,
452 SoupConnection* conn = user_data;
453 const char* get_certpath = NULL;
455 g_signal_emit (conn, signals[DYNAMIC_CERTIFICATEPATH], 0,
456 current_host, &get_certpath);
461 #if ENABLE(TIZEN_TV_CERTIFICATE_HANDLING)
463 soup_connection_accept_certificate (SoupSocket *sock,
464 GTlsCertificate* certificate,
465 GTlsCertificateFlags errors,
468 SoupConnection* conn = user_data;
469 gboolean accept = FALSE;
471 g_signal_emit (conn, signals[ACCEPT_CERTIFICATE], 0,
472 certificate, errors, &accept);
479 idle_timeout (gpointer conn)
481 soup_connection_disconnect (conn);
486 start_idle_timer (SoupConnection *conn)
488 SoupConnectionPrivate *priv = SOUP_CONNECTION_GET_PRIVATE (conn);
490 if (priv->idle_timeout > 0 && !priv->idle_timeout_src) {
491 priv->idle_timeout_src =
492 soup_add_timeout (priv->async_context,
493 priv->idle_timeout * 1000,
499 stop_idle_timer (SoupConnectionPrivate *priv)
501 if (priv->idle_timeout_src) {
502 g_source_destroy (priv->idle_timeout_src);
503 priv->idle_timeout_src = NULL;
508 current_msg_got_body (SoupMessage *msg, gpointer user_data)
510 SoupConnection *conn = user_data;
511 SoupConnectionPrivate *priv = SOUP_CONNECTION_GET_PRIVATE (conn);
513 priv->unused_timeout = 0;
515 if (priv->proxy_uri &&
516 msg->method == SOUP_METHOD_CONNECT &&
517 SOUP_STATUS_IS_SUCCESSFUL (msg->status_code)) {
518 soup_connection_event (conn, G_SOCKET_CLIENT_PROXY_NEGOTIATED, NULL);
520 /* We're now effectively no longer proxying */
521 g_clear_pointer (&priv->proxy_uri, soup_uri_free);
524 priv->reusable = soup_message_is_keepalive (msg);
528 clear_current_msg (SoupConnection *conn)
530 SoupConnectionPrivate *priv = SOUP_CONNECTION_GET_PRIVATE (conn);
533 msg = priv->current_msg;
534 priv->current_msg = NULL;
536 g_signal_handlers_disconnect_by_func (msg, G_CALLBACK (current_msg_got_body), conn);
537 g_object_unref (msg);
540 #if ENABLE(TIZEN_TV_CREATE_IDLE_TCP_CONNECTION)
542 soup_connection_has_current_item (SoupConnection *conn)
544 SoupConnectionPrivate *priv = SOUP_CONNECTION_GET_PRIVATE (conn);
547 return (priv->cur_item == NULL) ? FALSE : TRUE;
552 SoupMessageQueueItem *
553 soup_connection_get_current_item (SoupConnection *conn)
555 SoupConnectionPrivate *priv = SOUP_CONNECTION_GET_PRIVATE (conn);
558 return priv->cur_item;
564 clear_current_item (SoupConnection *conn)
566 SoupConnectionPrivate *priv = SOUP_CONNECTION_GET_PRIVATE (conn);
568 g_return_if_fail (priv != NULL);
570 g_object_freeze_notify (G_OBJECT (conn));
572 priv->cur_item = NULL;
576 set_current_item (SoupConnection *conn, SoupMessageQueueItem *item)
578 SoupConnectionPrivate *priv = SOUP_CONNECTION_GET_PRIVATE (conn);
580 g_return_if_fail (priv != NULL);
582 priv->cur_item = item;
587 /* soup_connection_set_current_item() sets only item, and does not change any state.
588 * That is what this function is different from set_current_item() above. */
590 soup_connection_set_current_item (SoupConnection *conn, SoupMessageQueueItem *item)
592 SoupConnectionPrivate *priv = SOUP_CONNECTION_GET_PRIVATE (conn);
594 g_return_if_fail (priv != NULL);
595 g_return_if_fail (priv->cur_item == NULL);
597 g_object_freeze_notify (G_OBJECT (conn));
599 stop_idle_timer (priv);
601 priv->cur_item = item;
603 g_object_thaw_notify (G_OBJECT (conn));
608 set_current_msg (SoupConnection *conn, SoupMessage *msg)
610 SoupConnectionPrivate *priv = SOUP_CONNECTION_GET_PRIVATE (conn);
612 g_return_if_fail (priv->state == SOUP_CONNECTION_IN_USE);
614 g_object_freeze_notify (G_OBJECT (conn));
616 if (priv->current_msg) {
617 g_return_if_fail (priv->current_msg->method == SOUP_METHOD_CONNECT);
618 clear_current_msg (conn);
621 stop_idle_timer (priv);
623 priv->current_msg = g_object_ref (msg);
624 priv->reusable = FALSE;
626 g_signal_connect (msg, "got-body",
627 G_CALLBACK (current_msg_got_body), conn);
629 if (priv->proxy_uri && msg->method == SOUP_METHOD_CONNECT)
630 soup_connection_event (conn, G_SOCKET_CLIENT_PROXY_NEGOTIATING, NULL);
632 g_object_thaw_notify (G_OBJECT (conn));
636 re_emit_socket_event (SoupSocket *socket,
637 GSocketClientEvent event,
638 GIOStream *connection,
641 SoupConnection *conn = user_data;
643 /* We handle COMPLETE ourselves */
644 if (event != G_SOCKET_CLIENT_COMPLETE)
645 soup_connection_event (conn, event, connection);
649 socket_connect_finished (GTask *task, SoupSocket *sock, GError *error)
651 SoupConnection *conn = g_task_get_source_object (task);
652 SoupConnectionPrivate *priv = SOUP_CONNECTION_GET_PRIVATE (conn);
654 if (priv->async_context && !priv->use_thread_context)
655 g_main_context_pop_thread_default (priv->async_context);
657 g_signal_handlers_disconnect_by_func (sock, G_CALLBACK (re_emit_socket_event), conn);
660 if (priv->ssl && !priv->proxy_uri) {
661 soup_connection_event (conn,
662 G_SOCKET_CLIENT_TLS_HANDSHAKED,
665 if (!priv->ssl || !priv->proxy_uri) {
666 soup_connection_event (conn,
667 G_SOCKET_CLIENT_COMPLETE,
671 soup_connection_set_state (conn, SOUP_CONNECTION_IN_USE);
672 priv->unused_timeout = time (NULL) + SOUP_CONNECTION_UNUSED_TIMEOUT;
673 start_idle_timer (conn);
675 g_task_return_boolean (task, TRUE);
677 g_task_return_error (task, error);
678 g_object_unref (task);
682 socket_handshake_complete (GObject *object, GAsyncResult *result, gpointer user_data)
684 SoupSocket *sock = SOUP_SOCKET (object);
685 GTask *task = user_data;
686 GError *error = NULL;
688 soup_socket_handshake_finish (sock, result, &error);
689 socket_connect_finished (task, sock, error);
693 socket_connect_complete (GObject *object, GAsyncResult *result, gpointer user_data)
695 SoupSocket *sock = SOUP_SOCKET (object);
696 GTask *task = user_data;
697 SoupConnection *conn = g_task_get_source_object (task);
698 SoupConnectionPrivate *priv = SOUP_CONNECTION_GET_PRIVATE (conn);
699 GError *error = NULL;
701 if (!soup_socket_connect_finish_internal (sock, result, &error)) {
702 socket_connect_finished (task, sock, error);
706 priv->proxy_uri = soup_socket_get_http_proxy_uri (sock);
708 if (priv->ssl && !priv->proxy_uri) {
709 soup_connection_event (conn,
710 G_SOCKET_CLIENT_TLS_HANDSHAKING,
713 soup_socket_handshake_async (sock, priv->remote_uri->host,
714 g_task_get_cancellable (task),
715 socket_handshake_complete, task);
719 socket_connect_finished (task, sock, NULL);
723 soup_connection_connect_async (SoupConnection *conn,
724 GCancellable *cancellable,
725 GAsyncReadyCallback callback,
728 SoupConnectionPrivate *priv;
729 SoupAddress *remote_addr;
732 g_return_if_fail (SOUP_IS_CONNECTION (conn));
733 priv = SOUP_CONNECTION_GET_PRIVATE (conn);
734 g_return_if_fail (priv->socket == NULL);
736 soup_connection_set_state (conn, SOUP_CONNECTION_CONNECTING);
738 /* Set the protocol to ensure correct proxy resolution. */
740 g_object_new (SOUP_TYPE_ADDRESS,
741 SOUP_ADDRESS_NAME, priv->remote_uri->host,
742 SOUP_ADDRESS_PORT, priv->remote_uri->port,
743 SOUP_ADDRESS_PROTOCOL, priv->remote_uri->scheme,
747 soup_socket_new (SOUP_SOCKET_REMOTE_ADDRESS, remote_addr,
748 SOUP_SOCKET_SSL_CREDENTIALS, priv->tlsdb,
749 SOUP_SOCKET_SSL_STRICT, priv->ssl_strict,
750 SOUP_SOCKET_SSL_FALLBACK, priv->ssl_fallback,
751 SOUP_SOCKET_ASYNC_CONTEXT, priv->async_context,
752 SOUP_SOCKET_USE_THREAD_CONTEXT, priv->use_thread_context,
753 SOUP_SOCKET_PROXY_RESOLVER, priv->proxy_resolver,
754 SOUP_SOCKET_TIMEOUT, priv->io_timeout,
755 SOUP_SOCKET_CLEAN_DISPOSE, TRUE,
756 SOUP_SOCKET_LOCAL_ADDRESS, priv->local_addr,
757 #if ENABLE(TIZEN_TV_CLIENT_CERTIFICATE)
758 SOUP_SOCKET_WIDGET_ENGINE, priv->widget_engine,
761 g_object_unref (remote_addr);
763 g_signal_connect (priv->socket, "event",
764 G_CALLBACK (re_emit_socket_event), conn);
765 #if ENABLE(TIZEN_TV_CERTIFICATE_HANDLING)
766 g_signal_connect (priv->socket, "accept-certificate",
767 G_CALLBACK (soup_connection_accept_certificate), conn);
770 #if ENABLE(TIZEN_TV_DYNAMIC_CERTIFICATE_LOADING)
771 g_signal_connect (priv->socket, "dynamic-certificatePath",
772 G_CALLBACK (soup_connection_dynamic_client_certificate), conn);
774 if (priv->async_context && !priv->use_thread_context)
775 g_main_context_push_thread_default (priv->async_context);
776 task = g_task_new (conn, cancellable, callback, user_data);
778 soup_socket_connect_async_internal (priv->socket, cancellable,
779 socket_connect_complete, task);
783 soup_connection_connect_finish (SoupConnection *conn,
784 GAsyncResult *result,
787 return g_task_propagate_boolean (G_TASK (result), error);
791 soup_connection_connect_sync (SoupConnection *conn,
792 GCancellable *cancellable,
795 SoupConnectionPrivate *priv;
797 SoupAddress *remote_addr;
798 gboolean success = TRUE;
800 g_return_val_if_fail (SOUP_IS_CONNECTION (conn), FALSE);
801 priv = SOUP_CONNECTION_GET_PRIVATE (conn);
802 g_return_val_if_fail (priv->socket == NULL, FALSE);
804 soup_connection_set_state (conn, SOUP_CONNECTION_CONNECTING);
806 /* Set the protocol to ensure correct proxy resolution. */
808 g_object_new (SOUP_TYPE_ADDRESS,
809 SOUP_ADDRESS_NAME, priv->remote_uri->host,
810 SOUP_ADDRESS_PORT, priv->remote_uri->port,
811 SOUP_ADDRESS_PROTOCOL, priv->remote_uri->scheme,
815 soup_socket_new (SOUP_SOCKET_REMOTE_ADDRESS, remote_addr,
816 SOUP_SOCKET_PROXY_RESOLVER, priv->proxy_resolver,
817 SOUP_SOCKET_SSL_CREDENTIALS, priv->tlsdb,
818 SOUP_SOCKET_SSL_STRICT, priv->ssl_strict,
819 SOUP_SOCKET_SSL_FALLBACK, priv->ssl_fallback,
820 SOUP_SOCKET_FLAG_NONBLOCKING, FALSE,
821 SOUP_SOCKET_TIMEOUT, priv->io_timeout,
822 SOUP_SOCKET_CLEAN_DISPOSE, TRUE,
823 SOUP_SOCKET_LOCAL_ADDRESS, priv->local_addr,
824 #if ENABLE(TIZEN_TV_CLIENT_CERTIFICATE)
825 SOUP_SOCKET_WIDGET_ENGINE, priv->widget_engine,
828 g_object_unref (remote_addr);
830 event_id = g_signal_connect (priv->socket, "event",
831 G_CALLBACK (re_emit_socket_event), conn);
832 #if ENABLE(TIZEN_TV_CERTIFICATE_HANDLING)
833 g_signal_connect (priv->socket, "accept-certificate",
834 G_CALLBACK (soup_connection_accept_certificate), conn);
837 if (!soup_socket_connect_sync_internal (priv->socket, cancellable, error)) {
842 priv->proxy_uri = soup_socket_get_http_proxy_uri (priv->socket);
844 if (priv->ssl && !priv->proxy_uri) {
845 soup_connection_event (conn,
846 G_SOCKET_CLIENT_TLS_HANDSHAKING,
848 if (!soup_socket_handshake_sync (priv->socket,
849 priv->remote_uri->host,
850 cancellable, error)) {
854 soup_connection_event (conn,
855 G_SOCKET_CLIENT_TLS_HANDSHAKED,
859 if (!priv->ssl || !priv->proxy_uri) {
860 soup_connection_event (conn,
861 G_SOCKET_CLIENT_COMPLETE,
864 soup_connection_set_state (conn, SOUP_CONNECTION_IN_USE);
865 priv->unused_timeout = time (NULL) + SOUP_CONNECTION_UNUSED_TIMEOUT;
866 start_idle_timer (conn);
869 if (priv->socket && event_id)
870 g_signal_handler_disconnect (priv->socket, event_id);
876 soup_connection_is_tunnelled (SoupConnection *conn)
878 SoupConnectionPrivate *priv;
880 g_return_val_if_fail (SOUP_IS_CONNECTION (conn), FALSE);
881 priv = SOUP_CONNECTION_GET_PRIVATE (conn);
883 return priv->ssl && priv->proxy_uri != NULL;
887 soup_connection_start_ssl_sync (SoupConnection *conn,
888 GCancellable *cancellable,
891 SoupConnectionPrivate *priv;
893 g_return_val_if_fail (SOUP_IS_CONNECTION (conn), FALSE);
894 priv = SOUP_CONNECTION_GET_PRIVATE (conn);
896 soup_connection_event (conn, G_SOCKET_CLIENT_TLS_HANDSHAKING, NULL);
897 if (soup_socket_handshake_sync (priv->socket, priv->remote_uri->host,
898 cancellable, error)) {
899 soup_connection_event (conn, G_SOCKET_CLIENT_TLS_HANDSHAKED, NULL);
900 soup_connection_event (conn, G_SOCKET_CLIENT_COMPLETE, NULL);
907 start_ssl_completed (GObject *object, GAsyncResult *result, gpointer user_data)
909 GTask *task = user_data;
910 SoupConnection *conn = g_task_get_source_object (task);
911 SoupConnectionPrivate *priv = SOUP_CONNECTION_GET_PRIVATE (conn);
912 GError *error = NULL;
914 if (priv->async_context && !priv->use_thread_context)
915 g_main_context_pop_thread_default (priv->async_context);
917 if (soup_socket_handshake_finish (priv->socket, result, &error)) {
918 soup_connection_event (conn, G_SOCKET_CLIENT_TLS_HANDSHAKED, NULL);
919 soup_connection_event (conn, G_SOCKET_CLIENT_COMPLETE, NULL);
920 g_task_return_boolean (task, TRUE);
921 #if ENABLE(TIZEN_PERFORMANCE_TEST_LOG)
922 prctl_with_url_and_free("[EVT] soup handshake complete : ", soup_uri_to_string(soup_connection_get_remote_uri(conn), FALSE));
925 g_task_return_error (task, error);
926 g_object_unref (task);
930 soup_connection_start_ssl_async (SoupConnection *conn,
931 GCancellable *cancellable,
932 GAsyncReadyCallback callback,
935 SoupConnectionPrivate *priv;
938 g_return_if_fail (SOUP_IS_CONNECTION (conn));
939 priv = SOUP_CONNECTION_GET_PRIVATE (conn);
941 soup_connection_event (conn, G_SOCKET_CLIENT_TLS_HANDSHAKING, NULL);
943 if (priv->async_context && !priv->use_thread_context)
944 g_main_context_push_thread_default (priv->async_context);
945 task = g_task_new (conn, cancellable, callback, user_data);
947 soup_socket_handshake_async (priv->socket, priv->remote_uri->host,
948 cancellable, start_ssl_completed, task);
952 soup_connection_start_ssl_finish (SoupConnection *conn,
953 GAsyncResult *result,
956 return g_task_propagate_boolean (G_TASK (result), error);
960 * soup_connection_disconnect:
961 * @conn: a connection
963 * Disconnects @conn's socket and emits a %disconnected signal.
964 * After calling this, @conn will be essentially useless.
967 soup_connection_disconnect (SoupConnection *conn)
969 SoupConnectionPrivate *priv;
970 SoupConnectionState old_state;
972 g_return_if_fail (SOUP_IS_CONNECTION (conn));
973 priv = SOUP_CONNECTION_GET_PRIVATE (conn);
975 old_state = priv->state;
976 if (old_state != SOUP_CONNECTION_DISCONNECTED)
977 soup_connection_set_state (conn, SOUP_CONNECTION_DISCONNECTED);
980 SoupSocket *socket = priv->socket;
983 soup_socket_disconnect (socket);
984 g_object_unref (socket);
987 if (old_state != SOUP_CONNECTION_DISCONNECTED)
988 g_signal_emit (conn, signals[DISCONNECTED], 0);
992 soup_connection_get_socket (SoupConnection *conn)
994 g_return_val_if_fail (SOUP_IS_CONNECTION (conn), NULL);
996 return SOUP_CONNECTION_GET_PRIVATE (conn)->socket;
1000 soup_connection_get_remote_uri (SoupConnection *conn)
1002 g_return_val_if_fail (SOUP_IS_CONNECTION (conn), NULL);
1004 return SOUP_CONNECTION_GET_PRIVATE (conn)->remote_uri;
1008 soup_connection_get_proxy_uri (SoupConnection *conn)
1010 g_return_val_if_fail (SOUP_IS_CONNECTION (conn), NULL);
1012 return SOUP_CONNECTION_GET_PRIVATE (conn)->proxy_uri;
1016 soup_connection_is_via_proxy (SoupConnection *conn)
1018 g_return_val_if_fail (SOUP_IS_CONNECTION (conn), FALSE);
1020 return SOUP_CONNECTION_GET_PRIVATE (conn)->proxy_uri != NULL;
1024 soup_connection_get_state (SoupConnection *conn)
1026 SoupConnectionPrivate *priv;
1028 g_return_val_if_fail (SOUP_IS_CONNECTION (conn),
1029 SOUP_CONNECTION_DISCONNECTED);
1030 priv = SOUP_CONNECTION_GET_PRIVATE (conn);
1032 if (priv->state == SOUP_CONNECTION_IDLE &&
1033 g_socket_condition_check (soup_socket_get_gsocket (priv->socket), G_IO_IN))
1034 soup_connection_set_state (conn, SOUP_CONNECTION_REMOTE_DISCONNECTED);
1036 if (priv->state == SOUP_CONNECTION_IDLE &&
1037 priv->unused_timeout && priv->unused_timeout < time (NULL))
1038 soup_connection_set_state (conn, SOUP_CONNECTION_REMOTE_DISCONNECTED);
1044 soup_connection_set_state (SoupConnection *conn, SoupConnectionState state)
1046 SoupConnectionPrivate *priv;
1048 g_return_if_fail (SOUP_IS_CONNECTION (conn));
1049 g_return_if_fail (state >= SOUP_CONNECTION_NEW &&
1050 state <= SOUP_CONNECTION_DISCONNECTED);
1052 g_object_freeze_notify (G_OBJECT (conn));
1054 priv = SOUP_CONNECTION_GET_PRIVATE (conn);
1056 if (priv->current_msg) {
1057 g_warn_if_fail (state == SOUP_CONNECTION_IDLE ||
1058 state == SOUP_CONNECTION_DISCONNECTED);
1059 #if ENABLE(TIZEN_TV_CREATE_IDLE_TCP_CONNECTION)
1060 clear_current_item (conn);
1062 clear_current_msg (conn);
1065 if (state == SOUP_CONNECTION_IDLE && !priv->reusable) {
1066 /* This will recursively call set_state() */
1067 soup_connection_disconnect (conn);
1069 priv->state = state;
1071 if (priv->state == SOUP_CONNECTION_IDLE)
1072 start_idle_timer (conn);
1074 g_object_notify (G_OBJECT (conn), "state");
1077 g_object_thaw_notify (G_OBJECT (conn));
1081 soup_connection_get_ever_used (SoupConnection *conn)
1083 g_return_val_if_fail (SOUP_IS_CONNECTION (conn), FALSE);
1085 return SOUP_CONNECTION_GET_PRIVATE (conn)->unused_timeout == 0;
1089 soup_connection_get_ssl_fallback (SoupConnection *conn)
1091 return SOUP_CONNECTION_GET_PRIVATE (conn)->ssl_fallback;
1095 soup_connection_send_request (SoupConnection *conn,
1096 SoupMessageQueueItem *item,
1097 SoupMessageCompletionFn completion_cb,
1100 SoupConnectionPrivate *priv;
1102 g_return_if_fail (SOUP_IS_CONNECTION (conn));
1103 g_return_if_fail (item != NULL);
1104 priv = SOUP_CONNECTION_GET_PRIVATE (conn);
1105 g_return_if_fail (priv->state != SOUP_CONNECTION_NEW &&
1106 priv->state != SOUP_CONNECTION_DISCONNECTED);
1108 #if ENABLE(TIZEN_TV_CREATE_IDLE_TCP_CONNECTION)
1109 set_current_item (conn, item);
1110 set_current_msg (conn, item->msg);
1112 if (item->msg != priv->current_msg)
1113 set_current_msg (conn, item->msg);
1115 priv->reusable = FALSE;
1118 soup_message_send_request (item, completion_cb, user_data);
1121 #if ENABLE(TIZEN_TV_CREATE_IDLE_TCP_CONNECTION)
1123 soup_connection_set_pre_connect_idle (SoupConnection *conn)
1125 SoupConnectionPrivate *priv = NULL;
1127 g_return_if_fail (SOUP_IS_CONNECTION (conn));
1128 priv = SOUP_CONNECTION_GET_PRIVATE (conn);
1131 if (priv->state == SOUP_CONNECTION_IN_USE)
1132 priv->state = SOUP_CONNECTION_IDLE;