1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; 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
19 /**
20 * SECTION:soup-message
21 * @short_description: An HTTP request and response.
22 * @see_also: #SoupMessageHeaders, #SoupMessageBody
23 *
24 * A #SoupMessage represents an HTTP message that is being sent or
25 * received.
26 *
27 * For client-side usage, if you are using the traditional
28 * #SoupSession APIs (soup_session_queue_message() and
29 * soup_session_send_message()), you would create a #SoupMessage with
30 * soup_message_new() or soup_message_new_from_uri(), set up its
31 * fields appropriately, and send it. If you are using the newer
32 * #SoupRequest API, you would create a request with
33 * soup_session_request_http() or soup_session_request_http_uri(), and
34 * the returned #SoupRequestHTTP will already have an associated
35 * #SoupMessage that you can retrieve via
36 * soup_request_http_get_message().
37 *
38 * For server-side usage, #SoupServer will create #SoupMessage<!--
39 * -->s automatically for incoming requests, which your application
40 * will receive via handlers.
41 *
42 * Note that libsoup's terminology here does not quite match the HTTP
43 * specification: in RFC 2616, an "HTTP-message" is
44 * <emphasis>either</emphasis> a Request, <emphasis>or</emphasis> a
45 * Response. In libsoup, a #SoupMessage combines both the request and
46 * the response.
47 **/
48
49 /**
50 * SoupMessage:
51 * @method: the HTTP method
52 * @status_code: the HTTP status code
53 * @reason_phrase: the status phrase associated with @status_code
54 * @request_body: the request body
55 * @request_headers: the request headers
56 * @response_body: the response body
57 * @response_headers: the response headers
58 *
59 * Represents an HTTP message being sent or received.
60 *
61 * @status_code will normally be a #SoupStatus value, eg,
62 * %SOUP_STATUS_OK, though of course it might actually be an unknown
63 * status code. @reason_phrase is the actual text returned from the
64 * server, which may or may not correspond to the "standard"
65 * description of @status_code. At any rate, it is almost certainly
66 * not localized, and not very descriptive even if it is in the user's
67 * language; you should not use @reason_phrase in user-visible
68 * messages. Rather, you should look at @status_code, and determine an
69 * end-user-appropriate message based on that and on what you were
70 * trying to do.
71 *
72 * As described in the #SoupMessageBody documentation, the
73 * @request_body and @response_body <literal>data</literal> fields
74 * will not necessarily be filled in at all times. When the body
75 * fields are filled in, they will be terminated with a '\0' byte
76 * (which is not included in the <literal>length</literal>), so you
77 * can use them as ordinary C strings (assuming that you know that the
78 * body doesn't have any other '\0' bytes).
79 *
80 * For a client-side #SoupMessage, @request_body's
81 * <literal>data</literal> is usually filled in right before libsoup
82 * writes the request to the network, but you should not count on
83 * this; use soup_message_body_flatten() if you want to ensure that
84 * <literal>data</literal> is filled in. If you are not using
85 * #SoupRequest to read the response, then @response_body's
86 * <literal>data</literal> will be filled in before
87 * #SoupMessage::finished is emitted. (If you are using #SoupRequest,
88 * then the message body is not accumulated by default, so
89 * @response_body's <literal>data</literal> will always be %NULL.)
90 *
91 * For a server-side #SoupMessage, @request_body's %data will be
92 * filled in before #SoupMessage::got_body is emitted.
93 *
94 * To prevent the %data field from being filled in at all (eg, if you
95 * are handling the data from a #SoupMessage::got_chunk, and so don't
96 * need to see it all at the end), call
97 * soup_message_body_set_accumulate() on @response_body or
98 * @request_body as appropriate, passing %FALSE.
99 **/
100
101 G_DEFINE_TYPE_WITH_PRIVATE (SoupMessage, soup_message, G_TYPE_OBJECT)
102
103 enum {
104 WROTE_INFORMATIONAL,
105 WROTE_HEADERS,
106 WROTE_CHUNK,
107 WROTE_BODY_DATA,
108 WROTE_BODY,
109
110 GOT_INFORMATIONAL,
111 GOT_HEADERS,
112 GOT_CHUNK,
113 GOT_BODY,
114 CONTENT_SNIFFED,
115
116 STARTING,
117 RESTARTED,
118 FINISHED,
119
120 NETWORK_EVENT,
121
122 LAST_SIGNAL
123 };
124
125 static guint signals[LAST_SIGNAL] = { 0 };
126
127 enum {
128 PROP_0,
129
130 PROP_METHOD,
131 PROP_URI,
132 PROP_HTTP_VERSION,
133 PROP_FLAGS,
134 PROP_SERVER_SIDE,
135 PROP_STATUS_CODE,
136 PROP_REASON_PHRASE,
137 PROP_FIRST_PARTY,
138 PROP_REQUEST_BODY,
139 PROP_REQUEST_BODY_DATA,
140 PROP_REQUEST_HEADERS,
141 PROP_RESPONSE_BODY,
142 PROP_RESPONSE_BODY_DATA,
143 PROP_RESPONSE_HEADERS,
144 PROP_TLS_CERTIFICATE,
145 PROP_TLS_ERRORS,
146 PROP_PRIORITY,
147 PROP_SITE_FOR_COOKIES,
148 PROP_IS_TOP_LEVEL_NAVIGATION,
149
150 LAST_PROP
151 };
152
153 static void
soup_message_init(SoupMessage * msg)154 soup_message_init (SoupMessage *msg)
155 {
156 SoupMessagePrivate *priv = soup_message_get_instance_private (msg);
157
158 priv->http_version = priv->orig_http_version = SOUP_HTTP_1_1;
159 priv->priority = SOUP_MESSAGE_PRIORITY_NORMAL;
160
161 msg->request_body = soup_message_body_new ();
162 msg->request_headers = soup_message_headers_new (SOUP_MESSAGE_HEADERS_REQUEST);
163 msg->response_body = soup_message_body_new ();
164 msg->response_headers = soup_message_headers_new (SOUP_MESSAGE_HEADERS_RESPONSE);
165 }
166
167 static void
soup_message_finalize(GObject * object)168 soup_message_finalize (GObject *object)
169 {
170 SoupMessage *msg = SOUP_MESSAGE (object);
171 SoupMessagePrivate *priv = soup_message_get_instance_private (msg);
172
173 soup_message_io_cleanup (msg);
174 if (priv->chunk_allocator_dnotify)
175 priv->chunk_allocator_dnotify (priv->chunk_allocator_data);
176
177 g_clear_pointer (&priv->uri, soup_uri_free);
178 g_clear_pointer (&priv->first_party, soup_uri_free);
179 g_clear_pointer (&priv->site_for_cookies, soup_uri_free);
180 g_clear_object (&priv->addr);
181
182 g_clear_object (&priv->auth);
183 g_clear_object (&priv->proxy_auth);
184
185 g_clear_pointer (&priv->disabled_features, g_hash_table_destroy);
186
187 g_clear_object (&priv->tls_certificate);
188
189 soup_message_body_free (msg->request_body);
190 soup_message_headers_free (msg->request_headers);
191 soup_message_body_free (msg->response_body);
192 soup_message_headers_free (msg->response_headers);
193
194 g_free (msg->reason_phrase);
195
196 G_OBJECT_CLASS (soup_message_parent_class)->finalize (object);
197 }
198
199 static void
soup_message_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)200 soup_message_set_property (GObject *object, guint prop_id,
201 const GValue *value, GParamSpec *pspec)
202 {
203 SoupMessage *msg = SOUP_MESSAGE (object);
204 SoupMessagePrivate *priv = soup_message_get_instance_private (msg);
205
206 switch (prop_id) {
207 case PROP_METHOD:
208 msg->method = g_intern_string (g_value_get_string (value));
209 break;
210 case PROP_URI:
211 soup_message_set_uri (msg, g_value_get_boxed (value));
212 break;
213 case PROP_SITE_FOR_COOKIES:
214 soup_message_set_site_for_cookies (msg, g_value_get_boxed (value));
215 break;
216 case PROP_IS_TOP_LEVEL_NAVIGATION:
217 soup_message_set_is_top_level_navigation (msg, g_value_get_boolean (value));
218 break;
219 case PROP_HTTP_VERSION:
220 soup_message_set_http_version (msg, g_value_get_enum (value));
221 break;
222 case PROP_FLAGS:
223 soup_message_set_flags (msg, g_value_get_flags (value));
224 break;
225 case PROP_SERVER_SIDE:
226 priv->server_side = g_value_get_boolean (value);
227 if (priv->server_side) {
228 soup_message_headers_set_encoding (msg->response_headers,
229 SOUP_ENCODING_CONTENT_LENGTH);
230 }
231 break;
232 case PROP_STATUS_CODE:
233 soup_message_set_status (msg, g_value_get_uint (value));
234 break;
235 case PROP_REASON_PHRASE:
236 soup_message_set_status_full (msg, msg->status_code,
237 g_value_get_string (value));
238 break;
239 case PROP_FIRST_PARTY:
240 soup_message_set_first_party (msg, g_value_get_boxed (value));
241 break;
242 case PROP_TLS_CERTIFICATE:
243 if (priv->tls_certificate)
244 g_object_unref (priv->tls_certificate);
245 priv->tls_certificate = g_value_dup_object (value);
246 if (priv->tls_errors)
247 priv->msg_flags &= ~SOUP_MESSAGE_CERTIFICATE_TRUSTED;
248 else if (priv->tls_certificate)
249 priv->msg_flags |= SOUP_MESSAGE_CERTIFICATE_TRUSTED;
250 break;
251 case PROP_TLS_ERRORS:
252 priv->tls_errors = g_value_get_flags (value);
253 if (priv->tls_errors)
254 priv->msg_flags &= ~SOUP_MESSAGE_CERTIFICATE_TRUSTED;
255 else if (priv->tls_certificate)
256 priv->msg_flags |= SOUP_MESSAGE_CERTIFICATE_TRUSTED;
257 break;
258 case PROP_PRIORITY:
259 priv->priority = g_value_get_enum (value);
260 break;
261 default:
262 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
263 break;
264 }
265 }
266
267 static void
soup_message_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)268 soup_message_get_property (GObject *object, guint prop_id,
269 GValue *value, GParamSpec *pspec)
270 {
271 SoupMessage *msg = SOUP_MESSAGE (object);
272 SoupMessagePrivate *priv = soup_message_get_instance_private (msg);
273 SoupBuffer *buf;
274
275 switch (prop_id) {
276 case PROP_METHOD:
277 g_value_set_string (value, msg->method);
278 break;
279 case PROP_URI:
280 g_value_set_boxed (value, priv->uri);
281 break;
282 case PROP_SITE_FOR_COOKIES:
283 g_value_set_boxed (value, priv->site_for_cookies);
284 break;
285 case PROP_IS_TOP_LEVEL_NAVIGATION:
286 g_value_set_boolean (value, priv->is_top_level_navigation);
287 break;
288 case PROP_HTTP_VERSION:
289 g_value_set_enum (value, priv->http_version);
290 break;
291 case PROP_FLAGS:
292 g_value_set_flags (value, priv->msg_flags);
293 break;
294 case PROP_SERVER_SIDE:
295 g_value_set_boolean (value, priv->server_side);
296 break;
297 case PROP_STATUS_CODE:
298 g_value_set_uint (value, msg->status_code);
299 break;
300 case PROP_REASON_PHRASE:
301 g_value_set_string (value, msg->reason_phrase);
302 break;
303 case PROP_FIRST_PARTY:
304 g_value_set_boxed (value, priv->first_party);
305 break;
306 case PROP_REQUEST_BODY:
307 g_value_set_boxed (value, msg->request_body);
308 break;
309 case PROP_REQUEST_BODY_DATA:
310 buf = soup_message_body_flatten (msg->request_body);
311 g_value_take_boxed (value, soup_buffer_get_as_bytes (buf));
312 soup_buffer_free (buf);
313 break;
314 case PROP_REQUEST_HEADERS:
315 g_value_set_boxed (value, msg->request_headers);
316 break;
317 case PROP_RESPONSE_BODY:
318 g_value_set_boxed (value, msg->response_body);
319 break;
320 case PROP_RESPONSE_BODY_DATA:
321 buf = soup_message_body_flatten (msg->response_body);
322 g_value_take_boxed (value, soup_buffer_get_as_bytes (buf));
323 soup_buffer_free (buf);
324 break;
325 case PROP_RESPONSE_HEADERS:
326 g_value_set_boxed (value, msg->response_headers);
327 break;
328 case PROP_TLS_CERTIFICATE:
329 g_value_set_object (value, priv->tls_certificate);
330 break;
331 case PROP_TLS_ERRORS:
332 g_value_set_flags (value, priv->tls_errors);
333 break;
334 case PROP_PRIORITY:
335 g_value_set_enum (value, priv->priority);
336 break;
337 default:
338 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
339 break;
340 }
341 }
342
343 static void
soup_message_real_got_body(SoupMessage * msg)344 soup_message_real_got_body (SoupMessage *msg)
345 {
346 SoupMessagePrivate *priv = soup_message_get_instance_private (msg);
347 SoupMessageBody *body;
348
349 body = priv->server_side ? msg->request_body : msg->response_body;
350 if (soup_message_body_get_accumulate (body)) {
351 SoupBuffer *buffer;
352
353 buffer = soup_message_body_flatten (body);
354 soup_buffer_free (buffer);
355 }
356 }
357
358 static void
soup_message_class_init(SoupMessageClass * message_class)359 soup_message_class_init (SoupMessageClass *message_class)
360 {
361 GObjectClass *object_class = G_OBJECT_CLASS (message_class);
362
363 /* virtual method definition */
364 message_class->got_body = soup_message_real_got_body;
365
366 /* virtual method override */
367 object_class->finalize = soup_message_finalize;
368 object_class->set_property = soup_message_set_property;
369 object_class->get_property = soup_message_get_property;
370
371 /* signals */
372
373 /**
374 * SoupMessage::wrote-informational:
375 * @msg: the message
376 *
377 * Emitted immediately after writing a 1xx (Informational)
378 * response for a (server-side) message.
379 **/
380 signals[WROTE_INFORMATIONAL] =
381 g_signal_new ("wrote_informational",
382 G_OBJECT_CLASS_TYPE (object_class),
383 G_SIGNAL_RUN_FIRST,
384 G_STRUCT_OFFSET (SoupMessageClass, wrote_informational),
385 NULL, NULL,
386 NULL,
387 G_TYPE_NONE, 0);
388
389 /**
390 * SoupMessage::wrote-headers:
391 * @msg: the message
392 *
393 * Emitted immediately after writing the headers for a
394 * message. (For a client-side message, this is after writing
395 * the request headers; for a server-side message, it is after
396 * writing the response headers.)
397 **/
398 signals[WROTE_HEADERS] =
399 g_signal_new ("wrote_headers",
400 G_OBJECT_CLASS_TYPE (object_class),
401 G_SIGNAL_RUN_FIRST,
402 G_STRUCT_OFFSET (SoupMessageClass, wrote_headers),
403 NULL, NULL,
404 NULL,
405 G_TYPE_NONE, 0);
406
407 /**
408 * SoupMessage::wrote-chunk:
409 * @msg: the message
410 *
411 * Emitted immediately after writing a body chunk for a message.
412 *
413 * Note that this signal is not parallel to
414 * #SoupMessage::got_chunk; it is emitted only when a complete
415 * chunk (added with soup_message_body_append() or
416 * soup_message_body_append_buffer()) has been written. To get
417 * more useful continuous progress information, use
418 * #SoupMessage::wrote_body_data.
419 **/
420 signals[WROTE_CHUNK] =
421 g_signal_new ("wrote_chunk",
422 G_OBJECT_CLASS_TYPE (object_class),
423 G_SIGNAL_RUN_FIRST,
424 G_STRUCT_OFFSET (SoupMessageClass, wrote_chunk),
425 NULL, NULL,
426 NULL,
427 G_TYPE_NONE, 0);
428
429 /**
430 * SoupMessage::wrote-body-data:
431 * @msg: the message
432 * @chunk: the data written
433 *
434 * Emitted immediately after writing a portion of the message
435 * body to the network.
436 *
437 * Unlike #SoupMessage::wrote_chunk, this is emitted after
438 * every successful write() call, not only after finishing a
439 * complete "chunk".
440 *
441 * Since: 2.24
442 **/
443 signals[WROTE_BODY_DATA] =
444 g_signal_new ("wrote_body_data",
445 G_OBJECT_CLASS_TYPE (object_class),
446 G_SIGNAL_RUN_FIRST,
447 0, /* FIXME after next ABI break */
448 NULL, NULL,
449 NULL,
450 G_TYPE_NONE, 1,
451 SOUP_TYPE_BUFFER);
452
453 /**
454 * SoupMessage::wrote-body:
455 * @msg: the message
456 *
457 * Emitted immediately after writing the complete body for a
458 * message. (For a client-side message, this means that
459 * libsoup is done writing and is now waiting for the response
460 * from the server. For a server-side message, this means that
461 * libsoup has finished writing the response and is nearly
462 * done with the message.)
463 **/
464 signals[WROTE_BODY] =
465 g_signal_new ("wrote_body",
466 G_OBJECT_CLASS_TYPE (object_class),
467 G_SIGNAL_RUN_FIRST,
468 G_STRUCT_OFFSET (SoupMessageClass, wrote_body),
469 NULL, NULL,
470 NULL,
471 G_TYPE_NONE, 0);
472
473 /**
474 * SoupMessage::got-informational:
475 * @msg: the message
476 *
477 * Emitted after receiving a 1xx (Informational) response for
478 * a (client-side) message. The response_headers will be
479 * filled in with the headers associated with the
480 * informational response; however, those header values will
481 * be erased after this signal is done.
482 *
483 * If you cancel or requeue @msg while processing this signal,
484 * then the current HTTP I/O will be stopped after this signal
485 * emission finished, and @msg's connection will be closed.
486 **/
487 signals[GOT_INFORMATIONAL] =
488 g_signal_new ("got_informational",
489 G_OBJECT_CLASS_TYPE (object_class),
490 G_SIGNAL_RUN_FIRST,
491 G_STRUCT_OFFSET (SoupMessageClass, got_informational),
492 NULL, NULL,
493 NULL,
494 G_TYPE_NONE, 0);
495
496 /**
497 * SoupMessage::got-headers:
498 * @msg: the message
499 *
500 * Emitted after receiving all message headers for a message.
501 * (For a client-side message, this is after receiving the
502 * Status-Line and response headers; for a server-side
503 * message, it is after receiving the Request-Line and request
504 * headers.)
505 *
506 * See also soup_message_add_header_handler() and
507 * soup_message_add_status_code_handler(), which can be used
508 * to connect to a subset of emissions of this signal.
509 *
510 * If you cancel or requeue @msg while processing this signal,
511 * then the current HTTP I/O will be stopped after this signal
512 * emission finished, and @msg's connection will be closed.
513 * (If you need to requeue a message--eg, after handling
514 * authentication or redirection--it is usually better to
515 * requeue it from a #SoupMessage::got_body handler rather
516 * than a #SoupMessage::got_headers handler, so that the
517 * existing HTTP connection can be reused.)
518 **/
519 signals[GOT_HEADERS] =
520 g_signal_new ("got_headers",
521 G_OBJECT_CLASS_TYPE (object_class),
522 G_SIGNAL_RUN_FIRST,
523 G_STRUCT_OFFSET (SoupMessageClass, got_headers),
524 NULL, NULL,
525 NULL,
526 G_TYPE_NONE, 0);
527
528 /**
529 * SoupMessage::got-chunk:
530 * @msg: the message
531 * @chunk: the just-read chunk
532 *
533 * Emitted after receiving a chunk of a message body. Note
534 * that "chunk" in this context means any subpiece of the
535 * body, not necessarily the specific HTTP 1.1 chunks sent by
536 * the other side.
537 *
538 * If you cancel or requeue @msg while processing this signal,
539 * then the current HTTP I/O will be stopped after this signal
540 * emission finished, and @msg's connection will be closed.
541 **/
542 signals[GOT_CHUNK] =
543 g_signal_new ("got_chunk",
544 G_OBJECT_CLASS_TYPE (object_class),
545 G_SIGNAL_RUN_FIRST,
546 G_STRUCT_OFFSET (SoupMessageClass, got_chunk),
547 NULL, NULL,
548 NULL,
549 G_TYPE_NONE, 1,
550 /* Use %G_SIGNAL_TYPE_STATIC_SCOPE so that
551 * the %SOUP_MEMORY_TEMPORARY buffers used
552 * by soup-message-io.c when emitting this
553 * signal don't get forcibly copied by
554 * g_signal_emit().
555 */
556 SOUP_TYPE_BUFFER | G_SIGNAL_TYPE_STATIC_SCOPE);
557
558 /**
559 * SoupMessage::got-body:
560 * @msg: the message
561 *
562 * Emitted after receiving the complete message body. (For a
563 * server-side message, this means it has received the request
564 * body. For a client-side message, this means it has received
565 * the response body and is nearly done with the message.)
566 *
567 * See also soup_message_add_header_handler() and
568 * soup_message_add_status_code_handler(), which can be used
569 * to connect to a subset of emissions of this signal.
570 **/
571 signals[GOT_BODY] =
572 g_signal_new ("got_body",
573 G_OBJECT_CLASS_TYPE (object_class),
574 G_SIGNAL_RUN_FIRST,
575 G_STRUCT_OFFSET (SoupMessageClass, got_body),
576 NULL, NULL,
577 NULL,
578 G_TYPE_NONE, 0);
579
580 /**
581 * SoupMessage::content-sniffed:
582 * @msg: the message
583 * @type: the content type that we got from sniffing
584 * @params: (element-type utf8 utf8): a #GHashTable with the parameters
585 *
586 * This signal is emitted after #SoupMessage::got-headers, and
587 * before the first #SoupMessage::got-chunk. If content
588 * sniffing is disabled, or no content sniffing will be
589 * performed, due to the sniffer deciding to trust the
590 * Content-Type sent by the server, this signal is emitted
591 * immediately after #SoupMessage::got-headers, and @type is
592 * %NULL.
593 *
594 * If the #SoupContentSniffer feature is enabled, and the
595 * sniffer decided to perform sniffing, the first
596 * #SoupMessage::got-chunk emission may be delayed, so that the
597 * sniffer has enough data to correctly sniff the content. It
598 * notified the library user that the content has been
599 * sniffed, and allows it to change the header contents in the
600 * message, if desired.
601 *
602 * After this signal is emitted, the data that was spooled so
603 * that sniffing could be done is delivered on the first
604 * emission of #SoupMessage::got-chunk.
605 *
606 * Since: 2.28
607 **/
608 signals[CONTENT_SNIFFED] =
609 g_signal_new ("content_sniffed",
610 G_OBJECT_CLASS_TYPE (object_class),
611 G_SIGNAL_RUN_FIRST,
612 0,
613 NULL, NULL,
614 NULL,
615 G_TYPE_NONE, 2,
616 G_TYPE_STRING,
617 G_TYPE_HASH_TABLE);
618
619 /**
620 * SoupMessage::starting:
621 * @msg: the message
622 *
623 * Emitted just before a message is sent.
624 *
625 * Since: 2.50
626 */
627 signals[STARTING] =
628 g_signal_new ("starting",
629 G_OBJECT_CLASS_TYPE (object_class),
630 G_SIGNAL_RUN_FIRST,
631 G_STRUCT_OFFSET (SoupMessageClass, starting),
632 NULL, NULL,
633 NULL,
634 G_TYPE_NONE, 0);
635
636 /**
637 * SoupMessage::restarted:
638 * @msg: the message
639 *
640 * Emitted when a request that was already sent once is now
641 * being sent again (eg, because the first attempt received a
642 * redirection response, or because we needed to use
643 * authentication).
644 **/
645 signals[RESTARTED] =
646 g_signal_new ("restarted",
647 G_OBJECT_CLASS_TYPE (object_class),
648 G_SIGNAL_RUN_FIRST,
649 G_STRUCT_OFFSET (SoupMessageClass, restarted),
650 NULL, NULL,
651 NULL,
652 G_TYPE_NONE, 0);
653
654 /**
655 * SoupMessage::finished:
656 * @msg: the message
657 *
658 * Emitted when all HTTP processing is finished for a message.
659 * (After #SoupMessage::got_body for client-side messages, or
660 * after #SoupMessage::wrote_body for server-side messages.)
661 **/
662 signals[FINISHED] =
663 g_signal_new ("finished",
664 G_OBJECT_CLASS_TYPE (object_class),
665 G_SIGNAL_RUN_FIRST,
666 G_STRUCT_OFFSET (SoupMessageClass, finished),
667 NULL, NULL,
668 NULL,
669 G_TYPE_NONE, 0);
670
671 /**
672 * SoupMessage::network-event:
673 * @msg: the message
674 * @event: the network event
675 * @connection: the current state of the network connection
676 *
677 * Emitted to indicate that some network-related event
678 * related to @msg has occurred. This essentially proxies the
679 * #GSocketClient::event signal, but only for events that
680 * occur while @msg "owns" the connection; if @msg is sent on
681 * an existing persistent connection, then this signal will
682 * not be emitted. (If you want to force the message to be
683 * sent on a new connection, set the
684 * %SOUP_MESSAGE_NEW_CONNECTION flag on it.)
685 *
686 * See #GSocketClient::event for more information on what
687 * the different values of @event correspond to, and what
688 * @connection will be in each case.
689 *
690 * Since: 2.38
691 **/
692 signals[NETWORK_EVENT] =
693 g_signal_new ("network_event",
694 G_OBJECT_CLASS_TYPE (object_class),
695 G_SIGNAL_RUN_FIRST,
696 0,
697 NULL, NULL,
698 NULL,
699 G_TYPE_NONE, 2,
700 G_TYPE_SOCKET_CLIENT_EVENT,
701 G_TYPE_IO_STREAM);
702
703 /* properties */
704 /**
705 * SOUP_MESSAGE_METHOD:
706 *
707 * Alias for the #SoupMessage:method property. (The message's
708 * HTTP method.)
709 **/
710 g_object_class_install_property (
711 object_class, PROP_METHOD,
712 g_param_spec_string (SOUP_MESSAGE_METHOD,
713 "Method",
714 "The message's HTTP method",
715 SOUP_METHOD_GET,
716 G_PARAM_READWRITE |
717 G_PARAM_STATIC_STRINGS));
718 /**
719 * SOUP_MESSAGE_URI:
720 *
721 * Alias for the #SoupMessage:uri property. (The message's
722 * #SoupURI.)
723 **/
724 g_object_class_install_property (
725 object_class, PROP_URI,
726 g_param_spec_boxed (SOUP_MESSAGE_URI,
727 "URI",
728 "The message's Request-URI",
729 SOUP_TYPE_URI,
730 G_PARAM_READWRITE |
731 G_PARAM_STATIC_STRINGS));
732 /**
733 * SOUP_MESSAGE_HTTP_VERSION:
734 *
735 * Alias for the #SoupMessage:http-version property. (The
736 * message's #SoupHTTPVersion.)
737 **/
738 g_object_class_install_property (
739 object_class, PROP_HTTP_VERSION,
740 g_param_spec_enum (SOUP_MESSAGE_HTTP_VERSION,
741 "HTTP Version",
742 "The HTTP protocol version to use",
743 SOUP_TYPE_HTTP_VERSION,
744 SOUP_HTTP_1_1,
745 G_PARAM_READWRITE |
746 G_PARAM_STATIC_STRINGS));
747 /**
748 * SOUP_MESSAGE_FLAGS:
749 *
750 * Alias for the #SoupMessage:flags property. (The message's
751 * #SoupMessageFlags.)
752 **/
753 g_object_class_install_property (
754 object_class, PROP_FLAGS,
755 g_param_spec_flags (SOUP_MESSAGE_FLAGS,
756 "Flags",
757 "Various message options",
758 SOUP_TYPE_MESSAGE_FLAGS,
759 0,
760 G_PARAM_READWRITE |
761 G_PARAM_STATIC_STRINGS));
762 /**
763 * SOUP_MESSAGE_SERVER_SIDE:
764 *
765 * Alias for the #SoupMessage:server-side property. (%TRUE if
766 * the message was created by #SoupServer.)
767 **/
768 g_object_class_install_property (
769 object_class, PROP_SERVER_SIDE,
770 g_param_spec_boolean (SOUP_MESSAGE_SERVER_SIDE,
771 "Server-side",
772 "Whether or not the message is server-side rather than client-side",
773 FALSE,
774 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
775 G_PARAM_STATIC_STRINGS));
776 /**
777 * SOUP_MESSAGE_STATUS_CODE:
778 *
779 * Alias for the #SoupMessage:status-code property. (The
780 * message's HTTP response status code.)
781 **/
782 g_object_class_install_property (
783 object_class, PROP_STATUS_CODE,
784 g_param_spec_uint (SOUP_MESSAGE_STATUS_CODE,
785 "Status code",
786 "The HTTP response status code",
787 0, 999, 0,
788 G_PARAM_READWRITE |
789 G_PARAM_STATIC_STRINGS));
790 /**
791 * SOUP_MESSAGE_REASON_PHRASE:
792 *
793 * Alias for the #SoupMessage:reason-phrase property. (The
794 * message's HTTP response reason phrase.)
795 **/
796 g_object_class_install_property (
797 object_class, PROP_REASON_PHRASE,
798 g_param_spec_string (SOUP_MESSAGE_REASON_PHRASE,
799 "Reason phrase",
800 "The HTTP response reason phrase",
801 NULL,
802 G_PARAM_READWRITE |
803 G_PARAM_STATIC_STRINGS));
804 /**
805 * SOUP_MESSAGE_FIRST_PARTY:
806 *
807 * Alias for the #SoupMessage:first-party property. (The
808 * #SoupURI loaded in the application when the message was
809 * queued.)
810 *
811 * Since: 2.30
812 **/
813 /**
814 * SoupMessage:first-party:
815 *
816 * The #SoupURI loaded in the application when the message was
817 * queued.
818 *
819 * Since: 2.30
820 */
821 g_object_class_install_property (
822 object_class, PROP_FIRST_PARTY,
823 g_param_spec_boxed (SOUP_MESSAGE_FIRST_PARTY,
824 "First party",
825 "The URI loaded in the application when the message was requested.",
826 SOUP_TYPE_URI,
827 G_PARAM_READWRITE |
828 G_PARAM_STATIC_STRINGS));
829 /**
830 * SoupMessage:site-for-cookkies:
831 *
832 * Site used to compare cookies against. Used for SameSite cookie support.
833 *
834 * Since: 2.70
835 */
836 g_object_class_install_property (
837 object_class, PROP_SITE_FOR_COOKIES,
838 g_param_spec_boxed (SOUP_MESSAGE_SITE_FOR_COOKIES,
839 "Site for cookies",
840 "The URI for the site to compare cookies against",
841 SOUP_TYPE_URI,
842 G_PARAM_READWRITE));
843 /**
844 * SoupMessage:is-top-level-navigation:
845 *
846 * Set when the message is navigating between top level domains.
847 *
848 * Since: 2.70
849 */
850 g_object_class_install_property (
851 object_class, PROP_IS_TOP_LEVEL_NAVIGATION,
852 g_param_spec_boolean (SOUP_MESSAGE_IS_TOP_LEVEL_NAVIGATION,
853 "Is top-level navigation",
854 "If the current messsage is navigating between top-levels",
855 FALSE,
856 G_PARAM_READWRITE));
857 /**
858 * SOUP_MESSAGE_REQUEST_BODY:
859 *
860 * Alias for the #SoupMessage:request-body property. (The
861 * message's HTTP request body.)
862 **/
863 g_object_class_install_property (
864 object_class, PROP_REQUEST_BODY,
865 g_param_spec_boxed (SOUP_MESSAGE_REQUEST_BODY,
866 "Request Body",
867 "The HTTP request content",
868 SOUP_TYPE_MESSAGE_BODY,
869 G_PARAM_READABLE |
870 G_PARAM_STATIC_STRINGS));
871 /**
872 * SOUP_MESSAGE_REQUEST_BODY_DATA:
873 *
874 * Alias for the #SoupMessage:request-body-data property. (The
875 * message's HTTP request body, as a #GBytes.)
876 *
877 * Since: 2.46
878 **/
879 /**
880 * SoupMessage:request-body-data:
881 *
882 * The message's HTTP request body, as a #GBytes.
883 *
884 * Since: 2.46
885 **/
886 g_object_class_install_property (
887 object_class, PROP_REQUEST_BODY_DATA,
888 g_param_spec_boxed (SOUP_MESSAGE_REQUEST_BODY_DATA,
889 "Request Body Data",
890 "The HTTP request body",
891 G_TYPE_BYTES,
892 G_PARAM_READABLE |
893 G_PARAM_STATIC_STRINGS));
894 /**
895 * SOUP_MESSAGE_REQUEST_HEADERS:
896 *
897 * Alias for the #SoupMessage:request-headers property. (The
898 * message's HTTP request headers.)
899 **/
900 g_object_class_install_property (
901 object_class, PROP_REQUEST_HEADERS,
902 g_param_spec_boxed (SOUP_MESSAGE_REQUEST_HEADERS,
903 "Request Headers",
904 "The HTTP request headers",
905 SOUP_TYPE_MESSAGE_HEADERS,
906 G_PARAM_READABLE |
907 G_PARAM_STATIC_STRINGS));
908 /**
909 * SOUP_MESSAGE_RESPONSE_BODY:
910 *
911 * Alias for the #SoupMessage:response-body property. (The
912 * message's HTTP response body.)
913 **/
914 g_object_class_install_property (
915 object_class, PROP_RESPONSE_BODY,
916 g_param_spec_boxed (SOUP_MESSAGE_RESPONSE_BODY,
917 "Response Body",
918 "The HTTP response content",
919 SOUP_TYPE_MESSAGE_BODY,
920 G_PARAM_READABLE |
921 G_PARAM_STATIC_STRINGS));
922 /**
923 * SOUP_MESSAGE_RESPONSE_BODY_DATA:
924 *
925 * Alias for the #SoupMessage:response-body-data property. (The
926 * message's HTTP response body, as a #GBytes.)
927 *
928 * Since: 2.46
929 **/
930 /**
931 * SoupMessage:response-body-data:
932 *
933 * The message's HTTP response body, as a #GBytes.
934 *
935 * Since: 2.46
936 **/
937 g_object_class_install_property (
938 object_class, PROP_RESPONSE_BODY_DATA,
939 g_param_spec_boxed (SOUP_MESSAGE_RESPONSE_BODY_DATA,
940 "Response Body Data",
941 "The HTTP response body",
942 G_TYPE_BYTES,
943 G_PARAM_READABLE |
944 G_PARAM_STATIC_STRINGS));
945 /**
946 * SOUP_MESSAGE_RESPONSE_HEADERS:
947 *
948 * Alias for the #SoupMessage:response-headers property. (The
949 * message's HTTP response headers.)
950 **/
951 g_object_class_install_property (
952 object_class, PROP_RESPONSE_HEADERS,
953 g_param_spec_boxed (SOUP_MESSAGE_RESPONSE_HEADERS,
954 "Response Headers",
955 "The HTTP response headers",
956 SOUP_TYPE_MESSAGE_HEADERS,
957 G_PARAM_READABLE |
958 G_PARAM_STATIC_STRINGS));
959 /**
960 * SOUP_MESSAGE_TLS_CERTIFICATE:
961 *
962 * Alias for the #SoupMessage:tls-certificate property. (The
963 * TLS certificate associated with the message, if any.)
964 *
965 * Since: 2.34
966 **/
967 /**
968 * SoupMessage:tls-certificate:
969 *
970 * The #GTlsCertificate associated with the message
971 *
972 * Since: 2.34
973 */
974 g_object_class_install_property (
975 object_class, PROP_TLS_CERTIFICATE,
976 g_param_spec_object (SOUP_MESSAGE_TLS_CERTIFICATE,
977 "TLS Certificate",
978 "The TLS certificate associated with the message",
979 G_TYPE_TLS_CERTIFICATE,
980 G_PARAM_READWRITE |
981 G_PARAM_STATIC_STRINGS));
982 /**
983 * SOUP_MESSAGE_TLS_ERRORS:
984 *
985 * Alias for the #SoupMessage:tls-errors property. (The
986 * verification errors on #SoupMessage:tls-certificate.)
987 *
988 * Since: 2.34
989 **/
990 /**
991 * SoupMessage:tls-errors:
992 *
993 * The verification errors on #SoupMessage:tls-certificate
994 *
995 * Since: 2.34
996 */
997 g_object_class_install_property (
998 object_class, PROP_TLS_ERRORS,
999 g_param_spec_flags (SOUP_MESSAGE_TLS_ERRORS,
1000 "TLS Errors",
1001 "The verification errors on the message's TLS certificate",
1002 G_TYPE_TLS_CERTIFICATE_FLAGS, 0,
1003 G_PARAM_READWRITE |
1004 G_PARAM_STATIC_STRINGS));
1005 /**
1006 * SOUP_MESSAGE_PRIORITY:
1007 *
1008 * Sets the priority of the #SoupMessage. See
1009 * soup_message_set_priority() for further details.
1010 *
1011 * Since: 2.44
1012 **/
1013 g_object_class_install_property (
1014 object_class, PROP_PRIORITY,
1015 g_param_spec_enum (SOUP_MESSAGE_PRIORITY,
1016 "Priority",
1017 "The priority of the message",
1018 SOUP_TYPE_MESSAGE_PRIORITY,
1019 SOUP_MESSAGE_PRIORITY_NORMAL,
1020 G_PARAM_READWRITE |
1021 G_PARAM_STATIC_STRINGS));
1022 }
1023
1024
1025 /**
1026 * soup_message_new:
1027 * @method: the HTTP method for the created request
1028 * @uri_string: the destination endpoint (as a string)
1029 *
1030 * Creates a new empty #SoupMessage, which will connect to @uri
1031 *
1032 * Return value: (nullable): the new #SoupMessage (or %NULL if @uri
1033 * could not be parsed).
1034 */
1035 SoupMessage *
soup_message_new(const char * method,const char * uri_string)1036 soup_message_new (const char *method, const char *uri_string)
1037 {
1038 SoupMessage *msg;
1039 SoupURI *uri;
1040
1041 g_return_val_if_fail (method != NULL, NULL);
1042 g_return_val_if_fail (uri_string != NULL, NULL);
1043
1044 uri = soup_uri_new (uri_string);
1045 if (!uri)
1046 return NULL;
1047 if (!uri->host) {
1048 soup_uri_free (uri);
1049 return NULL;
1050 }
1051
1052 msg = soup_message_new_from_uri (method, uri);
1053 soup_uri_free (uri);
1054 return msg;
1055 }
1056
1057 /**
1058 * soup_message_new_from_uri:
1059 * @method: the HTTP method for the created request
1060 * @uri: the destination endpoint (as a #SoupURI)
1061 *
1062 * Creates a new empty #SoupMessage, which will connect to @uri
1063 *
1064 * Return value: the new #SoupMessage
1065 */
1066 SoupMessage *
soup_message_new_from_uri(const char * method,SoupURI * uri)1067 soup_message_new_from_uri (const char *method, SoupURI *uri)
1068 {
1069 return g_object_new (SOUP_TYPE_MESSAGE,
1070 SOUP_MESSAGE_METHOD, method,
1071 SOUP_MESSAGE_URI, uri,
1072 NULL);
1073 }
1074
1075 /**
1076 * soup_message_set_request:
1077 * @msg: the message
1078 * @content_type: (allow-none): MIME Content-Type of the body
1079 * @req_use: a #SoupMemoryUse describing how to handle @req_body
1080 * @req_body: (allow-none) (array length=req_length) (element-type guint8):
1081 * a data buffer containing the body of the message request.
1082 * @req_length: the byte length of @req_body.
1083 *
1084 * Convenience function to set the request body of a #SoupMessage. If
1085 * @content_type is %NULL, the request body must be empty as well.
1086 */
1087 void
soup_message_set_request(SoupMessage * msg,const char * content_type,SoupMemoryUse req_use,const char * req_body,gsize req_length)1088 soup_message_set_request (SoupMessage *msg,
1089 const char *content_type,
1090 SoupMemoryUse req_use,
1091 const char *req_body,
1092 gsize req_length)
1093 {
1094 g_return_if_fail (SOUP_IS_MESSAGE (msg));
1095 g_return_if_fail (content_type != NULL || req_length == 0);
1096
1097 if (content_type) {
1098 g_warn_if_fail (strchr (content_type, '/') != NULL);
1099
1100 soup_message_headers_replace (msg->request_headers,
1101 "Content-Type", content_type);
1102 soup_message_body_append (msg->request_body, req_use,
1103 req_body, req_length);
1104 } else {
1105 soup_message_headers_remove (msg->request_headers,
1106 "Content-Type");
1107 soup_message_body_truncate (msg->request_body);
1108 }
1109 }
1110
1111 /**
1112 * soup_message_set_response:
1113 * @msg: the message
1114 * @content_type: (allow-none): MIME Content-Type of the body
1115 * @resp_use: a #SoupMemoryUse describing how to handle @resp_body
1116 * @resp_body: (allow-none) (array length=resp_length) (element-type guint8):
1117 * a data buffer containing the body of the message response.
1118 * @resp_length: the byte length of @resp_body.
1119 *
1120 * Convenience function to set the response body of a #SoupMessage. If
1121 * @content_type is %NULL, the response body must be empty as well.
1122 */
1123 void
soup_message_set_response(SoupMessage * msg,const char * content_type,SoupMemoryUse resp_use,const char * resp_body,gsize resp_length)1124 soup_message_set_response (SoupMessage *msg,
1125 const char *content_type,
1126 SoupMemoryUse resp_use,
1127 const char *resp_body,
1128 gsize resp_length)
1129 {
1130 g_return_if_fail (SOUP_IS_MESSAGE (msg));
1131 g_return_if_fail (content_type != NULL || resp_length == 0);
1132
1133 if (content_type) {
1134 g_warn_if_fail (strchr (content_type, '/') != NULL);
1135
1136 soup_message_headers_replace (msg->response_headers,
1137 "Content-Type", content_type);
1138 soup_message_body_append (msg->response_body, resp_use,
1139 resp_body, resp_length);
1140 } else {
1141 soup_message_headers_remove (msg->response_headers,
1142 "Content-Type");
1143 soup_message_body_truncate (msg->response_body);
1144 }
1145 }
1146
1147 void
soup_message_wrote_informational(SoupMessage * msg)1148 soup_message_wrote_informational (SoupMessage *msg)
1149 {
1150 g_signal_emit (msg, signals[WROTE_INFORMATIONAL], 0);
1151 }
1152
1153 void
soup_message_wrote_headers(SoupMessage * msg)1154 soup_message_wrote_headers (SoupMessage *msg)
1155 {
1156 g_signal_emit (msg, signals[WROTE_HEADERS], 0);
1157 }
1158
1159 void
soup_message_wrote_chunk(SoupMessage * msg)1160 soup_message_wrote_chunk (SoupMessage *msg)
1161 {
1162 g_signal_emit (msg, signals[WROTE_CHUNK], 0);
1163 }
1164
1165 void
soup_message_wrote_body_data(SoupMessage * msg,SoupBuffer * chunk)1166 soup_message_wrote_body_data (SoupMessage *msg, SoupBuffer *chunk)
1167 {
1168 g_signal_emit (msg, signals[WROTE_BODY_DATA], 0, chunk);
1169 }
1170
1171 void
soup_message_wrote_body(SoupMessage * msg)1172 soup_message_wrote_body (SoupMessage *msg)
1173 {
1174 g_signal_emit (msg, signals[WROTE_BODY], 0);
1175 }
1176
1177 void
soup_message_got_informational(SoupMessage * msg)1178 soup_message_got_informational (SoupMessage *msg)
1179 {
1180 g_signal_emit (msg, signals[GOT_INFORMATIONAL], 0);
1181 }
1182
1183 void
soup_message_got_headers(SoupMessage * msg)1184 soup_message_got_headers (SoupMessage *msg)
1185 {
1186 g_signal_emit (msg, signals[GOT_HEADERS], 0);
1187 }
1188
1189 void
soup_message_got_chunk(SoupMessage * msg,SoupBuffer * chunk)1190 soup_message_got_chunk (SoupMessage *msg, SoupBuffer *chunk)
1191 {
1192 g_signal_emit (msg, signals[GOT_CHUNK], 0, chunk);
1193 }
1194
1195 void
soup_message_got_body(SoupMessage * msg)1196 soup_message_got_body (SoupMessage *msg)
1197 {
1198 g_signal_emit (msg, signals[GOT_BODY], 0);
1199 }
1200
1201 void
soup_message_content_sniffed(SoupMessage * msg,const char * content_type,GHashTable * params)1202 soup_message_content_sniffed (SoupMessage *msg, const char *content_type, GHashTable *params)
1203 {
1204 g_signal_emit (msg, signals[CONTENT_SNIFFED], 0, content_type, params);
1205 }
1206
1207 void
soup_message_starting(SoupMessage * msg)1208 soup_message_starting (SoupMessage *msg)
1209 {
1210 g_signal_emit (msg, signals[STARTING], 0);
1211 }
1212
1213 void
soup_message_restarted(SoupMessage * msg)1214 soup_message_restarted (SoupMessage *msg)
1215 {
1216 SoupMessagePrivate *priv = soup_message_get_instance_private (msg);
1217
1218 if (priv->msg_flags & SOUP_MESSAGE_CAN_REBUILD)
1219 soup_message_body_truncate (msg->request_body);
1220
1221 g_signal_emit (msg, signals[RESTARTED], 0);
1222 }
1223
1224 void
soup_message_finished(SoupMessage * msg)1225 soup_message_finished (SoupMessage *msg)
1226 {
1227 g_signal_emit (msg, signals[FINISHED], 0);
1228 }
1229
1230 void
soup_message_network_event(SoupMessage * msg,GSocketClientEvent event,GIOStream * connection)1231 soup_message_network_event (SoupMessage *msg,
1232 GSocketClientEvent event,
1233 GIOStream *connection)
1234 {
1235 g_signal_emit (msg, signals[NETWORK_EVENT], 0,
1236 event, connection);
1237 }
1238
1239 static void
header_handler_free(gpointer header_name,GClosure * closure)1240 header_handler_free (gpointer header_name, GClosure *closure)
1241 {
1242 g_free (header_name);
1243 }
1244
1245 static void
header_handler_metamarshal(GClosure * closure,GValue * return_value,guint n_param_values,const GValue * param_values,gpointer invocation_hint,gpointer marshal_data)1246 header_handler_metamarshal (GClosure *closure, GValue *return_value,
1247 guint n_param_values, const GValue *param_values,
1248 gpointer invocation_hint, gpointer marshal_data)
1249 {
1250 SoupMessage *msg = g_value_get_object (¶m_values[0]);
1251 SoupMessagePrivate *priv = soup_message_get_instance_private (msg);
1252 const char *header_name = marshal_data;
1253 SoupMessageHeaders *hdrs;
1254
1255 hdrs = priv->server_side ? msg->request_headers : msg->response_headers;
1256 if (soup_message_headers_get_one (hdrs, header_name)) {
1257 closure->marshal (closure, return_value, n_param_values,
1258 param_values, invocation_hint,
1259 ((GCClosure *)closure)->callback);
1260 }
1261 }
1262
1263 /**
1264 * soup_message_add_header_handler: (skip)
1265 * @msg: a #SoupMessage
1266 * @signal: signal to connect the handler to.
1267 * @header: HTTP response header to match against
1268 * @callback: the header handler
1269 * @user_data: data to pass to @handler_cb
1270 *
1271 * Adds a signal handler to @msg for @signal, as with
1272 * g_signal_connect(), but the @callback will only be run if @msg's
1273 * incoming messages headers (that is, the
1274 * <literal>request_headers</literal> for a client #SoupMessage, or
1275 * the <literal>response_headers</literal> for a server #SoupMessage)
1276 * contain a header named @header.
1277 *
1278 * Return value: the handler ID from g_signal_connect()
1279 **/
1280 guint
soup_message_add_header_handler(SoupMessage * msg,const char * signal,const char * header,GCallback callback,gpointer user_data)1281 soup_message_add_header_handler (SoupMessage *msg,
1282 const char *signal,
1283 const char *header,
1284 GCallback callback,
1285 gpointer user_data)
1286 {
1287 GClosure *closure;
1288 char *header_name;
1289
1290 g_return_val_if_fail (SOUP_IS_MESSAGE (msg), 0);
1291 g_return_val_if_fail (signal != NULL, 0);
1292 g_return_val_if_fail (header != NULL, 0);
1293 g_return_val_if_fail (callback != NULL, 0);
1294
1295 closure = g_cclosure_new (callback, user_data, NULL);
1296
1297 header_name = g_strdup (header);
1298 g_closure_set_meta_marshal (closure, header_name,
1299 header_handler_metamarshal);
1300 g_closure_add_finalize_notifier (closure, header_name,
1301 header_handler_free);
1302
1303 return g_signal_connect_closure (msg, signal, closure, FALSE);
1304 }
1305
1306 static void
status_handler_metamarshal(GClosure * closure,GValue * return_value,guint n_param_values,const GValue * param_values,gpointer invocation_hint,gpointer marshal_data)1307 status_handler_metamarshal (GClosure *closure, GValue *return_value,
1308 guint n_param_values, const GValue *param_values,
1309 gpointer invocation_hint, gpointer marshal_data)
1310 {
1311 SoupMessage *msg = g_value_get_object (¶m_values[0]);
1312 guint status = GPOINTER_TO_UINT (marshal_data);
1313
1314 if (msg->status_code == status) {
1315 closure->marshal (closure, return_value, n_param_values,
1316 param_values, invocation_hint,
1317 ((GCClosure *)closure)->callback);
1318 }
1319 }
1320
1321 /**
1322 * soup_message_add_status_code_handler: (skip)
1323 * @msg: a #SoupMessage
1324 * @signal: signal to connect the handler to.
1325 * @status_code: status code to match against
1326 * @callback: the header handler
1327 * @user_data: data to pass to @handler_cb
1328 *
1329 * Adds a signal handler to @msg for @signal, as with
1330 * g_signal_connect(), but the @callback will only be run if @msg has
1331 * the status @status_code.
1332 *
1333 * @signal must be a signal that will be emitted after @msg's status
1334 * is set. For a client #SoupMessage, this means it can't be a "wrote"
1335 * signal. For a server #SoupMessage, this means it can't be a "got"
1336 * signal.
1337 *
1338 * Return value: the handler ID from g_signal_connect()
1339 **/
1340 guint
soup_message_add_status_code_handler(SoupMessage * msg,const char * signal,guint status_code,GCallback callback,gpointer user_data)1341 soup_message_add_status_code_handler (SoupMessage *msg,
1342 const char *signal,
1343 guint status_code,
1344 GCallback callback,
1345 gpointer user_data)
1346 {
1347 GClosure *closure;
1348
1349 g_return_val_if_fail (SOUP_IS_MESSAGE (msg), 0);
1350 g_return_val_if_fail (signal != NULL, 0);
1351 g_return_val_if_fail (callback != NULL, 0);
1352
1353 closure = g_cclosure_new (callback, user_data, NULL);
1354 g_closure_set_meta_marshal (closure, GUINT_TO_POINTER (status_code),
1355 status_handler_metamarshal);
1356
1357 return g_signal_connect_closure (msg, signal, closure, FALSE);
1358 }
1359
1360
1361 void
soup_message_set_auth(SoupMessage * msg,SoupAuth * auth)1362 soup_message_set_auth (SoupMessage *msg, SoupAuth *auth)
1363 {
1364 SoupMessagePrivate *priv;
1365
1366 g_return_if_fail (SOUP_IS_MESSAGE (msg));
1367 g_return_if_fail (auth == NULL || SOUP_IS_AUTH (auth));
1368
1369 priv = soup_message_get_instance_private (msg);
1370
1371 if (priv->auth == auth)
1372 return;
1373
1374 if (priv->auth)
1375 g_object_unref (priv->auth);
1376 priv->auth = auth ? g_object_ref (auth) : NULL;
1377 }
1378
1379 SoupAuth *
soup_message_get_auth(SoupMessage * msg)1380 soup_message_get_auth (SoupMessage *msg)
1381 {
1382 SoupMessagePrivate *priv;
1383
1384 g_return_val_if_fail (SOUP_IS_MESSAGE (msg), NULL);
1385
1386 priv = soup_message_get_instance_private (msg);
1387
1388 return priv->auth;
1389 }
1390
1391 void
soup_message_set_proxy_auth(SoupMessage * msg,SoupAuth * auth)1392 soup_message_set_proxy_auth (SoupMessage *msg, SoupAuth *auth)
1393 {
1394 SoupMessagePrivate *priv;
1395
1396 g_return_if_fail (SOUP_IS_MESSAGE (msg));
1397 g_return_if_fail (auth == NULL || SOUP_IS_AUTH (auth));
1398
1399 priv = soup_message_get_instance_private (msg);
1400
1401 if (priv->proxy_auth == auth)
1402 return;
1403
1404 if (priv->proxy_auth)
1405 g_object_unref (priv->proxy_auth);
1406 priv->proxy_auth = auth ? g_object_ref (auth) : NULL;
1407 }
1408
1409 SoupAuth *
soup_message_get_proxy_auth(SoupMessage * msg)1410 soup_message_get_proxy_auth (SoupMessage *msg)
1411 {
1412 SoupMessagePrivate *priv;
1413
1414 g_return_val_if_fail (SOUP_IS_MESSAGE (msg), NULL);
1415
1416 priv = soup_message_get_instance_private (msg);
1417
1418 return priv->proxy_auth;
1419 }
1420
1421 SoupConnection *
soup_message_get_connection(SoupMessage * msg)1422 soup_message_get_connection (SoupMessage *msg)
1423 {
1424 SoupMessagePrivate *priv = soup_message_get_instance_private (msg);
1425
1426 return priv->connection;
1427 }
1428
1429 void
soup_message_set_connection(SoupMessage * msg,SoupConnection * conn)1430 soup_message_set_connection (SoupMessage *msg,
1431 SoupConnection *conn)
1432 {
1433 SoupMessagePrivate *priv = soup_message_get_instance_private (msg);
1434
1435 priv->connection = conn;
1436 }
1437
1438 /**
1439 * soup_message_cleanup_response:
1440 * @msg: a #SoupMessage
1441 *
1442 * Cleans up all response data on @msg, so that the request can be sent
1443 * again and receive a new response. (Eg, as a result of a redirect or
1444 * authorization request.)
1445 **/
1446 void
soup_message_cleanup_response(SoupMessage * msg)1447 soup_message_cleanup_response (SoupMessage *msg)
1448 {
1449 SoupMessagePrivate *priv = soup_message_get_instance_private (msg);
1450
1451 soup_message_body_truncate (msg->response_body);
1452 soup_message_headers_clear (msg->response_headers);
1453 if (priv->server_side) {
1454 soup_message_headers_set_encoding (msg->response_headers,
1455 SOUP_ENCODING_CONTENT_LENGTH);
1456 }
1457
1458 priv->msg_flags &= ~SOUP_MESSAGE_CONTENT_DECODED;
1459
1460 msg->status_code = SOUP_STATUS_NONE;
1461 if (msg->reason_phrase) {
1462 g_free (msg->reason_phrase);
1463 msg->reason_phrase = NULL;
1464 }
1465 priv->http_version = priv->orig_http_version;
1466
1467 g_object_notify (G_OBJECT (msg), SOUP_MESSAGE_STATUS_CODE);
1468 g_object_notify (G_OBJECT (msg), SOUP_MESSAGE_REASON_PHRASE);
1469 g_object_notify (G_OBJECT (msg), SOUP_MESSAGE_HTTP_VERSION);
1470 g_object_notify (G_OBJECT (msg), SOUP_MESSAGE_FLAGS);
1471 g_object_notify (G_OBJECT (msg), SOUP_MESSAGE_TLS_CERTIFICATE);
1472 g_object_notify (G_OBJECT (msg), SOUP_MESSAGE_TLS_ERRORS);
1473 }
1474
1475 /**
1476 * SoupMessageFlags:
1477 * @SOUP_MESSAGE_NO_REDIRECT: The session should not follow redirect
1478 * (3xx) responses received by this message.
1479 * @SOUP_MESSAGE_CAN_REBUILD: The caller will rebuild the request
1480 * body if the message is restarted; see
1481 * soup_message_body_set_accumulate() for more details.
1482 * @SOUP_MESSAGE_OVERWRITE_CHUNKS: Deprecated: equivalent to calling
1483 * soup_message_body_set_accumulate() on the incoming message body
1484 * (ie, #SoupMessage:response_body for a client-side request),
1485 * passing %FALSE.
1486 * @SOUP_MESSAGE_CONTENT_DECODED: Set by #SoupContentDecoder to
1487 * indicate that it has removed the Content-Encoding on a message (and
1488 * so headers such as Content-Length may no longer accurately describe
1489 * the body).
1490 * @SOUP_MESSAGE_CERTIFICATE_TRUSTED: if set after an https response
1491 * has been received, indicates that the server's SSL certificate is
1492 * trusted according to the session's CA.
1493 * @SOUP_MESSAGE_NEW_CONNECTION: Requests that the message should be
1494 * sent on a newly-created connection, not reusing an existing
1495 * persistent connection. Note that messages with non-idempotent
1496 * #SoupMessage:method<!-- -->s behave this way by default, unless
1497 * #SOUP_MESSAGE_IDEMPOTENT is set.
1498 * @SOUP_MESSAGE_IDEMPOTENT: The message is considered idempotent,
1499 * regardless its #SoupMessage:method, and allows reuse of existing
1500 * idle connections, instead of always requiring a new one, unless
1501 * #SOUP_MESSAGE_NEW_CONNECTION is set.
1502 * @SOUP_MESSAGE_IGNORE_CONNECTION_LIMITS: Request that a new connection is
1503 * created for the message if there aren't idle connections available
1504 * and it's not possible to create new connections due to any of the
1505 * connection limits has been reached. If a dedicated connection is
1506 * eventually created for this message, it will be dropped when the
1507 * message finishes. Since 2.50
1508 * @SOUP_MESSAGE_DO_NOT_USE_AUTH_CACHE: The #SoupAuthManager should not use
1509 * the credentials cache for this message, neither to use cached credentials
1510 * to automatically authenticate this message nor to cache the credentials
1511 * after the message is successfully authenticated. This applies to both server
1512 * and proxy authentication. Note that #SoupSession::authenticate signal will
1513 * be emitted, if you want to disable authentication for a message use
1514 * soup_message_disable_feature() passing #SOUP_TYPE_AUTH_MANAGER instead. Since 2.58
1515 *
1516 * Various flags that can be set on a #SoupMessage to alter its
1517 * behavior.
1518 **/
1519
1520 /**
1521 * soup_message_set_flags:
1522 * @msg: a #SoupMessage
1523 * @flags: a set of #SoupMessageFlags values
1524 *
1525 * Sets the specified flags on @msg.
1526 **/
1527 void
soup_message_set_flags(SoupMessage * msg,SoupMessageFlags flags)1528 soup_message_set_flags (SoupMessage *msg, SoupMessageFlags flags)
1529 {
1530 SoupMessagePrivate *priv;
1531
1532 g_return_if_fail (SOUP_IS_MESSAGE (msg));
1533 priv = soup_message_get_instance_private (msg);
1534
1535 if ((priv->msg_flags ^ flags) & SOUP_MESSAGE_OVERWRITE_CHUNKS) {
1536 soup_message_body_set_accumulate (
1537 priv->server_side ? msg->request_body : msg->response_body,
1538 !(flags & SOUP_MESSAGE_OVERWRITE_CHUNKS));
1539 }
1540
1541 priv->msg_flags = flags;
1542 g_object_notify (G_OBJECT (msg), SOUP_MESSAGE_FLAGS);
1543 }
1544
1545 /**
1546 * soup_message_get_flags:
1547 * @msg: a #SoupMessage
1548 *
1549 * Gets the flags on @msg
1550 *
1551 * Return value: the flags
1552 **/
1553 SoupMessageFlags
soup_message_get_flags(SoupMessage * msg)1554 soup_message_get_flags (SoupMessage *msg)
1555 {
1556 SoupMessagePrivate *priv;
1557
1558 g_return_val_if_fail (SOUP_IS_MESSAGE (msg), 0);
1559
1560 priv = soup_message_get_instance_private (msg);
1561
1562 return priv->msg_flags;
1563 }
1564
1565 /**
1566 * SoupHTTPVersion:
1567 * @SOUP_HTTP_1_0: HTTP 1.0 (RFC 1945)
1568 * @SOUP_HTTP_1_1: HTTP 1.1 (RFC 2616)
1569 *
1570 * Indicates the HTTP protocol version being used.
1571 **/
1572
1573 /**
1574 * soup_message_set_http_version:
1575 * @msg: a #SoupMessage
1576 * @version: the HTTP version
1577 *
1578 * Sets the HTTP version on @msg. The default version is
1579 * %SOUP_HTTP_1_1. Setting it to %SOUP_HTTP_1_0 will prevent certain
1580 * functionality from being used.
1581 **/
1582 void
soup_message_set_http_version(SoupMessage * msg,SoupHTTPVersion version)1583 soup_message_set_http_version (SoupMessage *msg, SoupHTTPVersion version)
1584 {
1585 SoupMessagePrivate *priv;
1586
1587 g_return_if_fail (SOUP_IS_MESSAGE (msg));
1588 priv = soup_message_get_instance_private (msg);
1589
1590 priv->http_version = version;
1591 if (msg->status_code == SOUP_STATUS_NONE)
1592 priv->orig_http_version = version;
1593 g_object_notify (G_OBJECT (msg), SOUP_MESSAGE_HTTP_VERSION);
1594 }
1595
1596 /**
1597 * soup_message_get_http_version:
1598 * @msg: a #SoupMessage
1599 *
1600 * Gets the HTTP version of @msg. This is the minimum of the
1601 * version from the request and the version from the response.
1602 *
1603 * Return value: the HTTP version
1604 **/
1605 SoupHTTPVersion
soup_message_get_http_version(SoupMessage * msg)1606 soup_message_get_http_version (SoupMessage *msg)
1607 {
1608 SoupMessagePrivate *priv;
1609
1610 g_return_val_if_fail (SOUP_IS_MESSAGE (msg), SOUP_HTTP_1_0);
1611
1612 priv = soup_message_get_instance_private (msg);
1613
1614 return priv->http_version;
1615 }
1616
1617 /**
1618 * soup_message_is_keepalive:
1619 * @msg: a #SoupMessage
1620 *
1621 * Determines whether or not @msg's connection can be kept alive for
1622 * further requests after processing @msg, based on the HTTP version,
1623 * Connection header, etc.
1624 *
1625 * Return value: %TRUE or %FALSE.
1626 **/
1627 gboolean
soup_message_is_keepalive(SoupMessage * msg)1628 soup_message_is_keepalive (SoupMessage *msg)
1629 {
1630 SoupMessagePrivate *priv = soup_message_get_instance_private (msg);
1631
1632 if (msg->status_code == SOUP_STATUS_OK &&
1633 msg->method == SOUP_METHOD_CONNECT)
1634 return TRUE;
1635
1636 /* Not persistent if the server sent a terminate-by-EOF response */
1637 if (soup_message_headers_get_encoding (msg->response_headers) == SOUP_ENCODING_EOF)
1638 return FALSE;
1639
1640 if (priv->http_version == SOUP_HTTP_1_0) {
1641 /* In theory, HTTP/1.0 connections are only persistent
1642 * if the client requests it, and the server agrees.
1643 * But some servers do keep-alive even if the client
1644 * doesn't request it. So ignore c_conn.
1645 */
1646
1647 if (!soup_message_headers_header_contains (msg->response_headers,
1648 "Connection", "Keep-Alive"))
1649 return FALSE;
1650 } else {
1651 /* Normally persistent unless either side requested otherwise */
1652 if (soup_message_headers_header_contains (msg->request_headers,
1653 "Connection", "close") ||
1654 soup_message_headers_header_contains (msg->response_headers,
1655 "Connection", "close"))
1656 return FALSE;
1657
1658 return TRUE;
1659 }
1660
1661 return TRUE;
1662 }
1663
1664 /**
1665 * soup_message_set_uri:
1666 * @msg: a #SoupMessage
1667 * @uri: the new #SoupURI
1668 *
1669 * Sets @msg's URI to @uri. If @msg has already been sent and you want
1670 * to re-send it with the new URI, you need to call
1671 * soup_session_requeue_message().
1672 **/
1673 void
soup_message_set_uri(SoupMessage * msg,SoupURI * uri)1674 soup_message_set_uri (SoupMessage *msg, SoupURI *uri)
1675 {
1676 SoupMessagePrivate *priv;
1677
1678 g_return_if_fail (SOUP_IS_MESSAGE (msg));
1679 priv = soup_message_get_instance_private (msg);
1680
1681 if (priv->uri)
1682 soup_uri_free (priv->uri);
1683 if (priv->addr) {
1684 g_object_unref (priv->addr);
1685 priv->addr = NULL;
1686 }
1687 priv->uri = soup_uri_copy (uri);
1688
1689 g_object_notify (G_OBJECT (msg), SOUP_MESSAGE_URI);
1690 }
1691
1692 /**
1693 * soup_message_get_uri:
1694 * @msg: a #SoupMessage
1695 *
1696 * Gets @msg's URI
1697 *
1698 * Return value: (transfer none): the URI @msg is targeted for.
1699 **/
1700 SoupURI *
soup_message_get_uri(SoupMessage * msg)1701 soup_message_get_uri (SoupMessage *msg)
1702 {
1703 SoupMessagePrivate *priv;
1704
1705 g_return_val_if_fail (SOUP_IS_MESSAGE (msg), NULL);
1706
1707 priv = soup_message_get_instance_private (msg);
1708
1709 return priv->uri;
1710 }
1711
1712 /**
1713 * soup_message_get_address:
1714 * @msg: a #SoupMessage
1715 *
1716 * Gets the address @msg's URI points to. After first setting the
1717 * URI on a message, this will be unresolved, although the message's
1718 * session will resolve it before sending the message.
1719 *
1720 * Return value: (transfer none): the address @msg's URI points to
1721 *
1722 * Since: 2.26
1723 **/
1724 SoupAddress *
soup_message_get_address(SoupMessage * msg)1725 soup_message_get_address (SoupMessage *msg)
1726 {
1727 SoupMessagePrivate *priv;
1728
1729 g_return_val_if_fail (SOUP_IS_MESSAGE (msg), NULL);
1730
1731 priv = soup_message_get_instance_private (msg);
1732 if (!priv->addr) {
1733 priv->addr = soup_address_new (priv->uri->host,
1734 priv->uri->port);
1735 }
1736 return priv->addr;
1737 }
1738
1739 /**
1740 * soup_message_set_status:
1741 * @msg: a #SoupMessage
1742 * @status_code: an HTTP status code
1743 *
1744 * Sets @msg's status code to @status_code. If @status_code is a
1745 * known value, it will also set @msg's reason_phrase.
1746 **/
1747 void
soup_message_set_status(SoupMessage * msg,guint status_code)1748 soup_message_set_status (SoupMessage *msg, guint status_code)
1749 {
1750 g_return_if_fail (SOUP_IS_MESSAGE (msg));
1751 g_return_if_fail (status_code != 0);
1752
1753 g_free (msg->reason_phrase);
1754
1755 msg->status_code = status_code;
1756 msg->reason_phrase = g_strdup (soup_status_get_phrase (status_code));
1757 g_object_notify (G_OBJECT (msg), SOUP_MESSAGE_STATUS_CODE);
1758 g_object_notify (G_OBJECT (msg), SOUP_MESSAGE_REASON_PHRASE);
1759 }
1760
1761 /**
1762 * soup_message_set_status_full:
1763 * @msg: a #SoupMessage
1764 * @status_code: an HTTP status code
1765 * @reason_phrase: a description of the status
1766 *
1767 * Sets @msg's status code and reason phrase.
1768 **/
1769 void
soup_message_set_status_full(SoupMessage * msg,guint status_code,const char * reason_phrase)1770 soup_message_set_status_full (SoupMessage *msg,
1771 guint status_code,
1772 const char *reason_phrase)
1773 {
1774 g_return_if_fail (SOUP_IS_MESSAGE (msg));
1775 g_return_if_fail (status_code != 0);
1776 g_return_if_fail (reason_phrase != NULL);
1777
1778 g_free (msg->reason_phrase);
1779
1780 msg->status_code = status_code;
1781 msg->reason_phrase = g_strdup (reason_phrase);
1782 g_object_notify (G_OBJECT (msg), SOUP_MESSAGE_STATUS_CODE);
1783 g_object_notify (G_OBJECT (msg), SOUP_MESSAGE_REASON_PHRASE);
1784 }
1785
1786 /**
1787 * SoupChunkAllocator:
1788 * @msg: the #SoupMessage the chunk is being allocated for
1789 * @max_len: the maximum length that will be read, or 0.
1790 * @user_data: the data passed to soup_message_set_chunk_allocator()
1791 *
1792 * The prototype for a chunk allocation callback. This should allocate
1793 * a new #SoupBuffer and return it for the I/O layer to read message
1794 * body data off the network into.
1795 *
1796 * If @max_len is non-0, it indicates the maximum number of bytes that
1797 * could be read, based on what is known about the message size. Note
1798 * that this might be a very large number, and you should not simply
1799 * try to allocate that many bytes blindly. If @max_len is 0, that
1800 * means that libsoup does not know how many bytes remain to be read,
1801 * and the allocator should return a buffer of a size that it finds
1802 * convenient.
1803 *
1804 * If the allocator returns %NULL, the message will be paused. It is
1805 * up to the application to make sure that it gets unpaused when it
1806 * becomes possible to allocate a new buffer.
1807 *
1808 * Return value: (nullable): the new buffer (or %NULL)
1809 *
1810 * Deprecated: Use #SoupRequest if you want to read into your
1811 * own buffers.
1812 **/
1813
1814 /**
1815 * soup_message_set_chunk_allocator:
1816 * @msg: a #SoupMessage
1817 * @allocator: the chunk allocator callback
1818 * @user_data: data to pass to @allocator
1819 * @destroy_notify: destroy notifier to free @user_data when @msg is
1820 * destroyed
1821 *
1822 * Sets an alternate chunk-allocation function to use when reading
1823 * @msg's body when using the traditional (ie,
1824 * non-#SoupRequest<!-- -->-based) API. Every time data is available
1825 * to read, libsoup will call @allocator, which should return a
1826 * #SoupBuffer. (See #SoupChunkAllocator for additional details.)
1827 * Libsoup will then read data from the network into that buffer, and
1828 * update the buffer's <literal>length</literal> to indicate how much
1829 * data it read.
1830 *
1831 * Generally, a custom chunk allocator would be used in conjunction
1832 * with soup_message_body_set_accumulate() %FALSE and
1833 * #SoupMessage::got_chunk, as part of a strategy to avoid unnecessary
1834 * copying of data. However, you cannot assume that every call to the
1835 * allocator will be followed by a call to your
1836 * #SoupMessage::got_chunk handler; if an I/O error occurs, then the
1837 * buffer will be unreffed without ever having been used. If your
1838 * buffer-allocation strategy requires special cleanup, use
1839 * soup_buffer_new_with_owner() rather than doing the cleanup from the
1840 * #SoupMessage::got_chunk handler.
1841 *
1842 * The other thing to remember when using non-accumulating message
1843 * bodies is that the buffer passed to the #SoupMessage::got_chunk
1844 * handler will be unreffed after the handler returns, just as it
1845 * would be in the non-custom-allocated case. If you want to hand the
1846 * chunk data off to some other part of your program to use later,
1847 * you'll need to ref the #SoupBuffer (or its owner, in the
1848 * soup_buffer_new_with_owner() case) to ensure that the data remains
1849 * valid.
1850 *
1851 * Deprecated: #SoupRequest provides a much simpler API that lets you
1852 * read the response directly into your own buffers without needing to
1853 * mess with callbacks, pausing/unpausing, etc.
1854 **/
1855 void
soup_message_set_chunk_allocator(SoupMessage * msg,SoupChunkAllocator allocator,gpointer user_data,GDestroyNotify destroy_notify)1856 soup_message_set_chunk_allocator (SoupMessage *msg,
1857 SoupChunkAllocator allocator,
1858 gpointer user_data,
1859 GDestroyNotify destroy_notify)
1860 {
1861 SoupMessagePrivate *priv;
1862
1863 g_return_if_fail (SOUP_IS_MESSAGE (msg));
1864
1865 priv = soup_message_get_instance_private (msg);
1866
1867 if (priv->chunk_allocator_dnotify)
1868 priv->chunk_allocator_dnotify (priv->chunk_allocator_data);
1869
1870 priv->chunk_allocator = allocator;
1871 priv->chunk_allocator_data = user_data;
1872 priv->chunk_allocator_dnotify = destroy_notify;
1873 }
1874
1875 /**
1876 * soup_message_disable_feature:
1877 * @msg: a #SoupMessage
1878 * @feature_type: the #GType of a #SoupSessionFeature
1879 *
1880 * This disables the actions of #SoupSessionFeature<!-- -->s with the
1881 * given @feature_type (or a subclass of that type) on @msg, so that
1882 * @msg is processed as though the feature(s) hadn't been added to the
1883 * session. Eg, passing #SOUP_TYPE_CONTENT_SNIFFER for @feature_type
1884 * will disable Content-Type sniffing on the message.
1885 *
1886 * You must call this before queueing @msg on a session; calling it on
1887 * a message that has already been queued is undefined. In particular,
1888 * you cannot call this on a message that is being requeued after a
1889 * redirect or authentication.
1890 *
1891 * Since: 2.28
1892 **/
1893 void
soup_message_disable_feature(SoupMessage * msg,GType feature_type)1894 soup_message_disable_feature (SoupMessage *msg, GType feature_type)
1895 {
1896 SoupMessagePrivate *priv;
1897
1898 g_return_if_fail (SOUP_IS_MESSAGE (msg));
1899
1900 priv = soup_message_get_instance_private (msg);
1901
1902 if (!priv->disabled_features)
1903 priv->disabled_features = g_hash_table_new (g_direct_hash, g_direct_equal);
1904
1905 g_hash_table_add (priv->disabled_features, GSIZE_TO_POINTER (feature_type));
1906 }
1907
1908 gboolean
soup_message_disables_feature(SoupMessage * msg,gpointer feature)1909 soup_message_disables_feature (SoupMessage *msg, gpointer feature)
1910 {
1911 SoupMessagePrivate *priv;
1912 GHashTableIter iter;
1913 gpointer key;
1914
1915 g_return_val_if_fail (SOUP_IS_MESSAGE (msg), FALSE);
1916
1917 priv = soup_message_get_instance_private (msg);
1918
1919 if (!priv->disabled_features)
1920 return FALSE;
1921
1922 g_hash_table_iter_init (&iter, priv->disabled_features);
1923 while (g_hash_table_iter_next (&iter, &key, NULL)) {
1924 if (G_TYPE_CHECK_INSTANCE_TYPE (feature, GPOINTER_TO_SIZE (key)))
1925 return TRUE;
1926 }
1927 return FALSE;
1928 }
1929
1930 /**
1931 * soup_message_is_feature_disabled:
1932 * @msg: a #SoupMessage
1933 * @feature_type: the #GType of a #SoupSessionFeature
1934 *
1935 * Get whether #SoupSessionFeature<!-- -->s of the given @feature_type
1936 * (or a subclass of that type) are disabled on @msg.
1937 * See soup_message_disable_feature().
1938 *
1939 * Returns: %TRUE if feature is disabled, or %FALSE otherwise.
1940 *
1941 * Since: 2.72
1942 */
1943 gboolean
soup_message_is_feature_disabled(SoupMessage * msg,GType feature_type)1944 soup_message_is_feature_disabled (SoupMessage *msg, GType feature_type)
1945 {
1946 SoupMessagePrivate *priv;
1947 GHashTableIter iter;
1948 gpointer key;
1949
1950 g_return_val_if_fail (SOUP_IS_MESSAGE (msg), FALSE);
1951
1952 priv = soup_message_get_instance_private (msg);
1953
1954 if (!priv->disabled_features)
1955 return FALSE;
1956
1957 g_hash_table_iter_init (&iter, priv->disabled_features);
1958 while (g_hash_table_iter_next (&iter, &key, NULL)) {
1959 if (g_type_is_a (GPOINTER_TO_SIZE (key), feature_type))
1960 return TRUE;
1961 }
1962 return FALSE;
1963 }
1964
1965 GList *
soup_message_get_disabled_features(SoupMessage * msg)1966 soup_message_get_disabled_features (SoupMessage *msg)
1967 {
1968 SoupMessagePrivate *priv = soup_message_get_instance_private (msg);
1969
1970 return priv->disabled_features ? g_hash_table_get_keys (priv->disabled_features) : NULL;
1971 }
1972
1973 /**
1974 * soup_message_get_first_party:
1975 * @msg: a #SoupMessage
1976 *
1977 * Gets @msg's first-party #SoupURI
1978 *
1979 * Returns: (transfer none): the @msg's first party #SoupURI
1980 *
1981 * Since: 2.30
1982 **/
1983 SoupURI *
soup_message_get_first_party(SoupMessage * msg)1984 soup_message_get_first_party (SoupMessage *msg)
1985 {
1986 SoupMessagePrivate *priv;
1987
1988 g_return_val_if_fail (SOUP_IS_MESSAGE (msg), NULL);
1989
1990 priv = soup_message_get_instance_private (msg);
1991 return priv->first_party;
1992 }
1993
1994 /**
1995 * soup_message_set_first_party:
1996 * @msg: a #SoupMessage
1997 * @first_party: the #SoupURI for the @msg's first party
1998 *
1999 * Sets @first_party as the main document #SoupURI for @msg. For
2000 * details of when and how this is used refer to the documentation for
2001 * #SoupCookieJarAcceptPolicy.
2002 *
2003 * Since: 2.30
2004 **/
2005 void
soup_message_set_first_party(SoupMessage * msg,SoupURI * first_party)2006 soup_message_set_first_party (SoupMessage *msg,
2007 SoupURI *first_party)
2008 {
2009 SoupMessagePrivate *priv;
2010
2011 g_return_if_fail (SOUP_IS_MESSAGE (msg));
2012 g_return_if_fail (first_party != NULL);
2013
2014 priv = soup_message_get_instance_private (msg);
2015
2016 if (priv->first_party) {
2017 if (soup_uri_equal (priv->first_party, first_party))
2018 return;
2019
2020 soup_uri_free (priv->first_party);
2021 }
2022
2023 priv->first_party = soup_uri_copy (first_party);
2024 g_object_notify (G_OBJECT (msg), SOUP_MESSAGE_FIRST_PARTY);
2025 }
2026
2027 /**
2028 * soup_message_get_site_for_cookies:
2029 * @msg: a #SoupMessage
2030 *
2031 * Gets @msg's site for cookies #SoupURI
2032 *
2033 * Returns: (transfer none): the @msg's site for cookies #SoupURI
2034 *
2035 * Since: 2.70
2036 **/
2037 SoupURI *
soup_message_get_site_for_cookies(SoupMessage * msg)2038 soup_message_get_site_for_cookies (SoupMessage *msg)
2039 {
2040 SoupMessagePrivate *priv;
2041
2042 g_return_val_if_fail (SOUP_IS_MESSAGE (msg), NULL);
2043
2044 priv = soup_message_get_instance_private (msg);
2045 return priv->site_for_cookies;
2046 }
2047
2048 /**
2049 * soup_message_set_site_for_cookies:
2050 * @msg: a #SoupMessage
2051 * @site_for_cookies: (nullable): the #SoupURI for the @msg's site for cookies
2052 *
2053 * Sets @site_for_cookies as the policy URL for same-site cookies for @msg.
2054 *
2055 * It is either the URL of the top-level document or %NULL depending on whether the registrable
2056 * domain of this document's URL matches the registrable domain of its parent's/opener's
2057 * URL. For the top-level document it is set to the document's URL.
2058 *
2059 * See the [same-site spec](https://tools.ietf.org/html/draft-ietf-httpbis-cookie-same-site-00)
2060 * for more information.
2061 *
2062 * Since: 2.70
2063 **/
2064 void
soup_message_set_site_for_cookies(SoupMessage * msg,SoupURI * site_for_cookies)2065 soup_message_set_site_for_cookies (SoupMessage *msg,
2066 SoupURI *site_for_cookies)
2067 {
2068 SoupMessagePrivate *priv;
2069
2070 g_return_if_fail (SOUP_IS_MESSAGE (msg));
2071
2072 priv = soup_message_get_instance_private (msg);
2073
2074 if (priv->site_for_cookies == site_for_cookies)
2075 return;
2076
2077 if (priv->site_for_cookies) {
2078 if (site_for_cookies && soup_uri_equal (priv->site_for_cookies, site_for_cookies))
2079 return;
2080
2081 soup_uri_free (priv->site_for_cookies);
2082 }
2083
2084 priv->site_for_cookies = site_for_cookies ? soup_uri_copy (site_for_cookies) : NULL;
2085 g_object_notify (G_OBJECT (msg), SOUP_MESSAGE_SITE_FOR_COOKIES);
2086 }
2087
2088 /**
2089 * soup_message_set_is_top_level_navigation:
2090 * @msg: a #SoupMessage
2091 * @is_top_level_navigation: if %TRUE indicate the current request is a top-level navigation
2092 *
2093 * See the [same-site spec](https://tools.ietf.org/html/draft-ietf-httpbis-cookie-same-site-00)
2094 * for more information.
2095 *
2096 * Since: 2.70
2097 **/
2098 void
soup_message_set_is_top_level_navigation(SoupMessage * msg,gboolean is_top_level_navigation)2099 soup_message_set_is_top_level_navigation (SoupMessage *msg,
2100 gboolean is_top_level_navigation)
2101 {
2102 SoupMessagePrivate *priv;
2103
2104 g_return_if_fail (SOUP_IS_MESSAGE (msg));
2105
2106 priv = soup_message_get_instance_private (msg);
2107
2108 if (priv->is_top_level_navigation == is_top_level_navigation)
2109 return;
2110
2111 priv->is_top_level_navigation = is_top_level_navigation;
2112 g_object_notify (G_OBJECT (msg), SOUP_MESSAGE_IS_TOP_LEVEL_NAVIGATION);
2113 }
2114
2115 /**
2116 * soup_message_get_is_top_level_navigation:
2117 * @msg: a #SoupMessage
2118 *
2119 * Since: 2.70
2120 **/
2121 gboolean
soup_message_get_is_top_level_navigation(SoupMessage * msg)2122 soup_message_get_is_top_level_navigation (SoupMessage *msg)
2123 {
2124 SoupMessagePrivate *priv;
2125
2126 g_return_val_if_fail (SOUP_IS_MESSAGE (msg), FALSE);
2127
2128 priv = soup_message_get_instance_private (msg);
2129 return priv->is_top_level_navigation;
2130 }
2131
2132 void
soup_message_set_https_status(SoupMessage * msg,SoupConnection * conn)2133 soup_message_set_https_status (SoupMessage *msg, SoupConnection *conn)
2134 {
2135 SoupSocket *sock;
2136
2137 sock = conn ? soup_connection_get_socket (conn) : NULL;
2138 if (sock && soup_socket_is_ssl (sock)) {
2139 GTlsCertificate *certificate;
2140 GTlsCertificateFlags errors;
2141
2142 g_object_get (sock,
2143 SOUP_SOCKET_TLS_CERTIFICATE, &certificate,
2144 SOUP_SOCKET_TLS_ERRORS, &errors,
2145 NULL);
2146 g_object_set (msg,
2147 SOUP_MESSAGE_TLS_CERTIFICATE, certificate,
2148 SOUP_MESSAGE_TLS_ERRORS, errors,
2149 NULL);
2150 if (certificate)
2151 g_object_unref (certificate);
2152 } else {
2153 g_object_set (msg,
2154 SOUP_MESSAGE_TLS_CERTIFICATE, NULL,
2155 SOUP_MESSAGE_TLS_ERRORS, 0,
2156 NULL);
2157 }
2158 }
2159
2160 /**
2161 * soup_message_get_https_status:
2162 * @msg: a #SoupMessage
2163 * @certificate: (out) (transfer none): @msg's TLS certificate
2164 * @errors: (out): the verification status of @certificate
2165 *
2166 * If @msg is using https (or attempted to use https but got
2167 * %SOUP_STATUS_SSL_FAILED), this retrieves the #GTlsCertificate
2168 * associated with its connection, and the #GTlsCertificateFlags
2169 * showing what problems, if any, have been found with that
2170 * certificate.
2171 *
2172 * <note><para>This is only meaningful with messages processed by a #SoupSession and is
2173 * not useful for messages received by a #SoupServer</para></note>
2174 *
2175 * Return value: %TRUE if @msg used/attempted https, %FALSE if not
2176 *
2177 * Since: 2.34
2178 */
2179 gboolean
soup_message_get_https_status(SoupMessage * msg,GTlsCertificate ** certificate,GTlsCertificateFlags * errors)2180 soup_message_get_https_status (SoupMessage *msg,
2181 GTlsCertificate **certificate,
2182 GTlsCertificateFlags *errors)
2183 {
2184 SoupMessagePrivate *priv;
2185
2186 g_return_val_if_fail (SOUP_IS_MESSAGE (msg), FALSE);
2187
2188 priv = soup_message_get_instance_private (msg);
2189
2190 if (certificate)
2191 *certificate = priv->tls_certificate;
2192 if (errors)
2193 *errors = priv->tls_errors;
2194 return priv->tls_certificate != NULL;
2195 }
2196
2197 /**
2198 * soup_message_set_redirect:
2199 * @msg: a #SoupMessage
2200 * @status_code: a 3xx status code
2201 * @redirect_uri: the URI to redirect @msg to
2202 *
2203 * Sets @msg's status_code to @status_code and adds a Location header
2204 * pointing to @redirect_uri. Use this from a #SoupServer when you
2205 * want to redirect the client to another URI.
2206 *
2207 * @redirect_uri can be a relative URI, in which case it is
2208 * interpreted relative to @msg's current URI. In particular, if
2209 * @redirect_uri is just a path, it will replace the path
2210 * <emphasis>and query</emphasis> of @msg's URI.
2211 *
2212 * Since: 2.38
2213 */
2214 void
soup_message_set_redirect(SoupMessage * msg,guint status_code,const char * redirect_uri)2215 soup_message_set_redirect (SoupMessage *msg, guint status_code,
2216 const char *redirect_uri)
2217 {
2218 SoupURI *location;
2219 char *location_str;
2220
2221 location = soup_uri_new_with_base (soup_message_get_uri (msg), redirect_uri);
2222 g_return_if_fail (location != NULL);
2223
2224 soup_message_set_status (msg, status_code);
2225 location_str = soup_uri_to_string (location, FALSE);
2226 soup_message_headers_replace (msg->response_headers, "Location",
2227 location_str);
2228 g_free (location_str);
2229 soup_uri_free (location);
2230 }
2231
2232 void
soup_message_set_soup_request(SoupMessage * msg,SoupRequest * req)2233 soup_message_set_soup_request (SoupMessage *msg,
2234 SoupRequest *req)
2235 {
2236 SoupMessagePrivate *priv = soup_message_get_instance_private (msg);
2237
2238 priv->request = req;
2239 }
2240
2241 /**
2242 * soup_message_get_soup_request:
2243 * @msg: a #SoupMessage
2244 *
2245 * If @msg is associated with a #SoupRequest, this returns that
2246 * request. Otherwise it returns %NULL.
2247 *
2248 * Return value: (transfer none): @msg's associated #SoupRequest
2249 *
2250 * Since: 2.42
2251 */
2252 SoupRequest *
soup_message_get_soup_request(SoupMessage * msg)2253 soup_message_get_soup_request (SoupMessage *msg)
2254 {
2255 SoupMessagePrivate *priv;
2256
2257 g_return_val_if_fail (SOUP_IS_MESSAGE (msg), NULL);
2258
2259 priv = soup_message_get_instance_private (msg);
2260 return priv->request;
2261 }
2262
2263 /**
2264 * SoupMessagePriority:
2265 * @SOUP_MESSAGE_PRIORITY_VERY_LOW: The lowest priority, the messages
2266 * with this priority will be the last ones to be attended.
2267 * @SOUP_MESSAGE_PRIORITY_LOW: Use this for low priority messages, a
2268 * #SoupMessage with the default priority will be processed first.
2269 * @SOUP_MESSAGE_PRIORITY_NORMAL: The default priotity, this is the
2270 * priority assigned to the #SoupMessage by default.
2271 * @SOUP_MESSAGE_PRIORITY_HIGH: High priority, a #SoupMessage with
2272 * this priority will be processed before the ones with the default
2273 * priority.
2274 * @SOUP_MESSAGE_PRIORITY_VERY_HIGH: The highest priority, use this
2275 * for very urgent #SoupMessage as they will be the first ones to be
2276 * attended.
2277 *
2278 * Priorities that can be set on a #SoupMessage to instruct the
2279 * message queue to process it before any other message with lower
2280 * priority.
2281 **/
2282
2283 /**
2284 * soup_message_set_priority:
2285 * @msg: a #SoupMessage
2286 * @priority: the #SoupMessagePriority
2287 *
2288 * Sets the priority of a message. Note that this won't have any
2289 * effect unless used before the message is added to the session's
2290 * message processing queue.
2291 *
2292 * The message will be placed just before any other previously added
2293 * message with lower priority (messages with the same priority are
2294 * processed on a FIFO basis).
2295 *
2296 * Setting priorities does not currently work with #SoupSessionSync
2297 * (or with synchronous messages on a plain #SoupSession) because in
2298 * the synchronous/blocking case, priority ends up being determined
2299 * semi-randomly by thread scheduling.
2300 *
2301 * Since: 2.44
2302 */
2303 void
soup_message_set_priority(SoupMessage * msg,SoupMessagePriority priority)2304 soup_message_set_priority (SoupMessage *msg,
2305 SoupMessagePriority priority)
2306 {
2307 g_return_if_fail (SOUP_IS_MESSAGE (msg));
2308
2309 g_object_set (msg, SOUP_MESSAGE_PRIORITY, priority, NULL);
2310 }
2311
2312 /**
2313 * soup_message_get_priority:
2314 * @msg: a #SoupMessage
2315 *
2316 * Retrieves the #SoupMessagePriority. If not set this value defaults
2317 * to #SOUP_MESSAGE_PRIORITY_NORMAL.
2318 *
2319 * Return value: the priority of the message.
2320 *
2321 * Since: 2.44
2322 */
2323 SoupMessagePriority
soup_message_get_priority(SoupMessage * msg)2324 soup_message_get_priority (SoupMessage *msg)
2325 {
2326 SoupMessagePrivate *priv;
2327
2328 g_return_val_if_fail (SOUP_IS_MESSAGE (msg), SOUP_MESSAGE_PRIORITY_NORMAL);
2329
2330 priv = soup_message_get_instance_private (msg);
2331
2332 return priv->priority;
2333 }
2334
2335 gpointer
soup_message_get_io_data(SoupMessage * msg)2336 soup_message_get_io_data (SoupMessage *msg)
2337 {
2338 SoupMessagePrivate *priv = soup_message_get_instance_private (msg);
2339
2340 return priv->io_data;
2341 }
2342
2343 void
soup_message_set_io_data(SoupMessage * msg,gpointer io)2344 soup_message_set_io_data (SoupMessage *msg, gpointer io)
2345 {
2346 SoupMessagePrivate *priv = soup_message_get_instance_private (msg);
2347
2348 priv->io_data = io;
2349 }
2350
2351 SoupContentSniffer *
soup_message_get_content_sniffer(SoupMessage * msg)2352 soup_message_get_content_sniffer (SoupMessage *msg)
2353 {
2354 SoupMessagePrivate *priv = soup_message_get_instance_private (msg);
2355
2356 return priv->sniffer;
2357 }
2358
2359 void
soup_message_set_content_sniffer(SoupMessage * msg,SoupContentSniffer * sniffer)2360 soup_message_set_content_sniffer (SoupMessage *msg, SoupContentSniffer *sniffer)
2361 {
2362 SoupMessagePrivate *priv = soup_message_get_instance_private (msg);
2363
2364 if (priv->sniffer)
2365 g_object_unref (priv->sniffer);
2366
2367 priv->sniffer = sniffer ? g_object_ref (sniffer) : NULL;
2368 }
2369
2370 void
soup_message_set_bytes_for_sniffing(SoupMessage * msg,gsize bytes)2371 soup_message_set_bytes_for_sniffing (SoupMessage *msg, gsize bytes)
2372 {
2373 SoupMessagePrivate *priv = soup_message_get_instance_private (msg);
2374
2375 priv->bytes_for_sniffing = bytes;
2376 }
2377
2378 gboolean
soup_message_has_chunk_allocator(SoupMessage * msg)2379 soup_message_has_chunk_allocator (SoupMessage *msg)
2380 {
2381 SoupMessagePrivate *priv = soup_message_get_instance_private (msg);
2382
2383 return priv->chunk_allocator != NULL;
2384 }
2385
2386 SoupBuffer *
soup_message_allocate_chunk(SoupMessage * msg,goffset read_length)2387 soup_message_allocate_chunk (SoupMessage *msg,
2388 goffset read_length)
2389 {
2390 SoupMessagePrivate *priv = soup_message_get_instance_private (msg);
2391
2392 return priv->chunk_allocator (msg, read_length, priv->chunk_allocator_data);
2393 }
2394