1 /*
2  * soup-server-message.c: HTTP server request/response
3  *
4  * Copyright (C) 2020 Igalia S.L.
5  */
6 
7 #ifdef HAVE_CONFIG_H
8 #include <config.h>
9 #endif
10 
11 #include <string.h>
12 
13 #include "soup-server-message.h"
14 #include "soup.h"
15 #include "soup-connection.h"
16 #include "soup-server-message-private.h"
17 #include "soup-message-headers-private.h"
18 #include "soup-socket.h"
19 #include "soup-uri-utils-private.h"
20 
21 /**
22  * SECTION:soup-server-message
23  * @short_description: An HTTP server request and response.
24  * @see_also: #SoupMessageHeaders, #SoupMessageBody
25  *
26  * A SoupServerMessage represents an HTTP message that is being sent or
27  * received on a #SoupServer
28  *
29  * #SoupServer will create #SoupServerMessage<!-- -->s automatically for
30  * incoming requests, which your application will receive via handlers.
31  *
32  * Note that libsoup's terminology here does not quite match the HTTP
33  * specification: in RFC 2616, an "HTTP-message" is
34  * <emphasis>either</emphasis> a Request, <emphasis>or</emphasis> a
35  * Response. In libsoup, a #SoupServerMessage combines both the request and
36  * the response.
37  **/
38 
39 /**
40  * SoupServerMessage:
41  *
42  * Class represnting an HTTP request and response pair for a server.
43  */
44 
45 struct _SoupServerMessage {
46         GObject             parent;
47 
48         SoupSocket         *sock;
49         GSocket            *gsock;
50         SoupAuthDomain     *auth_domain;
51         char               *auth_user;
52 
53         GSocketAddress     *remote_addr;
54         char               *remote_ip;
55         GSocketAddress     *local_addr;
56 
57         const char         *method;
58         SoupHTTPVersion     http_version;
59         SoupHTTPVersion     orig_http_version;
60 
61         guint               status_code;
62         char               *reason_phrase;
63 
64         GUri               *uri;
65 
66         SoupMessageBody    *request_body;
67         SoupMessageHeaders *request_headers;
68 
69         SoupMessageBody    *response_body;
70         SoupMessageHeaders *response_headers;
71 
72         SoupServerMessageIOData *io_data;
73 
74         gboolean                 options_ping;
75 };
76 
77 struct _SoupServerMessageClass {
78         GObjectClass parent_class;
79 };
80 
81 G_DEFINE_FINAL_TYPE (SoupServerMessage, soup_server_message, G_TYPE_OBJECT)
82 
83 enum {
84         WROTE_INFORMATIONAL,
85         WROTE_HEADERS,
86         WROTE_CHUNK,
87         WROTE_BODY_DATA,
88         WROTE_BODY,
89 
90         GOT_HEADERS,
91         GOT_CHUNK,
92         GOT_BODY,
93 
94         DISCONNECTED,
95         FINISHED,
96 
97         ACCEPT_CERTIFICATE,
98 
99         LAST_SIGNAL
100 };
101 
102 static guint signals[LAST_SIGNAL] = { 0 };
103 
104 static void
soup_server_message_init(SoupServerMessage * msg)105 soup_server_message_init (SoupServerMessage *msg)
106 {
107         msg->request_body = soup_message_body_new ();
108         msg->request_headers = soup_message_headers_new (SOUP_MESSAGE_HEADERS_REQUEST);
109         msg->response_body = soup_message_body_new ();
110         msg->response_headers = soup_message_headers_new (SOUP_MESSAGE_HEADERS_RESPONSE);
111         soup_message_headers_set_encoding (msg->response_headers, SOUP_ENCODING_CONTENT_LENGTH);
112 }
113 
114 static void
soup_server_message_finalize(GObject * object)115 soup_server_message_finalize (GObject *object)
116 {
117         SoupServerMessage *msg = SOUP_SERVER_MESSAGE (object);
118 
119         soup_server_message_io_data_free (msg->io_data);
120 
121         g_clear_object (&msg->auth_domain);
122         g_clear_pointer (&msg->auth_user, g_free);
123         g_clear_object (&msg->remote_addr);
124         g_clear_object (&msg->local_addr);
125 
126         if (msg->sock) {
127                 g_signal_handlers_disconnect_by_data (msg->sock, msg);
128                 g_object_unref (msg->sock);
129         }
130         g_clear_object (&msg->gsock);
131         g_clear_pointer (&msg->remote_ip, g_free);
132 
133         g_clear_pointer (&msg->uri, g_uri_unref);
134         g_free (msg->reason_phrase);
135 
136         soup_message_body_unref (msg->request_body);
137         soup_message_headers_unref (msg->request_headers);
138         soup_message_body_unref (msg->response_body);
139         soup_message_headers_unref (msg->response_headers);
140 
141         G_OBJECT_CLASS (soup_server_message_parent_class)->finalize (object);
142 }
143 
144 static void
soup_server_message_class_init(SoupServerMessageClass * klass)145 soup_server_message_class_init (SoupServerMessageClass *klass)
146 {
147         GObjectClass *object_class = G_OBJECT_CLASS (klass);
148 
149         object_class->finalize = soup_server_message_finalize;
150 
151         /**
152          * SoupServerMessage::wrote-informational:
153          * @msg: the message
154          *
155          * Emitted immediately after writing a 1xx (Informational) response.
156          */
157         signals[WROTE_INFORMATIONAL] =
158                 g_signal_new ("wrote-informational",
159                               G_OBJECT_CLASS_TYPE (object_class),
160                               G_SIGNAL_RUN_LAST,
161                               0,
162                               NULL, NULL,
163                               NULL,
164                               G_TYPE_NONE, 0);
165 
166         /**
167          * SoupServerMessage::wrote-headers:
168          * @msg: the message
169          *
170          * Emitted immediately after writing the response headers for a
171          * message.
172          */
173         signals[WROTE_HEADERS] =
174                 g_signal_new ("wrote-headers",
175                               G_OBJECT_CLASS_TYPE (object_class),
176                               G_SIGNAL_RUN_LAST,
177                               0,
178                               NULL, NULL,
179                               NULL,
180                               G_TYPE_NONE, 0);
181 
182         /**
183          * SoupServerMessage::wrote-chunk:
184          * @msg: the message
185          *
186          * Emitted immediately after writing a body chunk for a message.
187          *
188          * Note that this signal is not parallel to
189          * #SoupServerMessage::got-chunk; it is emitted only when a complete
190          * chunk (added with soup_message_body_append() or
191          * soup_message_body_append_bytes()) has been written. To get
192          * more useful continuous progress information, use
193          * #SoupServerMessage::wrote-body-data.
194          */
195         signals[WROTE_CHUNK] =
196                 g_signal_new ("wrote-chunk",
197                               G_OBJECT_CLASS_TYPE (object_class),
198                               G_SIGNAL_RUN_LAST,
199                               0,
200                               NULL, NULL,
201                               NULL,
202                               G_TYPE_NONE, 0);
203 
204         /**
205          * SoupServerMessage::wrote-body-data:
206          * @msg: the message
207          * @chunk_size: the number of bytes written
208          *
209          * Emitted immediately after writing a portion of the message
210          * body to the network.
211          */
212         signals[WROTE_BODY_DATA] =
213                 g_signal_new ("wrote-body-data",
214                               G_OBJECT_CLASS_TYPE (object_class),
215                               G_SIGNAL_RUN_LAST,
216                               0,
217                               NULL, NULL,
218                               NULL,
219                               G_TYPE_NONE, 1,
220                               G_TYPE_UINT);
221 
222         /**
223          * SoupServerMessage::wrote-body:
224          * @msg: the message
225          *
226          * Emitted immediately after writing the complete response body for a
227          * message.
228          */
229         signals[WROTE_BODY] =
230                 g_signal_new ("wrote-body",
231                               G_OBJECT_CLASS_TYPE (object_class),
232                               G_SIGNAL_RUN_LAST,
233                               0,
234                               NULL, NULL,
235                               NULL,
236                               G_TYPE_NONE, 0);
237 
238         /**
239          * SoupServerMessage::got-headers:
240          * @msg: the message
241          *
242          * Emitted after receiving the Request-Line and request headers.
243          */
244         signals[GOT_HEADERS] =
245                 g_signal_new ("got-headers",
246                               G_OBJECT_CLASS_TYPE (object_class),
247                               G_SIGNAL_RUN_LAST,
248                               0,
249                               NULL, NULL,
250                               NULL,
251                               G_TYPE_NONE, 0);
252 
253         /**
254          * SoupServerMessage::got-chunk:
255          * @msg: the message
256          * @chunk: the just-read chunk
257          *
258          * Emitted after receiving a chunk of a message body. Note
259          * that "chunk" in this context means any subpiece of the
260          * body, not necessarily the specific HTTP 1.1 chunks sent by
261          * the other side.
262          */
263         signals[GOT_CHUNK] =
264                 g_signal_new ("got-chunk",
265                               G_OBJECT_CLASS_TYPE (object_class),
266                               G_SIGNAL_RUN_FIRST,
267                               0,
268                               NULL, NULL,
269                               NULL,
270                               G_TYPE_NONE, 1,
271                               G_TYPE_BYTES);
272 
273         /**
274          * SoupServerMessage::got-body:
275          * @msg: the message
276          *
277          * Emitted after receiving the complete request body.
278          */
279         signals[GOT_BODY] =
280                 g_signal_new ("got-body",
281                               G_OBJECT_CLASS_TYPE (object_class),
282                               G_SIGNAL_RUN_LAST,
283                               0,
284                               NULL, NULL,
285                               NULL,
286                               G_TYPE_NONE, 0);
287 
288         /**
289          * SoupServerMessage::finished:
290          * @msg: the message
291          *
292          * Emitted when all HTTP processing is finished for a message.
293          * (After #SoupServerMessage::wrote-body).
294          */
295         signals[FINISHED] =
296                 g_signal_new ("finished",
297                               G_OBJECT_CLASS_TYPE (object_class),
298                               G_SIGNAL_RUN_LAST,
299                               0,
300                               NULL, NULL,
301                               NULL,
302                               G_TYPE_NONE, 0);
303 
304         /**
305          * SoupServerMessage::disconnected:
306          * @msg: the message
307          *
308          * Emitted when the @msg's socket is disconnected.
309          */
310         signals[DISCONNECTED] =
311                 g_signal_new ("disconnected",
312                               G_OBJECT_CLASS_TYPE (object_class),
313                               G_SIGNAL_RUN_LAST,
314                               0,
315                               NULL, NULL,
316                               NULL,
317                               G_TYPE_NONE, 0);
318 
319 	/**
320 	 * SoupServerMessage::accept-certificate:
321 	 * @msg: the message
322 	 * @tls_peer_certificate: the peer's #GTlsCertificate
323 	 * @tls_peer_errors: the tls errors of @tls_certificate
324 	 *
325 	 * Emitted during the @msg's connection TLS handshake
326 	 * after client TLS certificate has been received.
327 	 * You can return %TRUE to accept @tls_certificate despite
328 	 * @tls_errors.
329 	 *
330 	 * Returns: %TRUE to accept the TLS certificate and stop other
331 	 *     handlers from being invoked, or %FALSE to propagate the
332 	 *     event further.
333 	 */
334 	signals[ACCEPT_CERTIFICATE] =
335 		g_signal_new ("accept-certificate",
336 			      G_OBJECT_CLASS_TYPE (object_class),
337 			      G_SIGNAL_RUN_LAST,
338 			      0,
339 			      g_signal_accumulator_true_handled, NULL,
340 			      NULL,
341 			      G_TYPE_BOOLEAN, 2,
342 			      G_TYPE_TLS_CERTIFICATE,
343 			      G_TYPE_TLS_CERTIFICATE_FLAGS);
344 }
345 
346 static void
socket_disconnected(SoupServerMessage * msg)347 socket_disconnected (SoupServerMessage *msg)
348 {
349         g_signal_emit (msg, signals[DISCONNECTED], 0);
350 }
351 
352 static gboolean
socket_accept_certificate(SoupServerMessage * msg,GTlsCertificate * tls_certificate,GTlsCertificateFlags * tls_errors)353 socket_accept_certificate (SoupServerMessage    *msg,
354                            GTlsCertificate      *tls_certificate,
355                            GTlsCertificateFlags *tls_errors)
356 {
357 	gboolean accept = FALSE;
358 
359 	g_signal_emit (msg, signals[ACCEPT_CERTIFICATE], 0,
360 		       tls_certificate, tls_errors, &accept);
361 	return accept;
362 }
363 
364 SoupServerMessage *
soup_server_message_new(SoupSocket * sock)365 soup_server_message_new (SoupSocket *sock)
366 {
367         SoupServerMessage *msg;
368 
369         msg = g_object_new (SOUP_TYPE_SERVER_MESSAGE, NULL);
370         msg->sock = g_object_ref (sock);
371         msg->gsock = soup_socket_get_gsocket (sock);
372         if (msg->gsock)
373                 g_object_ref (msg->gsock);
374 
375         g_signal_connect_object (sock, "disconnected",
376                                  G_CALLBACK (socket_disconnected),
377                                  msg, G_CONNECT_SWAPPED);
378         g_signal_connect_object (sock, "accept-certificate",
379                                  G_CALLBACK (socket_accept_certificate),
380                                  msg, G_CONNECT_SWAPPED);
381 
382         return msg;
383 }
384 
385 void
soup_server_message_set_uri(SoupServerMessage * msg,GUri * uri)386 soup_server_message_set_uri (SoupServerMessage *msg,
387                              GUri              *uri)
388 {
389         if (msg->uri)
390                 g_uri_unref (msg->uri);
391         msg->uri = soup_uri_copy_with_normalized_flags (uri);
392 }
393 
394 SoupSocket *
soup_server_message_get_soup_socket(SoupServerMessage * msg)395 soup_server_message_get_soup_socket (SoupServerMessage *msg)
396 {
397         return msg->sock;
398 }
399 
400 void
soup_server_message_set_auth(SoupServerMessage * msg,SoupAuthDomain * domain,char * user)401 soup_server_message_set_auth (SoupServerMessage *msg,
402                               SoupAuthDomain    *domain,
403                               char              *user)
404 {
405         if (msg->auth_domain)
406                 g_object_unref (msg->auth_domain);
407         msg->auth_domain = domain;
408 
409         if (msg->auth_user)
410                 g_free (msg->auth_user);
411         msg->auth_user = user;
412 }
413 
414 gboolean
soup_server_message_is_keepalive(SoupServerMessage * msg)415 soup_server_message_is_keepalive (SoupServerMessage *msg)
416 {
417         if (msg->status_code == SOUP_STATUS_OK && msg->method == SOUP_METHOD_CONNECT)
418                 return TRUE;
419 
420         /* Not persistent if the server sent a terminate-by-EOF response */
421         if (soup_message_headers_get_encoding (msg->response_headers) == SOUP_ENCODING_EOF)
422                 return FALSE;
423 
424         if (msg->http_version == SOUP_HTTP_1_0) {
425                 /* In theory, HTTP/1.0 connections are only persistent
426                  * if the client requests it, and the server agrees.
427                  * But some servers do keep-alive even if the client
428                  * doesn't request it. So ignore c_conn.
429                  */
430 
431                 if (!soup_message_headers_header_contains_common (msg->response_headers,
432                                                                   SOUP_HEADER_CONNECTION,
433                                                                   "Keep-Alive"))
434                         return FALSE;
435         } else {
436                 /* Normally persistent unless either side requested otherwise */
437                 if (soup_message_headers_header_contains_common (msg->request_headers,
438                                                                  SOUP_HEADER_CONNECTION,
439                                                                  "close") ||
440                     soup_message_headers_header_contains_common (msg->response_headers,
441                                                                  SOUP_HEADER_CONNECTION,
442                                                                  "close"))
443                         return FALSE;
444 
445                 return TRUE;
446         }
447 
448         return TRUE;
449 }
450 
451 void
soup_server_message_set_io_data(SoupServerMessage * msg,SoupServerMessageIOData * io)452 soup_server_message_set_io_data (SoupServerMessage       *msg,
453                                  SoupServerMessageIOData *io)
454 {
455         soup_server_message_io_data_free (msg->io_data);
456         msg->io_data = io;
457 }
458 
459 SoupServerMessageIOData *
soup_server_message_get_io_data(SoupServerMessage * msg)460 soup_server_message_get_io_data (SoupServerMessage *msg)
461 {
462         return msg->io_data;
463 }
464 
465 void
soup_server_message_cleanup_response(SoupServerMessage * msg)466 soup_server_message_cleanup_response (SoupServerMessage *msg)
467 {
468         soup_message_body_truncate (msg->response_body);
469         soup_message_headers_clear (msg->response_headers);
470         soup_message_headers_set_encoding (msg->response_headers,
471                                            SOUP_ENCODING_CONTENT_LENGTH);
472         msg->status_code = SOUP_STATUS_NONE;
473         g_clear_pointer (&msg->reason_phrase, g_free);
474         msg->http_version = msg->orig_http_version;
475 }
476 
477 void
soup_server_message_wrote_informational(SoupServerMessage * msg)478 soup_server_message_wrote_informational (SoupServerMessage *msg)
479 {
480         g_signal_emit (msg, signals[WROTE_INFORMATIONAL], 0);
481 }
482 
483 void
soup_server_message_wrote_headers(SoupServerMessage * msg)484 soup_server_message_wrote_headers (SoupServerMessage *msg)
485 {
486         g_signal_emit (msg, signals[WROTE_HEADERS], 0);
487 }
488 
489 void
soup_server_message_wrote_chunk(SoupServerMessage * msg)490 soup_server_message_wrote_chunk (SoupServerMessage *msg)
491 {
492         g_signal_emit (msg, signals[WROTE_CHUNK], 0);
493 }
494 
495 void
soup_server_message_wrote_body_data(SoupServerMessage * msg,gsize chunk_size)496 soup_server_message_wrote_body_data (SoupServerMessage *msg,
497                                      gsize              chunk_size)
498 {
499         g_signal_emit (msg, signals[WROTE_BODY_DATA], 0, chunk_size);
500 }
501 
502 void
soup_server_message_wrote_body(SoupServerMessage * msg)503 soup_server_message_wrote_body (SoupServerMessage *msg)
504 {
505         g_signal_emit (msg, signals[WROTE_BODY], 0);
506 }
507 
508 void
soup_server_message_got_headers(SoupServerMessage * msg)509 soup_server_message_got_headers (SoupServerMessage *msg)
510 {
511         g_signal_emit (msg, signals[GOT_HEADERS], 0);
512 }
513 
514 void
soup_server_message_got_chunk(SoupServerMessage * msg,GBytes * chunk)515 soup_server_message_got_chunk (SoupServerMessage *msg,
516                                GBytes            *chunk)
517 {
518         g_signal_emit (msg, signals[GOT_CHUNK], 0, chunk);
519 }
520 
521 void
soup_server_message_got_body(SoupServerMessage * msg)522 soup_server_message_got_body (SoupServerMessage *msg)
523 {
524         if (soup_message_body_get_accumulate (msg->request_body))
525                 g_bytes_unref (soup_message_body_flatten (msg->request_body));
526         g_signal_emit (msg, signals[GOT_BODY], 0);
527 }
528 
529 void
soup_server_message_finished(SoupServerMessage * msg)530 soup_server_message_finished (SoupServerMessage *msg)
531 {
532         g_signal_emit (msg, signals[FINISHED], 0);
533 }
534 
535 /**
536  * soup_server_message_get_request_headers:
537  * @msg: a #SoupServerMessage
538  *
539  * Get the request headers of @msg.
540  *
541  * Returns: (transfer none): a #SoupMessageHeaders with the request headers.
542  */
543 SoupMessageHeaders *
soup_server_message_get_request_headers(SoupServerMessage * msg)544 soup_server_message_get_request_headers (SoupServerMessage *msg)
545 {
546         g_return_val_if_fail (SOUP_IS_SERVER_MESSAGE (msg), NULL);
547 
548         return msg->request_headers;
549 }
550 
551 /**
552  * soup_server_message_get_response_headers:
553  * @msg: a #SoupServerMessage
554  *
555  * Get the response headers of @msg.
556  *
557  * Returns: (transfer none): a #SoupMessageHeaders with the response headers.
558  */
559 SoupMessageHeaders *
soup_server_message_get_response_headers(SoupServerMessage * msg)560 soup_server_message_get_response_headers (SoupServerMessage *msg)
561 {
562         g_return_val_if_fail (SOUP_IS_SERVER_MESSAGE (msg), NULL);
563 
564         return msg->response_headers;
565 }
566 
567 /**
568  * soup_server_message_get_request_body:
569  * @msg: a #SoupServerMessage
570  *
571  * Get the request body of @msg.
572  *
573  * Returns: (transfer none): a #SoupMessageBody.
574  */
575 SoupMessageBody *
soup_server_message_get_request_body(SoupServerMessage * msg)576 soup_server_message_get_request_body (SoupServerMessage *msg)
577 {
578         g_return_val_if_fail (SOUP_IS_SERVER_MESSAGE (msg), NULL);
579 
580         return msg->request_body;
581 }
582 
583 /**
584  * soup_server_message_get_response_body:
585  * @msg: a #SoupServerMessage
586  *
587  * Get the response body of @msg.
588  *
589  * Returns: (transfer none): a #SoupMessageBody.
590  */
591 SoupMessageBody *
soup_server_message_get_response_body(SoupServerMessage * msg)592 soup_server_message_get_response_body (SoupServerMessage *msg)
593 {
594         g_return_val_if_fail (SOUP_IS_SERVER_MESSAGE (msg), NULL);
595 
596         return msg->response_body;
597 }
598 
599 /**
600  * soup_server_message_get_method:
601  * @msg: a #SoupServerMessage
602  *
603  * Get the HTTP method of @msg.
604  *
605  * Returns: the HTTP method.
606  */
607 const char *
soup_server_message_get_method(SoupServerMessage * msg)608 soup_server_message_get_method (SoupServerMessage *msg)
609 {
610         g_return_val_if_fail (SOUP_IS_SERVER_MESSAGE (msg), NULL);
611 
612         return msg->method;
613 }
614 
615 void
soup_server_message_set_method(SoupServerMessage * msg,const char * method)616 soup_server_message_set_method (SoupServerMessage *msg,
617                                 const char        *method)
618 {
619         msg->method = g_intern_string (method);
620 }
621 
622 void
soup_server_message_set_options_ping(SoupServerMessage * msg,gboolean is_options_ping)623 soup_server_message_set_options_ping (SoupServerMessage *msg,
624                                       gboolean           is_options_ping)
625 {
626         msg->options_ping = is_options_ping;
627 }
628 
629 /**
630  * soup_server_message_is_options_ping:
631  * @msg: a #SoupServerMessage
632  *
633  * Gets if @msg represents an OPTIONS message with the path `*`.
634  *
635  * Returns: %TRUE if is an OPTIONS ping
636  */
637 gboolean
soup_server_message_is_options_ping(SoupServerMessage * msg)638 soup_server_message_is_options_ping (SoupServerMessage *msg)
639 {
640         g_return_val_if_fail (SOUP_IS_SERVER_MESSAGE (msg), FALSE);
641 
642         return msg->options_ping;
643 }
644 
645 /**
646  * soup_server_message_get_http_version:
647  * @msg: a #SoupServerMessage
648  *
649  * Get the HTTP version of @msg.
650  *
651  * Returns: a #SoupHTTPVersion.
652  */
653 SoupHTTPVersion
soup_server_message_get_http_version(SoupServerMessage * msg)654 soup_server_message_get_http_version (SoupServerMessage *msg)
655 {
656         g_return_val_if_fail (SOUP_IS_SERVER_MESSAGE (msg), SOUP_HTTP_1_1);
657 
658         return msg->http_version;
659 }
660 
661 /**
662  * soup_server_message_set_http_version:
663  * @msg: a #SoupServerMessage
664  * @version: a #SoupHTTPVersion
665  *
666  * Set the HTTP version of @msg.
667  */
668 void
soup_server_message_set_http_version(SoupServerMessage * msg,SoupHTTPVersion version)669 soup_server_message_set_http_version (SoupServerMessage *msg,
670                                       SoupHTTPVersion    version)
671 {
672         g_return_if_fail (SOUP_IS_SERVER_MESSAGE (msg));
673 
674         msg->http_version = version;
675         if (msg->status_code == SOUP_STATUS_NONE)
676                 msg->orig_http_version = version;
677 }
678 
679 /**
680  * soup_server_message_get_reason_phrase:
681  * @msg: a #SoupServerMessage:
682  *
683  * Get the HTTP reason phrase of @msg or %NULL.
684  *
685  * Returns: the reason phrase.
686  */
687 const char *
soup_server_message_get_reason_phrase(SoupServerMessage * msg)688 soup_server_message_get_reason_phrase (SoupServerMessage *msg)
689 {
690         g_return_val_if_fail (SOUP_IS_SERVER_MESSAGE (msg), NULL);
691 
692         return msg->reason_phrase;
693 }
694 
695 /**
696  * soup_server_message_get_status:
697  * @msg: a #SoupServerMessage
698  *
699  * Get the HTTP status code of @msg.
700  *
701  * Returns: the HTTP status code.
702  */
703 guint
soup_server_message_get_status(SoupServerMessage * msg)704 soup_server_message_get_status (SoupServerMessage *msg)
705 {
706         g_return_val_if_fail (SOUP_IS_SERVER_MESSAGE (msg), 0);
707 
708         return msg->status_code;
709 }
710 
711 /**
712  * soup_server_message_set_status:
713  * @msg: a #SoupServerMessage
714  * @status_code: an HTTP status code
715  * @reason_phrase: (nullable): a reason phrase
716  *
717  * Sets @msg's status code to @status_code. If @status_code is a
718  * known value and @reason_phrase is %NULL, the reason_phrase will
719  * be set automatically.
720  **/
721 void
soup_server_message_set_status(SoupServerMessage * msg,guint status_code,const char * reason_phrase)722 soup_server_message_set_status (SoupServerMessage *msg,
723                                 guint              status_code,
724                                 const char        *reason_phrase)
725 {
726         g_return_if_fail (SOUP_IS_SERVER_MESSAGE (msg));
727         g_return_if_fail (status_code != 0);
728 
729         g_free (msg->reason_phrase);
730 
731         msg->status_code = status_code;
732         msg->reason_phrase = g_strdup (reason_phrase ? reason_phrase : soup_status_get_phrase (status_code));
733 }
734 
735 /**
736  * soup_server_message_get_uri:
737  * @msg: a #SoupServerMessage
738  *
739  * Get @msg's URI.
740  *
741  * Returns: (transfer none): a #GUri
742  */
743 GUri *
soup_server_message_get_uri(SoupServerMessage * msg)744 soup_server_message_get_uri (SoupServerMessage *msg)
745 {
746         g_return_val_if_fail (SOUP_IS_SERVER_MESSAGE (msg), NULL);
747 
748         return msg->uri;
749 }
750 
751 /**
752  * soup_server_message_set_response:
753  * @msg: the message
754  * @content_type: (nullable): MIME Content-Type of the body
755  * @resp_use: a #SoupMemoryUse describing how to handle @resp_body
756  * @resp_body: (nullable) (array length=resp_length) (element-type guint8):
757  *   a data buffer containing the body of the message response.
758  * @resp_length: the byte length of @resp_body.
759  *
760  * Convenience function to set the response body of a #SoupServerMessage. If
761  * @content_type is %NULL, the response body must be empty as well.
762  */
763 void
soup_server_message_set_response(SoupServerMessage * msg,const char * content_type,SoupMemoryUse resp_use,const char * resp_body,gsize resp_length)764 soup_server_message_set_response (SoupServerMessage *msg,
765                                   const char        *content_type,
766                                   SoupMemoryUse      resp_use,
767                                   const char        *resp_body,
768                                   gsize              resp_length)
769 {
770         g_return_if_fail (SOUP_IS_SERVER_MESSAGE (msg));
771         g_return_if_fail (content_type != NULL || resp_length == 0);
772 
773         if (content_type) {
774                 g_warn_if_fail (strchr (content_type, '/') != NULL);
775 
776                 soup_message_headers_replace_common (msg->response_headers,
777                                                      SOUP_HEADER_CONTENT_TYPE,
778                                                      content_type);
779                 soup_message_body_append (msg->response_body, resp_use,
780                                           resp_body, resp_length);
781         } else {
782                 soup_message_headers_remove_common (msg->response_headers,
783                                                     SOUP_HEADER_CONTENT_TYPE);
784                 soup_message_body_truncate (msg->response_body);
785         }
786 }
787 
788 /**
789  * soup_server_message_set_redirect:
790  * @msg: a #SoupServerMessage
791  * @status_code: a 3xx status code
792  * @redirect_uri: the URI to redirect @msg to
793  *
794  * Sets @msg's status_code to @status_code and adds a Location header
795  * pointing to @redirect_uri. Use this from a #SoupServer when you
796  * want to redirect the client to another URI.
797  *
798  * @redirect_uri can be a relative URI, in which case it is
799  * interpreted relative to @msg's current URI. In particular, if
800  * @redirect_uri is just a path, it will replace the path
801  * <emphasis>and query</emphasis> of @msg's URI.
802  */
803 void
soup_server_message_set_redirect(SoupServerMessage * msg,guint status_code,const char * redirect_uri)804 soup_server_message_set_redirect (SoupServerMessage *msg,
805                                   guint              status_code,
806                                   const char        *redirect_uri)
807 {
808 	GUri *location;
809 	char *location_str;
810 
811         g_return_if_fail (SOUP_IS_SERVER_MESSAGE (msg));
812 
813 	location = g_uri_parse_relative (soup_server_message_get_uri (msg), redirect_uri, SOUP_HTTP_URI_FLAGS, NULL);
814 	g_return_if_fail (location != NULL);
815 
816 	soup_server_message_set_status (msg, status_code, NULL);
817 	location_str = g_uri_to_string (location);
818 	soup_message_headers_replace_common (msg->response_headers, SOUP_HEADER_LOCATION,
819                                              location_str);
820 	g_free (location_str);
821 	g_uri_unref (location);
822 }
823 
824 /**
825  * soup_server_message_get_socket:
826  * @msg: a #SoupServerMessage
827  *
828  * Retrieves the #GSocket that @msg is associated with.
829  *
830  * If you are using this method to observe when multiple requests are
831  * made on the same persistent HTTP connection (eg, as the ntlm-test
832  * test program does), you will need to pay attention to socket
833  * destruction as well (eg, by using weak references), so that you do
834  * not get fooled when the allocator reuses the memory address of a
835  * previously-destroyed socket to represent a new socket.
836  *
837  * Returns: (nullable) (transfer none): the #GSocket that @msg is
838  * associated with, %NULL if you used soup_server_accept_iostream().
839  */
840 GSocket *
soup_server_message_get_socket(SoupServerMessage * msg)841 soup_server_message_get_socket (SoupServerMessage *msg)
842 {
843         g_return_val_if_fail (SOUP_IS_SERVER_MESSAGE (msg), NULL);
844 
845         return msg->gsock;
846 }
847 
848 /**
849  * soup_server_message_get_remote_address:
850  * @msg: a #SoupServerMessage
851  *
852  * Retrieves the #GSocketAddress associated with the remote end
853  * of a connection.
854  *
855  * Returns: (nullable) (transfer none): the #GSocketAddress
856  *     associated with the remote end of a connection, it may be
857  *     %NULL if you used soup_server_accept_iostream().
858  */
859 GSocketAddress *
soup_server_message_get_remote_address(SoupServerMessage * msg)860 soup_server_message_get_remote_address (SoupServerMessage *msg)
861 {
862         g_return_val_if_fail (SOUP_IS_SERVER_MESSAGE (msg), NULL);
863 
864         if (msg->remote_addr)
865                 return msg->remote_addr;
866 
867         msg->remote_addr = msg->gsock ?
868                 g_socket_get_remote_address (msg->gsock, NULL) :
869                 G_SOCKET_ADDRESS (g_object_ref (soup_socket_get_remote_address (msg->sock)));
870 
871         return msg->remote_addr;
872 }
873 
874 /**
875  * soup_server_message_get_local_address:
876  * @msg: a #SoupServerMessage
877  *
878  * Retrieves the #GSocketAddress associated with the local end
879  * of a connection.
880  *
881  * Returns: (nullable) (transfer none): the #GSocketAddress
882  *     associated with the local end of a connection, it may be
883  *     %NULL if you used soup_server_accept_iostream().
884  */
885 GSocketAddress *
soup_server_message_get_local_address(SoupServerMessage * msg)886 soup_server_message_get_local_address (SoupServerMessage *msg)
887 {
888         g_return_val_if_fail (SOUP_IS_SERVER_MESSAGE (msg), NULL);
889 
890         if (msg->local_addr)
891                 return msg->local_addr;
892 
893         msg->local_addr = msg->gsock ?
894                 g_socket_get_local_address (msg->gsock, NULL) :
895                 G_SOCKET_ADDRESS (g_object_ref (soup_socket_get_local_address (msg->sock)));
896 
897         return msg->local_addr;
898 }
899 
900 /**
901  * soup_server_message_get_remote_host:
902  * @msg: a #SoupServerMessage
903  *
904  * Retrieves the IP address associated with the remote end of a
905  * connection.
906  *
907  * Returns: (nullable): the IP address associated with the remote
908  *     end of a connection, it may be %NULL if you used
909  *     soup_server_accept_iostream().
910  */
911 const char *
soup_server_message_get_remote_host(SoupServerMessage * msg)912 soup_server_message_get_remote_host (SoupServerMessage *msg)
913 {
914         g_return_val_if_fail (SOUP_IS_SERVER_MESSAGE (msg), NULL);
915 
916         if (msg->remote_ip)
917                 return msg->remote_ip;
918 
919         if (msg->gsock) {
920                 GSocketAddress *addr = soup_server_message_get_remote_address (msg);
921                 GInetAddress *iaddr;
922 
923                 if (!addr || !G_IS_INET_SOCKET_ADDRESS (addr))
924                         return NULL;
925                 iaddr = g_inet_socket_address_get_address (G_INET_SOCKET_ADDRESS (addr));
926                 msg->remote_ip = g_inet_address_to_string (iaddr);
927         } else {
928                 GInetSocketAddress *addr = G_INET_SOCKET_ADDRESS (soup_socket_get_remote_address (msg->sock));
929                 GInetAddress *inet_addr = g_inet_socket_address_get_address (addr);
930                 msg->remote_ip = g_inet_address_to_string (inet_addr);
931         }
932 
933         return msg->remote_ip;
934 }
935 
936 /**
937  * soup_server_message_steal_connection:
938  * @msg: a #SoupServerMessage
939  *
940  * "Steals" the HTTP connection associated with @msg from its
941  * #SoupServer. This happens immediately, regardless of the current
942  * state of the connection; if the response to @msg has not yet finished
943  * being sent, then it will be discarded; you can steal the connection from a
944  * #SoupServerMessage::wrote-informational or #SoupServerMessage::wrote-body signal
945  * handler if you need to wait for part or all of the response to be sent.
946  *
947  * Note that when calling this function from C, @msg will most
948  * likely be freed as a side effect.
949  *
950  * Returns: (transfer full): the #GIOStream formerly associated
951  *   with @msg (or %NULL if @msg was no longer associated with a
952  *   connection). No guarantees are made about what kind of #GIOStream
953  *   is returned.
954  */
955 GIOStream *
soup_server_message_steal_connection(SoupServerMessage * msg)956 soup_server_message_steal_connection (SoupServerMessage *msg)
957 {
958         GIOStream *stream;
959 
960         g_object_ref (msg);
961         stream = soup_server_message_io_steal (msg);
962         if (stream) {
963                 g_object_set_data_full (G_OBJECT (stream), "GSocket",
964                                         soup_socket_steal_gsocket (msg->sock),
965                                         g_object_unref);
966         }
967 
968         g_signal_handlers_disconnect_by_data (msg, msg->sock);
969 
970         socket_disconnected (msg);
971         g_object_unref (msg);
972 
973         return stream;
974 }
975