/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 | } |