1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
2 /*
3  * soup-connection.c: A single HTTP/HTTPS connection
4  *
5  * Copyright (C) 2000-2003, Ximian, Inc.
6  */
7 
8 #ifdef HAVE_CONFIG_H
9 #include <config.h>
10 #endif
11 
12 #include "soup-connection.h"
13 #include "soup.h"
14 #include "soup-io-stream.h"
15 #include "soup-message-queue-item.h"
16 #include "soup-client-message-io-http1.h"
17 #include "soup-client-message-io-http2.h"
18 #include "soup-socket-properties.h"
19 #include "soup-private-enum-types.h"
20 #include "soup-tls-interaction.h"
21 #include <gio/gnetworking.h>
22 
23 struct _SoupConnection {
24         GObject parent_instance;
25 };
26 
27 typedef struct {
28 	GIOStream *connection;
29 	GSocketConnectable *remote_connectable;
30 	GIOStream *iostream;
31 	SoupSocketProperties *socket_props;
32         guint64 id;
33         GSocketAddress *remote_address;
34         gboolean force_http1;
35 
36 	GUri *proxy_uri;
37 	gboolean ssl;
38 
39 	SoupMessage *proxy_msg;
40         SoupClientMessageIO *io_data;
41 	SoupConnectionState state;
42 	time_t       unused_timeout;
43 	GSource     *idle_timeout_src;
44         guint        in_use;
45         SoupHTTPVersion http_version;
46 
47         GTlsCertificate *tls_client_cert;
48 
49 	GCancellable *cancellable;
50 } SoupConnectionPrivate;
51 
52 G_DEFINE_FINAL_TYPE_WITH_PRIVATE (SoupConnection, soup_connection, G_TYPE_OBJECT)
53 
54 enum {
55 	EVENT,
56 	ACCEPT_CERTIFICATE,
57         REQUEST_CERTIFICATE,
58         REQUEST_CERTIFICATE_PASSWORD,
59 	DISCONNECTED,
60 	LAST_SIGNAL
61 };
62 
63 static guint signals[LAST_SIGNAL] = { 0 };
64 
65 enum {
66 	PROP_0,
67 
68         PROP_ID,
69 	PROP_REMOTE_CONNECTABLE,
70         PROP_REMOTE_ADDRESS,
71 	PROP_SOCKET_PROPERTIES,
72 	PROP_STATE,
73 	PROP_SSL,
74 	PROP_TLS_CERTIFICATE,
75 	PROP_TLS_CERTIFICATE_ERRORS,
76         PROP_TLS_PROTOCOL_VERSION,
77         PROP_TLS_CIPHERSUITE_NAME,
78         PROP_FORCE_HTTP1,
79 
80 	LAST_PROPERTY
81 };
82 
83 static GParamSpec *properties[LAST_PROPERTY] = { NULL, };
84 
85 static void stop_idle_timer (SoupConnectionPrivate *priv);
86 
87 /* Number of seconds after which we close a connection that hasn't yet
88  * been used.
89  */
90 #define SOUP_CONNECTION_UNUSED_TIMEOUT 3
91 
92 static void
soup_connection_init(SoupConnection * conn)93 soup_connection_init (SoupConnection *conn)
94 {
95         SoupConnectionPrivate *priv = soup_connection_get_instance_private (conn);
96 
97         priv->http_version = SOUP_HTTP_1_1;
98 }
99 
100 static void
soup_connection_finalize(GObject * object)101 soup_connection_finalize (GObject *object)
102 {
103 	SoupConnectionPrivate *priv = soup_connection_get_instance_private (SOUP_CONNECTION (object));
104 
105 	g_clear_pointer (&priv->proxy_uri, g_uri_unref);
106 	g_clear_pointer (&priv->socket_props, soup_socket_properties_unref);
107         g_clear_pointer (&priv->io_data, soup_client_message_io_destroy);
108 	g_clear_object (&priv->remote_connectable);
109         g_clear_object (&priv->remote_address);
110 	g_clear_object (&priv->proxy_msg);
111 
112 	if (priv->cancellable) {
113 		g_warning ("Disposing connection %p during connect", object);
114 		g_object_unref (priv->cancellable);
115 	}
116 
117 	if (priv->connection) {
118 		g_warning ("Disposing connection %p while still connected", object);
119 		g_io_stream_close (priv->connection, NULL, NULL);
120 		g_object_unref (priv->connection);
121 	}
122 
123 	g_clear_object (&priv->iostream);
124         g_clear_object (&priv->tls_client_cert);
125 
126 	G_OBJECT_CLASS (soup_connection_parent_class)->finalize (object);
127 }
128 
129 static void
soup_connection_dispose(GObject * object)130 soup_connection_dispose (GObject *object)
131 {
132 	SoupConnection *conn = SOUP_CONNECTION (object);
133 	SoupConnectionPrivate *priv = soup_connection_get_instance_private (conn);
134 
135 	stop_idle_timer (priv);
136 
137 	G_OBJECT_CLASS (soup_connection_parent_class)->dispose (object);
138 }
139 
140 static void
soup_connection_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)141 soup_connection_set_property (GObject *object, guint prop_id,
142 			      const GValue *value, GParamSpec *pspec)
143 {
144 	SoupConnectionPrivate *priv = soup_connection_get_instance_private (SOUP_CONNECTION (object));
145 
146 	switch (prop_id) {
147 	case PROP_REMOTE_CONNECTABLE:
148 		priv->remote_connectable = g_value_dup_object (value);
149 		break;
150 	case PROP_SOCKET_PROPERTIES:
151 		priv->socket_props = g_value_dup_boxed (value);
152 		break;
153 	case PROP_SSL:
154 		priv->ssl = g_value_get_boolean (value);
155 		break;
156 	case PROP_ID:
157 		priv->id = g_value_get_uint64 (value);
158 		break;
159 	case PROP_FORCE_HTTP1:
160 		priv->force_http1 = g_value_get_boolean (value);
161 		break;
162 	default:
163 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
164 		break;
165 	}
166 }
167 
168 static void
soup_connection_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)169 soup_connection_get_property (GObject *object, guint prop_id,
170 			      GValue *value, GParamSpec *pspec)
171 {
172 	SoupConnectionPrivate *priv = soup_connection_get_instance_private (SOUP_CONNECTION (object));
173 
174 	switch (prop_id) {
175 	case PROP_REMOTE_CONNECTABLE:
176 		g_value_set_object (value, priv->remote_connectable);
177 		break;
178         case PROP_REMOTE_ADDRESS:
179                 g_value_set_object (value, priv->remote_address);
180 	        break;
181 	case PROP_SOCKET_PROPERTIES:
182 		g_value_set_boxed (value, priv->socket_props);
183 		break;
184 	case PROP_STATE:
185 		g_value_set_enum (value, priv->state);
186 		break;
187 	case PROP_SSL:
188 		g_value_set_boolean (value, priv->ssl);
189 		break;
190 	case PROP_ID:
191 		g_value_set_uint64 (value, priv->id);
192 		break;
193 	case PROP_TLS_CERTIFICATE:
194 		g_value_set_object (value, soup_connection_get_tls_certificate (SOUP_CONNECTION (object)));
195 		break;
196 	case PROP_TLS_CERTIFICATE_ERRORS:
197 		g_value_set_flags (value, soup_connection_get_tls_certificate_errors (SOUP_CONNECTION (object)));
198 		break;
199         case PROP_TLS_PROTOCOL_VERSION:
200                 g_value_set_enum (value, soup_connection_get_tls_protocol_version (SOUP_CONNECTION (object)));
201                 break;
202         case PROP_TLS_CIPHERSUITE_NAME:
203                 g_value_set_string (value, soup_connection_get_tls_ciphersuite_name (SOUP_CONNECTION (object)));
204                 break;
205 	case PROP_FORCE_HTTP1:
206 		g_value_set_boolean (value, priv->force_http1);
207 		break;
208 	default:
209 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
210 		break;
211 	}
212 }
213 
214 static void
soup_connection_class_init(SoupConnectionClass * connection_class)215 soup_connection_class_init (SoupConnectionClass *connection_class)
216 {
217 	GObjectClass *object_class = G_OBJECT_CLASS (connection_class);
218 
219 	/* virtual method override */
220 	object_class->dispose = soup_connection_dispose;
221 	object_class->finalize = soup_connection_finalize;
222 	object_class->set_property = soup_connection_set_property;
223 	object_class->get_property = soup_connection_get_property;
224 
225 	/* signals */
226 	signals[EVENT] =
227 		g_signal_new ("event",
228 			      G_OBJECT_CLASS_TYPE (object_class),
229 			      G_SIGNAL_RUN_FIRST,
230 			      0,
231 			      NULL, NULL,
232 			      NULL,
233 			      G_TYPE_NONE, 2,
234 			      G_TYPE_SOCKET_CLIENT_EVENT,
235 			      G_TYPE_IO_STREAM);
236 	signals[ACCEPT_CERTIFICATE] =
237 		g_signal_new ("accept-certificate",
238                               G_OBJECT_CLASS_TYPE (object_class),
239                               G_SIGNAL_RUN_LAST,
240                               0,
241                               g_signal_accumulator_true_handled, NULL,
242                               NULL,
243                               G_TYPE_BOOLEAN, 2,
244                               G_TYPE_TLS_CERTIFICATE,
245                               G_TYPE_TLS_CERTIFICATE_FLAGS);
246         signals[REQUEST_CERTIFICATE] =
247                 g_signal_new ("request-certificate",
248                               G_OBJECT_CLASS_TYPE (object_class),
249                               G_SIGNAL_RUN_LAST,
250                               0,
251                               g_signal_accumulator_true_handled, NULL,
252                               NULL,
253                               G_TYPE_BOOLEAN, 2,
254                               G_TYPE_TLS_CLIENT_CONNECTION,
255                               G_TYPE_TASK);
256         signals[REQUEST_CERTIFICATE_PASSWORD] =
257                 g_signal_new ("request-certificate-password",
258                               G_OBJECT_CLASS_TYPE (object_class),
259                               G_SIGNAL_RUN_LAST,
260                               0,
261                               g_signal_accumulator_true_handled, NULL,
262                               NULL,
263                               G_TYPE_BOOLEAN, 2,
264                               G_TYPE_TLS_PASSWORD,
265                               G_TYPE_TASK);
266 	signals[DISCONNECTED] =
267 		g_signal_new ("disconnected",
268 			      G_OBJECT_CLASS_TYPE (object_class),
269 			      G_SIGNAL_RUN_FIRST,
270 			      0,
271 			      NULL, NULL,
272 			      NULL,
273 			      G_TYPE_NONE, 0);
274 
275 	/* properties */
276         properties[PROP_REMOTE_CONNECTABLE] =
277                 g_param_spec_object ("remote-connectable",
278                                      "Remote Connectable",
279                                      "Socket to connect to make outgoing connections on",
280                                      G_TYPE_SOCKET_CONNECTABLE,
281                                      G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
282                                      G_PARAM_STATIC_STRINGS);
283         properties[PROP_REMOTE_ADDRESS] =
284                 g_param_spec_object ("remote-address",
285                                      "Remote Address",
286                                      "Remote address of connection",
287                                      G_TYPE_SOCKET_ADDRESS,
288                                      G_PARAM_READABLE |
289                                      G_PARAM_STATIC_STRINGS);
290         properties[PROP_SOCKET_PROPERTIES] =
291 		g_param_spec_boxed ("socket-properties",
292 				    "Socket properties",
293 				    "Socket properties",
294 				    SOUP_TYPE_SOCKET_PROPERTIES,
295 				    G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
296 				    G_PARAM_STATIC_STRINGS);
297         properties[PROP_STATE] =
298 		g_param_spec_enum ("state",
299 				   "Connection state",
300 				   "Current state of connection",
301 				   SOUP_TYPE_CONNECTION_STATE,
302                                    SOUP_CONNECTION_NEW,
303 				   G_PARAM_READABLE |
304 				   G_PARAM_STATIC_STRINGS);
305         properties[PROP_SSL] =
306 		g_param_spec_boolean ("ssl",
307 				      "Connection uses TLS",
308 				      "Whether the connection should use TLS",
309 				      FALSE,G_PARAM_READWRITE |
310 				      G_PARAM_STATIC_STRINGS);
311         properties[PROP_ID] =
312 		g_param_spec_uint64 ("id",
313                                      "Connection Identifier",
314                                      "Unique identifier for the connection",
315                                      0, G_MAXUINT64,
316                                      0, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
317                                      G_PARAM_STATIC_STRINGS);
318         properties[PROP_TLS_CERTIFICATE] =
319 		g_param_spec_object ("tls-certificate",
320                                      "TLS Certificate",
321                                      "The TLS certificate associated with the connection",
322                                      G_TYPE_TLS_CERTIFICATE,
323                                      G_PARAM_READABLE |
324 	                             G_PARAM_STATIC_STRINGS);
325         properties[PROP_TLS_CERTIFICATE_ERRORS] =
326                 g_param_spec_flags ("tls-certificate-errors",
327                                     "TLS Certificate Errors",
328                                     "The verification errors on the connections's TLS certificate",
329                                     G_TYPE_TLS_CERTIFICATE_FLAGS, 0,
330                                     G_PARAM_READABLE |
331                                     G_PARAM_STATIC_STRINGS);
332         properties[PROP_TLS_PROTOCOL_VERSION] =
333                 g_param_spec_enum ("tls-protocol-version",
334                                    "TLS Protocol Version",
335                                    "TLS protocol version negotiated for this connection",
336                                    G_TYPE_TLS_PROTOCOL_VERSION,
337                                    G_TLS_PROTOCOL_VERSION_UNKNOWN,
338                                    G_PARAM_READABLE |
339                                    G_PARAM_STATIC_STRINGS);
340         properties[PROP_TLS_CIPHERSUITE_NAME] =
341                 g_param_spec_string ("tls-ciphersuite-name",
342                                      "TLS Ciphersuite Name",
343                                      "Name of TLS ciphersuite negotiated for this connection",
344                                      NULL,
345                                      G_PARAM_READABLE |
346                                      G_PARAM_STATIC_STRINGS);
347         properties[PROP_FORCE_HTTP1] =
348                 g_param_spec_boolean ("force-http1",
349                                       "Force HTTP 1.x",
350                                       "Force connection to use HTTP 1.x",
351                                       FALSE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
352                                       G_PARAM_STATIC_STRINGS);
353 
354         g_object_class_install_properties (object_class, LAST_PROPERTY, properties);
355 }
356 
357 static void
soup_connection_event(SoupConnection * conn,GSocketClientEvent event,GIOStream * connection)358 soup_connection_event (SoupConnection      *conn,
359 		       GSocketClientEvent   event,
360 		       GIOStream           *connection)
361 {
362 	SoupConnectionPrivate *priv = soup_connection_get_instance_private (conn);
363 
364 	g_signal_emit (conn, signals[EVENT], 0,
365 		       event, connection ? connection : priv->connection);
366 }
367 
368 static gboolean
idle_timeout(gpointer conn)369 idle_timeout (gpointer conn)
370 {
371 	soup_connection_disconnect (conn);
372 	return FALSE;
373 }
374 
375 static void
start_idle_timer(SoupConnection * conn)376 start_idle_timer (SoupConnection *conn)
377 {
378 	SoupConnectionPrivate *priv = soup_connection_get_instance_private (conn);
379 
380 	if (priv->socket_props->idle_timeout > 0 && !priv->idle_timeout_src) {
381 		priv->idle_timeout_src =
382 			soup_add_timeout (g_main_context_get_thread_default (),
383 					  priv->socket_props->idle_timeout * 1000,
384 					  idle_timeout, conn);
385 	}
386 }
387 
388 static void
stop_idle_timer(SoupConnectionPrivate * priv)389 stop_idle_timer (SoupConnectionPrivate *priv)
390 {
391 	if (priv->idle_timeout_src) {
392 		g_source_destroy (priv->idle_timeout_src);
393                 g_clear_pointer (&priv->idle_timeout_src, g_source_unref);
394 	}
395 }
396 
397 static void
soup_connection_set_state(SoupConnection * conn,SoupConnectionState state)398 soup_connection_set_state (SoupConnection     *conn,
399                            SoupConnectionState state)
400 {
401         SoupConnectionPrivate *priv = soup_connection_get_instance_private (conn);
402 
403         if (priv->state == state)
404                 return;
405 
406         priv->state = state;
407         if (priv->state == SOUP_CONNECTION_IDLE)
408                 start_idle_timer (conn);
409 
410         g_object_notify_by_pspec (G_OBJECT (conn), properties[PROP_STATE]);
411 }
412 
413 static void
proxy_msg_got_body(SoupMessage * msg,SoupConnection * conn)414 proxy_msg_got_body (SoupMessage    *msg,
415                     SoupConnection *conn)
416 {
417 	SoupConnectionPrivate *priv = soup_connection_get_instance_private (conn);
418 
419 	if (SOUP_STATUS_IS_SUCCESSFUL (soup_message_get_status (msg))) {
420 		soup_connection_event (conn, G_SOCKET_CLIENT_PROXY_NEGOTIATED, NULL);
421 
422 		/* We're now effectively no longer proxying */
423 		g_clear_pointer (&priv->proxy_uri, g_uri_unref);
424                 g_signal_handlers_disconnect_by_func (priv->proxy_msg, proxy_msg_got_body, conn);
425                 g_clear_object (&priv->proxy_msg);
426 	}
427 }
428 
429 static void
clear_proxy_msg(SoupConnection * conn)430 clear_proxy_msg (SoupConnection *conn)
431 {
432 	SoupConnectionPrivate *priv = soup_connection_get_instance_private (conn);
433 
434         if (!priv->proxy_msg)
435                 return;
436 
437         g_signal_handlers_disconnect_by_func (priv->proxy_msg, proxy_msg_got_body, conn);
438         g_clear_object (&priv->proxy_msg);
439 }
440 
441 static void
set_proxy_msg(SoupConnection * conn,SoupMessage * msg)442 set_proxy_msg (SoupConnection *conn,
443                SoupMessage    *msg)
444 {
445 	SoupConnectionPrivate *priv = soup_connection_get_instance_private (conn);
446 
447         g_assert (priv->http_version != SOUP_HTTP_2_0);
448 
449         clear_proxy_msg (conn);
450 	priv->proxy_msg = g_object_ref (msg);
451 	g_signal_connect_object (msg, "got-body",
452                                  G_CALLBACK (proxy_msg_got_body),
453                                  conn, 0);
454 
455         soup_connection_event (conn, G_SOCKET_CLIENT_PROXY_NEGOTIATING, NULL);
456 }
457 
458 static void
soup_connection_set_connection(SoupConnection * conn,GIOStream * connection)459 soup_connection_set_connection (SoupConnection *conn,
460 				GIOStream      *connection)
461 {
462 	SoupConnectionPrivate *priv = soup_connection_get_instance_private (conn);
463 
464         g_clear_pointer (&priv->io_data, soup_client_message_io_destroy);
465 
466 	g_clear_object (&priv->connection);
467 	priv->connection = connection;
468 	g_clear_object (&priv->iostream);
469 	priv->iostream = soup_io_stream_new (G_IO_STREAM (priv->connection), FALSE);
470 }
471 
472 static void
soup_connection_create_io_data(SoupConnection * conn)473 soup_connection_create_io_data (SoupConnection *conn)
474 {
475         SoupConnectionPrivate *priv = soup_connection_get_instance_private (conn);
476 
477         g_assert (!priv->io_data);
478         switch (priv->http_version) {
479         case SOUP_HTTP_1_0:
480         case SOUP_HTTP_1_1:
481                 priv->io_data = soup_client_message_io_http1_new (conn);
482                 break;
483         case SOUP_HTTP_2_0:
484                 priv->io_data = soup_client_message_io_http2_new (conn);
485                 break;
486         }
487 }
488 
489 static void
re_emit_socket_event(GSocketClient * client,GSocketClientEvent event,GSocketConnectable * connectable,GIOStream * connection,SoupConnection * conn)490 re_emit_socket_event (GSocketClient       *client,
491 		      GSocketClientEvent   event,
492 		      GSocketConnectable  *connectable,
493 		      GIOStream           *connection,
494 		      SoupConnection      *conn)
495 {
496 	/* We handle COMPLETE ourselves */
497 	if (event == G_SOCKET_CLIENT_COMPLETE)
498 		return;
499 
500 	soup_connection_event (conn, event, connection);
501 }
502 
503 static GSocketClient *
new_socket_client(SoupConnection * conn)504 new_socket_client (SoupConnection *conn)
505 {
506         SoupConnectionPrivate *priv = soup_connection_get_instance_private (conn);
507         GSocketClient *client;
508         SoupSocketProperties *props = priv->socket_props;
509 
510         client = g_socket_client_new ();
511         g_signal_connect_object (client, "event",
512                                  G_CALLBACK (re_emit_socket_event),
513                                  conn, 0);
514 
515 	if (!props->proxy_use_default) {
516 		if (props->proxy_resolver) {
517 			g_socket_client_set_proxy_resolver (client, props->proxy_resolver);
518 			g_socket_client_add_application_proxy (client, "http");
519 		} else
520 			g_socket_client_set_enable_proxy (client, FALSE);
521 	}
522         if (props->io_timeout)
523                 g_socket_client_set_timeout (client, props->io_timeout);
524         if (props->local_addr)
525                 g_socket_client_set_local_address (client, G_SOCKET_ADDRESS (props->local_addr));
526 
527         return client;
528 }
529 
530 static gboolean
tls_connection_accept_certificate(SoupConnection * conn,GTlsCertificate * tls_certificate,GTlsCertificateFlags tls_errors)531 tls_connection_accept_certificate (SoupConnection      *conn,
532                                    GTlsCertificate     *tls_certificate,
533                                    GTlsCertificateFlags tls_errors)
534 {
535 	gboolean accept = FALSE;
536 
537         g_signal_emit (conn, signals[ACCEPT_CERTIFICATE], 0,
538 		       tls_certificate, tls_errors, &accept);
539         return accept;
540 }
541 
542 static void
tls_connection_peer_certificate_changed(SoupConnection * conn)543 tls_connection_peer_certificate_changed (SoupConnection *conn)
544 {
545 	g_object_notify_by_pspec (G_OBJECT (conn), properties[PROP_TLS_CERTIFICATE]);
546 }
547 
548 static void
tls_connection_protocol_version_changed(SoupConnection * conn)549 tls_connection_protocol_version_changed (SoupConnection *conn)
550 {
551         g_object_notify_by_pspec (G_OBJECT (conn), properties[PROP_TLS_PROTOCOL_VERSION]);
552 }
553 
554 static void
tls_connection_ciphersuite_name_changed(SoupConnection * conn)555 tls_connection_ciphersuite_name_changed (SoupConnection *conn)
556 {
557         g_object_notify_by_pspec (G_OBJECT (conn), properties[PROP_TLS_CIPHERSUITE_NAME]);
558 }
559 
560 static GTlsClientConnection *
new_tls_connection(SoupConnection * conn,GSocketConnection * connection,GError ** error)561 new_tls_connection (SoupConnection    *conn,
562                     GSocketConnection *connection,
563                     GError           **error)
564 {
565         SoupConnectionPrivate *priv = soup_connection_get_instance_private (conn);
566         GTlsClientConnection *tls_connection;
567         GTlsInteraction *tls_interaction;
568         GPtrArray *advertised_protocols = g_ptr_array_sized_new (4);
569 
570         // https://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xhtml
571         if (!priv->force_http1)
572                 g_ptr_array_add (advertised_protocols, "h2");
573 
574         g_ptr_array_add (advertised_protocols, "http/1.1");
575         g_ptr_array_add (advertised_protocols, "http/1.0");
576         g_ptr_array_add (advertised_protocols, NULL);
577 
578         tls_interaction = priv->socket_props->tls_interaction ? g_object_ref (priv->socket_props->tls_interaction) : soup_tls_interaction_new (conn);
579         tls_connection = g_initable_new (g_tls_backend_get_client_connection_type (g_tls_backend_get_default ()),
580                                          priv->cancellable, error,
581                                          "base-io-stream", connection,
582                                          "server-identity", priv->remote_connectable,
583                                          "require-close-notify", FALSE,
584                                          "interaction", tls_interaction,
585                                          "advertised-protocols", advertised_protocols->pdata,
586                                          NULL);
587 
588         g_object_unref (tls_interaction);
589         g_ptr_array_unref (advertised_protocols);
590 
591         if (!tls_connection)
592                 return NULL;
593 
594 	if (!priv->socket_props->tlsdb_use_default)
595 		g_tls_connection_set_database (G_TLS_CONNECTION (tls_connection), priv->socket_props->tlsdb);
596 
597 	g_signal_connect_object (tls_connection, "accept-certificate",
598 				 G_CALLBACK (tls_connection_accept_certificate),
599 				 conn, G_CONNECT_SWAPPED);
600 	g_signal_connect_object (tls_connection, "notify::peer-certificate",
601 				 G_CALLBACK (tls_connection_peer_certificate_changed),
602 				 conn, G_CONNECT_SWAPPED);
603         g_signal_connect_object (tls_connection, "notify::protocol-version",
604 				 G_CALLBACK (tls_connection_protocol_version_changed),
605 				 conn, G_CONNECT_SWAPPED);
606         g_signal_connect_object (tls_connection, "notify::ciphersuite-name",
607 				 G_CALLBACK (tls_connection_ciphersuite_name_changed),
608 				 conn, G_CONNECT_SWAPPED);
609 
610         return tls_connection;
611 }
612 
613 static gboolean
soup_connection_connected(SoupConnection * conn,GSocketConnection * connection,GError ** error)614 soup_connection_connected (SoupConnection    *conn,
615                            GSocketConnection *connection,
616                            GError           **error)
617 {
618         SoupConnectionPrivate *priv = soup_connection_get_instance_private (conn);
619         GSocket *socket;
620 
621         socket = g_socket_connection_get_socket (connection);
622         g_socket_set_timeout (socket, priv->socket_props->io_timeout);
623         g_socket_set_option (socket, IPPROTO_TCP, TCP_NODELAY, TRUE, NULL);
624 
625         g_clear_object (&priv->remote_address);
626         priv->remote_address = g_socket_get_remote_address (socket, NULL);
627         g_object_notify_by_pspec (G_OBJECT (conn), properties[PROP_REMOTE_ADDRESS]);
628 
629         if (priv->remote_address && G_IS_PROXY_ADDRESS (priv->remote_address)) {
630                 GProxyAddress *paddr = G_PROXY_ADDRESS (priv->remote_address);
631 
632                 if (strcmp (g_proxy_address_get_protocol (paddr), "http") == 0) {
633                         GError *error = NULL;
634                         priv->proxy_uri = g_uri_parse (g_proxy_address_get_uri (paddr), SOUP_HTTP_URI_FLAGS, &error);
635                         if (error) {
636                                 g_warning ("Failed to parse proxy URI %s: %s", g_proxy_address_get_uri (paddr), error->message);
637                                 g_error_free (error);
638                         }
639                 }
640         }
641 
642         if (priv->ssl && !priv->proxy_uri) {
643                 GTlsClientConnection *tls_connection;
644 
645                 tls_connection = new_tls_connection (conn, connection, error);
646                 if (!tls_connection)
647                         return FALSE;
648 
649                 g_object_unref (connection);
650                 soup_connection_set_connection (conn, G_IO_STREAM (tls_connection));
651         } else {
652                 soup_connection_set_connection (conn, G_IO_STREAM (connection));
653         }
654 
655         return TRUE;
656 }
657 
658 static void
soup_connection_complete(SoupConnection * conn)659 soup_connection_complete (SoupConnection *conn)
660 {
661         SoupConnectionPrivate *priv = soup_connection_get_instance_private (conn);
662 
663         g_clear_object (&priv->cancellable);
664 
665         if (G_IS_TLS_CONNECTION (priv->connection)) {
666                 const char *protocol = g_tls_connection_get_negotiated_protocol (G_TLS_CONNECTION (priv->connection));
667                 if (g_strcmp0 (protocol, "h2") == 0)
668                         priv->http_version = SOUP_HTTP_2_0;
669                 else if (g_strcmp0 (protocol, "http/1.0") == 0)
670                         priv->http_version = SOUP_HTTP_1_0;
671                 else if (g_strcmp0 (protocol, "http/1.1") == 0)
672                         priv->http_version = SOUP_HTTP_1_1;
673         }
674 
675         if (!priv->ssl || !priv->proxy_uri) {
676                 soup_connection_event (conn,
677                                        G_SOCKET_CLIENT_COMPLETE,
678                                        NULL);
679         }
680 
681         soup_connection_create_io_data (conn);
682 
683         soup_connection_set_state (conn, SOUP_CONNECTION_IN_USE);
684         priv->unused_timeout = time (NULL) + SOUP_CONNECTION_UNUSED_TIMEOUT;
685         start_idle_timer (conn);
686 }
687 
688 static void
handshake_ready_cb(GTlsConnection * tls_connection,GAsyncResult * result,GTask * task)689 handshake_ready_cb (GTlsConnection *tls_connection,
690                     GAsyncResult   *result,
691                     GTask          *task)
692 {
693         SoupConnection *conn = g_task_get_source_object (task);
694         SoupConnectionPrivate *priv = soup_connection_get_instance_private (conn);
695         GError *error = NULL;
696 
697         if (g_tls_connection_handshake_finish (tls_connection, result, &error)) {
698                 soup_connection_event (conn, G_SOCKET_CLIENT_TLS_HANDSHAKED, NULL);
699                 soup_connection_complete (conn);
700                 g_task_return_boolean (task, TRUE);
701         } else {
702                 g_clear_object (&priv->cancellable);
703                 g_task_return_error (task, error);
704         }
705         g_object_unref (task);
706 }
707 
708 static void
connect_async_ready_cb(GSocketClient * client,GAsyncResult * result,GTask * task)709 connect_async_ready_cb (GSocketClient *client,
710                         GAsyncResult  *result,
711                         GTask         *task)
712 {
713         SoupConnection *conn = g_task_get_source_object (task);
714         SoupConnectionPrivate *priv = soup_connection_get_instance_private (conn);
715         GSocketConnection *connection;
716         GError *error = NULL;
717 
718         connection = g_socket_client_connect_finish (client, result, &error);
719         if (!connection) {
720 		g_clear_object (&priv->cancellable);
721                 g_task_return_error (task, error);
722                 g_object_unref (task);
723                 return;
724         }
725 
726         if (!soup_connection_connected (conn, connection, &error)) {
727 		g_clear_object (&priv->cancellable);
728                 g_task_return_error (task, error);
729                 g_object_unref (task);
730                 g_object_unref (connection);
731                 return;
732         }
733 
734         if (G_IS_TLS_CONNECTION (priv->connection)) {
735                 soup_connection_event (conn, G_SOCKET_CLIENT_TLS_HANDSHAKING, NULL);
736 
737                 g_tls_connection_handshake_async (G_TLS_CONNECTION (priv->connection),
738                                                   g_task_get_priority (task),
739                                                   priv->cancellable,
740                                                   (GAsyncReadyCallback)handshake_ready_cb,
741                                                   task);
742                 return;
743         }
744 
745         soup_connection_complete (conn);
746         g_task_return_boolean (task, TRUE);
747         g_object_unref (task);
748 }
749 
750 void
soup_connection_connect_async(SoupConnection * conn,int io_priority,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)751 soup_connection_connect_async (SoupConnection      *conn,
752                                int                  io_priority,
753                                GCancellable        *cancellable,
754                                GAsyncReadyCallback  callback,
755                                gpointer             user_data)
756 {
757         SoupConnectionPrivate *priv;
758         GTask *task;
759         GSocketClient *client;
760 
761         g_return_if_fail (SOUP_IS_CONNECTION (conn));
762 
763         priv = soup_connection_get_instance_private (conn);
764 
765         soup_connection_set_state (conn, SOUP_CONNECTION_CONNECTING);
766 
767         priv->cancellable = cancellable ? g_object_ref (cancellable) : g_cancellable_new ();
768         task = g_task_new (conn, priv->cancellable, callback, user_data);
769         g_task_set_priority (task, io_priority);
770 
771         client = new_socket_client (conn);
772         g_socket_client_connect_async (client,
773                                        priv->remote_connectable,
774                                        priv->cancellable,
775                                        (GAsyncReadyCallback)connect_async_ready_cb,
776                                        task);
777         g_object_unref (client);
778 }
779 
780 gboolean
soup_connection_connect_finish(SoupConnection * conn,GAsyncResult * result,GError ** error)781 soup_connection_connect_finish (SoupConnection  *conn,
782                                 GAsyncResult    *result,
783                                 GError         **error)
784 {
785         return g_task_propagate_boolean (G_TASK (result), error);
786 }
787 
788 gboolean
soup_connection_connect(SoupConnection * conn,GCancellable * cancellable,GError ** error)789 soup_connection_connect (SoupConnection  *conn,
790 			 GCancellable    *cancellable,
791 			 GError         **error)
792 {
793         SoupConnectionPrivate *priv;
794         GSocketClient *client;
795         GSocketConnection *connection;
796 
797         g_return_val_if_fail (SOUP_IS_CONNECTION (conn), FALSE);
798 
799         priv = soup_connection_get_instance_private (conn);
800 
801         soup_connection_set_state (conn, SOUP_CONNECTION_CONNECTING);
802 
803         priv->cancellable = cancellable ? g_object_ref (cancellable) : g_cancellable_new ();
804 
805         client = new_socket_client (conn);
806         connection = g_socket_client_connect (client,
807                                               priv->remote_connectable,
808                                               priv->cancellable,
809                                               error);
810         g_object_unref (client);
811 
812         if (!connection) {
813                 g_clear_object (&priv->cancellable);
814                 return FALSE;
815         }
816 
817         if (!soup_connection_connected (conn, connection, error)) {
818                 g_object_unref (connection);
819                 g_clear_object (&priv->cancellable);
820                 return FALSE;
821         }
822 
823         if (G_IS_TLS_CONNECTION (priv->connection)) {
824                 soup_connection_event (conn, G_SOCKET_CLIENT_TLS_HANDSHAKING, NULL);
825                 if (!g_tls_connection_handshake (G_TLS_CONNECTION (priv->connection),
826                                                  priv->cancellable, error)) {
827                         g_clear_object (&priv->cancellable);
828                         return FALSE;
829                 }
830                 soup_connection_event (conn, G_SOCKET_CLIENT_TLS_HANDSHAKED, NULL);
831         }
832 
833         soup_connection_complete (conn);
834 
835         return TRUE;
836 }
837 
838 gboolean
soup_connection_is_tunnelled(SoupConnection * conn)839 soup_connection_is_tunnelled (SoupConnection *conn)
840 {
841 	SoupConnectionPrivate *priv;
842 
843 	g_return_val_if_fail (SOUP_IS_CONNECTION (conn), FALSE);
844 	priv = soup_connection_get_instance_private (conn);
845 
846 	return priv->ssl && priv->proxy_uri != NULL;
847 }
848 
849 static void
tunnel_handshake_ready_cb(GTlsConnection * tls_connection,GAsyncResult * result,GTask * task)850 tunnel_handshake_ready_cb (GTlsConnection *tls_connection,
851                            GAsyncResult   *result,
852                            GTask          *task)
853 {
854         SoupConnection *conn = g_task_get_source_object (task);
855         SoupConnectionPrivate *priv = soup_connection_get_instance_private (conn);
856         GError *error = NULL;
857 
858         g_clear_object (&priv->cancellable);
859 
860         if (g_tls_connection_handshake_finish (tls_connection, result, &error)) {
861                 soup_connection_event (conn, G_SOCKET_CLIENT_TLS_HANDSHAKED, NULL);
862                 soup_connection_event (conn, G_SOCKET_CLIENT_COMPLETE, NULL);
863 
864                 g_assert (!priv->io_data);
865                 priv->io_data = soup_client_message_io_http1_new (conn);
866 
867                 g_task_return_boolean (task, TRUE);
868         } else {
869                 g_task_return_error (task, error);
870         }
871         g_object_unref (task);
872 }
873 
874 void
soup_connection_tunnel_handshake_async(SoupConnection * conn,int io_priority,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)875 soup_connection_tunnel_handshake_async (SoupConnection     *conn,
876                                         int                 io_priority,
877                                         GCancellable       *cancellable,
878                                         GAsyncReadyCallback callback,
879                                         gpointer            user_data)
880 {
881         SoupConnectionPrivate *priv;
882         GTask *task;
883         GTlsClientConnection *tls_connection;
884         GError *error = NULL;
885 
886         g_return_if_fail (SOUP_IS_CONNECTION (conn));
887 
888         priv = soup_connection_get_instance_private (conn);
889         g_return_if_fail (G_IS_SOCKET_CONNECTION (priv->connection));
890         g_return_if_fail (priv->cancellable == NULL);
891 
892         priv->cancellable = cancellable ? g_object_ref (cancellable) : g_cancellable_new ();
893         task = g_task_new (conn, priv->cancellable, callback, user_data);
894         g_task_set_priority (task, io_priority);
895 
896         tls_connection = new_tls_connection (conn, G_SOCKET_CONNECTION (priv->connection), &error);
897         if (!tls_connection) {
898 		g_clear_object (&priv->cancellable);
899                 g_task_return_error (task, error);
900                 g_object_unref (task);
901                 return;
902         }
903 
904         soup_connection_set_connection (conn, G_IO_STREAM (tls_connection));
905         soup_connection_event (conn, G_SOCKET_CLIENT_TLS_HANDSHAKING, NULL);
906         g_tls_connection_handshake_async (G_TLS_CONNECTION (priv->connection),
907                                           g_task_get_priority (task),
908                                           priv->cancellable,
909                                           (GAsyncReadyCallback)tunnel_handshake_ready_cb,
910                                           task);
911 }
912 
913 gboolean
soup_connection_tunnel_handshake_finish(SoupConnection * conn,GAsyncResult * result,GError ** error)914 soup_connection_tunnel_handshake_finish (SoupConnection *conn,
915                                          GAsyncResult   *result,
916                                          GError        **error)
917 {
918         g_return_val_if_fail (SOUP_IS_CONNECTION (conn), FALSE);
919 
920         return g_task_propagate_boolean (G_TASK (result), error);
921 }
922 
923 gboolean
soup_connection_tunnel_handshake(SoupConnection * conn,GCancellable * cancellable,GError ** error)924 soup_connection_tunnel_handshake (SoupConnection *conn,
925                                   GCancellable   *cancellable,
926                                   GError        **error)
927 {
928         SoupConnectionPrivate *priv;
929         GTlsClientConnection *tls_connection;
930 
931         g_return_val_if_fail (SOUP_IS_CONNECTION (conn), FALSE);
932 
933         priv = soup_connection_get_instance_private (conn);
934         g_return_val_if_fail (G_IS_SOCKET_CONNECTION (priv->connection), FALSE);
935         g_return_val_if_fail (priv->cancellable == NULL, FALSE);
936 
937         tls_connection = new_tls_connection (conn, G_SOCKET_CONNECTION (priv->connection), error);
938         if (!tls_connection)
939                 return FALSE;
940 
941         soup_connection_set_connection (conn, G_IO_STREAM (tls_connection));
942         soup_connection_event (conn, G_SOCKET_CLIENT_TLS_HANDSHAKING, NULL);
943 
944         priv->cancellable = cancellable ? g_object_ref (cancellable) : g_cancellable_new ();
945         if (!g_tls_connection_handshake (G_TLS_CONNECTION (priv->connection),
946                                          priv->cancellable, error)) {
947                 g_clear_object (&priv->cancellable);
948                 return FALSE;
949         }
950         g_clear_object (&priv->cancellable);
951 
952         soup_connection_event (conn, G_SOCKET_CLIENT_TLS_HANDSHAKED, NULL);
953         soup_connection_event (conn, G_SOCKET_CLIENT_COMPLETE, NULL);
954 
955         g_assert (!priv->io_data);
956         priv->io_data = soup_client_message_io_http1_new (conn);
957 
958         return TRUE;
959 }
960 
961 static void
soup_connection_disconnected(SoupConnection * conn)962 soup_connection_disconnected (SoupConnection *conn)
963 {
964         SoupConnectionPrivate *priv = soup_connection_get_instance_private (conn);
965 
966         if (priv->connection) {
967                 GIOStream *connection;
968 
969                 connection = priv->connection;
970                 priv->connection = NULL;
971 
972                 g_io_stream_close (connection, NULL, NULL);
973                 g_signal_handlers_disconnect_by_data (connection, conn);
974                 g_object_unref (connection);
975         }
976 
977         g_signal_emit (conn, signals[DISCONNECTED], 0);
978 }
979 
980 static void
client_message_io_closed_cb(SoupConnection * conn,GAsyncResult * result)981 client_message_io_closed_cb (SoupConnection *conn,
982                              GAsyncResult   *result)
983 {
984         g_task_propagate_boolean (G_TASK (result), NULL);
985         soup_connection_disconnected (conn);
986 }
987 
988 /**
989  * soup_connection_disconnect:
990  * @conn: a connection
991  *
992  * Disconnects @conn's socket and emits a %disconnected signal.
993  * After calling this, @conn will be essentially useless.
994  **/
995 void
soup_connection_disconnect(SoupConnection * conn)996 soup_connection_disconnect (SoupConnection *conn)
997 {
998         SoupConnectionPrivate *priv = soup_connection_get_instance_private (conn);
999 
1000         if (priv->state == SOUP_CONNECTION_DISCONNECTED)
1001                 return;
1002 
1003         soup_connection_set_state (conn, SOUP_CONNECTION_DISCONNECTED);
1004 
1005         if (priv->cancellable) {
1006                 g_cancellable_cancel (priv->cancellable);
1007                 priv->cancellable = NULL;
1008         }
1009 
1010         if (priv->io_data &&
1011             soup_client_message_io_close_async (priv->io_data, conn, (GAsyncReadyCallback)client_message_io_closed_cb))
1012                 return;
1013 
1014         soup_connection_disconnected (conn);
1015 }
1016 
1017 GSocket *
soup_connection_get_socket(SoupConnection * conn)1018 soup_connection_get_socket (SoupConnection *conn)
1019 {
1020         SoupConnectionPrivate *priv = soup_connection_get_instance_private (conn);
1021         GSocketConnection *connection = NULL;
1022 
1023         g_return_val_if_fail (SOUP_IS_CONNECTION (conn), NULL);
1024 
1025         if (G_IS_TLS_CONNECTION (priv->connection)) {
1026                 g_object_get (priv->connection, "base-io-stream", &connection, NULL);
1027                 g_object_unref (connection);
1028         } else if (G_IS_SOCKET_CONNECTION (priv->connection))
1029                 connection = G_SOCKET_CONNECTION (priv->connection);
1030 
1031         return connection ? g_socket_connection_get_socket (connection) : NULL;
1032 }
1033 
1034 GIOStream *
soup_connection_get_iostream(SoupConnection * conn)1035 soup_connection_get_iostream (SoupConnection *conn)
1036 {
1037         SoupConnectionPrivate *priv = soup_connection_get_instance_private (conn);
1038 
1039         g_return_val_if_fail (SOUP_IS_CONNECTION (conn), NULL);
1040 
1041         return priv->iostream;
1042 }
1043 
1044 GIOStream *
soup_connection_steal_iostream(SoupConnection * conn)1045 soup_connection_steal_iostream (SoupConnection *conn)
1046 {
1047         SoupConnectionPrivate *priv;
1048         GSocket *socket;
1049         GIOStream *iostream;
1050 
1051         g_return_val_if_fail (SOUP_IS_CONNECTION (conn), NULL);
1052 
1053         socket = soup_connection_get_socket (conn);
1054         g_socket_set_timeout (socket, 0);
1055 
1056         priv = soup_connection_get_instance_private (conn);
1057         iostream = priv->iostream;
1058         priv->iostream = NULL;
1059 
1060         g_object_set_data_full (G_OBJECT (iostream), "GSocket",
1061                                 g_object_ref (socket), g_object_unref);
1062         g_clear_object (&priv->connection);
1063 
1064         if (priv->io_data)
1065                 soup_client_message_io_stolen (priv->io_data);
1066 
1067         return iostream;
1068 }
1069 
1070 GUri *
soup_connection_get_proxy_uri(SoupConnection * conn)1071 soup_connection_get_proxy_uri (SoupConnection *conn)
1072 {
1073 	SoupConnectionPrivate *priv = soup_connection_get_instance_private (conn);
1074 
1075 	g_return_val_if_fail (SOUP_IS_CONNECTION (conn), NULL);
1076 
1077 	return priv->proxy_uri;
1078 }
1079 
1080 gboolean
soup_connection_is_via_proxy(SoupConnection * conn)1081 soup_connection_is_via_proxy (SoupConnection *conn)
1082 {
1083 	SoupConnectionPrivate *priv = soup_connection_get_instance_private (conn);
1084 
1085 	g_return_val_if_fail (SOUP_IS_CONNECTION (conn), FALSE);
1086 
1087 	return priv->proxy_uri != NULL;
1088 }
1089 
1090 gboolean
soup_connection_is_idle_open(SoupConnection * conn)1091 soup_connection_is_idle_open (SoupConnection *conn)
1092 {
1093         SoupConnectionPrivate *priv = soup_connection_get_instance_private (conn);
1094 
1095         g_assert (priv->state == SOUP_CONNECTION_IDLE);
1096 
1097 	if (!g_socket_is_connected (soup_connection_get_socket (conn)))
1098 		return FALSE;
1099 
1100 	if (priv->unused_timeout && priv->unused_timeout < time (NULL))
1101 		return FALSE;
1102 
1103         return soup_client_message_io_is_open (priv->io_data);
1104 }
1105 
1106 SoupConnectionState
soup_connection_get_state(SoupConnection * conn)1107 soup_connection_get_state (SoupConnection *conn)
1108 {
1109 	SoupConnectionPrivate *priv = soup_connection_get_instance_private (conn);
1110 
1111 	return priv->state;
1112 }
1113 
1114 void
soup_connection_set_in_use(SoupConnection * conn,gboolean in_use)1115 soup_connection_set_in_use (SoupConnection *conn,
1116                             gboolean        in_use)
1117 {
1118         SoupConnectionPrivate *priv = soup_connection_get_instance_private (conn);
1119 
1120         g_assert (in_use || priv->in_use > 0);
1121 
1122         if (in_use)
1123                 priv->in_use++;
1124         else
1125                 priv->in_use--;
1126 
1127         if (priv->in_use > 0) {
1128                 if (priv->state == SOUP_CONNECTION_IDLE)
1129                         soup_connection_set_state (conn, SOUP_CONNECTION_IN_USE);
1130                 return;
1131         }
1132 
1133         clear_proxy_msg (conn);
1134 
1135         if (soup_connection_is_reusable (conn))
1136                 soup_connection_set_state (conn, SOUP_CONNECTION_IDLE);
1137         else
1138                 soup_connection_disconnect (conn);
1139 }
1140 
1141 SoupClientMessageIO *
soup_connection_setup_message_io(SoupConnection * conn,SoupMessage * msg)1142 soup_connection_setup_message_io (SoupConnection *conn,
1143                                   SoupMessage    *msg)
1144 {
1145         SoupConnectionPrivate *priv = soup_connection_get_instance_private (conn);
1146 
1147         g_assert (priv->state == SOUP_CONNECTION_IN_USE);
1148 
1149         priv->unused_timeout = 0;
1150         stop_idle_timer (priv);
1151 
1152         if (priv->proxy_uri && soup_message_get_method (msg) == SOUP_METHOD_CONNECT)
1153                 set_proxy_msg (conn, msg);
1154 
1155         if (!soup_client_message_io_is_reusable (priv->io_data))
1156                 g_warn_if_reached ();
1157 
1158         return priv->io_data;
1159 }
1160 
1161 GTlsCertificate *
soup_connection_get_tls_certificate(SoupConnection * conn)1162 soup_connection_get_tls_certificate (SoupConnection *conn)
1163 {
1164 	SoupConnectionPrivate *priv;
1165 
1166 	g_return_val_if_fail (SOUP_IS_CONNECTION (conn), NULL);
1167 
1168 	priv = soup_connection_get_instance_private (conn);
1169 
1170 	if (!G_IS_TLS_CONNECTION (priv->connection))
1171 		return NULL;
1172 
1173 	return g_tls_connection_get_peer_certificate (G_TLS_CONNECTION (priv->connection));
1174 }
1175 
1176 GTlsCertificateFlags
soup_connection_get_tls_certificate_errors(SoupConnection * conn)1177 soup_connection_get_tls_certificate_errors (SoupConnection *conn)
1178 {
1179 	SoupConnectionPrivate *priv;
1180 
1181 	g_return_val_if_fail (SOUP_IS_CONNECTION (conn), 0);
1182 
1183 	priv = soup_connection_get_instance_private (conn);
1184 
1185 	if (!G_IS_TLS_CONNECTION (priv->connection))
1186 		return 0;
1187 
1188 	return g_tls_connection_get_peer_certificate_errors (G_TLS_CONNECTION (priv->connection));
1189 }
1190 
1191 GTlsProtocolVersion
soup_connection_get_tls_protocol_version(SoupConnection * conn)1192 soup_connection_get_tls_protocol_version (SoupConnection *conn)
1193 {
1194         SoupConnectionPrivate *priv = soup_connection_get_instance_private (conn);
1195 
1196         if (!G_IS_TLS_CONNECTION (priv->connection))
1197                 return G_TLS_PROTOCOL_VERSION_UNKNOWN;
1198 
1199         return g_tls_connection_get_protocol_version (G_TLS_CONNECTION (priv->connection));
1200 }
1201 
1202 char *
soup_connection_get_tls_ciphersuite_name(SoupConnection * conn)1203 soup_connection_get_tls_ciphersuite_name (SoupConnection *conn)
1204 {
1205         SoupConnectionPrivate *priv = soup_connection_get_instance_private (conn);
1206 
1207         if (!G_IS_TLS_CONNECTION (priv->connection))
1208                 return NULL;
1209 
1210         return g_tls_connection_get_ciphersuite_name (G_TLS_CONNECTION (priv->connection));
1211 }
1212 
1213 void
soup_connection_set_tls_client_certificate(SoupConnection * conn,GTlsCertificate * certificate)1214 soup_connection_set_tls_client_certificate (SoupConnection  *conn,
1215                                             GTlsCertificate *certificate)
1216 {
1217         SoupConnectionPrivate *priv = soup_connection_get_instance_private (conn);
1218 
1219         if (G_IS_TLS_CONNECTION (priv->connection) && certificate) {
1220                 g_tls_connection_set_certificate (G_TLS_CONNECTION (priv->connection),
1221                                                   certificate);
1222                 g_clear_object (&priv->tls_client_cert);
1223                 return;
1224         }
1225 
1226         if (priv->tls_client_cert == certificate)
1227                 return;
1228 
1229         g_clear_object (&priv->tls_client_cert);
1230         priv->tls_client_cert = certificate ? g_object_ref (certificate) : NULL;
1231 }
1232 
1233 void
soup_connection_request_tls_certificate(SoupConnection * conn,GTlsConnection * connection,GTask * task)1234 soup_connection_request_tls_certificate (SoupConnection *conn,
1235                                          GTlsConnection *connection,
1236                                          GTask          *task)
1237 {
1238         SoupConnectionPrivate *priv = soup_connection_get_instance_private (conn);
1239         gboolean handled = FALSE;
1240 
1241         if (!G_IS_TLS_CONNECTION (priv->connection) || G_TLS_CONNECTION (priv->connection) != connection) {
1242                 g_task_return_int (task, G_TLS_INTERACTION_FAILED);
1243                 return;
1244         }
1245 
1246         if (priv->tls_client_cert) {
1247                 soup_connection_complete_tls_certificate_request (conn,
1248                                                                   priv->tls_client_cert,
1249                                                                   g_object_ref (task));
1250                 g_clear_object (&priv->tls_client_cert);
1251                 return;
1252         }
1253 
1254         g_signal_emit (conn, signals[REQUEST_CERTIFICATE], 0, connection, task, &handled);
1255         if (!handled)
1256                 g_task_return_int (task, G_TLS_INTERACTION_FAILED);
1257 }
1258 
1259 void
soup_connection_complete_tls_certificate_request(SoupConnection * conn,GTlsCertificate * certificate,GTask * task)1260 soup_connection_complete_tls_certificate_request (SoupConnection  *conn,
1261                                                   GTlsCertificate *certificate,
1262                                                   GTask           *task)
1263 {
1264         SoupConnectionPrivate *priv = soup_connection_get_instance_private (conn);
1265 
1266         if (G_IS_TLS_CONNECTION (priv->connection) && certificate) {
1267                 g_tls_connection_set_certificate (G_TLS_CONNECTION (priv->connection),
1268                                                   certificate);
1269                 g_task_return_int (task, G_TLS_INTERACTION_HANDLED);
1270         } else {
1271                 g_task_return_int (task, G_TLS_INTERACTION_FAILED);
1272         }
1273         g_object_unref (task);
1274 }
1275 
1276 void
soup_connection_request_tls_certificate_password(SoupConnection * conn,GTlsPassword * password,GTask * task)1277 soup_connection_request_tls_certificate_password (SoupConnection *conn,
1278                                                   GTlsPassword   *password,
1279                                                   GTask          *task)
1280 {
1281         SoupConnectionPrivate *priv = soup_connection_get_instance_private (conn);
1282         gboolean handled = FALSE;
1283 
1284         if (!G_IS_TLS_CONNECTION (priv->connection)) {
1285                 g_task_return_int (task, G_TLS_INTERACTION_FAILED);
1286                 return;
1287         }
1288 
1289         g_signal_emit (conn, signals[REQUEST_CERTIFICATE_PASSWORD], 0, password, task, &handled);
1290         if (!handled)
1291                 g_task_return_int (task, G_TLS_INTERACTION_FAILED);
1292 }
1293 
1294 void
soup_connection_complete_tls_certificate_password_request(SoupConnection * conn,GTask * task)1295 soup_connection_complete_tls_certificate_password_request (SoupConnection *conn,
1296                                                            GTask          *task)
1297 {
1298         SoupConnectionPrivate *priv = soup_connection_get_instance_private (conn);
1299 
1300         if (G_IS_TLS_CONNECTION (priv->connection))
1301                 g_task_return_int (task, G_TLS_INTERACTION_HANDLED);
1302         else
1303                 g_task_return_int (task, G_TLS_INTERACTION_FAILED);
1304         g_object_unref (task);
1305 }
1306 
1307 guint64
soup_connection_get_id(SoupConnection * conn)1308 soup_connection_get_id (SoupConnection *conn)
1309 {
1310         SoupConnectionPrivate *priv = soup_connection_get_instance_private (conn);
1311 
1312         return priv->id;
1313 }
1314 
1315 GSocketAddress *
soup_connection_get_remote_address(SoupConnection * conn)1316 soup_connection_get_remote_address (SoupConnection *conn)
1317 {
1318         SoupConnectionPrivate *priv = soup_connection_get_instance_private (conn);
1319 
1320         return priv->remote_address;
1321 }
1322 
1323 SoupHTTPVersion
soup_connection_get_negotiated_protocol(SoupConnection * conn)1324 soup_connection_get_negotiated_protocol (SoupConnection *conn)
1325 {
1326         SoupConnectionPrivate *priv = soup_connection_get_instance_private (conn);
1327 
1328         return priv->http_version;
1329 }
1330 
1331 gboolean
soup_connection_is_reusable(SoupConnection * conn)1332 soup_connection_is_reusable (SoupConnection *conn)
1333 {
1334         SoupConnectionPrivate *priv = soup_connection_get_instance_private (conn);
1335 
1336         return priv->io_data && soup_client_message_io_is_reusable (priv->io_data);
1337 }
1338