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 (¶m_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 (¶m_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, ¶ms);
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