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