1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
2 /*
3  * soup-message.c: HTTP request/response
4  *
5  * Copyright (C) 2000-2003, Ximian, Inc.
6  */
7 
8 #ifdef HAVE_CONFIG_H
9 #include <config.h>
10 #endif
11 
12 #include <string.h>
13 
14 #include "soup-message.h"
15 #include "soup.h"
16 #include "soup-connection.h"
17 #include "soup-message-private.h"
18 #include "soup-message-headers-private.h"
19 #include "soup-message-metrics-private.h"
20 #include "soup-uri-utils-private.h"
21 #include "content-sniffer/soup-content-sniffer-stream.h"
22 
23 /**
24  * SECTION:soup-message
25  * @short_description: An HTTP request and response.
26  * @see_also: #SoupMessageHeaders
27  *
28  * A #SoupMessage represents an HTTP message that is being sent or
29  * received.
30  *
31  * You would create a #SoupMessage with soup_message_new() or
32  * soup_message_new_from_uri(), set up its
33  * fields appropriately, and send it.
34  *
35  * Note that libsoup's terminology here does not quite match the HTTP
36  * specification: in RFC 2616, an "HTTP-message" is
37  * <emphasis>either</emphasis> a Request, <emphasis>or</emphasis> a
38  * Response. In libsoup, a #SoupMessage combines both the request and
39  * the response.
40  **/
41 
42 /**
43  * SoupMessage:
44  *
45  * Represents an HTTP message being sent or received.
46  *
47  * @status_code will normally be a #SoupStatus value, eg,
48  * %SOUP_STATUS_OK, though of course it might actually be an unknown
49  * status code. @reason_phrase is the actual text returned from the
50  * server, which may or may not correspond to the "standard"
51  * description of @status_code. At any rate, it is almost certainly
52  * not localized, and not very descriptive even if it is in the user's
53  * language; you should not use @reason_phrase in user-visible
54  * messages. Rather, you should look at @status_code, and determine an
55  * end-user-appropriate message based on that and on what you were
56  * trying to do.
57  */
58 
59 struct _SoupMessage {
60 	GObject parent_instance;
61 };
62 
63 typedef struct {
64 	SoupClientMessageIO *io_data;
65 
66         SoupMessageHeaders *request_headers;
67 	SoupMessageHeaders *response_headers;
68 
69 	GInputStream      *request_body_stream;
70         const char        *method;
71         char              *reason_phrase;
72         SoupStatus         status_code;
73 
74 	guint              msg_flags;
75 
76 	SoupContentSniffer *sniffer;
77 
78 	SoupHTTPVersion    http_version, orig_http_version;
79 
80 	GUri              *uri;
81 
82 	SoupAuth          *auth, *proxy_auth;
83 	SoupConnection    *connection;
84 
85 	GHashTable        *disabled_features;
86 
87 	GUri              *first_party;
88 	GUri              *site_for_cookies;
89 
90 	GTlsCertificate      *tls_peer_certificate;
91 	GTlsCertificateFlags  tls_peer_certificate_errors;
92         GTlsProtocolVersion   tls_protocol_version;
93         char                 *tls_ciphersuite_name;
94 
95         GTlsCertificate *tls_client_certificate;
96         GTask *pending_tls_cert_request;
97         GTlsClientConnection *pending_tls_cert_conn;
98         GTask *pending_tls_cert_pass_request;
99         GTlsPassword *pending_tls_cert_password;
100 
101 	SoupMessagePriority priority;
102 
103 	gboolean is_top_level_navigation;
104         gboolean is_options_ping;
105         gboolean is_preconnect;
106         gboolean force_http1;
107         gboolean is_misdirected_retry;
108         guint    last_connection_id;
109         GSocketAddress *remote_address;
110 
111         SoupMessageMetrics *metrics;
112 } SoupMessagePrivate;
113 
114 G_DEFINE_FINAL_TYPE_WITH_PRIVATE (SoupMessage, soup_message, G_TYPE_OBJECT)
115 
116 enum {
117 	WROTE_HEADERS,
118 	WROTE_BODY_DATA,
119 	WROTE_BODY,
120 
121 	GOT_INFORMATIONAL,
122 	GOT_HEADERS,
123 	GOT_BODY,
124 	CONTENT_SNIFFED,
125 
126 	STARTING,
127 	RESTARTED,
128 	FINISHED,
129 
130 	AUTHENTICATE,
131 	NETWORK_EVENT,
132 	ACCEPT_CERTIFICATE,
133         REQUEST_CERTIFICATE,
134         REQUEST_CERTIFICATE_PASSWORD,
135 	HSTS_ENFORCED,
136 
137 	LAST_SIGNAL
138 };
139 
140 static guint signals[LAST_SIGNAL] = { 0 };
141 
142 enum {
143 	PROP_0,
144 
145 	PROP_METHOD,
146 	PROP_URI,
147 	PROP_HTTP_VERSION,
148 	PROP_FLAGS,
149 	PROP_STATUS_CODE,
150 	PROP_REASON_PHRASE,
151 	PROP_FIRST_PARTY,
152 	PROP_REQUEST_HEADERS,
153 	PROP_RESPONSE_HEADERS,
154 	PROP_TLS_PEER_CERTIFICATE,
155 	PROP_TLS_PEER_CERTIFICATE_ERRORS,
156         PROP_TLS_PROTOCOL_VERSION,
157         PROP_TLS_CIPHERSUITE_NAME,
158         PROP_REMOTE_ADDRESS,
159 	PROP_PRIORITY,
160 	PROP_SITE_FOR_COOKIES,
161 	PROP_IS_TOP_LEVEL_NAVIGATION,
162         PROP_IS_OPTIONS_PING,
163 
164 	LAST_PROPERTY
165 };
166 
167 static GParamSpec *properties[LAST_PROPERTY] = { NULL, };
168 
169 static void
soup_message_init(SoupMessage * msg)170 soup_message_init (SoupMessage *msg)
171 {
172 	SoupMessagePrivate *priv = soup_message_get_instance_private (msg);
173 
174 	priv->http_version = priv->orig_http_version = SOUP_HTTP_1_1;
175 	priv->priority = SOUP_MESSAGE_PRIORITY_NORMAL;
176 
177 	priv->request_headers = soup_message_headers_new (SOUP_MESSAGE_HEADERS_REQUEST);
178 	priv->response_headers = soup_message_headers_new (SOUP_MESSAGE_HEADERS_RESPONSE);
179 }
180 
181 static void
soup_message_finalize(GObject * object)182 soup_message_finalize (GObject *object)
183 {
184 	SoupMessage *msg = SOUP_MESSAGE (object);
185 	SoupMessagePrivate *priv = soup_message_get_instance_private (msg);
186 
187         if (priv->pending_tls_cert_request) {
188                 g_task_return_int (priv->pending_tls_cert_request, G_TLS_INTERACTION_FAILED);
189                 g_object_unref (priv->pending_tls_cert_request);
190         }
191         g_clear_object (&priv->pending_tls_cert_conn);
192 
193         if (priv->pending_tls_cert_pass_request) {
194                 g_task_return_int (priv->pending_tls_cert_pass_request, G_TLS_INTERACTION_FAILED);
195                 g_object_unref (priv->pending_tls_cert_pass_request);
196         }
197         g_clear_object (&priv->pending_tls_cert_password);
198 
199 	soup_message_set_connection (msg, NULL);
200 
201 	g_clear_pointer (&priv->uri, g_uri_unref);
202 	g_clear_pointer (&priv->first_party, g_uri_unref);
203 	g_clear_pointer (&priv->site_for_cookies, g_uri_unref);
204         g_clear_pointer (&priv->metrics, soup_message_metrics_free);
205         g_clear_pointer (&priv->tls_ciphersuite_name, g_free);
206 
207 	g_clear_object (&priv->auth);
208 	g_clear_object (&priv->proxy_auth);
209 
210 	g_clear_pointer (&priv->disabled_features, g_hash_table_destroy);
211 
212 	g_clear_object (&priv->tls_peer_certificate);
213         g_clear_object (&priv->remote_address);
214         g_clear_object (&priv->tls_client_certificate);
215 
216 	soup_message_headers_unref (priv->request_headers);
217 	soup_message_headers_unref (priv->response_headers);
218 	g_clear_object (&priv->request_body_stream);
219 
220 	g_free (priv->reason_phrase);
221 
222 	G_OBJECT_CLASS (soup_message_parent_class)->finalize (object);
223 }
224 
225 static void
soup_message_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)226 soup_message_set_property (GObject *object, guint prop_id,
227 			   const GValue *value, GParamSpec *pspec)
228 {
229 	SoupMessage *msg = SOUP_MESSAGE (object);
230 
231 	switch (prop_id) {
232 	case PROP_METHOD:
233                 soup_message_set_method (msg, g_value_get_string (value));
234 		break;
235 	case PROP_URI:
236 		soup_message_set_uri (msg, g_value_get_boxed (value));
237 		break;
238 	case PROP_SITE_FOR_COOKIES:
239 		soup_message_set_site_for_cookies (msg, g_value_get_boxed (value));
240 		break;
241 	case PROP_IS_TOP_LEVEL_NAVIGATION:
242 		soup_message_set_is_top_level_navigation (msg, g_value_get_boolean (value));
243 		break;
244 	case PROP_FLAGS:
245 		soup_message_set_flags (msg, g_value_get_flags (value));
246 		break;
247 	case PROP_FIRST_PARTY:
248 		soup_message_set_first_party (msg, g_value_get_boxed (value));
249 		break;
250 	case PROP_PRIORITY:
251                 soup_message_set_priority (msg, g_value_get_enum (value));
252 		break;
253 	case PROP_IS_OPTIONS_PING:
254                 soup_message_set_is_options_ping (msg, g_value_get_boolean (value));
255 		break;
256 	default:
257 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
258 		break;
259 	}
260 }
261 
262 static void
soup_message_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)263 soup_message_get_property (GObject *object, guint prop_id,
264 			   GValue *value, GParamSpec *pspec)
265 {
266 	SoupMessage *msg = SOUP_MESSAGE (object);
267 	SoupMessagePrivate *priv = soup_message_get_instance_private (msg);
268 
269 	switch (prop_id) {
270 	case PROP_METHOD:
271 		g_value_set_string (value, priv->method);
272 		break;
273 	case PROP_URI:
274 		g_value_set_boxed (value, priv->uri);
275 		break;
276 	case PROP_SITE_FOR_COOKIES:
277 		g_value_set_boxed (value, priv->site_for_cookies);
278 		break;
279 	case PROP_IS_TOP_LEVEL_NAVIGATION:
280 		g_value_set_boolean (value, priv->is_top_level_navigation);
281 		break;
282 	case PROP_HTTP_VERSION:
283 		g_value_set_enum (value, priv->http_version);
284 		break;
285 	case PROP_FLAGS:
286 		g_value_set_flags (value, priv->msg_flags);
287 		break;
288 	case PROP_STATUS_CODE:
289 		g_value_set_uint (value, priv->status_code);
290 		break;
291 	case PROP_REASON_PHRASE:
292 		g_value_set_string (value, priv->reason_phrase);
293 		break;
294 	case PROP_FIRST_PARTY:
295 		g_value_set_boxed (value, priv->first_party);
296 		break;
297 	case PROP_REQUEST_HEADERS:
298 		g_value_set_boxed (value, priv->request_headers);
299 		break;
300 	case PROP_RESPONSE_HEADERS:
301 		g_value_set_boxed (value, priv->response_headers);
302 		break;
303 	case PROP_TLS_PEER_CERTIFICATE:
304 		g_value_set_object (value, priv->tls_peer_certificate);
305 		break;
306 	case PROP_TLS_PEER_CERTIFICATE_ERRORS:
307 		g_value_set_flags (value, priv->tls_peer_certificate_errors);
308 		break;
309         case PROP_TLS_PROTOCOL_VERSION:
310                 g_value_set_enum (value, priv->tls_protocol_version);
311 		break;
312         case PROP_TLS_CIPHERSUITE_NAME:
313 		g_value_set_string (value, priv->tls_ciphersuite_name);
314                 break;
315         case PROP_REMOTE_ADDRESS:
316                 g_value_set_object (value, priv->remote_address);
317                 break;
318 	case PROP_PRIORITY:
319 		g_value_set_enum (value, priv->priority);
320 		break;
321 	case PROP_IS_OPTIONS_PING:
322                 g_value_set_boolean (value, priv->is_options_ping);
323                 break;
324 	default:
325 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
326 		break;
327 	}
328 }
329 
330 static void
soup_message_class_init(SoupMessageClass * message_class)331 soup_message_class_init (SoupMessageClass *message_class)
332 {
333 	GObjectClass *object_class = G_OBJECT_CLASS (message_class);
334 
335 	/* virtual method override */
336 	object_class->finalize = soup_message_finalize;
337 	object_class->set_property = soup_message_set_property;
338 	object_class->get_property = soup_message_get_property;
339 
340 	/* signals */
341 
342 	/**
343 	 * SoupMessage::wrote-headers:
344 	 * @msg: the message
345 	 *
346 	 * Emitted immediately after writing the request headers for a
347 	 * message.
348 	 **/
349 	signals[WROTE_HEADERS] =
350 		g_signal_new ("wrote-headers",
351 			      G_OBJECT_CLASS_TYPE (object_class),
352 			      G_SIGNAL_RUN_FIRST,
353 			      0,
354 			      NULL, NULL,
355 			      NULL,
356 			      G_TYPE_NONE, 0);
357 
358 	/**
359 	 * SoupMessage::wrote-body-data:
360 	 * @msg: the message
361 	 * @chunk_size: the number of bytes written
362 	 *
363 	 * Emitted immediately after writing a portion of the message
364 	 * body to the network.
365 	 *
366 	 **/
367 	signals[WROTE_BODY_DATA] =
368 		g_signal_new ("wrote-body-data",
369 			      G_OBJECT_CLASS_TYPE (object_class),
370 			      G_SIGNAL_RUN_FIRST,
371 			      0,
372 			      NULL, NULL,
373 			      NULL,
374 			      G_TYPE_NONE, 1,
375 			      G_TYPE_UINT);
376 
377 	/**
378 	 * SoupMessage::wrote-body:
379 	 * @msg: the message
380 	 *
381 	 * Emitted immediately after writing the complete body for a
382 	 * message.
383 	 **/
384 	signals[WROTE_BODY] =
385 		g_signal_new ("wrote-body",
386 			      G_OBJECT_CLASS_TYPE (object_class),
387 			      G_SIGNAL_RUN_FIRST,
388 			      0,
389 			      NULL, NULL,
390 			      NULL,
391 			      G_TYPE_NONE, 0);
392 
393 	/**
394 	 * SoupMessage::got-informational:
395 	 * @msg: the message
396 	 *
397 	 * Emitted after receiving a 1xx (Informational) response for
398 	 * a (client-side) message. The response_headers will be
399 	 * filled in with the headers associated with the
400 	 * informational response; however, those header values will
401 	 * be erased after this signal is done.
402 	 *
403 	 * If you cancel or requeue @msg while processing this signal,
404 	 * then the current HTTP I/O will be stopped after this signal
405 	 * emission finished, and @msg's connection will be closed.
406 	 **/
407 	signals[GOT_INFORMATIONAL] =
408 		g_signal_new ("got-informational",
409 			      G_OBJECT_CLASS_TYPE (object_class),
410 			      G_SIGNAL_RUN_FIRST,
411 			      0,
412 			      NULL, NULL,
413 			      NULL,
414 			      G_TYPE_NONE, 0);
415 
416 	/**
417 	 * SoupMessage::got-headers:
418 	 * @msg: the message
419 	 *
420 	 * Emitted after receiving the Status-Line and response headers.
421 	 *
422 	 * See also soup_message_add_header_handler() and
423 	 * soup_message_add_status_code_handler(), which can be used
424 	 * to connect to a subset of emissions of this signal.
425 	 *
426 	 * If you cancel or requeue @msg while processing this signal,
427 	 * then the current HTTP I/O will be stopped after this signal
428 	 * emission finished, and @msg's connection will be closed.
429 	 * (If you need to requeue a message--eg, after handling
430 	 * authentication or redirection--it is usually better to
431 	 * requeue it from a #SoupMessage::got_body handler rather
432 	 * than a #SoupMessage::got_headers handler, so that the
433 	 * existing HTTP connection can be reused.)
434 	 **/
435 	signals[GOT_HEADERS] =
436 		g_signal_new ("got-headers",
437 			      G_OBJECT_CLASS_TYPE (object_class),
438 			      G_SIGNAL_RUN_FIRST,
439 			      0,
440 			      NULL, NULL,
441 			      NULL,
442 			      G_TYPE_NONE, 0);
443 
444 	/**
445 	 * SoupMessage::got-body:
446 	 * @msg: the message
447 	 *
448 	 * Emitted after receiving the complete message request body.
449 	 *
450 	 * See also soup_message_add_header_handler() and
451 	 * soup_message_add_status_code_handler(), which can be used
452 	 * to connect to a subset of emissions of this signal.
453 	 **/
454 	signals[GOT_BODY] =
455 		g_signal_new ("got-body",
456 			      G_OBJECT_CLASS_TYPE (object_class),
457 			      G_SIGNAL_RUN_FIRST,
458 			      0,
459 			      NULL, NULL,
460 			      NULL,
461 			      G_TYPE_NONE, 0);
462 
463 	/**
464 	 * SoupMessage::content-sniffed:
465 	 * @msg: the message
466 	 * @type: the content type that we got from sniffing
467 	 * @params: (element-type utf8 utf8): a #GHashTable with the parameters
468 	 *
469 	 * This signal is emitted after #SoupMessage::got-headers.
470 	 * If content sniffing is disabled, or no content sniffing will be
471 	 * performed, due to the sniffer deciding to trust the
472 	 * Content-Type sent by the server, this signal is emitted
473 	 * immediately after #SoupMessage::got-headers, and @type is
474 	 * %NULL.
475 	 *
476 	 **/
477 	signals[CONTENT_SNIFFED] =
478 		g_signal_new ("content-sniffed",
479 			      G_OBJECT_CLASS_TYPE (object_class),
480 			      G_SIGNAL_RUN_FIRST,
481 			      0,
482 			      NULL, NULL,
483 			      NULL,
484 			      G_TYPE_NONE, 2,
485 			      G_TYPE_STRING,
486 			      G_TYPE_HASH_TABLE);
487 
488 	/**
489 	 * SoupMessage::starting:
490 	 * @msg: the message
491 	 *
492 	 * Emitted just before a message is sent.
493 	 *
494 	 */
495 	signals[STARTING] =
496 		g_signal_new ("starting",
497 			      G_OBJECT_CLASS_TYPE (object_class),
498 			      G_SIGNAL_RUN_FIRST,
499 			      0,
500 			      NULL, NULL,
501 			      NULL,
502 			      G_TYPE_NONE, 0);
503 
504 	/**
505 	 * SoupMessage::restarted:
506 	 * @msg: the message
507 	 *
508 	 * Emitted when a request that was already sent once is now
509 	 * being sent again (eg, because the first attempt received a
510 	 * redirection response, or because we needed to use
511 	 * authentication).
512 	 **/
513 	signals[RESTARTED] =
514 		g_signal_new ("restarted",
515 			      G_OBJECT_CLASS_TYPE (object_class),
516 			      G_SIGNAL_RUN_FIRST,
517 			      0,
518 			      NULL, NULL,
519 			      NULL,
520 			      G_TYPE_NONE, 0);
521 
522 	/**
523 	 * SoupMessage::finished:
524 	 * @msg: the message
525 	 *
526 	 * Emitted when all HTTP processing is finished for a message.
527 	 * (After #SoupMessage::got_body).
528 	 **/
529 	signals[FINISHED] =
530 		g_signal_new ("finished",
531 			      G_OBJECT_CLASS_TYPE (object_class),
532 			      G_SIGNAL_RUN_FIRST,
533 			      0,
534 			      NULL, NULL,
535 			      NULL,
536 			      G_TYPE_NONE, 0);
537 
538 	/**
539 	 * SoupMessage::authenticate:
540 	 * @msg: the message
541 	 * @auth: the #SoupAuth to authenticate
542 	 * @retrying: %TRUE if this is the second (or later) attempt
543 	 *
544 	 * Emitted when the message requires authentication. If
545 	 * credentials are available call soup_auth_authenticate() on
546 	 * @auth. If these credentials fail, the signal will be
547 	 * emitted again, with @retrying set to %TRUE, which will
548 	 * continue until you return without calling
549 	 * soup_auth_authenticate() on @auth.
550 	 *
551 	 * Note that this may be emitted before @msg's body has been
552 	 * fully read.
553 	 *
554 	 * You can authenticate @auth asynchronously by calling g_object_ref()
555 	 * on @auth and returning %TRUE. The operation will complete once
556 	 * either soup_auth_authenticate() or soup_auth_cancel() are called.
557 	 *
558 	 * Returns: %TRUE to stop other handlers from being invoked
559 	 *    or %FALSE to propagate the event further.
560 	 **/
561 	signals[AUTHENTICATE] =
562 		g_signal_new ("authenticate",
563 			      G_OBJECT_CLASS_TYPE (object_class),
564 			      G_SIGNAL_RUN_LAST,
565 			      0,
566 			      g_signal_accumulator_true_handled, NULL,
567 			      NULL,
568 			      G_TYPE_BOOLEAN, 2,
569 			      SOUP_TYPE_AUTH,
570 			      G_TYPE_BOOLEAN);
571 
572 	/**
573 	 * SoupMessage::network-event:
574 	 * @msg: the message
575 	 * @event: the network event
576 	 * @connection: the current state of the network connection
577 	 *
578 	 * Emitted to indicate that some network-related event
579 	 * related to @msg has occurred. This essentially proxies the
580 	 * #GSocketClient::event signal, but only for events that
581 	 * occur while @msg "owns" the connection; if @msg is sent on
582 	 * an existing persistent connection, then this signal will
583 	 * not be emitted. (If you want to force the message to be
584 	 * sent on a new connection, set the
585 	 * %SOUP_MESSAGE_NEW_CONNECTION flag on it.)
586 	 *
587 	 * See #GSocketClient::event for more information on what
588 	 * the different values of @event correspond to, and what
589 	 * @connection will be in each case.
590 	 *
591 	 **/
592 	signals[NETWORK_EVENT] =
593 		g_signal_new ("network-event",
594 			      G_OBJECT_CLASS_TYPE (object_class),
595 			      G_SIGNAL_RUN_FIRST,
596 			      0,
597 			      NULL, NULL,
598 			      NULL,
599 			      G_TYPE_NONE, 2,
600 			      G_TYPE_SOCKET_CLIENT_EVENT,
601 			      G_TYPE_IO_STREAM);
602 
603 	/**
604 	 * SoupMessage::accept-certificate:
605 	 * @msg: the message
606 	 * @tls_peer_certificate: the peer's #GTlsCertificate
607 	 * @tls_peer_errors: the tls errors of @tls_certificate
608 	 *
609 	 * Emitted during the @msg's connection TLS handshake
610 	 * after an unacceptable TLS certificate has been received.
611 	 * You can return %TRUE to accept @tls_certificate despite
612 	 * @tls_errors.
613 	 *
614 	 * Returns: %TRUE to accept the TLS certificate and stop other
615 	 *     handlers from being invoked, or %FALSE to propagate the
616 	 *     event further.
617 	 */
618 	signals[ACCEPT_CERTIFICATE] =
619 		g_signal_new ("accept-certificate",
620 			      G_OBJECT_CLASS_TYPE (object_class),
621 			      G_SIGNAL_RUN_LAST,
622 			      0,
623 			      g_signal_accumulator_true_handled, NULL,
624 			      NULL,
625 			      G_TYPE_BOOLEAN, 2,
626 			      G_TYPE_TLS_CERTIFICATE,
627 			      G_TYPE_TLS_CERTIFICATE_FLAGS);
628 
629         /**
630          * SoupMessage::request-certificate:
631          * @msg: the message
632          * @tls_connection: the #GTlsClientConnection
633          *
634          * Emitted during the @msg's connection TLS handshake when
635          * @tls_connection requests a certificate from the client.
636          * You can set the client certificate by calling
637          * soup_message_set_tls_client_certificate() and returning %TRUE.
638          * It's possible to handle the request asynchornously by returning
639          * %TRUE and call soup_message_set_tls_client_certificate() later
640          * once the certificate is available.
641          * Note that this signal is not emitted if #SoupSession::tls-interaction
642          * was set, or if soup_message_set_tls_client_certificate() was called
643          * before the connection TLS handshake started.
644          *
645          * Returns: %TRUE to handle the request, or %FALSE to make the connection
646          *     fail with %G_TLS_ERROR_CERTIFICATE_REQUIRED.
647          */
648         signals[REQUEST_CERTIFICATE] =
649                 g_signal_new ("request-certificate",
650                               G_OBJECT_CLASS_TYPE (object_class),
651                               G_SIGNAL_RUN_LAST,
652                               0,
653                               g_signal_accumulator_true_handled, NULL,
654                               NULL,
655                               G_TYPE_BOOLEAN, 1,
656                               G_TYPE_TLS_CLIENT_CONNECTION);
657 
658         /**
659          * SoupMessage::request-certificate-password:
660          * @msg: the message
661          * @tls_password: the #GTlsPassword
662          *
663          * Emitted during the @msg's connection TLS handshake when
664          * @tls_connection requests a certificate password from the client.
665          * You can set the certificate password on @password, then call
666          * soup_message_tls_client_certificate_password_request_complete() and return %TRUE
667          * to handle the signal synchronously.
668          * It's possible to handle the request asynchornously by calling g_object_ref()
669          * on @password, then returning %TRUE and call
670          * soup_message_tls_client_certificate_password_request_complete() later after
671          * setting the password on @password.
672          * Note that this signal is not emitted if #SoupSession::tls-interaction
673          * was set.
674          *
675          * Returns: %TRUE to handle the request, or %FALSE to make the connection
676          *     fail with %G_TLS_ERROR_CERTIFICATE_REQUIRED.
677          */
678         signals[REQUEST_CERTIFICATE_PASSWORD] =
679                 g_signal_new ("request-certificate-password",
680                               G_OBJECT_CLASS_TYPE (object_class),
681                               G_SIGNAL_RUN_LAST,
682                               0,
683                               g_signal_accumulator_true_handled, NULL,
684                               NULL,
685                               G_TYPE_BOOLEAN, 1,
686                               G_TYPE_TLS_PASSWORD);
687 
688 	/**
689 	 * SoupMessage::hsts-enforced:
690 	 * @msg: the message
691 	 *
692 	 * Emitted when #SoupHSTSEnforcer has upgraded the protocol
693 	 * for @msg to HTTPS as a result of matching its domain with
694 	 * a HSTS policy.
695 	 **/
696 	signals[HSTS_ENFORCED] =
697 		g_signal_new ("hsts-enforced",
698 			      G_OBJECT_CLASS_TYPE (object_class),
699 			      G_SIGNAL_RUN_LAST,
700 			      0,
701 			      NULL, NULL,
702 			      NULL,
703 			      G_TYPE_NONE, 0);
704 
705 	/* properties */
706         properties[PROP_METHOD] =
707 		g_param_spec_string ("method",
708 				     "Method",
709 				     "The message's HTTP method",
710 				     SOUP_METHOD_GET,
711 				     G_PARAM_READWRITE |
712 				     G_PARAM_STATIC_STRINGS);
713         properties[PROP_URI] =
714 		g_param_spec_boxed ("uri",
715 				    "URI",
716 				    "The message's Request-URI",
717 				    G_TYPE_URI,
718 				    G_PARAM_READWRITE |
719 				    G_PARAM_STATIC_STRINGS);
720         properties[PROP_HTTP_VERSION] =
721 		g_param_spec_enum ("http-version",
722 				   "HTTP Version",
723 				   "The HTTP protocol version to use",
724 				   SOUP_TYPE_HTTP_VERSION,
725 				   SOUP_HTTP_1_1,
726 				   G_PARAM_READABLE |
727 				   G_PARAM_STATIC_STRINGS);
728         properties[PROP_FLAGS] =
729 		g_param_spec_flags ("flags",
730 				    "Flags",
731 				    "Various message options",
732 				    SOUP_TYPE_MESSAGE_FLAGS,
733 				    0,
734 				    G_PARAM_READWRITE |
735 				    G_PARAM_STATIC_STRINGS);
736         properties[PROP_STATUS_CODE] =
737 		g_param_spec_uint ("status-code",
738 				   "Status code",
739 				   "The HTTP response status code",
740 				   0, 999, 0,
741 				   G_PARAM_READABLE |
742 				   G_PARAM_STATIC_STRINGS);
743         properties[PROP_REASON_PHRASE] =
744 		g_param_spec_string ("reason-phrase",
745 				     "Reason phrase",
746 				     "The HTTP response reason phrase",
747 				     NULL,
748 				     G_PARAM_READABLE |
749 				     G_PARAM_STATIC_STRINGS);
750 	/**
751 	 * SoupMessage:first-party:
752 	 *
753 	 * The #GUri loaded in the application when the message was
754 	 * queued.
755 	 *
756 	 */
757         properties[PROP_FIRST_PARTY] =
758 		g_param_spec_boxed ("first-party",
759 				    "First party",
760 				    "The URI loaded in the application when the message was requested.",
761 				    G_TYPE_URI,
762 				    G_PARAM_READWRITE |
763 				    G_PARAM_STATIC_STRINGS);
764 	/**
765 	 * SoupMessage:site-for-cookkies:
766 	 *
767 	 * Site used to compare cookies against. Used for SameSite cookie support.
768 	 *
769 	 */
770         properties[PROP_SITE_FOR_COOKIES] =
771 		g_param_spec_boxed ("site-for-cookies",
772 				    "Site for cookies",
773 				    "The URI for the site to compare cookies against",
774 				    G_TYPE_URI,
775 				    G_PARAM_READWRITE);
776 	/**
777 	 * SoupMessage:is-top-level-navigation:
778 	 *
779 	 * Set when the message is navigating between top level domains.
780 	 *
781 	 */
782         properties[PROP_IS_TOP_LEVEL_NAVIGATION] =
783 		g_param_spec_boolean ("is-top-level-navigation",
784 				     "Is top-level navigation",
785 				     "If the current messsage is navigating between top-levels",
786 				     FALSE,
787 				     G_PARAM_READWRITE);
788         properties[PROP_REQUEST_HEADERS] =
789 		g_param_spec_boxed ("request-headers",
790 				    "Request Headers",
791 				    "The HTTP request headers",
792 				    SOUP_TYPE_MESSAGE_HEADERS,
793 				    G_PARAM_READABLE |
794 				    G_PARAM_STATIC_STRINGS);
795         properties[PROP_RESPONSE_HEADERS] =
796 		g_param_spec_boxed ("response-headers",
797 				    "Response Headers",
798 				     "The HTTP response headers",
799 				    SOUP_TYPE_MESSAGE_HEADERS,
800 				    G_PARAM_READABLE |
801 				    G_PARAM_STATIC_STRINGS);
802 	/**
803 	 * SoupMessage:tls-peer-certificate:
804 	 *
805 	 * The peer's #GTlsCertificate associated with the message
806 	 *
807 	 */
808         properties[PROP_TLS_PEER_CERTIFICATE] =
809 		g_param_spec_object ("tls-peer-certificate",
810 				     "TLS Peer Certificate",
811 				     "The TLS peer certificate associated with the message",
812 				     G_TYPE_TLS_CERTIFICATE,
813 				     G_PARAM_READABLE |
814 				     G_PARAM_STATIC_STRINGS);
815 	/**
816 	 * SoupMessage:tls-peer-certificate-errors:
817 	 *
818 	 * The verification errors on #SoupMessage:tls-peer-certificate
819 	 *
820 	 */
821         properties[PROP_TLS_PEER_CERTIFICATE_ERRORS] =
822 		g_param_spec_flags ("tls-peer-certificate-errors",
823 				    "TLS Peer Certificate Errors",
824 				    "The verification errors on the message's TLS peer certificate",
825 				    G_TYPE_TLS_CERTIFICATE_FLAGS, 0,
826 				    G_PARAM_READABLE |
827 				    G_PARAM_STATIC_STRINGS);
828         /**
829          * SoupMessage:tls-protocol-version:
830          *
831          * The TLS protocol version negotiated for the message connection.
832          */
833         properties[PROP_TLS_PROTOCOL_VERSION] =
834 	        g_param_spec_enum ("tls-protocol-version",
835                                    "TLS Protocol Version",
836                                    "TLS protocol version negotiated for this connection",
837                                    G_TYPE_TLS_PROTOCOL_VERSION,
838                                    G_TLS_PROTOCOL_VERSION_UNKNOWN,
839                                    G_PARAM_READABLE |
840                                    G_PARAM_STATIC_STRINGS);
841 
842         /**
843          * SoupMessage:tls-ciphersuite-name:
844          *
845          * The Name of TLS ciphersuite negotiated for this message connection.
846          */
847         properties[PROP_TLS_CIPHERSUITE_NAME] =
848                 g_param_spec_string ("tls-ciphersuite-name",
849                                      "TLS Ciphersuite Name",
850                                      "Name of TLS ciphersuite negotiated for this connection",
851                                      NULL,
852                                      G_PARAM_READABLE |
853                                      G_PARAM_STATIC_STRINGS);
854 
855         /**
856          * SoupMessage:remote-address:
857          *
858          * The remote #GSocketAddress of the connection associated with the message
859          *
860          */
861         properties[PROP_REMOTE_ADDRESS] =
862                 g_param_spec_object ("remote-address",
863                                      "Remote Address",
864                                      "The remote address of the connection associated with the message",
865                                      G_TYPE_SOCKET_ADDRESS,
866                                      G_PARAM_READABLE |
867                                      G_PARAM_STATIC_STRINGS);
868 	/**
869 	 SoupMessage:priority:
870 	 *
871 	 * Sets the priority of the #SoupMessage. See
872 	 * soup_message_set_priority() for further details.
873 	 *
874 	 **/
875         properties[PROP_PRIORITY] =
876 		g_param_spec_enum ("priority",
877 				   "Priority",
878 				   "The priority of the message",
879 				   SOUP_TYPE_MESSAGE_PRIORITY,
880 				   SOUP_MESSAGE_PRIORITY_NORMAL,
881 				   G_PARAM_READWRITE |
882 				   G_PARAM_STATIC_STRINGS);
883 
884 	/**
885 	 * SoupMessage:is-options-ping:
886 	 *
887 	 * The #SoupMessage is intended to be used to send
888          * `OPTIONS *` to a server. When set to %TRUE, the
889          * path of #SoupMessage:uri will be ignored and
890          * #SoupMessage:method set to %SOUP_METHOD_OPTIONS.
891 	 */
892         properties[PROP_IS_OPTIONS_PING] =
893 		g_param_spec_boolean ("is-options-ping",
894 				      "Is Options Ping",
895 				      "The message is an OPTIONS ping",
896                                       FALSE,
897 				      G_PARAM_READWRITE |
898 				      G_PARAM_STATIC_STRINGS);
899 
900         g_object_class_install_properties (object_class, LAST_PROPERTY, properties);
901 }
902 
903 
904 /**
905  * soup_message_new:
906  * @method: the HTTP method for the created request
907  * @uri_string: the destination endpoint (as a string)
908  *
909  * Creates a new empty #SoupMessage, which will connect to @uri
910  *
911  * Returns: (transfer full) (nullable): the new #SoupMessage (or %NULL if @uri
912  * could not be parsed).
913  */
914 SoupMessage *
soup_message_new(const char * method,const char * uri_string)915 soup_message_new (const char *method, const char *uri_string)
916 {
917 	SoupMessage *msg;
918 	GUri *uri;
919 
920 	g_return_val_if_fail (method != NULL, NULL);
921 	g_return_val_if_fail (uri_string != NULL, NULL);
922 
923 	uri = g_uri_parse (uri_string, SOUP_HTTP_URI_FLAGS, NULL);
924 	if (!uri)
925 		return NULL;
926 	if (!g_uri_get_host (uri)) {
927 		g_uri_unref (uri);
928 		return NULL;
929 	}
930 
931 	msg = soup_message_new_from_uri (method, uri);
932 	g_uri_unref (uri);
933 	return msg;
934 }
935 
936 /**
937  * soup_message_new_from_uri:
938  * @method: the HTTP method for the created request
939  * @uri: the destination endpoint (as a #GUri)
940  *
941  * Creates a new empty #SoupMessage, which will connect to @uri
942  *
943  * Returns: (transfer full): the new #SoupMessage
944  */
945 SoupMessage *
soup_message_new_from_uri(const char * method,GUri * uri)946 soup_message_new_from_uri (const char *method, GUri *uri)
947 {
948         g_return_val_if_fail (method != NULL, NULL);
949         g_return_val_if_fail (SOUP_URI_IS_VALID (uri), NULL);
950 
951 	return g_object_new (SOUP_TYPE_MESSAGE,
952 			     "method", method,
953 			     "uri", uri,
954 			     NULL);
955 }
956 
957 /**
958  * soup_message_new_options_ping:
959  * @base_uri: the destination endpoint (as a #GUri)
960  *
961  * Creates a new #SoupMessage to send `OPTIONS *` to a server. The path of @base_uri
962  * will be ignored.
963  *
964  * Returns: (transfer full): the new #SoupMessage
965  */
966 SoupMessage *
soup_message_new_options_ping(GUri * base_uri)967 soup_message_new_options_ping (GUri *base_uri)
968 {
969         g_return_val_if_fail (SOUP_URI_IS_VALID (base_uri), NULL);
970 
971         return g_object_new (SOUP_TYPE_MESSAGE,
972                              "method", SOUP_METHOD_OPTIONS,
973                              "uri", base_uri,
974                              "is-options-ping", TRUE,
975                              NULL);
976 }
977 
978 /**
979  * soup_message_new_from_encoded_form:
980  * @method: the HTTP method for the created request (GET, POST or PUT)
981  * @uri_string: the destination endpoint (as a string)
982  * @encoded_form: (transfer full): a encoded form
983  *
984  * Creates a new #SoupMessage and sets it up to send the given @encoded_form
985  * to @uri via @method. If @method is "GET", it will include the form data
986  * into @uri's query field, and if @method is "POST" or "PUT", it will be set as
987  * request body.
988  * This function takes the ownership of @encoded_form, that will be released
989  * with g_free() when no longer in use. See also soup_form_encode(),
990  * soup_form_encode_hash() and soup_form_encode_datalist().
991  *
992  * Returns: (transfer full) (nullable): the new #SoupMessage, or %NULL if @uri_string
993  *     could not be parsed or @method is not "GET, "POST" or "PUT"
994  */
995 SoupMessage *
soup_message_new_from_encoded_form(const char * method,const char * uri_string,char * encoded_form)996 soup_message_new_from_encoded_form (const char *method,
997                                     const char *uri_string,
998                                     char       *encoded_form)
999 {
1000         SoupMessage *msg = NULL;
1001         GUri *uri;
1002 
1003         g_return_val_if_fail (method != NULL, NULL);
1004         g_return_val_if_fail (uri_string != NULL, NULL);
1005         g_return_val_if_fail (encoded_form != NULL, NULL);
1006 
1007         uri = g_uri_parse (uri_string, SOUP_HTTP_URI_FLAGS, NULL);
1008         if (!uri || !g_uri_get_host (uri)) {
1009                 g_free (encoded_form);
1010                 g_clear_pointer (&uri, g_uri_unref);
1011                 return NULL;
1012         }
1013 
1014         if (strcmp (method, "GET") == 0) {
1015                 GUri *new_uri = soup_uri_copy (uri, SOUP_URI_QUERY, encoded_form, SOUP_URI_NONE);
1016                 msg = soup_message_new_from_uri (method, new_uri);
1017                 g_uri_unref (new_uri);
1018         } else if (strcmp (method, "POST") == 0 || strcmp (method, "PUT") == 0) {
1019                 GBytes *body;
1020 
1021                 msg = soup_message_new_from_uri (method, uri);
1022                 body = g_bytes_new_take (encoded_form, strlen (encoded_form));
1023                 soup_message_set_request_body_from_bytes (msg, SOUP_FORM_MIME_TYPE_URLENCODED, body);
1024                 g_bytes_unref (body);
1025         } else {
1026                 g_free (encoded_form);
1027         }
1028 
1029         g_uri_unref (uri);
1030 
1031         return msg;
1032 }
1033 
1034 /**
1035  * soup_message_new_from_multipart:
1036  * @uri_string: the destination endpoint (as a string)
1037  * @multipart: a #SoupMultipart
1038  *
1039  * Creates a new #SoupMessage and sets it up to send @multipart to
1040  * @uri_string via POST.
1041  *
1042  * Returns: (transfer full) (nullable): the new #SoupMessage, or %NULL if @uri_string
1043  *     could not be parsed
1044  */
1045 SoupMessage *
soup_message_new_from_multipart(const char * uri_string,SoupMultipart * multipart)1046 soup_message_new_from_multipart (const char    *uri_string,
1047                                  SoupMultipart *multipart)
1048 {
1049         SoupMessage *msg = NULL;
1050         GUri *uri;
1051         GBytes *body = NULL;
1052 
1053         g_return_val_if_fail (uri_string != NULL, NULL);
1054         g_return_val_if_fail (multipart != NULL, NULL);
1055 
1056         uri = g_uri_parse (uri_string, SOUP_HTTP_URI_FLAGS, NULL);
1057         if (!uri || !g_uri_get_host (uri)) {
1058                 g_clear_pointer (&uri, g_uri_unref);
1059                 return NULL;
1060         }
1061 
1062         msg = soup_message_new_from_uri ("POST", uri);
1063         soup_multipart_to_message (multipart, soup_message_get_request_headers (msg), &body);
1064         soup_message_set_request_body_from_bytes (msg,
1065                                                   soup_message_headers_get_content_type (soup_message_get_request_headers (msg), NULL),
1066                                                   body);
1067         g_bytes_unref (body);
1068         g_uri_unref (uri);
1069 
1070         return msg;
1071 }
1072 
1073 /**
1074  * soup_message_set_request_body:
1075  * @msg: the message
1076  * @content_type: (nullable): MIME Content-Type of the body, or %NULL if unknown
1077  * @stream: (nullable): a #GInputStream to read the request body from
1078  * @content_length: the byte length of @stream or -1 if unknown
1079  *
1080  * Set the request body of a #SoupMessage.
1081  * If @content_type is %NULL and @stream is not %NULL the Content-Type header will
1082  * not be changed if present.
1083  * The request body needs to be set again in case @msg is restarted
1084  * (in case of redirection or authentication).
1085  */
1086 void
soup_message_set_request_body(SoupMessage * msg,const char * content_type,GInputStream * stream,gssize content_length)1087 soup_message_set_request_body (SoupMessage  *msg,
1088                                const char   *content_type,
1089                                GInputStream *stream,
1090                                gssize        content_length)
1091 {
1092         g_return_if_fail (SOUP_IS_MESSAGE (msg));
1093         g_return_if_fail (stream == NULL || G_IS_INPUT_STREAM (stream));
1094         g_return_if_fail (content_length == -1 || content_length >= 0);
1095 
1096         SoupMessagePrivate *priv = soup_message_get_instance_private (msg);
1097 
1098         g_clear_object (&priv->request_body_stream);
1099 
1100         if (stream) {
1101                 if (content_type) {
1102                         g_warn_if_fail (strchr (content_type, '/') != NULL);
1103 
1104                         if (soup_message_headers_get_content_type (priv->request_headers, NULL) != content_type)
1105                                 soup_message_headers_replace_common (priv->request_headers, SOUP_HEADER_CONTENT_TYPE, content_type);
1106                 }
1107 
1108                 if (content_length == -1)
1109                         soup_message_headers_set_encoding (priv->request_headers, SOUP_ENCODING_CHUNKED);
1110                 else
1111                         soup_message_headers_set_content_length (priv->request_headers, content_length);
1112 
1113                 priv->request_body_stream = g_object_ref (stream);
1114         } else {
1115                 soup_message_headers_remove_common (priv->request_headers, SOUP_HEADER_CONTENT_TYPE);
1116                 soup_message_headers_remove_common (priv->request_headers, SOUP_HEADER_CONTENT_LENGTH);
1117         }
1118 }
1119 
1120 /**
1121  * soup_message_set_request_body_from_bytes:
1122  * @msg: the message
1123  * @content_type: (nullable): MIME Content-Type of the body, or %NULL if unknown
1124  * @bytes: (nullable): a #GBytes with the request body data
1125  *
1126  * Set the request body of a #SoupMessage from #GBytes.
1127  * If @content_type is %NULL and @bytes is not %NULL the Content-Type header will
1128  * not be changed if present.
1129  * The request body needs to be set again in case @msg is restarted
1130  * (in case of redirection or authentication).
1131  */
1132 void
soup_message_set_request_body_from_bytes(SoupMessage * msg,const char * content_type,GBytes * bytes)1133 soup_message_set_request_body_from_bytes (SoupMessage  *msg,
1134                                           const char   *content_type,
1135                                           GBytes       *bytes)
1136 {
1137         g_return_if_fail (SOUP_IS_MESSAGE (msg));
1138 
1139         if (bytes) {
1140                 GInputStream *stream;
1141 
1142                 stream = g_memory_input_stream_new_from_bytes (bytes);
1143                 soup_message_set_request_body (msg, content_type, stream, g_bytes_get_size (bytes));
1144                 g_object_unref (stream);
1145         } else
1146                 soup_message_set_request_body (msg, NULL, NULL, 0);
1147 }
1148 
1149 void
soup_message_wrote_headers(SoupMessage * msg)1150 soup_message_wrote_headers (SoupMessage *msg)
1151 {
1152 	g_signal_emit (msg, signals[WROTE_HEADERS], 0);
1153 }
1154 
1155 void
soup_message_wrote_body_data(SoupMessage * msg,gsize chunk_size)1156 soup_message_wrote_body_data (SoupMessage *msg,
1157 			      gsize        chunk_size)
1158 {
1159 	g_signal_emit (msg, signals[WROTE_BODY_DATA], 0, chunk_size);
1160 }
1161 
1162 void
soup_message_wrote_body(SoupMessage * msg)1163 soup_message_wrote_body (SoupMessage *msg)
1164 {
1165 	g_signal_emit (msg, signals[WROTE_BODY], 0);
1166 }
1167 
1168 void
soup_message_got_informational(SoupMessage * msg)1169 soup_message_got_informational (SoupMessage *msg)
1170 {
1171 	g_signal_emit (msg, signals[GOT_INFORMATIONAL], 0);
1172 }
1173 
1174 void
soup_message_got_headers(SoupMessage * msg)1175 soup_message_got_headers (SoupMessage *msg)
1176 {
1177 	g_signal_emit (msg, signals[GOT_HEADERS], 0);
1178 }
1179 
1180 void
soup_message_got_body(SoupMessage * msg)1181 soup_message_got_body (SoupMessage *msg)
1182 {
1183 	g_signal_emit (msg, signals[GOT_BODY], 0);
1184 }
1185 
1186 void
soup_message_content_sniffed(SoupMessage * msg,const char * content_type,GHashTable * params)1187 soup_message_content_sniffed (SoupMessage *msg, const char *content_type, GHashTable *params)
1188 {
1189 	g_signal_emit (msg, signals[CONTENT_SNIFFED], 0, content_type, params);
1190 }
1191 
1192 void
soup_message_starting(SoupMessage * msg)1193 soup_message_starting (SoupMessage *msg)
1194 {
1195 	g_signal_emit (msg, signals[STARTING], 0);
1196 }
1197 
1198 void
soup_message_restarted(SoupMessage * msg)1199 soup_message_restarted (SoupMessage *msg)
1200 {
1201         SoupMessagePrivate *priv = soup_message_get_instance_private (msg);
1202 
1203 	g_clear_object (&priv->request_body_stream);
1204 
1205 	g_signal_emit (msg, signals[RESTARTED], 0);
1206 }
1207 
1208 void
soup_message_finished(SoupMessage * msg)1209 soup_message_finished (SoupMessage *msg)
1210 {
1211 	g_signal_emit (msg, signals[FINISHED], 0);
1212 }
1213 
1214 gboolean
soup_message_authenticate(SoupMessage * msg,SoupAuth * auth,gboolean retrying)1215 soup_message_authenticate (SoupMessage *msg,
1216 			   SoupAuth    *auth,
1217 			   gboolean     retrying)
1218 {
1219 	gboolean handled;
1220 	g_signal_emit (msg, signals[AUTHENTICATE], 0,
1221 		       auth, retrying, &handled);
1222 	return handled;
1223 }
1224 
1225 void
soup_message_hsts_enforced(SoupMessage * msg)1226 soup_message_hsts_enforced (SoupMessage *msg)
1227 {
1228 	g_signal_emit (msg, signals[HSTS_ENFORCED], 0);
1229 }
1230 
1231 static void
header_handler_free(gpointer header_name,GClosure * closure)1232 header_handler_free (gpointer header_name, GClosure *closure)
1233 {
1234 	g_free (header_name);
1235 }
1236 
1237 static void
header_handler_metamarshal(GClosure * closure,GValue * return_value,guint n_param_values,const GValue * param_values,gpointer invocation_hint,gpointer marshal_data)1238 header_handler_metamarshal (GClosure *closure, GValue *return_value,
1239 			    guint n_param_values, const GValue *param_values,
1240 			    gpointer invocation_hint, gpointer marshal_data)
1241 {
1242 	SoupMessage *msg = g_value_get_object (&param_values[0]);
1243         SoupMessagePrivate *priv = soup_message_get_instance_private (msg);
1244 	const char *header_name = marshal_data;
1245 
1246 	if (soup_message_headers_get_one (priv->response_headers, header_name)) {
1247 		closure->marshal (closure, return_value, n_param_values,
1248 				  param_values, invocation_hint,
1249 				  ((GCClosure *)closure)->callback);
1250 	}
1251 }
1252 
1253 /**
1254  * soup_message_add_header_handler: (skip)
1255  * @msg: a #SoupMessage
1256  * @signal: signal to connect the handler to.
1257  * @header: HTTP response header to match against
1258  * @callback: the header handler
1259  * @user_data: data to pass to @handler_cb
1260  *
1261  * Adds a signal handler to @msg for @signal, as with
1262  * g_signal_connect(), but the @callback will only be run if @msg's
1263  * incoming messages headers (that is, the <literal>request_headers</literal>)
1264  * contain a header named @header.
1265  *
1266  * Returns: the handler ID from g_signal_connect()
1267  **/
1268 guint
soup_message_add_header_handler(SoupMessage * msg,const char * signal,const char * header,GCallback callback,gpointer user_data)1269 soup_message_add_header_handler (SoupMessage *msg,
1270 				 const char  *signal,
1271 				 const char  *header,
1272 				 GCallback    callback,
1273 				 gpointer     user_data)
1274 {
1275 	GClosure *closure;
1276 	char *header_name;
1277 
1278 	g_return_val_if_fail (SOUP_IS_MESSAGE (msg), 0);
1279 	g_return_val_if_fail (signal != NULL, 0);
1280 	g_return_val_if_fail (header != NULL, 0);
1281 	g_return_val_if_fail (callback != NULL, 0);
1282 
1283 	closure = g_cclosure_new (callback, user_data, NULL);
1284 
1285 	header_name = g_strdup (header);
1286 	g_closure_set_meta_marshal (closure, header_name,
1287 				    header_handler_metamarshal);
1288 	g_closure_add_finalize_notifier (closure, header_name,
1289 					 header_handler_free);
1290 
1291 	return g_signal_connect_closure (msg, signal, closure, FALSE);
1292 }
1293 
1294 static void
status_handler_metamarshal(GClosure * closure,GValue * return_value,guint n_param_values,const GValue * param_values,gpointer invocation_hint,gpointer marshal_data)1295 status_handler_metamarshal (GClosure *closure, GValue *return_value,
1296 			    guint n_param_values, const GValue *param_values,
1297 			    gpointer invocation_hint, gpointer marshal_data)
1298 {
1299 	SoupMessage *msg = g_value_get_object (&param_values[0]);
1300         SoupMessagePrivate *priv = soup_message_get_instance_private (msg);
1301 	guint status = GPOINTER_TO_UINT (marshal_data);
1302 
1303 	if (priv->status_code == status) {
1304 		closure->marshal (closure, return_value, n_param_values,
1305 				  param_values, invocation_hint,
1306 				  ((GCClosure *)closure)->callback);
1307 	}
1308 }
1309 
1310 /**
1311  * soup_message_add_status_code_handler: (skip)
1312  * @msg: a #SoupMessage
1313  * @signal: signal to connect the handler to.
1314  * @status_code: status code to match against
1315  * @callback: the header handler
1316  * @user_data: data to pass to @handler_cb
1317  *
1318  * Adds a signal handler to @msg for @signal, as with
1319  * g_signal_connect(), but the @callback will only be run if @msg has
1320  * the status @status_code.
1321  *
1322  * @signal must be a signal that will be emitted after @msg's status
1323  * is set (this means it can't be a "wrote" signal).
1324  *
1325  * Returns: the handler ID from g_signal_connect()
1326  **/
1327 guint
soup_message_add_status_code_handler(SoupMessage * msg,const char * signal,guint status_code,GCallback callback,gpointer user_data)1328 soup_message_add_status_code_handler (SoupMessage *msg,
1329 				      const char  *signal,
1330 				      guint        status_code,
1331 				      GCallback    callback,
1332 				      gpointer     user_data)
1333 {
1334 	GClosure *closure;
1335 
1336 	g_return_val_if_fail (SOUP_IS_MESSAGE (msg), 0);
1337 	g_return_val_if_fail (signal != NULL, 0);
1338 	g_return_val_if_fail (callback != NULL, 0);
1339 
1340 	closure = g_cclosure_new (callback, user_data, NULL);
1341 	g_closure_set_meta_marshal (closure, GUINT_TO_POINTER (status_code),
1342 				    status_handler_metamarshal);
1343 
1344 	return g_signal_connect_closure (msg, signal, closure, FALSE);
1345 }
1346 
1347 void
soup_message_set_auth(SoupMessage * msg,SoupAuth * auth)1348 soup_message_set_auth (SoupMessage *msg, SoupAuth *auth)
1349 {
1350 	SoupMessagePrivate *priv;
1351 
1352 	g_return_if_fail (SOUP_IS_MESSAGE (msg));
1353 	g_return_if_fail (auth == NULL || SOUP_IS_AUTH (auth));
1354 
1355 	priv = soup_message_get_instance_private (msg);
1356 
1357 	if (priv->auth == auth)
1358 		return;
1359 
1360 	if (priv->auth)
1361 		g_object_unref (priv->auth);
1362 	priv->auth = auth ? g_object_ref (auth) : NULL;
1363 }
1364 
1365 SoupAuth *
soup_message_get_auth(SoupMessage * msg)1366 soup_message_get_auth (SoupMessage *msg)
1367 {
1368 	SoupMessagePrivate *priv;
1369 
1370 	g_return_val_if_fail (SOUP_IS_MESSAGE (msg), NULL);
1371 
1372 	priv = soup_message_get_instance_private (msg);
1373 
1374 	return priv->auth;
1375 }
1376 
1377 void
soup_message_set_proxy_auth(SoupMessage * msg,SoupAuth * auth)1378 soup_message_set_proxy_auth (SoupMessage *msg, SoupAuth *auth)
1379 {
1380 	SoupMessagePrivate *priv;
1381 
1382 	g_return_if_fail (SOUP_IS_MESSAGE (msg));
1383 	g_return_if_fail (auth == NULL || SOUP_IS_AUTH (auth));
1384 
1385 	priv = soup_message_get_instance_private (msg);
1386 
1387 	if (priv->proxy_auth == auth)
1388 		return;
1389 
1390 	if (priv->proxy_auth)
1391 		g_object_unref (priv->proxy_auth);
1392 	priv->proxy_auth = auth ? g_object_ref (auth) : NULL;
1393 }
1394 
1395 SoupAuth *
soup_message_get_proxy_auth(SoupMessage * msg)1396 soup_message_get_proxy_auth (SoupMessage *msg)
1397 {
1398 	SoupMessagePrivate *priv;
1399 
1400 	g_return_val_if_fail (SOUP_IS_MESSAGE (msg), NULL);
1401 
1402 	priv = soup_message_get_instance_private (msg);
1403 
1404 	return priv->proxy_auth;
1405 }
1406 
1407 GUri *
soup_message_get_uri_for_auth(SoupMessage * msg)1408 soup_message_get_uri_for_auth (SoupMessage *msg)
1409 {
1410 	SoupMessagePrivate *priv = soup_message_get_instance_private (msg);
1411 
1412 	if (priv->status_code == SOUP_STATUS_PROXY_UNAUTHORIZED) {
1413 		/* When loaded from the disk cache, the connection is NULL. */
1414                 return priv->connection ? soup_connection_get_proxy_uri (priv->connection) : NULL;
1415 	}
1416 
1417 	return priv->uri;
1418 }
1419 
1420 static void
soup_message_set_tls_peer_certificate(SoupMessage * msg,GTlsCertificate * tls_certificate,GTlsCertificateFlags tls_errors)1421 soup_message_set_tls_peer_certificate (SoupMessage         *msg,
1422                                        GTlsCertificate     *tls_certificate,
1423                                        GTlsCertificateFlags tls_errors)
1424 {
1425         SoupMessagePrivate *priv = soup_message_get_instance_private (msg);
1426 
1427         if (priv->tls_peer_certificate == tls_certificate && priv->tls_peer_certificate_errors == tls_errors)
1428                 return;
1429 
1430         g_clear_object (&priv->tls_peer_certificate);
1431         priv->tls_peer_certificate = tls_certificate ? g_object_ref (tls_certificate) : NULL;
1432         priv->tls_peer_certificate_errors = tls_errors;
1433         g_object_notify_by_pspec (G_OBJECT (msg), properties[PROP_TLS_PEER_CERTIFICATE]);
1434         g_object_notify_by_pspec (G_OBJECT (msg), properties[PROP_TLS_PEER_CERTIFICATE_ERRORS]);
1435 }
1436 
1437 static void
soup_message_set_tls_protocol_version(SoupMessage * msg,GTlsProtocolVersion version)1438 soup_message_set_tls_protocol_version (SoupMessage        *msg,
1439                                        GTlsProtocolVersion version)
1440 {
1441         SoupMessagePrivate *priv = soup_message_get_instance_private (msg);
1442 
1443         if (priv->tls_protocol_version == version)
1444                 return;
1445 
1446         priv->tls_protocol_version = version;
1447         g_object_notify_by_pspec (G_OBJECT (msg), properties[PROP_TLS_PROTOCOL_VERSION]);
1448 }
1449 
1450 static void
soup_message_set_tls_ciphersuite_name(SoupMessage * msg,char * name)1451 soup_message_set_tls_ciphersuite_name (SoupMessage *msg,
1452                                        char        *name)
1453 {
1454         SoupMessagePrivate *priv = soup_message_get_instance_private (msg);
1455 
1456         if (g_strcmp0 (priv->tls_ciphersuite_name, name) == 0) {
1457                 g_free (name);
1458                 return;
1459         }
1460 
1461         g_clear_pointer (&priv->tls_ciphersuite_name, g_free);
1462         priv->tls_ciphersuite_name = name;
1463         g_object_notify_by_pspec (G_OBJECT (msg), properties[PROP_TLS_CIPHERSUITE_NAME]);
1464 }
1465 
1466 static void
soup_message_set_remote_address(SoupMessage * msg,GSocketAddress * address)1467 soup_message_set_remote_address (SoupMessage    *msg,
1468                                  GSocketAddress *address)
1469 {
1470         SoupMessagePrivate *priv = soup_message_get_instance_private (msg);
1471 
1472         if (priv->remote_address == address)
1473                 return;
1474 
1475         g_clear_object (&priv->remote_address);
1476         priv->remote_address = address ? g_object_ref (address) : NULL;
1477         g_object_notify_by_pspec (G_OBJECT (msg), properties[PROP_REMOTE_ADDRESS]);
1478 }
1479 
1480 SoupConnection *
soup_message_get_connection(SoupMessage * msg)1481 soup_message_get_connection (SoupMessage *msg)
1482 {
1483 	SoupMessagePrivate *priv = soup_message_get_instance_private (msg);
1484 
1485 	return priv->connection;
1486 }
1487 
1488 static void
soup_message_set_metrics_timestamp_for_network_event(SoupMessage * msg,GSocketClientEvent event)1489 soup_message_set_metrics_timestamp_for_network_event (SoupMessage       *msg,
1490                                                       GSocketClientEvent event)
1491 {
1492         switch (event) {
1493         case G_SOCKET_CLIENT_RESOLVING:
1494                 soup_message_set_metrics_timestamp (msg, SOUP_MESSAGE_METRICS_DNS_START);
1495                 break;
1496         case G_SOCKET_CLIENT_RESOLVED:
1497                 soup_message_set_metrics_timestamp (msg, SOUP_MESSAGE_METRICS_DNS_END);
1498                 break;
1499         case G_SOCKET_CLIENT_CONNECTING:
1500                 soup_message_set_metrics_timestamp (msg, SOUP_MESSAGE_METRICS_CONNECT_START);
1501                 break;
1502         case G_SOCKET_CLIENT_CONNECTED:
1503                 /* connect_end happens after proxy and tls */
1504         case G_SOCKET_CLIENT_PROXY_NEGOTIATING:
1505         case G_SOCKET_CLIENT_PROXY_NEGOTIATED:
1506                 break;
1507         case G_SOCKET_CLIENT_TLS_HANDSHAKING:
1508                 soup_message_set_metrics_timestamp (msg, SOUP_MESSAGE_METRICS_TLS_START);
1509                 break;
1510         case G_SOCKET_CLIENT_TLS_HANDSHAKED:
1511                 break;
1512         case G_SOCKET_CLIENT_COMPLETE:
1513                 soup_message_set_metrics_timestamp (msg, SOUP_MESSAGE_METRICS_CONNECT_END);
1514                 break;
1515         }
1516 }
1517 
1518 static void
re_emit_connection_event(SoupMessage * msg,GSocketClientEvent event,GIOStream * connection)1519 re_emit_connection_event (SoupMessage       *msg,
1520                           GSocketClientEvent event,
1521                           GIOStream         *connection)
1522 {
1523         soup_message_set_metrics_timestamp_for_network_event (msg, event);
1524 
1525 	g_signal_emit (msg, signals[NETWORK_EVENT], 0,
1526 		       event, connection);
1527 }
1528 
1529 static gboolean
re_emit_accept_certificate(SoupMessage * msg,GTlsCertificate * tls_certificate,GTlsCertificateFlags * tls_errors)1530 re_emit_accept_certificate (SoupMessage          *msg,
1531 			    GTlsCertificate      *tls_certificate,
1532 			    GTlsCertificateFlags *tls_errors)
1533 {
1534 	gboolean accept = FALSE;
1535 
1536 	g_signal_emit (msg, signals[ACCEPT_CERTIFICATE], 0,
1537 		       tls_certificate, tls_errors, &accept);
1538 	return accept;
1539 }
1540 
1541 static gboolean
re_emit_request_certificate(SoupMessage * msg,GTlsClientConnection * tls_conn,GTask * task)1542 re_emit_request_certificate (SoupMessage          *msg,
1543                              GTlsClientConnection *tls_conn,
1544                              GTask                *task)
1545 {
1546         SoupMessagePrivate *priv = soup_message_get_instance_private (msg);
1547         gboolean handled = FALSE;
1548 
1549         priv->pending_tls_cert_request = g_object_ref (task);
1550 
1551         /* Skip interaction for preconnect requests, keep the operation
1552          * pending that will be handled by the new message once the
1553          * connection is transferred.
1554          */
1555         if (priv->is_preconnect) {
1556                 priv->pending_tls_cert_conn = g_object_ref (tls_conn);
1557                 return TRUE;
1558         }
1559 
1560         g_signal_emit (msg, signals[REQUEST_CERTIFICATE], 0, tls_conn, &handled);
1561         if (!handled)
1562                 g_clear_object (&priv->pending_tls_cert_request);
1563 
1564         return handled;
1565 }
1566 
1567 static gboolean
re_emit_request_certificate_password(SoupMessage * msg,GTlsPassword * password,GTask * task)1568 re_emit_request_certificate_password (SoupMessage  *msg,
1569                                       GTlsPassword *password,
1570                                       GTask        *task)
1571 {
1572         SoupMessagePrivate *priv = soup_message_get_instance_private (msg);
1573         gboolean handled = FALSE;
1574 
1575         priv->pending_tls_cert_pass_request = g_object_ref (task);
1576 
1577         /* Skip interaction for preconnect requests, keep the operation
1578          * pending that will be handled by the new message once the
1579          * connection is transferred.
1580          */
1581         if (priv->is_preconnect) {
1582                 priv->pending_tls_cert_password = g_object_ref (password);
1583                 return TRUE;
1584         }
1585 
1586         g_signal_emit (msg, signals[REQUEST_CERTIFICATE_PASSWORD], 0, password, &handled);
1587         if (!handled)
1588                 g_clear_object (&priv->pending_tls_cert_pass_request);
1589 
1590         return handled;
1591 }
1592 
1593 static void
re_emit_tls_certificate_changed(SoupMessage * msg,GParamSpec * pspec,SoupConnection * conn)1594 re_emit_tls_certificate_changed (SoupMessage    *msg,
1595 				 GParamSpec     *pspec,
1596 				 SoupConnection *conn)
1597 {
1598         soup_message_set_tls_peer_certificate (msg,
1599                                                soup_connection_get_tls_certificate (conn),
1600                                                soup_connection_get_tls_certificate_errors (conn));
1601 }
1602 
1603 static void
connection_tls_protocol_version_changed(SoupMessage * msg,GParamSpec * pspec,SoupConnection * conn)1604 connection_tls_protocol_version_changed (SoupMessage    *msg,
1605                                          GParamSpec     *pspec,
1606                                          SoupConnection *conn)
1607 {
1608         soup_message_set_tls_protocol_version (msg, soup_connection_get_tls_protocol_version (conn));
1609 }
1610 
1611 static void
connection_tls_ciphersuite_name_changed(SoupMessage * msg,GParamSpec * pspec,SoupConnection * conn)1612 connection_tls_ciphersuite_name_changed (SoupMessage    *msg,
1613                                          GParamSpec     *pspec,
1614                                          SoupConnection *conn)
1615 {
1616         soup_message_set_tls_ciphersuite_name (msg, soup_connection_get_tls_ciphersuite_name (conn));
1617 }
1618 
1619 static void
connection_remote_address_changed(SoupMessage * msg,GParamSpec * pspec,SoupConnection * conn)1620 connection_remote_address_changed (SoupMessage    *msg,
1621                                    GParamSpec     *pspec,
1622                                    SoupConnection *conn)
1623 {
1624         soup_message_set_remote_address (msg, soup_connection_get_remote_address (conn));
1625 }
1626 
1627 void
soup_message_set_connection(SoupMessage * msg,SoupConnection * conn)1628 soup_message_set_connection (SoupMessage    *msg,
1629 			     SoupConnection *conn)
1630 {
1631 	SoupMessagePrivate *priv = soup_message_get_instance_private (msg);
1632 
1633         if (priv->connection == conn)
1634                 return;
1635 
1636 	if (priv->connection) {
1637 		g_signal_handlers_disconnect_by_data (priv->connection, msg);
1638                 priv->io_data = NULL;
1639 
1640                 if (priv->pending_tls_cert_request) {
1641                         soup_connection_complete_tls_certificate_request (priv->connection,
1642                                                                           priv->tls_client_certificate,
1643                                                                           g_steal_pointer (&priv->pending_tls_cert_request));
1644                         g_clear_object (&priv->tls_client_certificate);
1645                 }
1646 		g_object_remove_weak_pointer (G_OBJECT (priv->connection), (gpointer*)&priv->connection);
1647                 soup_connection_set_in_use (priv->connection, FALSE);
1648 	}
1649 
1650 	priv->connection = conn;
1651 	if (!priv->connection)
1652 		return;
1653 
1654         soup_connection_set_in_use (priv->connection, TRUE);
1655         priv->last_connection_id = soup_connection_get_id (priv->connection);
1656 
1657 	g_object_add_weak_pointer (G_OBJECT (priv->connection), (gpointer*)&priv->connection);
1658         soup_message_set_tls_peer_certificate (msg,
1659                                                soup_connection_get_tls_certificate (priv->connection),
1660                                                soup_connection_get_tls_certificate_errors (priv->connection));
1661         soup_message_set_tls_protocol_version (msg, soup_connection_get_tls_protocol_version (conn));
1662         soup_message_set_tls_ciphersuite_name (msg, soup_connection_get_tls_ciphersuite_name (conn));
1663         soup_message_set_remote_address (msg, soup_connection_get_remote_address (priv->connection));
1664 
1665         if (priv->tls_client_certificate) {
1666                 soup_connection_set_tls_client_certificate (priv->connection,
1667                                                             priv->tls_client_certificate);
1668                 g_clear_object (&priv->tls_client_certificate);
1669         }
1670 
1671 	g_signal_connect_object (priv->connection, "event",
1672 				 G_CALLBACK (re_emit_connection_event),
1673 				 msg, G_CONNECT_SWAPPED);
1674 	g_signal_connect_object (priv->connection, "accept-certificate",
1675 				 G_CALLBACK (re_emit_accept_certificate),
1676 				 msg, G_CONNECT_SWAPPED);
1677         g_signal_connect_object (priv->connection, "request-certificate",
1678                                  G_CALLBACK (re_emit_request_certificate),
1679                                  msg, G_CONNECT_SWAPPED);
1680         g_signal_connect_object (priv->connection, "request-certificate-password",
1681                                  G_CALLBACK (re_emit_request_certificate_password),
1682                                  msg, G_CONNECT_SWAPPED);
1683 	g_signal_connect_object (priv->connection, "notify::tls-certificate",
1684 				 G_CALLBACK (re_emit_tls_certificate_changed),
1685 				 msg, G_CONNECT_SWAPPED);
1686         g_signal_connect_object (priv->connection, "notify::tls-protocol-version",
1687                                  G_CALLBACK (connection_tls_protocol_version_changed),
1688                                  msg, G_CONNECT_SWAPPED);
1689         g_signal_connect_object (priv->connection, "notify::tls-ciphersuite-name",
1690                                  G_CALLBACK (connection_tls_ciphersuite_name_changed),
1691                                  msg, G_CONNECT_SWAPPED);
1692         g_signal_connect_object (priv->connection, "notify::remote-address",
1693                                  G_CALLBACK (connection_remote_address_changed),
1694                                  msg, G_CONNECT_SWAPPED);
1695 }
1696 
1697 void
soup_message_set_is_preconnect(SoupMessage * msg,gboolean is_preconnect)1698 soup_message_set_is_preconnect (SoupMessage *msg,
1699                                 gboolean     is_preconnect)
1700 {
1701         SoupMessagePrivate *priv = soup_message_get_instance_private (msg);
1702 
1703         priv->is_preconnect = is_preconnect;
1704 }
1705 
1706 void
soup_message_transfer_connection(SoupMessage * preconnect_msg,SoupMessage * msg)1707 soup_message_transfer_connection (SoupMessage *preconnect_msg,
1708                                   SoupMessage *msg)
1709 {
1710         SoupMessagePrivate *preconnect_priv = soup_message_get_instance_private (preconnect_msg);
1711         SoupMessagePrivate *priv = soup_message_get_instance_private (msg);
1712         GTlsCertificate *client_certificate = NULL;
1713 
1714         g_assert (preconnect_priv->is_preconnect);
1715         g_assert (!priv->connection);
1716         client_certificate = g_steal_pointer (&priv->tls_client_certificate);
1717         soup_message_set_connection (msg, preconnect_priv->connection);
1718 
1719         /* If connection has pending interactions, transfer them too */
1720         g_assert (!priv->pending_tls_cert_request);
1721         priv->pending_tls_cert_request = g_steal_pointer (&preconnect_priv->pending_tls_cert_request);
1722         if (priv->pending_tls_cert_request) {
1723                 if (client_certificate) {
1724                         soup_connection_complete_tls_certificate_request (priv->connection,
1725                                                                           client_certificate,
1726                                                                           g_steal_pointer (&priv->pending_tls_cert_request));
1727                         g_object_unref (client_certificate);
1728                 } else {
1729                         gboolean handled = FALSE;
1730 
1731                         g_signal_emit (msg, signals[REQUEST_CERTIFICATE], 0, preconnect_priv->pending_tls_cert_conn, &handled);
1732                         g_clear_object (&preconnect_priv->pending_tls_cert_conn);
1733                         if (!handled)
1734                                 g_clear_object (&priv->pending_tls_cert_request);
1735                 }
1736         } else if (client_certificate) {
1737                 soup_connection_set_tls_client_certificate (priv->connection, client_certificate);
1738                 g_object_unref (client_certificate);
1739         }
1740 
1741         g_assert (!priv->pending_tls_cert_pass_request);
1742         priv->pending_tls_cert_pass_request = g_steal_pointer (&preconnect_priv->pending_tls_cert_pass_request);
1743         if (priv->pending_tls_cert_pass_request) {
1744                 gboolean handled = FALSE;
1745 
1746                 g_signal_emit (msg, signals[REQUEST_CERTIFICATE_PASSWORD], 0, preconnect_priv->pending_tls_cert_password, &handled);
1747                 g_clear_object (&preconnect_priv->pending_tls_cert_password);
1748                 if (!handled)
1749                         g_clear_object (&priv->pending_tls_cert_pass_request);
1750         }
1751 
1752         soup_message_set_connection (preconnect_msg, NULL);
1753 }
1754 
1755 gboolean
soup_message_has_pending_tls_cert_request(SoupMessage * msg)1756 soup_message_has_pending_tls_cert_request (SoupMessage *msg)
1757 {
1758         SoupMessagePrivate *priv = soup_message_get_instance_private (msg);
1759 
1760         return priv->pending_tls_cert_request != NULL;
1761 }
1762 
1763 gboolean
soup_message_has_pending_tls_cert_pass_request(SoupMessage * msg)1764 soup_message_has_pending_tls_cert_pass_request (SoupMessage *msg)
1765 {
1766         SoupMessagePrivate *priv = soup_message_get_instance_private (msg);
1767 
1768         return priv->pending_tls_cert_pass_request != NULL;
1769 }
1770 
1771 /**
1772  * soup_message_cleanup_response:
1773  * @msg: a #SoupMessage
1774  *
1775  * Cleans up all response data on @msg, so that the request can be sent
1776  * again and receive a new response. (Eg, as a result of a redirect or
1777  * authorization request.)
1778  **/
1779 void
soup_message_cleanup_response(SoupMessage * msg)1780 soup_message_cleanup_response (SoupMessage *msg)
1781 {
1782 	SoupMessagePrivate *priv = soup_message_get_instance_private (msg);
1783 
1784         g_object_freeze_notify (G_OBJECT (msg));
1785 
1786 	soup_message_headers_clear (priv->response_headers);
1787 
1788         soup_message_set_status (msg, SOUP_STATUS_NONE, NULL);
1789         soup_message_set_http_version (msg, priv->orig_http_version);
1790 
1791         if (!priv->connection) {
1792                 soup_message_set_tls_peer_certificate (msg, NULL, 0);
1793                 soup_message_set_tls_protocol_version (msg, G_TLS_PROTOCOL_VERSION_UNKNOWN);
1794                 soup_message_set_tls_ciphersuite_name (msg, NULL);
1795                 soup_message_set_remote_address (msg, NULL);
1796                 priv->last_connection_id = 0;
1797         }
1798 
1799         g_object_thaw_notify (G_OBJECT (msg));
1800 }
1801 
1802 /**
1803  * SoupMessageFlags:
1804  * @SOUP_MESSAGE_NO_REDIRECT: The session should not follow redirect
1805  *   (3xx) responses received by this message.
1806  * @SOUP_MESSAGE_NEW_CONNECTION: Requests that the message should be
1807  *   sent on a newly-created connection, not reusing an existing
1808  *   persistent connection. Note that messages with non-idempotent
1809  *   #SoupMessage:method<!-- -->s behave this way by default, unless
1810  *   #SOUP_MESSAGE_IDEMPOTENT is set.
1811  * @SOUP_MESSAGE_IDEMPOTENT: The message is considered idempotent,
1812  *   regardless its #SoupMessage:method, and allows reuse of existing
1813  *   idle connections, instead of always requiring a new one, unless
1814  *   #SOUP_MESSAGE_NEW_CONNECTION is set.
1815  * @SOUP_MESSAGE_DO_NOT_USE_AUTH_CACHE: The #SoupAuthManager should not use
1816  *   the credentials cache for this message, neither to use cached credentials
1817  *   to automatically authenticate this message nor to cache the credentials
1818  *   after the message is successfully authenticated. This applies to both server
1819  *   and proxy authentication. Note that #SoupMessage::authenticate signal will
1820  *   be emitted, if you want to disable authentication for a message use
1821  *   soup_message_disable_feature() passing #SOUP_TYPE_AUTH_MANAGER instead.
1822  * @SOUP_MESSAGE_COLLECT_METRICS: Metrics will be collected for this message.
1823  *
1824  * Various flags that can be set on a #SoupMessage to alter its
1825  * behavior.
1826  **/
1827 
1828 /**
1829  * soup_message_set_flags:
1830  * @msg: a #SoupMessage
1831  * @flags: a set of #SoupMessageFlags values
1832  *
1833  * Sets the specified flags on @msg.
1834  **/
1835 void
soup_message_set_flags(SoupMessage * msg,SoupMessageFlags flags)1836 soup_message_set_flags (SoupMessage *msg, SoupMessageFlags flags)
1837 {
1838 	SoupMessagePrivate *priv;
1839 
1840 	g_return_if_fail (SOUP_IS_MESSAGE (msg));
1841 
1842 	priv = soup_message_get_instance_private (msg);
1843 
1844 	if (priv->msg_flags == flags)
1845 		return;
1846 
1847 	priv->msg_flags = flags;
1848 	g_object_notify_by_pspec (G_OBJECT (msg), properties[PROP_FLAGS]);
1849 }
1850 
1851 /**
1852  * soup_message_get_flags:
1853  * @msg: a #SoupMessage
1854  *
1855  * Gets the flags on @msg
1856  *
1857  * Returns: the flags
1858  **/
1859 SoupMessageFlags
soup_message_get_flags(SoupMessage * msg)1860 soup_message_get_flags (SoupMessage *msg)
1861 {
1862 	SoupMessagePrivate *priv;
1863 
1864 	g_return_val_if_fail (SOUP_IS_MESSAGE (msg), 0);
1865 
1866 	priv = soup_message_get_instance_private (msg);
1867 
1868 	return priv->msg_flags;
1869 }
1870 
1871 /**
1872  * soup_message_add_flags:
1873  * @msg: a #SoupMessage
1874  * @flags: a set of #SoupMessageFlags values
1875  *
1876  * Adds @flags to the set of @msg's flags
1877  */
1878 void
soup_message_add_flags(SoupMessage * msg,SoupMessageFlags flags)1879 soup_message_add_flags (SoupMessage     *msg,
1880 			SoupMessageFlags flags)
1881 {
1882 	SoupMessagePrivate *priv;
1883 
1884 	g_return_if_fail (SOUP_IS_MESSAGE (msg));
1885 
1886 	priv = soup_message_get_instance_private (msg);
1887 	soup_message_set_flags (msg, priv->msg_flags | flags);
1888 }
1889 
1890 /**
1891  * soup_message_query_flags:
1892  * @msg: a #SoupMessage
1893  * @flags: a set of #SoupMessageFlags values
1894  *
1895  * Queries if @flags are present in the set of @msg's flags
1896  *
1897  * Returns: %TRUE if @flags are enabled in @msg
1898  */
1899 gboolean
soup_message_query_flags(SoupMessage * msg,SoupMessageFlags flags)1900 soup_message_query_flags (SoupMessage     *msg,
1901 			  SoupMessageFlags flags)
1902 {
1903         SoupMessagePrivate *priv;
1904 
1905         g_return_val_if_fail (SOUP_IS_MESSAGE (msg), FALSE);
1906 
1907         priv = soup_message_get_instance_private (msg);
1908 	return !!(priv->msg_flags & flags);
1909 }
1910 
1911 /**
1912  * soup_message_remove_flags:
1913  * @msg: a #SoupMessage
1914  * @flags: a set of #SoupMessageFlags values
1915  *
1916  * Removes @flags from the set of @msg's flags
1917  */
1918 void
soup_message_remove_flags(SoupMessage * msg,SoupMessageFlags flags)1919 soup_message_remove_flags (SoupMessage     *msg,
1920 			   SoupMessageFlags flags)
1921 {
1922         SoupMessagePrivate *priv;
1923 
1924         g_return_if_fail (SOUP_IS_MESSAGE (msg));
1925 
1926         priv = soup_message_get_instance_private (msg);
1927 	soup_message_set_flags (msg, priv->msg_flags & ~flags);
1928 }
1929 
1930 /**
1931  * soup_message_set_http_version:
1932  * @msg: a #SoupMessage
1933  * @version: the HTTP version
1934  *
1935  * Sets the HTTP version on @msg. The default version is
1936  * %SOUP_HTTP_1_1. Setting it to %SOUP_HTTP_1_0 will prevent certain
1937  * functionality from being used.
1938  **/
1939 void
soup_message_set_http_version(SoupMessage * msg,SoupHTTPVersion version)1940 soup_message_set_http_version (SoupMessage *msg, SoupHTTPVersion version)
1941 {
1942 	SoupMessagePrivate *priv = soup_message_get_instance_private (msg);
1943 
1944         if (priv->http_version == version)
1945                 return;
1946 
1947 	priv->http_version = version;
1948 	if (priv->status_code == SOUP_STATUS_NONE)
1949 		priv->orig_http_version = version;
1950 	g_object_notify_by_pspec (G_OBJECT (msg), properties[PROP_HTTP_VERSION]);
1951 }
1952 
1953 /**
1954  * soup_message_get_http_version:
1955  * @msg: a #SoupMessage
1956  *
1957  * Gets the HTTP version of @msg. This is the minimum of the
1958  * version from the request and the version from the response.
1959  *
1960  * Returns: the HTTP version
1961  **/
1962 SoupHTTPVersion
soup_message_get_http_version(SoupMessage * msg)1963 soup_message_get_http_version (SoupMessage *msg)
1964 {
1965 	SoupMessagePrivate *priv;
1966 
1967 	g_return_val_if_fail (SOUP_IS_MESSAGE (msg), SOUP_HTTP_1_0);
1968 
1969 	priv = soup_message_get_instance_private (msg);
1970 
1971 	return priv->http_version;
1972 }
1973 
1974 /**
1975  * soup_message_is_keepalive:
1976  * @msg: a #SoupMessage
1977  *
1978  * Determines whether or not @msg's connection can be kept alive for
1979  * further requests after processing @msg, based on the HTTP version,
1980  * Connection header, etc.
1981  *
1982  * Returns: %TRUE or %FALSE.
1983  **/
1984 gboolean
soup_message_is_keepalive(SoupMessage * msg)1985 soup_message_is_keepalive (SoupMessage *msg)
1986 {
1987 	SoupMessagePrivate *priv = soup_message_get_instance_private (msg);
1988 
1989         if (priv->http_version == SOUP_HTTP_2_0)
1990                 return FALSE;
1991 
1992 	if (priv->status_code == SOUP_STATUS_OK &&
1993 	    priv->method == SOUP_METHOD_CONNECT)
1994 		return TRUE;
1995 
1996 	/* Not persistent if the server sent a terminate-by-EOF response */
1997 	if (soup_message_headers_get_encoding (priv->response_headers) == SOUP_ENCODING_EOF)
1998 		return FALSE;
1999 
2000 	if (priv->http_version == SOUP_HTTP_1_0) {
2001 		/* In theory, HTTP/1.0 connections are only persistent
2002 		 * if the client requests it, and the server agrees.
2003 		 * But some servers do keep-alive even if the client
2004 		 * doesn't request it. So ignore c_conn.
2005 		 */
2006 
2007 		if (!soup_message_headers_header_contains_common (priv->response_headers,
2008                                                                   SOUP_HEADER_CONNECTION,
2009                                                                   "Keep-Alive"))
2010 			return FALSE;
2011 	} else {
2012 		/* Normally persistent unless either side requested otherwise */
2013 		if (soup_message_headers_header_contains_common (priv->request_headers,
2014                                                                  SOUP_HEADER_CONNECTION,
2015                                                                  "close") ||
2016 		    soup_message_headers_header_contains_common (priv->response_headers,
2017                                                                  SOUP_HEADER_CONNECTION,
2018                                                                  "close"))
2019 			return FALSE;
2020 
2021 		return TRUE;
2022 	}
2023 
2024 	return TRUE;
2025 }
2026 
2027 /**
2028  * soup_message_set_uri:
2029  * @msg: a #SoupMessage
2030  * @uri: the new #GUri
2031  *
2032  * Sets @msg's URI to @uri. If @msg has already been sent and you want
2033  * to re-send it with the new URI, you need to send it again.
2034  **/
2035 void
soup_message_set_uri(SoupMessage * msg,GUri * uri)2036 soup_message_set_uri (SoupMessage *msg, GUri *uri)
2037 {
2038 	SoupMessagePrivate *priv;
2039         GUri *normalized_uri;
2040 
2041 	g_return_if_fail (SOUP_IS_MESSAGE (msg));
2042         g_return_if_fail (SOUP_URI_IS_VALID (uri));
2043 
2044 	priv = soup_message_get_instance_private (msg);
2045 
2046         normalized_uri = soup_uri_copy_with_normalized_flags (uri);
2047         if (!normalized_uri)
2048                 return;
2049 
2050         if (priv->uri) {
2051                 if (soup_uri_equal (priv->uri, normalized_uri)) {
2052                         g_uri_unref (normalized_uri);
2053                         return;
2054                 }
2055 
2056                 g_uri_unref (priv->uri);
2057         }
2058 
2059 	priv->uri = normalized_uri;
2060 	g_object_notify_by_pspec (G_OBJECT (msg), properties[PROP_URI]);
2061 }
2062 
2063 /**
2064  * soup_message_get_uri:
2065  * @msg: a #SoupMessage
2066  *
2067  * Gets @msg's URI
2068  *
2069  * Returns: (transfer none): the URI @msg is targeted for.
2070  **/
2071 GUri *
soup_message_get_uri(SoupMessage * msg)2072 soup_message_get_uri (SoupMessage *msg)
2073 {
2074 	SoupMessagePrivate *priv;
2075 
2076 	g_return_val_if_fail (SOUP_IS_MESSAGE (msg), NULL);
2077 
2078 	priv = soup_message_get_instance_private (msg);
2079 
2080 	return priv->uri;
2081 }
2082 
2083 /**
2084  * soup_message_set_status:
2085  * @msg: a #SoupMessage
2086  * @status_code: an HTTP status code
2087  *
2088  * Sets @msg's status code to @status_code. If @status_code is a
2089  * known value, it will also set @msg's reason_phrase.
2090  **/
2091 void
soup_message_set_status(SoupMessage * msg,guint status_code,const char * reason_phrase)2092 soup_message_set_status (SoupMessage *msg,
2093 			 guint        status_code,
2094 			 const char  *reason_phrase)
2095 {
2096         SoupMessagePrivate *priv = soup_message_get_instance_private (msg);
2097 
2098         g_object_freeze_notify (G_OBJECT (msg));
2099 
2100         if (priv->status_code != status_code) {
2101                 priv->status_code = status_code;
2102                 g_object_notify_by_pspec (G_OBJECT (msg), properties[PROP_STATUS_CODE]);
2103         }
2104 
2105         if (reason_phrase) {
2106                 soup_message_set_reason_phrase (msg, reason_phrase);
2107         } else {
2108                 soup_message_set_reason_phrase (msg, priv->status_code != SOUP_STATUS_NONE ?
2109                                                 soup_status_get_phrase (priv->status_code) :
2110                                                 NULL);
2111         }
2112 
2113         g_object_thaw_notify (G_OBJECT (msg));
2114 }
2115 
2116 /**
2117  * soup_message_disable_feature:
2118  * @msg: a #SoupMessage
2119  * @feature_type: the #GType of a #SoupSessionFeature
2120  *
2121  * This disables the actions of #SoupSessionFeature<!-- -->s with the
2122  * given @feature_type (or a subclass of that type) on @msg, so that
2123  * @msg is processed as though the feature(s) hadn't been added to the
2124  * session. Eg, passing #SOUP_TYPE_CONTENT_SNIFFER for @feature_type
2125  * will disable Content-Type sniffing on the message.
2126  *
2127  * You must call this before queueing @msg on a session; calling it on
2128  * a message that has already been queued is undefined. In particular,
2129  * you cannot call this on a message that is being requeued after a
2130  * redirect or authentication.
2131  *
2132  **/
2133 void
soup_message_disable_feature(SoupMessage * msg,GType feature_type)2134 soup_message_disable_feature (SoupMessage *msg, GType feature_type)
2135 {
2136 	SoupMessagePrivate *priv;
2137 
2138 	g_return_if_fail (SOUP_IS_MESSAGE (msg));
2139 
2140 	priv = soup_message_get_instance_private (msg);
2141 
2142 	if (!priv->disabled_features)
2143 		priv->disabled_features = g_hash_table_new (g_direct_hash, g_direct_equal);
2144 
2145 	g_hash_table_add (priv->disabled_features, GSIZE_TO_POINTER (feature_type));
2146 }
2147 
2148 gboolean
soup_message_disables_feature(SoupMessage * msg,gpointer feature)2149 soup_message_disables_feature (SoupMessage *msg, gpointer feature)
2150 {
2151 	SoupMessagePrivate *priv;
2152         GHashTableIter iter;
2153         gpointer key;
2154 
2155 	g_return_val_if_fail (SOUP_IS_MESSAGE (msg), FALSE);
2156 
2157 	priv = soup_message_get_instance_private (msg);
2158 
2159         if (!priv->disabled_features)
2160                 return FALSE;
2161 
2162         g_hash_table_iter_init (&iter, priv->disabled_features);
2163         while (g_hash_table_iter_next (&iter, &key, NULL)) {
2164                 if (G_TYPE_CHECK_INSTANCE_TYPE (feature, GPOINTER_TO_SIZE (key)))
2165                         return TRUE;
2166         }
2167         return FALSE;
2168 }
2169 
2170 /**
2171  * soup_message_is_feature_disabled:
2172  * @msg: a #SoupMessage
2173  * @feature_type: the #GType of a #SoupSessionFeature
2174  *
2175  * Get whether #SoupSessionFeature<!-- -->s of the given @feature_type
2176  * (or a subclass of that type) are disabled on @msg.
2177  * See soup_message_disable_feature().
2178  *
2179  * Returns: %TRUE if feature is disabled, or %FALSE otherwise.
2180  *
2181  */
2182 gboolean
soup_message_is_feature_disabled(SoupMessage * msg,GType feature_type)2183 soup_message_is_feature_disabled (SoupMessage *msg, GType feature_type)
2184 {
2185         SoupMessagePrivate *priv;
2186         GHashTableIter iter;
2187         gpointer key;
2188 
2189         g_return_val_if_fail (SOUP_IS_MESSAGE (msg), FALSE);
2190 
2191         priv = soup_message_get_instance_private (msg);
2192 
2193         if (!priv->disabled_features)
2194                 return FALSE;
2195 
2196         g_hash_table_iter_init (&iter, priv->disabled_features);
2197         while (g_hash_table_iter_next (&iter, &key, NULL)) {
2198                 if (g_type_is_a (GPOINTER_TO_SIZE (key), feature_type))
2199                         return TRUE;
2200         }
2201         return FALSE;
2202 }
2203 
2204 GList *
soup_message_get_disabled_features(SoupMessage * msg)2205 soup_message_get_disabled_features (SoupMessage *msg)
2206 {
2207 	SoupMessagePrivate *priv = soup_message_get_instance_private (msg);
2208 
2209 	return priv->disabled_features ? g_hash_table_get_keys (priv->disabled_features) : NULL;
2210 }
2211 
2212 /**
2213  * soup_message_get_first_party:
2214  * @msg: a #SoupMessage
2215  *
2216  * Gets @msg's first-party #GUri
2217  *
2218  * Returns: (transfer none): the @msg's first party #GUri
2219  *
2220  **/
2221 GUri *
soup_message_get_first_party(SoupMessage * msg)2222 soup_message_get_first_party (SoupMessage *msg)
2223 {
2224 	SoupMessagePrivate *priv;
2225 
2226 	g_return_val_if_fail (SOUP_IS_MESSAGE (msg), NULL);
2227 
2228 	priv = soup_message_get_instance_private (msg);
2229 	return priv->first_party;
2230 }
2231 
2232 /**
2233  * soup_message_set_first_party:
2234  * @msg: a #SoupMessage
2235  * @first_party: the #GUri for the @msg's first party
2236  *
2237  * Sets @first_party as the main document #GUri for @msg. For
2238  * details of when and how this is used refer to the documentation for
2239  * #SoupCookieJarAcceptPolicy.
2240  *
2241  **/
2242 void
soup_message_set_first_party(SoupMessage * msg,GUri * first_party)2243 soup_message_set_first_party (SoupMessage *msg,
2244 			      GUri        *first_party)
2245 {
2246 	SoupMessagePrivate *priv;
2247         GUri *first_party_normalized;
2248 
2249 	g_return_if_fail (SOUP_IS_MESSAGE (msg));
2250         g_return_if_fail (first_party != NULL);
2251 
2252 	priv = soup_message_get_instance_private (msg);
2253         first_party_normalized = soup_uri_copy_with_normalized_flags (first_party);
2254         if (!first_party_normalized)
2255                 return;
2256 
2257 	if (priv->first_party) {
2258 		if (soup_uri_equal (priv->first_party, first_party_normalized)) {
2259                         g_uri_unref (first_party_normalized);
2260                         return;
2261                 }
2262 
2263 		g_uri_unref (priv->first_party);
2264 	}
2265 
2266 	priv->first_party = g_steal_pointer (&first_party_normalized);
2267 	g_object_notify_by_pspec (G_OBJECT (msg), properties[PROP_FIRST_PARTY]);
2268 }
2269 
2270 /**
2271  * soup_message_get_site_for_cookies:
2272  * @msg: a #SoupMessage
2273  *
2274  * Gets @msg's site for cookies #GUri
2275  *
2276  * Returns: (transfer none): the @msg's site for cookies #GUri
2277  *
2278  **/
2279 GUri *
soup_message_get_site_for_cookies(SoupMessage * msg)2280 soup_message_get_site_for_cookies (SoupMessage *msg)
2281 {
2282 	SoupMessagePrivate *priv;
2283 
2284 	g_return_val_if_fail (SOUP_IS_MESSAGE (msg), NULL);
2285 
2286 	priv = soup_message_get_instance_private (msg);
2287 	return priv->site_for_cookies;
2288 }
2289 
2290 /**
2291  * soup_message_set_site_for_cookies:
2292  * @msg: a #SoupMessage
2293  * @site_for_cookies: (nullable): the #GUri for the @msg's site for cookies
2294  *
2295  * Sets @site_for_cookies as the policy URL for same-site cookies for @msg.
2296  *
2297  * It is either the URL of the top-level document or %NULL depending on whether the registrable
2298  * domain of this document's URL matches the registrable domain of its parent's/opener's
2299  * URL. For the top-level document it is set to the document's URL.
2300  *
2301  * See the [same-site spec](https://tools.ietf.org/html/draft-ietf-httpbis-cookie-same-site-00)
2302  * for more information.
2303  *
2304  **/
2305 void
soup_message_set_site_for_cookies(SoupMessage * msg,GUri * site_for_cookies)2306 soup_message_set_site_for_cookies (SoupMessage *msg,
2307 			           GUri        *site_for_cookies)
2308 {
2309 	SoupMessagePrivate *priv;
2310         GUri *site_for_cookies_normalized = NULL;
2311 
2312 	g_return_if_fail (SOUP_IS_MESSAGE (msg));
2313 
2314 	priv = soup_message_get_instance_private (msg);
2315         if (site_for_cookies) {
2316                 site_for_cookies_normalized = soup_uri_copy_with_normalized_flags (site_for_cookies);
2317                 if (!site_for_cookies_normalized)
2318                         return;
2319         }
2320 
2321 	if (priv->site_for_cookies) {
2322 		if (site_for_cookies_normalized && soup_uri_equal (priv->site_for_cookies, site_for_cookies_normalized)) {
2323                         g_uri_unref (site_for_cookies_normalized);
2324                         return;
2325                 }
2326 
2327 		g_uri_unref (priv->site_for_cookies);
2328 	}
2329 
2330 	priv->site_for_cookies = g_steal_pointer (&site_for_cookies_normalized);
2331 	g_object_notify_by_pspec (G_OBJECT (msg), properties[PROP_SITE_FOR_COOKIES]);
2332 }
2333 
2334 /**
2335  * soup_message_set_is_top_level_navigation:
2336  * @msg: a #SoupMessage
2337  * @is_top_level_navigation: if %TRUE indicate the current request is a top-level navigation
2338  *
2339  * See the [same-site spec](https://tools.ietf.org/html/draft-ietf-httpbis-cookie-same-site-00)
2340  * for more information.
2341  *
2342  **/
2343 void
soup_message_set_is_top_level_navigation(SoupMessage * msg,gboolean is_top_level_navigation)2344 soup_message_set_is_top_level_navigation (SoupMessage *msg,
2345 			                 gboolean     is_top_level_navigation)
2346 {
2347 	SoupMessagePrivate *priv;
2348 
2349 	g_return_if_fail (SOUP_IS_MESSAGE (msg));
2350 
2351 	priv = soup_message_get_instance_private (msg);
2352 
2353 	if (priv->is_top_level_navigation == is_top_level_navigation)
2354 		return;
2355 
2356 	priv->is_top_level_navigation = is_top_level_navigation;
2357 	g_object_notify_by_pspec (G_OBJECT (msg), properties[PROP_IS_TOP_LEVEL_NAVIGATION]);
2358 }
2359 
2360 /**
2361  * soup_message_get_is_top_level_navigation:
2362  * @msg: a #SoupMessage
2363  *
2364  * Returns if this message is set as a top level navigation.
2365  * Used for same-site policy checks.
2366  *
2367  **/
2368 gboolean
soup_message_get_is_top_level_navigation(SoupMessage * msg)2369 soup_message_get_is_top_level_navigation (SoupMessage *msg)
2370 {
2371 	SoupMessagePrivate *priv;
2372 
2373 	g_return_val_if_fail (SOUP_IS_MESSAGE (msg), FALSE);
2374 
2375 	priv = soup_message_get_instance_private (msg);
2376 	return priv->is_top_level_navigation;
2377 }
2378 
2379 /**
2380  * soup_message_get_tls_peer_certificate:
2381  * @msg: a #SoupMessage
2382  *
2383  * Gets the peer's #GTlsCertificate associated with @msg's connection.
2384  * Note that this is not set yet during the emission of
2385  * SoupMessage::accept-certificate signal.
2386  *
2387  * Returns: (transfer none) (nullable): @msg's TLS peer certificate,
2388  *    or %NULL if @msg's connection is not SSL.
2389  */
2390 GTlsCertificate *
soup_message_get_tls_peer_certificate(SoupMessage * msg)2391 soup_message_get_tls_peer_certificate (SoupMessage *msg)
2392 {
2393 	SoupMessagePrivate *priv;
2394 
2395 	g_return_val_if_fail (SOUP_IS_MESSAGE (msg), NULL);
2396 
2397 	priv = soup_message_get_instance_private (msg);
2398 
2399 	return priv->tls_peer_certificate;
2400 }
2401 
2402 /**
2403  * soup_message_get_tls_peer_certificate_errors:
2404  * @msg: a #SoupMessage
2405  *
2406  * Gets the errors associated with validating @msg's TLS peer certificate.
2407  * Note that this is not set yet during the emission of
2408  * SoupMessage::accept-certificate signal.
2409  *
2410  * Returns: a #GTlsCertificateFlags with @msg's TLS peer certificate errors.
2411  */
2412 GTlsCertificateFlags
soup_message_get_tls_peer_certificate_errors(SoupMessage * msg)2413 soup_message_get_tls_peer_certificate_errors (SoupMessage *msg)
2414 {
2415         SoupMessagePrivate *priv;
2416 
2417         g_return_val_if_fail (SOUP_IS_MESSAGE (msg), 0);
2418 
2419 	priv = soup_message_get_instance_private (msg);
2420 
2421 	return priv->tls_peer_certificate_errors;
2422 }
2423 
2424 /**
2425  * soup_message_get_tls_protocol_version:
2426  * @msg: a #SoupMessage
2427  *
2428  * Gets the TLS protocol version negotiated for @msg's connection.
2429  * If the message connection is not SSL, %G_TLS_PROTOCOL_VERSION_UNKNOWN is returned.
2430  *
2431  * Returns: a #GTlsProtocolVersion
2432  */
2433 GTlsProtocolVersion
soup_message_get_tls_protocol_version(SoupMessage * msg)2434 soup_message_get_tls_protocol_version (SoupMessage *msg)
2435 {
2436         SoupMessagePrivate *priv;
2437 
2438         g_return_val_if_fail (SOUP_IS_MESSAGE (msg), G_TLS_PROTOCOL_VERSION_UNKNOWN);
2439 
2440         priv = soup_message_get_instance_private (msg);
2441 
2442         return priv->tls_protocol_version;
2443 }
2444 
2445 /**
2446  * soup_message_get_tls_ciphersuite_name:
2447  * @msg: a #SoupMessage
2448  *
2449  * Gets the name of the TLS ciphersuite negotiated for @msg's connection.
2450  *
2451  * Returns: (transfer none): the name of the TLS ciphersuite,
2452  *    or %NULL if @msg's connection is not SSL.
2453  */
2454 const char *
soup_message_get_tls_ciphersuite_name(SoupMessage * msg)2455 soup_message_get_tls_ciphersuite_name (SoupMessage *msg)
2456 {
2457         SoupMessagePrivate *priv;
2458 
2459         g_return_val_if_fail (SOUP_IS_MESSAGE (msg), NULL);
2460 
2461         priv = soup_message_get_instance_private (msg);
2462 
2463         return priv->tls_ciphersuite_name;
2464 }
2465 
2466 /**
2467  * soup_message_set_tls_client_certificate:
2468  * @msg: a #SoupMessage
2469  * @certificate: (nullable): the #GTlsCertificate to set, or %NULL
2470  *
2471  * Sets the @certificate to be used by @msg's connection when a
2472  * client certificate is requested during the TLS handshake.
2473  * You can call this as a response to #SoupMessage::request-certificate
2474  * signal, or before the connection is started. If @certificate is %NULL
2475  * the handshake will continue without providing a GTlsCertificate.
2476  * Note that the #GTlsCertificate set by this function will be ignored if
2477  * #SoupSession::tls-interaction is not %NULL.
2478  */
2479 void
soup_message_set_tls_client_certificate(SoupMessage * msg,GTlsCertificate * certificate)2480 soup_message_set_tls_client_certificate (SoupMessage     *msg,
2481                                          GTlsCertificate *certificate)
2482 {
2483         SoupMessagePrivate *priv;
2484 
2485         g_return_if_fail (SOUP_IS_MESSAGE (msg));
2486         g_return_if_fail (certificate == NULL || G_IS_TLS_CERTIFICATE (certificate));
2487 
2488         priv = soup_message_get_instance_private (msg);
2489         if (priv->pending_tls_cert_request) {
2490                 g_assert (SOUP_IS_CONNECTION (priv->connection));
2491                 soup_connection_complete_tls_certificate_request (priv->connection,
2492                                                                   certificate,
2493                                                                   g_steal_pointer (&priv->pending_tls_cert_request));
2494                 return;
2495         }
2496 
2497         if (priv->connection) {
2498                 soup_connection_set_tls_client_certificate (priv->connection,
2499                                                             certificate);
2500                 return;
2501         }
2502 
2503         if (priv->tls_client_certificate == certificate)
2504                 return;
2505 
2506         g_clear_object (&priv->tls_client_certificate);
2507         priv->tls_client_certificate = certificate ? g_object_ref (certificate) : NULL;
2508 }
2509 
2510 /**
2511  * soup_message_tls_client_certificate_password_request_complete:
2512  * @msg: a #SoupMessage
2513  *
2514  * Completes a certificate password request.
2515  *
2516  * You must call this as a response to #SoupMessage::request-certificate-password
2517  * signal, to notify @msg that the #GTlsPassword has already been updated.
2518  */
2519 void
soup_message_tls_client_certificate_password_request_complete(SoupMessage * msg)2520 soup_message_tls_client_certificate_password_request_complete (SoupMessage *msg)
2521 {
2522         SoupMessagePrivate *priv;
2523 
2524         g_return_if_fail (SOUP_IS_MESSAGE (msg));
2525 
2526         priv = soup_message_get_instance_private (msg);
2527         if (!priv->pending_tls_cert_pass_request) {
2528                 g_warning ("soup_message_tls_client_certificate_password_request_complete should only be called as a response to SoupMessage::request-certificate-password signal");
2529                 return;
2530         }
2531 
2532         g_assert (SOUP_IS_CONNECTION (priv->connection));
2533         soup_connection_complete_tls_certificate_password_request (priv->connection,
2534                                                                    g_steal_pointer (&priv->pending_tls_cert_pass_request));
2535 }
2536 
2537 /**
2538  * SoupMessagePriority:
2539  * @SOUP_MESSAGE_PRIORITY_VERY_LOW: The lowest priority, the messages
2540  *   with this priority will be the last ones to be attended.
2541  * @SOUP_MESSAGE_PRIORITY_LOW: Use this for low priority messages, a
2542  *   #SoupMessage with the default priority will be processed first.
2543  * @SOUP_MESSAGE_PRIORITY_NORMAL: The default priotity, this is the
2544  *   priority assigned to the #SoupMessage by default.
2545  * @SOUP_MESSAGE_PRIORITY_HIGH: High priority, a #SoupMessage with
2546  *   this priority will be processed before the ones with the default
2547  *   priority.
2548  * @SOUP_MESSAGE_PRIORITY_VERY_HIGH: The highest priority, use this
2549  *   for very urgent #SoupMessage as they will be the first ones to be
2550  *   attended.
2551  *
2552  * Priorities that can be set on a #SoupMessage to instruct the
2553  * message queue to process it before any other message with lower
2554  * priority.
2555  **/
2556 
2557 /**
2558  * soup_message_set_priority:
2559  * @msg: a #SoupMessage
2560  * @priority: the #SoupMessagePriority
2561  *
2562  * Sets the priority of a message. Note that this won't have any
2563  * effect unless used before the message is added to the session's
2564  * message processing queue.
2565  *
2566  * The message will be placed just before any other previously added
2567  * message with lower priority (messages with the same priority are
2568  * processed on a FIFO basis).
2569  *
2570  * Setting priorities does not currently work with synchronous messages
2571  * because in the synchronous/blocking case, priority ends up being determined
2572  * semi-randomly by thread scheduling.
2573  *
2574  */
2575 void
soup_message_set_priority(SoupMessage * msg,SoupMessagePriority priority)2576 soup_message_set_priority (SoupMessage        *msg,
2577 			   SoupMessagePriority priority)
2578 {
2579         SoupMessagePrivate *priv;
2580 
2581 	g_return_if_fail (SOUP_IS_MESSAGE (msg));
2582 
2583         priv = soup_message_get_instance_private (msg);
2584         if (priv->priority == priority)
2585                 return;
2586 
2587         priv->priority = priority;
2588 	g_object_notify_by_pspec (G_OBJECT (msg), properties[PROP_PRIORITY]);
2589 }
2590 
2591 /**
2592  * soup_message_get_priority:
2593  * @msg: a #SoupMessage
2594  *
2595  * Retrieves the #SoupMessagePriority. If not set this value defaults
2596  * to #SOUP_MESSAGE_PRIORITY_NORMAL.
2597  *
2598  * Returns: the priority of the message.
2599  *
2600  */
2601 SoupMessagePriority
soup_message_get_priority(SoupMessage * msg)2602 soup_message_get_priority (SoupMessage *msg)
2603 {
2604 	SoupMessagePrivate *priv;
2605 
2606 	g_return_val_if_fail (SOUP_IS_MESSAGE (msg), SOUP_MESSAGE_PRIORITY_NORMAL);
2607 
2608 	priv = soup_message_get_instance_private (msg);
2609 
2610 	return priv->priority;
2611 }
2612 
2613 SoupClientMessageIO *
soup_message_get_io_data(SoupMessage * msg)2614 soup_message_get_io_data (SoupMessage *msg)
2615 {
2616 	SoupMessagePrivate *priv = soup_message_get_instance_private (msg);
2617 
2618 	return priv->io_data;
2619 }
2620 
2621 void
soup_message_io_finished(SoupMessage * msg)2622 soup_message_io_finished (SoupMessage *msg)
2623 {
2624         SoupMessagePrivate *priv = soup_message_get_instance_private (msg);
2625 
2626         if (!priv->io_data)
2627                 return;
2628 
2629         g_assert (priv->connection != NULL);
2630         soup_client_message_io_finished (g_steal_pointer (&priv->io_data), msg);
2631 }
2632 
2633 void
soup_message_io_pause(SoupMessage * msg)2634 soup_message_io_pause (SoupMessage *msg)
2635 {
2636         SoupMessagePrivate *priv = soup_message_get_instance_private (msg);
2637 
2638         g_return_if_fail (priv->io_data != NULL);
2639 
2640         soup_client_message_io_pause (priv->io_data, msg);
2641 }
2642 
2643 void
soup_message_io_unpause(SoupMessage * msg)2644 soup_message_io_unpause (SoupMessage *msg)
2645 {
2646         SoupMessagePrivate *priv = soup_message_get_instance_private (msg);
2647 
2648         g_return_if_fail (priv->io_data != NULL);
2649 
2650         soup_client_message_io_unpause (priv->io_data, msg);
2651 }
2652 
2653 gboolean
soup_message_is_io_paused(SoupMessage * msg)2654 soup_message_is_io_paused (SoupMessage *msg)
2655 {
2656         SoupMessagePrivate *priv = soup_message_get_instance_private (msg);
2657 
2658         return priv->io_data && soup_client_message_io_is_paused (priv->io_data, msg);
2659 }
2660 
2661 /**
2662  * soup_message_io_in_progress:
2663  * @msg: a #SoupMessage
2664  *
2665  * Tests whether or not I/O is currently in progress on @msg.
2666  *
2667  * Returns: whether or not I/O is currently in progress.
2668  **/
2669 gboolean
soup_message_io_in_progress(SoupMessage * msg)2670 soup_message_io_in_progress (SoupMessage *msg)
2671 {
2672         SoupMessagePrivate *priv = soup_message_get_instance_private (msg);
2673 
2674         return priv->io_data && soup_client_message_io_in_progress (priv->io_data, msg);
2675 }
2676 
2677 void
soup_message_io_run(SoupMessage * msg,gboolean blocking)2678 soup_message_io_run (SoupMessage *msg,
2679                      gboolean     blocking)
2680 {
2681         SoupMessagePrivate *priv = soup_message_get_instance_private (msg);
2682 
2683         soup_client_message_io_run (priv->io_data, msg, blocking);
2684 }
2685 
2686 gboolean
soup_message_io_run_until_read(SoupMessage * msg,GCancellable * cancellable,GError ** error)2687 soup_message_io_run_until_read (SoupMessage  *msg,
2688                                 GCancellable *cancellable,
2689                                 GError      **error)
2690 {
2691         SoupMessagePrivate *priv = soup_message_get_instance_private (msg);
2692 
2693         return soup_client_message_io_run_until_read (priv->io_data, msg, cancellable, error);
2694 }
2695 
2696 void
soup_message_io_run_until_read_async(SoupMessage * msg,int io_priority,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)2697 soup_message_io_run_until_read_async (SoupMessage        *msg,
2698                                       int                 io_priority,
2699                                       GCancellable       *cancellable,
2700                                       GAsyncReadyCallback callback,
2701                                       gpointer            user_data)
2702 {
2703         SoupMessagePrivate *priv = soup_message_get_instance_private (msg);
2704 
2705         soup_client_message_io_run_until_read_async (priv->io_data, msg, io_priority, cancellable, callback, user_data);
2706 }
2707 
2708 gboolean
soup_message_io_run_until_read_finish(SoupMessage * msg,GAsyncResult * result,GError ** error)2709 soup_message_io_run_until_read_finish (SoupMessage  *msg,
2710                                        GAsyncResult *result,
2711                                        GError      **error)
2712 {
2713         return g_task_propagate_boolean (G_TASK (result), error);
2714 }
2715 
2716 gboolean
soup_message_io_skip(SoupMessage * msg,gboolean blocking,GCancellable * cancellable,GError ** error)2717 soup_message_io_skip (SoupMessage  *msg,
2718                       gboolean      blocking,
2719                       GCancellable *cancellable,
2720                       GError      **error)
2721 {
2722         SoupMessagePrivate *priv = soup_message_get_instance_private (msg);
2723 
2724         return soup_client_message_io_skip (priv->io_data, msg, blocking, cancellable, error);
2725 }
2726 
2727 GCancellable *
soup_message_io_get_cancellable(SoupMessage * msg)2728 soup_message_io_get_cancellable (SoupMessage *msg)
2729 {
2730         SoupMessagePrivate *priv = soup_message_get_instance_private (msg);
2731 
2732         if (!priv->io_data)
2733                 return NULL;
2734 
2735         return soup_client_message_io_get_cancellable (priv->io_data, msg);
2736 }
2737 
2738 void
soup_message_send_item(SoupMessage * msg,SoupMessageQueueItem * item,SoupMessageIOCompletionFn completion_cb,gpointer user_data)2739 soup_message_send_item (SoupMessage              *msg,
2740                         SoupMessageQueueItem     *item,
2741                         SoupMessageIOCompletionFn completion_cb,
2742                         gpointer                  user_data)
2743 {
2744         SoupMessagePrivate *priv = soup_message_get_instance_private (msg);
2745 
2746         priv->io_data = soup_connection_setup_message_io (priv->connection, msg);
2747         soup_client_message_io_send_item (priv->io_data, item,
2748                                           completion_cb, user_data);
2749 }
2750 
2751 GInputStream *
soup_message_io_get_response_istream(SoupMessage * msg,GError ** error)2752 soup_message_io_get_response_istream (SoupMessage  *msg,
2753                                       GError      **error)
2754 {
2755         SoupMessagePrivate *priv = soup_message_get_instance_private (msg);
2756 
2757         return soup_client_message_io_get_response_stream (priv->io_data, msg, error);
2758 }
2759 
2760 void
soup_message_set_content_sniffer(SoupMessage * msg,SoupContentSniffer * sniffer)2761 soup_message_set_content_sniffer (SoupMessage *msg, SoupContentSniffer *sniffer)
2762 {
2763 	SoupMessagePrivate *priv = soup_message_get_instance_private (msg);
2764 
2765 	if (priv->sniffer)
2766 		g_object_unref (priv->sniffer);
2767 
2768 	priv->sniffer = sniffer ? g_object_ref (sniffer) : NULL;
2769 }
2770 
2771 gboolean
soup_message_has_content_sniffer(SoupMessage * msg)2772 soup_message_has_content_sniffer (SoupMessage *msg)
2773 {
2774         SoupMessagePrivate *priv = soup_message_get_instance_private (msg);
2775 
2776         return priv->sniffer != NULL;
2777 }
2778 
2779 gboolean
soup_message_try_sniff_content(SoupMessage * msg,GInputStream * stream,gboolean blocking,GCancellable * cancellable,GError ** error)2780 soup_message_try_sniff_content (SoupMessage  *msg,
2781                                 GInputStream *stream,
2782                                 gboolean      blocking,
2783                                 GCancellable *cancellable,
2784                                 GError      **error)
2785 {
2786         SoupMessagePrivate *priv = soup_message_get_instance_private (msg);
2787         SoupContentSnifferStream *sniffer_stream;
2788         const char *content_type;
2789         GHashTable *params;
2790 
2791         if (!priv->sniffer)
2792                 return TRUE;
2793 
2794         sniffer_stream = SOUP_CONTENT_SNIFFER_STREAM (stream);
2795         if (!soup_content_sniffer_stream_is_ready (sniffer_stream, blocking, cancellable, error))
2796                 return FALSE;
2797 
2798         content_type = soup_content_sniffer_stream_sniff (sniffer_stream, &params);
2799         soup_message_content_sniffed (msg, content_type, params);
2800 
2801         return TRUE;
2802 }
2803 
2804 GInputStream *
soup_message_get_request_body_stream(SoupMessage * msg)2805 soup_message_get_request_body_stream (SoupMessage *msg)
2806 {
2807         SoupMessagePrivate *priv = soup_message_get_instance_private (msg);
2808 
2809         return priv->request_body_stream;
2810 }
2811 
2812 /**
2813  * soup_message_get_method:
2814  * @msg: The #SoupMessage
2815  *
2816  * Returns the method of this message.
2817  *
2818  * Returns: A method such as %SOUP_METHOD_GET
2819  */
2820 const char *
soup_message_get_method(SoupMessage * msg)2821 soup_message_get_method (SoupMessage *msg)
2822 {
2823         SoupMessagePrivate *priv = soup_message_get_instance_private (msg);
2824 
2825 	g_return_val_if_fail (SOUP_IS_MESSAGE (msg), NULL);
2826 
2827         return priv->method;
2828 }
2829 
2830 /**
2831  * soup_message_get_status:
2832  * @msg: The #SoupMessage
2833  *
2834  * Returns the set status of this message.
2835  *
2836  * Returns: The #SoupStatus
2837  */
2838 SoupStatus
soup_message_get_status(SoupMessage * msg)2839 soup_message_get_status (SoupMessage *msg)
2840 {
2841         SoupMessagePrivate *priv = soup_message_get_instance_private (msg);
2842 
2843 	g_return_val_if_fail (SOUP_IS_MESSAGE (msg), SOUP_STATUS_NONE);
2844 
2845         return priv->status_code;
2846 }
2847 
2848 /**
2849  * soup_message_get_reason_phrase:
2850  * @msg: The #SoupMessage
2851  *
2852  * Returns the reason phrase for the status of this message.
2853  *
2854  * Returns: Phrase or %NULL
2855  */
2856 const char *
soup_message_get_reason_phrase(SoupMessage * msg)2857 soup_message_get_reason_phrase (SoupMessage *msg)
2858 {
2859         SoupMessagePrivate *priv = soup_message_get_instance_private (msg);
2860 
2861 	g_return_val_if_fail (SOUP_IS_MESSAGE (msg), NULL);
2862 
2863         return priv->reason_phrase;
2864 }
2865 
2866 /**
2867  * soup_message_get_request_headers:
2868  * @msg: The #SoupMessage
2869  *
2870  * Returns the headers sent with the request.
2871  *
2872  * Returns: (transfer none): The #SoupMessageHeaders
2873  */
2874 SoupMessageHeaders *
soup_message_get_request_headers(SoupMessage * msg)2875 soup_message_get_request_headers (SoupMessage  *msg)
2876 {
2877         SoupMessagePrivate *priv = soup_message_get_instance_private (msg);
2878 
2879 	g_return_val_if_fail (SOUP_IS_MESSAGE (msg), NULL);
2880 
2881         return priv->request_headers;
2882 }
2883 
2884 /**
2885  * soup_message_get_response_headers:
2886  * @msg: The #SoupMessage
2887  *
2888  * Returns the headers recieved with the response.
2889  *
2890  * Returns: (transfer none): The #SoupMessageHeaders
2891  */
2892 SoupMessageHeaders *
soup_message_get_response_headers(SoupMessage * msg)2893 soup_message_get_response_headers (SoupMessage  *msg)
2894 {
2895         SoupMessagePrivate *priv = soup_message_get_instance_private (msg);
2896 
2897 	g_return_val_if_fail (SOUP_IS_MESSAGE (msg), NULL);
2898 
2899         return priv->response_headers;
2900 }
2901 
2902 void
soup_message_set_reason_phrase(SoupMessage * msg,const char * reason_phrase)2903 soup_message_set_reason_phrase (SoupMessage *msg, const char *reason_phrase)
2904 {
2905         SoupMessagePrivate *priv = soup_message_get_instance_private (msg);
2906 
2907         if (g_strcmp0 (priv->reason_phrase, reason_phrase) == 0)
2908                 return;
2909 
2910         g_free (priv->reason_phrase);
2911         priv->reason_phrase = g_strdup (reason_phrase);
2912         g_object_notify_by_pspec (G_OBJECT (msg), properties[PROP_REASON_PHRASE]);
2913 }
2914 
2915 /**
2916  * soup_message_set_method:
2917  * @msg: a #SoupMessage
2918  * @method: the value to set
2919  *
2920  * Set @msg's HTTP method to @method.
2921  */
2922 void
soup_message_set_method(SoupMessage * msg,const char * method)2923 soup_message_set_method (SoupMessage *msg,
2924                          const char  *method)
2925 {
2926         SoupMessagePrivate *priv = soup_message_get_instance_private (msg);
2927         const char *new_method = g_intern_string (method);
2928 
2929         if (priv->method == new_method)
2930                 return;
2931 
2932         priv->method = new_method;
2933         g_object_notify_by_pspec (G_OBJECT (msg), properties[PROP_METHOD]);
2934 }
2935 
2936 /**
2937  * soup_message_get_is_options_ping:
2938  * @msg: a #SoupMessage
2939  *
2940  * Gets whether @msg is intended to be used to send `OPTIONS *` to a server.
2941  *
2942  * Returns: %TRUE if the message is options ping, or %FALSE otherwise
2943  */
2944 gboolean
soup_message_get_is_options_ping(SoupMessage * msg)2945 soup_message_get_is_options_ping (SoupMessage *msg)
2946 {
2947         SoupMessagePrivate *priv;
2948 
2949         g_return_val_if_fail (SOUP_IS_MESSAGE (msg), FALSE);
2950 
2951         priv = soup_message_get_instance_private (msg);
2952 
2953         return priv->is_options_ping;
2954 }
2955 
2956 /**
2957  * soup_message_set_is_options_ping:
2958  * @msg: a #SoupMessage
2959  * @is_options_ping: the value to set
2960  *
2961  * Set whether @msg is intended to be used to send `OPTIONS *` to a server.
2962  * When set to %TRUE, the path of #SoupMessage:uri will be ignored and
2963  * #SoupMessage:method set to %SOUP_METHOD_OPTIONS.
2964  */
2965 void
soup_message_set_is_options_ping(SoupMessage * msg,gboolean is_options_ping)2966 soup_message_set_is_options_ping (SoupMessage *msg,
2967                                   gboolean     is_options_ping)
2968 {
2969         SoupMessagePrivate *priv;
2970 
2971         g_return_if_fail (SOUP_IS_MESSAGE (msg));
2972 
2973         priv = soup_message_get_instance_private (msg);
2974         if (priv->is_options_ping == is_options_ping)
2975                 return;
2976 
2977         priv->is_options_ping = is_options_ping;
2978         g_object_notify_by_pspec (G_OBJECT (msg), properties[PROP_IS_OPTIONS_PING]);
2979         if (priv->is_options_ping)
2980                 soup_message_set_method (msg, SOUP_METHOD_OPTIONS);
2981 }
2982 
2983 /**
2984  * soup_message_get_connection_id:
2985  * @msg: The #SoupMessage
2986  *
2987  * Returns the unique idenfier for the last connection used.
2988  * This may be 0 if it was a cached resource or it has not gotten
2989  * a connection yet.
2990  *
2991  * Returns: An id or 0 if no connection.
2992  */
2993 guint64
soup_message_get_connection_id(SoupMessage * msg)2994 soup_message_get_connection_id (SoupMessage *msg)
2995 {
2996         SoupMessagePrivate *priv = soup_message_get_instance_private (msg);
2997 
2998         g_return_val_if_fail (SOUP_IS_MESSAGE (msg), 0);
2999 
3000         return priv->last_connection_id;
3001 }
3002 
3003 /**
3004  * soup_message_get_remote_address:
3005  * @msg: The #SoupMessage
3006  *
3007  * Get the remote #GSocketAddress of the connection associated with the message.
3008  * The returned address can be %NULL if the connection hasn't been established yet,
3009  * or the resource was loaded from the disk cache.
3010  * In case of proxy connections, the remote address returned is a #GProxyAddress.
3011  * If #SoupSession::remote-connetable is set the returned address id for the connection
3012  * ot the session's remote connectable.
3013  *
3014  * Returns: (transfer none) (nullable): a #GSocketAddress or %NULL if the connection
3015  *     hasn't been established
3016  */
3017 GSocketAddress *
soup_message_get_remote_address(SoupMessage * msg)3018 soup_message_get_remote_address (SoupMessage *msg)
3019 {
3020         SoupMessagePrivate *priv;
3021 
3022         g_return_val_if_fail (SOUP_IS_MESSAGE (msg), NULL);
3023 
3024         priv = soup_message_get_instance_private (msg);
3025         return priv->remote_address;
3026 }
3027 
3028 /**
3029  * soup_message_get_metrics:
3030  * @msg: The #SoupMessage
3031  *
3032  * Get the #SoupMessageMetrics of @msg. If the flag %SOUP_MESSAGE_COLLECT_METRICS is not
3033  * enabled for @msg this will return %NULL.
3034  *
3035  * Returns: (transfer none) (nullable): a #SoupMessageMetrics, or %NULL
3036  */
3037 SoupMessageMetrics *
soup_message_get_metrics(SoupMessage * msg)3038 soup_message_get_metrics (SoupMessage *msg)
3039 {
3040         SoupMessagePrivate *priv;
3041 
3042         g_return_val_if_fail (SOUP_IS_MESSAGE (msg), NULL);
3043 
3044         priv = soup_message_get_instance_private (msg);
3045         if (priv->metrics)
3046                 return priv->metrics;
3047 
3048         if (priv->msg_flags & SOUP_MESSAGE_COLLECT_METRICS)
3049                 priv->metrics = soup_message_metrics_new ();
3050 
3051         return priv->metrics;
3052 }
3053 
3054 void
soup_message_set_metrics_timestamp(SoupMessage * msg,SoupMessageMetricsType type)3055 soup_message_set_metrics_timestamp (SoupMessage           *msg,
3056                                     SoupMessageMetricsType type)
3057 {
3058         SoupMessageMetrics *metrics = soup_message_get_metrics (msg);
3059         guint64 timestamp;
3060 
3061         if (!metrics)
3062                 return;
3063 
3064         timestamp = g_get_monotonic_time ();
3065         switch (type) {
3066         case SOUP_MESSAGE_METRICS_FETCH_START:
3067                 memset (metrics, 0, sizeof (SoupMessageMetrics));
3068                 metrics->fetch_start = timestamp;
3069                 break;
3070         case SOUP_MESSAGE_METRICS_DNS_START:
3071                 metrics->dns_start = timestamp;
3072                 break;
3073         case SOUP_MESSAGE_METRICS_DNS_END:
3074                 metrics->dns_end = timestamp;
3075                 break;
3076         case SOUP_MESSAGE_METRICS_CONNECT_START:
3077                 metrics->connect_start = timestamp;
3078                 break;
3079         case SOUP_MESSAGE_METRICS_CONNECT_END:
3080                 metrics->connect_end = timestamp;
3081                 break;
3082         case SOUP_MESSAGE_METRICS_TLS_START:
3083                 metrics->tls_start = timestamp;
3084                 break;
3085         case SOUP_MESSAGE_METRICS_REQUEST_START:
3086                 metrics->request_start = timestamp;
3087                 break;
3088         case SOUP_MESSAGE_METRICS_RESPONSE_START:
3089                 /* In case of multiple requests due to a informational response
3090                  * the response start is the first one.
3091                  */
3092                 if (metrics->response_start == 0)
3093                         metrics->response_start = timestamp;
3094                 break;
3095         case SOUP_MESSAGE_METRICS_RESPONSE_END:
3096                 metrics->response_end = timestamp;
3097                 break;
3098         }
3099 }
3100 
3101 void
soup_message_set_request_host_from_uri(SoupMessage * msg,GUri * uri)3102 soup_message_set_request_host_from_uri (SoupMessage *msg,
3103                                         GUri        *uri)
3104 {
3105         SoupMessagePrivate *priv = soup_message_get_instance_private (msg);
3106         char *host;
3107 
3108         if (priv->http_version == SOUP_HTTP_2_0)
3109                 return;
3110 
3111         host = soup_uri_get_host_for_headers (uri);
3112         if (soup_uri_uses_default_port (uri))
3113                 soup_message_headers_replace_common (priv->request_headers, SOUP_HEADER_HOST, host);
3114         else {
3115                 char *value;
3116 
3117                 value = g_strdup_printf ("%s:%d", host, g_uri_get_port (uri));
3118                 soup_message_headers_replace_common (priv->request_headers, SOUP_HEADER_HOST, value);
3119                 g_free (value);
3120         }
3121         g_free (host);
3122 }
3123 
3124 void
soup_message_update_request_host_if_needed(SoupMessage * msg)3125 soup_message_update_request_host_if_needed (SoupMessage *msg)
3126 {
3127         SoupMessagePrivate *priv = soup_message_get_instance_private (msg);
3128 
3129         if (priv->http_version == SOUP_HTTP_2_0)
3130                 return;
3131 
3132         if (soup_message_headers_get_one_common (priv->request_headers, SOUP_HEADER_HOST))
3133                 return;
3134 
3135         soup_message_set_request_host_from_uri (msg, priv->uri);
3136 }
3137 
3138 void
soup_message_force_keep_alive_if_needed(SoupMessage * msg)3139 soup_message_force_keep_alive_if_needed (SoupMessage *msg)
3140 {
3141         SoupMessagePrivate *priv = soup_message_get_instance_private (msg);
3142 
3143         if (priv->http_version == SOUP_HTTP_2_0)
3144                 return;
3145 
3146         /* Force keep alive connections for HTTP 1.0. Performance will
3147          * improve when issuing multiple requests to the same host in
3148          * a short period of time, as we wouldn't need to establish
3149          * new connections. Keep alive is implicit for HTTP 1.1.
3150          */
3151         if (!soup_message_headers_header_contains_common (priv->request_headers, SOUP_HEADER_CONNECTION, "Keep-Alive") &&
3152             !soup_message_headers_header_contains_common (priv->request_headers, SOUP_HEADER_CONNECTION, "close") &&
3153             !soup_message_headers_header_contains_common (priv->request_headers, SOUP_HEADER_CONNECTION, "Upgrade")) {
3154                 soup_message_headers_append_common (priv->request_headers, SOUP_HEADER_CONNECTION, "Keep-Alive");
3155         }
3156 }
3157 
3158 void
soup_message_set_force_http1(SoupMessage * msg,gboolean force_http1)3159 soup_message_set_force_http1 (SoupMessage *msg,
3160                               gboolean     force_http1)
3161 {
3162         SoupMessagePrivate *priv = soup_message_get_instance_private (msg);
3163 
3164         priv->force_http1 = force_http1;
3165 }
3166 
3167 gboolean
soup_message_get_force_http1(SoupMessage * msg)3168 soup_message_get_force_http1 (SoupMessage *msg)
3169 {
3170         SoupMessagePrivate *priv = soup_message_get_instance_private (msg);
3171 
3172         return priv->force_http1;
3173 }
3174 
3175 void
soup_message_set_is_misdirected_retry(SoupMessage * msg,gboolean is_misdirected_retry)3176 soup_message_set_is_misdirected_retry (SoupMessage *msg,
3177                                        gboolean     is_misdirected_retry)
3178 {
3179         SoupMessagePrivate *priv = soup_message_get_instance_private (msg);
3180 
3181         priv->is_misdirected_retry = is_misdirected_retry;
3182 }
3183 
3184 gboolean
soup_message_is_misdirected_retry(SoupMessage * msg)3185 soup_message_is_misdirected_retry (SoupMessage *msg)
3186 {
3187         SoupMessagePrivate *priv = soup_message_get_instance_private (msg);
3188 
3189         return priv->is_misdirected_retry;
3190 }
3191