Coverage Report

Created: 2025-12-14 06:57

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