1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3 * soup-server.c: Asynchronous HTTP server
5 * Copyright (C) 2001-2003, Ximian, Inc.
14 #include <glib/gi18n-lib.h>
16 #include "soup-server.h"
18 #include "soup-message-private.h"
19 #include "soup-misc-private.h"
20 #include "soup-path-map.h"
21 #include "soup-socket-private.h"
22 #include "soup-websocket.h"
23 #include "soup-websocket-connection.h"
24 #include "soup-websocket-extension-deflate.h"
28 * @short_description: HTTP server
29 * @see_also: #SoupAuthDomain
31 * #SoupServer implements a simple HTTP server.
33 * (The following documentation describes the current #SoupServer API,
34 * available in <application>libsoup</application> 2.48 and later. See
35 * the section "<link linkend="soup-server-old-api">The Old SoupServer
36 * Listening API</link>" in the server how-to documentation for
37 * details on the older #SoupServer API.)
39 * To begin, create a server using soup_server_new(). Add at least one
40 * handler by calling soup_server_add_handler() or
41 * soup_server_add_early_handler(); the handler will be called to
42 * process any requests underneath the path you pass. (If you want all
43 * requests to go to the same handler, just pass "/" (or %NULL) for
46 * When a new connection is accepted (or a new request is started on
47 * an existing persistent connection), the #SoupServer will emit
48 * #SoupServer::request-started and then begin processing the request
49 * as described below, but note that once the message is assigned a
50 * #SoupMessage:status-code, then callbacks after that point will be
51 * skipped. Note also that it is not defined when the callbacks happen
52 * relative to various #SoupMessage signals.
54 * Once the headers have been read, #SoupServer will check if there is
55 * a #SoupAuthDomain (qv) covering the Request-URI; if so, and if the
56 * message does not contain suitable authorization, then the
57 * #SoupAuthDomain will set a status of %SOUP_STATUS_UNAUTHORIZED on
60 * After checking for authorization, #SoupServer will look for "early"
61 * handlers (added with soup_server_add_early_handler()) matching the
62 * Request-URI. If one is found, it will be run; in particular, this
63 * can be used to connect to signals to do a streaming read of the
66 * (At this point, if the request headers contain "<literal>Expect:
67 * 100-continue</literal>", and a status code has been set, then
68 * #SoupServer will skip the remaining steps and return the response.
69 * If the request headers contain "<literal>Expect:
70 * 100-continue</literal>" and no status code has been set,
71 * #SoupServer will return a %SOUP_STATUS_CONTINUE status before
74 * The server will then read in the response body (if present). At
75 * this point, if there are no handlers at all defined for the
76 * Request-URI, then the server will return %SOUP_STATUS_NOT_FOUND to
79 * Otherwise (assuming no previous step assigned a status to the
80 * message) any "normal" handlers (added with
81 * soup_server_add_handler()) for the message's Request-URI will be
84 * Then, if the path has a WebSocket handler registered (and has
85 * not yet been assigned a status), #SoupServer will attempt to
86 * validate the WebSocket handshake, filling in the response and
87 * setting a status of %SOUP_STATUS_SWITCHING_PROTOCOLS or
88 * %SOUP_STATUS_BAD_REQUEST accordingly.
90 * If the message still has no status code at this point (and has not
91 * been paused with soup_server_pause_message()), then it will be
92 * given a status of %SOUP_STATUS_INTERNAL_SERVER_ERROR (because at
93 * least one handler ran, but returned without assigning a status).
95 * Finally, the server will emit #SoupServer::request-finished (or
96 * #SoupServer::request-aborted if an I/O error occurred before
97 * handling was completed).
99 * If you want to handle the special "*" URI (eg, "OPTIONS *"), you
100 * must explicitly register a handler for "*"; the default handler
101 * will not be used for that case.
103 * If you want to process https connections in addition to (or instead
104 * of) http connections, you can either set the
105 * %SOUP_SERVER_TLS_CERTIFICATE property when creating the server, or
106 * else call soup_server_set_ssl_certificate() after creating it.
108 * Once the server is set up, make one or more calls to
109 * soup_server_listen(), soup_server_listen_local(), or
110 * soup_server_listen_all() to tell it where to listen for
111 * connections. (All ports on a #SoupServer use the same handlers; if
112 * you need to handle some ports differently, such as returning
113 * different data for http and https, you'll need to create multiple
114 * #SoupServers, or else check the passed-in URI in the handler
117 * #SoupServer will begin processing connections as soon as you return
118 * to (or start) the main loop for the current thread-default
130 static guint signals[LAST_SIGNAL] = { 0 };
132 struct SoupClientContext {
137 SoupAuthDomain *auth_domain;
140 GSocketAddress *remote_addr;
142 GSocketAddress *local_addr;
150 SoupServerCallback early_callback;
151 GDestroyNotify early_destroy;
152 gpointer early_user_data;
154 SoupServerCallback callback;
155 GDestroyNotify destroy;
158 char *websocket_origin;
159 char **websocket_protocols;
160 GList *websocket_extensions;
161 SoupServerWebsocketCallback websocket_callback;
162 GDestroyNotify websocket_destroy;
163 gpointer websocket_user_data;
170 char *ssl_cert_file, *ssl_key_file;
171 GTlsCertificate *tls_cert;
175 GMainContext *async_context;
179 SoupPathMap *handlers;
181 GSList *auth_domains;
183 char **http_aliases, **https_aliases;
185 SoupAddress *legacy_iface;
188 GPtrArray *websocket_extension_types;
194 #define SOUP_SERVER_SERVER_HEADER_BASE "libsoup/" PACKAGE_VERSION
205 PROP_TLS_CERTIFICATE,
211 PROP_ADD_WEBSOCKET_EXTENSION,
212 PROP_REMOVE_WEBSOCKET_EXTENSION,
217 G_DEFINE_TYPE_WITH_PRIVATE (SoupServer, soup_server, G_TYPE_OBJECT)
219 static SoupClientContext *soup_client_context_ref (SoupClientContext *client);
220 static void soup_client_context_unref (SoupClientContext *client);
223 free_handler (SoupServerHandler *handler)
225 g_free (handler->path);
226 g_free (handler->websocket_origin);
227 g_strfreev (handler->websocket_protocols);
228 g_list_free_full (handler->websocket_extensions, g_object_unref);
229 if (handler->early_destroy)
230 handler->early_destroy (handler->early_user_data);
231 if (handler->destroy)
232 handler->destroy (handler->user_data);
233 if (handler->websocket_destroy)
234 handler->websocket_destroy (handler->websocket_user_data);
235 g_slice_free (SoupServerHandler, handler);
239 soup_server_init (SoupServer *server)
241 SoupServerPrivate *priv = soup_server_get_instance_private (server);
243 priv->handlers = soup_path_map_new ((GDestroyNotify)free_handler);
245 priv->http_aliases = g_new (char *, 2);
246 priv->http_aliases[0] = (char *)g_intern_string ("*");
247 priv->http_aliases[1] = NULL;
249 priv->legacy_port = -1;
251 priv->websocket_extension_types = g_ptr_array_new_with_free_func ((GDestroyNotify)g_type_class_unref);
253 /* Use permessage-deflate extension by default */
254 g_ptr_array_add (priv->websocket_extension_types, g_type_class_ref (SOUP_TYPE_WEBSOCKET_EXTENSION_DEFLATE));
258 soup_server_dispose (GObject *object)
260 SoupServer *server = SOUP_SERVER (object);
261 SoupServerPrivate *priv = soup_server_get_instance_private (server);
263 priv->disposed = TRUE;
264 soup_server_disconnect (server);
266 G_OBJECT_CLASS (soup_server_parent_class)->dispose (object);
270 soup_server_finalize (GObject *object)
272 SoupServer *server = SOUP_SERVER (object);
273 SoupServerPrivate *priv = soup_server_get_instance_private (server);
275 g_clear_object (&priv->legacy_iface);
277 g_free (priv->ssl_cert_file);
278 g_free (priv->ssl_key_file);
279 g_clear_object (&priv->tls_cert);
281 g_free (priv->server_header);
283 soup_path_map_free (priv->handlers);
285 g_slist_free_full (priv->auth_domains, g_object_unref);
287 g_clear_pointer (&priv->loop, g_main_loop_unref);
288 g_clear_pointer (&priv->async_context, g_main_context_unref);
290 g_free (priv->http_aliases);
291 g_free (priv->https_aliases);
293 g_ptr_array_free (priv->websocket_extension_types, TRUE);
295 G_OBJECT_CLASS (soup_server_parent_class)->finalize (object);
299 soup_server_ensure_listening (SoupServer *server)
301 SoupServerPrivate *priv = soup_server_get_instance_private (server);
302 SoupSocket *listener;
307 if (!priv->legacy_iface) {
309 soup_address_new_any (SOUP_ADDRESS_FAMILY_IPV4,
313 listener = soup_socket_new (SOUP_SOCKET_LOCAL_ADDRESS, priv->legacy_iface,
314 SOUP_SOCKET_SSL_CREDENTIALS, priv->tls_cert,
315 SOUP_SOCKET_ASYNC_CONTEXT, priv->async_context,
317 if (!soup_socket_listen (listener)) {
318 g_object_unref (listener);
322 /* Re-resolve the interface address, in particular in case
323 * the passed-in address had SOUP_ADDRESS_ANY_PORT.
325 g_object_unref (priv->legacy_iface);
326 priv->legacy_iface = soup_socket_get_local_address (listener);
327 g_object_ref (priv->legacy_iface);
328 priv->legacy_port = soup_address_get_port (priv->legacy_iface);
330 priv->listeners = g_slist_prepend (priv->listeners, listener);
335 soup_server_constructor (GType type,
336 guint n_construct_properties,
337 GObjectConstructParam *construct_properties)
340 SoupServerPrivate *priv;
341 gboolean legacy_port_set;
343 server = G_OBJECT_CLASS (soup_server_parent_class)->
344 constructor (type, n_construct_properties, construct_properties);
345 priv = soup_server_get_instance_private (SOUP_SERVER (server));
347 /* For backward compatibility, we have to process the
348 * :ssl-cert-file, :ssl-key-file, :interface, and :port
349 * properties now, and return NULL if they are
350 * invalid/unsatisfiable.
352 if (priv->ssl_cert_file && priv->ssl_key_file) {
353 GError *error = NULL;
356 g_object_unref (priv->tls_cert);
357 priv->tls_cert = g_tls_certificate_new_from_files (priv->ssl_cert_file, priv->ssl_key_file, &error);
358 if (!priv->tls_cert) {
359 g_warning ("Could not read TLS certificate from '%s': %s",
360 priv->ssl_cert_file, error->message);
361 g_error_free (error);
362 g_object_unref (server);
367 if (priv->legacy_port != -1)
368 legacy_port_set = TRUE;
370 legacy_port_set = FALSE;
371 priv->legacy_port = 0;
374 if (legacy_port_set || priv->legacy_iface) {
375 if (!soup_server_ensure_listening (SOUP_SERVER (server))) {
376 g_object_unref (server);
380 /* If neither port nor iface was specified, then
381 * either: (a) the caller is planning to use the new
382 * listen APIs, so we don't have to do anything now,
383 * or (b) the caller is using the legacy APIs but
384 * wants the default values for interface and port
385 * (address 0.0.0.0, port 0), in which case a later
386 * call to soup_server_ensure_listening() will set it
387 * up just-in-time; we don't have to worry about it
388 * failing in that case, because it can't (unless you
389 * have no IPv4 addresses configured [even localhost],
390 * or there are already listeners on all 65,535 ports.
391 * We assume neither of these will happen.)
398 /* priv->http_aliases and priv->https_aliases are stored as arrays of
399 * *interned* strings, so we can't just use g_strdupv() to set them.
402 set_aliases (char ***variable, char **value)
414 len = g_strv_length (value);
415 *variable = g_new (char *, len + 1);
416 for (i = 0; i < len; i++)
417 (*variable)[i] = (char *)g_intern_string (value[i]);
418 (*variable)[i] = NULL;
422 soup_server_set_property (GObject *object, guint prop_id,
423 const GValue *value, GParamSpec *pspec)
425 SoupServer *server = SOUP_SERVER (object);
426 SoupServerPrivate *priv = soup_server_get_instance_private (server);
431 if (g_value_get_uint (value) != 0)
432 priv->legacy_port = g_value_get_uint (value);
435 if (priv->legacy_iface)
436 g_object_unref (priv->legacy_iface);
437 priv->legacy_iface = g_value_get_object (value);
438 if (priv->legacy_iface)
439 g_object_ref (priv->legacy_iface);
441 case PROP_SSL_CERT_FILE:
442 g_free (priv->ssl_cert_file);
443 priv->ssl_cert_file = g_value_dup_string (value);
445 case PROP_SSL_KEY_FILE:
446 g_free (priv->ssl_key_file);
447 priv->ssl_key_file = g_value_dup_string (value);
449 case PROP_TLS_CERTIFICATE:
451 g_object_unref (priv->tls_cert);
452 priv->tls_cert = g_value_dup_object (value);
454 case PROP_ASYNC_CONTEXT:
455 priv->async_context = g_value_get_pointer (value);
456 if (priv->async_context)
457 g_main_context_ref (priv->async_context);
460 priv->raw_paths = g_value_get_boolean (value);
462 case PROP_SERVER_HEADER:
463 g_free (priv->server_header);
464 header = g_value_get_string (value);
466 priv->server_header = NULL;
468 priv->server_header =
469 g_strdup (SOUP_SERVER_SERVER_HEADER_BASE);
470 } else if (g_str_has_suffix (header, " ")) {
471 priv->server_header =
472 g_strdup_printf ("%s%s", header,
473 SOUP_SERVER_SERVER_HEADER_BASE);
475 priv->server_header = g_strdup (header);
477 case PROP_HTTP_ALIASES:
478 set_aliases (&priv->http_aliases, g_value_get_boxed (value));
480 case PROP_HTTPS_ALIASES:
481 set_aliases (&priv->https_aliases, g_value_get_boxed (value));
483 case PROP_ADD_WEBSOCKET_EXTENSION:
484 soup_server_add_websocket_extension (server, g_value_get_gtype (value));
486 case PROP_REMOVE_WEBSOCKET_EXTENSION:
487 soup_server_remove_websocket_extension (server, g_value_get_gtype (value));
490 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
496 soup_server_get_property (GObject *object, guint prop_id,
497 GValue *value, GParamSpec *pspec)
499 SoupServer *server = SOUP_SERVER (object);
500 SoupServerPrivate *priv = soup_server_get_instance_private (server);
504 soup_server_ensure_listening (server);
505 g_value_set_uint (value, priv->legacy_port > 0 ? priv->legacy_port : 0);
508 soup_server_ensure_listening (server);
509 g_value_set_object (value, priv->legacy_iface);
511 case PROP_SSL_CERT_FILE:
512 g_value_set_string (value, priv->ssl_cert_file);
514 case PROP_SSL_KEY_FILE:
515 g_value_set_string (value, priv->ssl_key_file);
517 case PROP_TLS_CERTIFICATE:
518 g_value_set_object (value, priv->tls_cert);
520 case PROP_ASYNC_CONTEXT:
521 g_value_set_pointer (value, priv->async_context ? g_main_context_ref (priv->async_context) : NULL);
524 g_value_set_boolean (value, priv->raw_paths);
526 case PROP_SERVER_HEADER:
527 g_value_set_string (value, priv->server_header);
529 case PROP_HTTP_ALIASES:
530 g_value_set_boxed (value, priv->http_aliases);
532 case PROP_HTTPS_ALIASES:
533 g_value_set_boxed (value, priv->https_aliases);
536 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
542 soup_server_class_init (SoupServerClass *server_class)
544 GObjectClass *object_class = G_OBJECT_CLASS (server_class);
546 /* virtual method override */
547 object_class->constructor = soup_server_constructor;
548 object_class->dispose = soup_server_dispose;
549 object_class->finalize = soup_server_finalize;
550 object_class->set_property = soup_server_set_property;
551 object_class->get_property = soup_server_get_property;
556 * SoupServer::request-started:
557 * @server: the server
558 * @message: the new message
559 * @client: the client context
561 * Emitted when the server has started reading a new request.
562 * @message will be completely blank; not even the
563 * Request-Line will have been read yet. About the only thing
564 * you can usefully do with it is connect to its signals.
566 * If the request is read successfully, this will eventually
567 * be followed by a #SoupServer::request_read signal. If a
568 * response is then sent, the request processing will end with
569 * a #SoupServer::request_finished signal. If a network error
570 * occurs, the processing will instead end with
571 * #SoupServer::request_aborted.
573 signals[REQUEST_STARTED] =
574 g_signal_new ("request-started",
575 G_OBJECT_CLASS_TYPE (object_class),
577 G_STRUCT_OFFSET (SoupServerClass, request_started),
582 SOUP_TYPE_CLIENT_CONTEXT);
585 * SoupServer::request-read:
586 * @server: the server
587 * @message: the message
588 * @client: the client context
590 * Emitted when the server has successfully read a request.
591 * @message will have all of its request-side information
592 * filled in, and if the message was authenticated, @client
593 * will have information about that. This signal is emitted
594 * before any (non-early) handlers are called for the message,
595 * and if it sets the message's #status_code, then normal
596 * handler processing will be skipped.
598 signals[REQUEST_READ] =
599 g_signal_new ("request-read",
600 G_OBJECT_CLASS_TYPE (object_class),
602 G_STRUCT_OFFSET (SoupServerClass, request_read),
607 SOUP_TYPE_CLIENT_CONTEXT);
610 * SoupServer::request-finished:
611 * @server: the server
612 * @message: the message
613 * @client: the client context
615 * Emitted when the server has finished writing a response to
618 signals[REQUEST_FINISHED] =
619 g_signal_new ("request-finished",
620 G_OBJECT_CLASS_TYPE (object_class),
622 G_STRUCT_OFFSET (SoupServerClass, request_finished),
627 SOUP_TYPE_CLIENT_CONTEXT);
630 * SoupServer::request-aborted:
631 * @server: the server
632 * @message: the message
633 * @client: the client context
635 * Emitted when processing has failed for a message; this
636 * could mean either that it could not be read (if
637 * #SoupServer::request_read has not been emitted for it yet),
638 * or that the response could not be written back (if
639 * #SoupServer::request_read has been emitted but
640 * #SoupServer::request_finished has not been).
642 * @message is in an undefined state when this signal is
643 * emitted; the signal exists primarily to allow the server to
644 * free any state that it may have allocated in
645 * #SoupServer::request_started.
647 signals[REQUEST_ABORTED] =
648 g_signal_new ("request-aborted",
649 G_OBJECT_CLASS_TYPE (object_class),
651 G_STRUCT_OFFSET (SoupServerClass, request_aborted),
656 SOUP_TYPE_CLIENT_CONTEXT);
662 * The port the server is listening on, if you are using the
663 * old #SoupServer API. (This will not be set if you use
664 * soup_server_listen(), etc.)
666 * Deprecated: #SoupServers can listen on multiple interfaces
667 * at once now. Use soup_server_listen(), etc, to listen on a
668 * port, and soup_server_get_uris() to see what ports are
674 * Alias for the deprecated #SoupServer:port property, qv.
676 * Deprecated: #SoupServers can listen on multiple interfaces
677 * at once now. Use soup_server_listen(), etc, to listen on a
678 * port, and soup_server_get_uris() to see what ports are
681 g_object_class_install_property (
682 object_class, PROP_PORT,
683 g_param_spec_uint (SOUP_SERVER_PORT,
685 "Port to listen on (Deprecated)",
688 G_PARAM_CONSTRUCT_ONLY |
689 G_PARAM_STATIC_STRINGS |
690 G_PARAM_DEPRECATED));
692 * SoupServer:interface:
694 * The address of the network interface the server is
695 * listening on, if you are using the old #SoupServer API.
696 * (This will not be set if you use soup_server_listen(),
699 * Deprecated: #SoupServers can listen on multiple interfaces
700 * at once now. Use soup_server_listen(), etc, to listen on an
701 * interface, and soup_server_get_uris() to see what addresses
702 * are being listened on.
705 * SOUP_SERVER_INTERFACE:
707 * Alias for the #SoupServer:interface property, qv.
709 * Deprecated: #SoupServers can listen on multiple interfaces
710 * at once now. Use soup_server_listen(), etc, to listen on an
711 * interface, and soup_server_get_uris() to see what addresses
712 * are being listened on.
714 g_object_class_install_property (
715 object_class, PROP_INTERFACE,
716 g_param_spec_object (SOUP_SERVER_INTERFACE,
718 "Address of interface to listen on (Deprecated)",
721 G_PARAM_CONSTRUCT_ONLY |
722 G_PARAM_STATIC_STRINGS |
723 G_PARAM_DEPRECATED));
725 * SOUP_SERVER_SSL_CERT_FILE:
727 * Alias for the #SoupServer:ssl-cert-file property, qv.
729 * Deprecated: use #SoupServer:tls-certificate or
730 * soup_server_set_ssl_certificate().
733 * SoupServer:ssl-cert-file:
735 * Path to a file containing a PEM-encoded certificate.
737 * If you set this property and #SoupServer:ssl-key-file at
738 * construct time, then soup_server_new() will try to read the
739 * files; if it cannot, it will return %NULL, with no explicit
740 * indication of what went wrong (and logging a warning with
741 * newer versions of glib, since returning %NULL from a
742 * constructor is illegal).
744 * Deprecated: use #SoupServer:tls-certificate or
745 * soup_server_set_ssl_certificate().
747 g_object_class_install_property (
748 object_class, PROP_SSL_CERT_FILE,
749 g_param_spec_string (SOUP_SERVER_SSL_CERT_FILE,
750 "TLS (aka SSL) certificate file",
751 "File containing server TLS (aka SSL) certificate",
754 G_PARAM_CONSTRUCT_ONLY |
755 G_PARAM_STATIC_STRINGS));
757 * SOUP_SERVER_SSL_KEY_FILE:
759 * Alias for the #SoupServer:ssl-key-file property, qv.
761 * Deprecated: use #SoupServer:tls-certificate or
762 * soup_server_set_ssl_certificate().
765 * SoupServer:ssl-key-file:
767 * Path to a file containing a PEM-encoded private key. See
768 * #SoupServer:ssl-cert-file for more information about how this
771 * Deprecated: use #SoupServer:tls-certificate or
772 * soup_server_set_ssl_certificate().
774 g_object_class_install_property (
775 object_class, PROP_SSL_KEY_FILE,
776 g_param_spec_string (SOUP_SERVER_SSL_KEY_FILE,
777 "TLS (aka SSL) key file",
778 "File containing server TLS (aka SSL) key",
781 G_PARAM_CONSTRUCT_ONLY |
782 G_PARAM_STATIC_STRINGS));
784 * SOUP_SERVER_TLS_CERTIFICATE:
786 * Alias for the #SoupServer:tls-certificate property, qv.
791 * SoupServer:tls-certificate:
793 * A #GTlsCertificate that has a #GTlsCertificate:private-key
794 * set. If this is set, then the server will be able to speak
795 * https in addition to (or instead of) plain http.
797 * Alternatively, you can call soup_server_set_ssl_cert_file()
798 * to have #SoupServer read in a a certificate from a file.
802 g_object_class_install_property (
803 object_class, PROP_TLS_CERTIFICATE,
804 g_param_spec_object (SOUP_SERVER_TLS_CERTIFICATE,
806 "GTlsCertificate to use for https",
807 G_TYPE_TLS_CERTIFICATE,
808 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
810 * SoupServer:async-context:
812 * The server's #GMainContext, if you are using the old API.
813 * Servers created using soup_server_listen() will listen on
814 * the #GMainContext that was the thread-default context at
815 * the time soup_server_listen() was called.
817 * Deprecated: The new API uses the thread-default #GMainContext
818 * rather than having an explicitly-specified one.
821 * SOUP_SERVER_ASYNC_CONTEXT:
823 * Alias for the deprecated #SoupServer:async-context
826 * Deprecated: The new API uses the thread-default #GMainContext
827 * rather than having an explicitly-specified one.
829 g_object_class_install_property (
830 object_class, PROP_ASYNC_CONTEXT,
831 g_param_spec_pointer (SOUP_SERVER_ASYNC_CONTEXT,
832 "Async GMainContext",
833 "The GMainContext to dispatch async I/O in",
835 G_PARAM_CONSTRUCT_ONLY |
836 G_PARAM_STATIC_STRINGS |
837 G_PARAM_DEPRECATED));
839 * SOUP_SERVER_RAW_PATHS:
841 * Alias for the #SoupServer:raw-paths property. (If %TRUE,
842 * percent-encoding in the Request-URI path will not be
843 * automatically decoded.)
845 g_object_class_install_property (
846 object_class, PROP_RAW_PATHS,
847 g_param_spec_boolean (SOUP_SERVER_RAW_PATHS,
849 "If %TRUE, percent-encoding in the Request-URI path will not be automatically decoded.",
851 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
854 * SoupServer:server-header:
856 * If non-%NULL, the value to use for the "Server" header on
857 * #SoupMessage<!-- -->s processed by this server.
859 * The Server header is the server equivalent of the
860 * User-Agent header, and provides information about the
861 * server and its components. It contains a list of one or
862 * more product tokens, separated by whitespace, with the most
863 * significant product token coming first. The tokens must be
864 * brief, ASCII, and mostly alphanumeric (although "-", "_",
865 * and "." are also allowed), and may optionally include a "/"
866 * followed by a version string. You may also put comments,
867 * enclosed in parentheses, between or after the tokens.
869 * Some HTTP server implementations intentionally do not use
870 * version numbers in their Server header, so that
871 * installations running older versions of the server don't
872 * end up advertising their vulnerability to specific security
875 * As with #SoupSession:user_agent, if you set a
876 * #SoupServer:server_header property that has trailing whitespace,
877 * #SoupServer will append its own product token (eg,
878 * "<literal>libsoup/2.3.2</literal>") to the end of the
882 * SOUP_SERVER_SERVER_HEADER:
884 * Alias for the #SoupServer:server-header property, qv.
886 g_object_class_install_property (
887 object_class, PROP_SERVER_HEADER,
888 g_param_spec_string (SOUP_SERVER_SERVER_HEADER,
892 G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
895 * SoupServer:http-aliases:
897 * A %NULL-terminated array of URI schemes that should be
898 * considered to be aliases for "http". Eg, if this included
899 * <literal>"dav"</literal>, than a URI of
900 * <literal>dav://example.com/path</literal> would be treated
901 * identically to <literal>http://example.com/path</literal>.
902 * In particular, this is needed in cases where a client
903 * sends requests with absolute URIs, where those URIs do
906 * The default value is an array containing the single element
907 * <literal>"*"</literal>, a special value which means that
908 * any scheme except "https" is considered to be an alias for
911 * See also #SoupServer:https-aliases.
916 * SOUP_SERVER_HTTP_ALIASES:
918 * Alias for the #SoupServer:http-aliases property, qv.
922 g_object_class_install_property (
923 object_class, PROP_HTTP_ALIASES,
924 g_param_spec_boxed (SOUP_SERVER_HTTP_ALIASES,
926 "URI schemes that are considered aliases for 'http'",
928 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
930 * SoupServer:https-aliases:
932 * A comma-delimited list of URI schemes that should be
933 * considered to be aliases for "https". See
934 * #SoupServer:http-aliases for more information.
936 * The default value is %NULL, meaning that no URI schemes
937 * are considered aliases for "https".
942 * SOUP_SERVER_HTTPS_ALIASES:
944 * Alias for the #SoupServer:https-aliases property, qv.
948 g_object_class_install_property (
949 object_class, PROP_HTTPS_ALIASES,
950 g_param_spec_boxed (SOUP_SERVER_HTTPS_ALIASES,
952 "URI schemes that are considered aliases for 'https'",
954 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
957 * SoupServer:add-websocket-extension: (skip)
959 * Add support for #SoupWebsocketExtension of the given type.
960 * (Shortcut for calling soup_server_add_websocket_extension().)
965 * SOUP_SERVER_ADD_WEBSOCKET_EXTENSION: (skip)
967 * Alias for the #SoupServer:add-websocket-extension property, qv.
971 g_object_class_install_property (
972 object_class, PROP_ADD_WEBSOCKET_EXTENSION,
973 g_param_spec_gtype (SOUP_SERVER_ADD_WEBSOCKET_EXTENSION,
974 "Add support for a WebSocket extension",
975 "Add support for a WebSocket extension of the given type",
976 SOUP_TYPE_WEBSOCKET_EXTENSION,
977 G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS));
979 * SoupServer:remove-websocket-extension: (skip)
981 * Remove support for #SoupWebsocketExtension of the given type. (Shortcut for
982 * calling soup_server_remove_websocket_extension().)
987 * SOUP_SERVER_REMOVE_WEBSOCKET_EXTENSION: (skip)
989 * Alias for the #SoupServer:remove-websocket-extension property, qv.
993 g_object_class_install_property (
994 object_class, PROP_REMOVE_WEBSOCKET_EXTENSION,
995 g_param_spec_gtype (SOUP_SERVER_REMOVE_WEBSOCKET_EXTENSION,
996 "Remove support for a WebSocket extension",
997 "Remove support for a WebSocket extension of the given type",
998 SOUP_TYPE_WEBSOCKET_EXTENSION,
999 G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS));
1004 * @optname1: name of first property to set
1005 * @...: value of @optname1, followed by additional property/value pairs
1007 * Creates a new #SoupServer. This is exactly equivalent to calling
1008 * g_object_new() and specifying %SOUP_TYPE_SERVER as the type.
1010 * Return value: (nullable): a new #SoupServer. If you are using
1011 * certain legacy properties, this may also return %NULL if an error
1015 soup_server_new (const char *optname1, ...)
1020 va_start (ap, optname1);
1021 server = (SoupServer *)g_object_new_valist (SOUP_TYPE_SERVER,
1029 * soup_server_get_port:
1030 * @server: a #SoupServer
1032 * Gets the TCP port that @server is listening on, if you are using
1035 * Return value: the port @server is listening on.
1037 * Deprecated: If you are using soup_server_listen(), etc, then use
1038 * soup_server_get_uris() to get a list of all listening addresses.
1041 soup_server_get_port (SoupServer *server)
1043 SoupServerPrivate *priv;
1045 g_return_val_if_fail (SOUP_IS_SERVER (server), 0);
1046 priv = soup_server_get_instance_private (server);
1048 soup_server_ensure_listening (server);
1049 g_return_val_if_fail (priv->legacy_iface != NULL, 0);
1051 return priv->legacy_port;
1055 * soup_server_set_ssl_cert_file:
1056 * @server: a #SoupServer
1057 * @ssl_cert_file: path to a file containing a PEM-encoded SSL/TLS
1059 * @ssl_key_file: path to a file containing a PEM-encoded private key.
1060 * @error: return location for a #GError
1062 * Sets @server up to do https, using the SSL/TLS certificate
1063 * specified by @ssl_cert_file and @ssl_key_file (which may point to
1066 * Alternatively, you can set the #SoupServer:tls-certificate property
1067 * at construction time, if you already have a #GTlsCertificate.
1069 * Return value: success or failure.
1074 soup_server_set_ssl_cert_file (SoupServer *server,
1075 const char *ssl_cert_file,
1076 const char *ssl_key_file,
1079 SoupServerPrivate *priv;
1081 g_return_val_if_fail (SOUP_IS_SERVER (server), FALSE);
1082 priv = soup_server_get_instance_private (server);
1085 g_object_unref (priv->tls_cert);
1087 g_free (priv->ssl_cert_file);
1088 priv->ssl_cert_file = g_strdup (ssl_cert_file);
1090 g_free (priv->ssl_key_file);
1091 priv->ssl_key_file = g_strdup (ssl_key_file);
1093 priv->tls_cert = g_tls_certificate_new_from_files (priv->ssl_cert_file,
1096 return priv->tls_cert != NULL;
1100 * soup_server_is_https:
1101 * @server: a #SoupServer
1103 * Checks whether @server is capable of https.
1105 * In order for a server to run https, you must call
1106 * soup_server_set_ssl_cert_file(), or set the
1107 * #SoupServer:tls-certificate property, to provide it with a
1108 * certificate to use.
1110 * If you are using the deprecated single-listener APIs, then a return
1111 * value of %TRUE indicates that the #SoupServer serves https
1112 * exclusively. If you are using soup_server_listen(), etc, then a
1113 * %TRUE return value merely indicates that the server is
1114 * <emphasis>able</emphasis> to do https, regardless of whether it
1115 * actually currently is or not. Use soup_server_get_uris() to see if
1116 * it currently has any https listeners.
1118 * Return value: %TRUE if @server is configured to serve https.
1121 soup_server_is_https (SoupServer *server)
1123 SoupServerPrivate *priv;
1125 g_return_val_if_fail (SOUP_IS_SERVER (server), 0);
1126 priv = soup_server_get_instance_private (server);
1128 return priv->tls_cert != NULL;
1132 * soup_server_get_listener:
1133 * @server: a #SoupServer
1135 * Gets @server's listening socket, if you are using the old API.
1137 * You should treat this socket as read-only; writing to it or
1138 * modifiying it may cause @server to malfunction.
1140 * Return value: (transfer none): the listening socket.
1142 * Deprecated: If you are using soup_server_listen(), etc, then use
1143 * soup_server_get_listeners() to get a list of all listening sockets,
1144 * but note that that function returns #GSockets, not #SoupSockets.
1147 soup_server_get_listener (SoupServer *server)
1149 SoupServerPrivate *priv;
1151 g_return_val_if_fail (SOUP_IS_SERVER (server), NULL);
1152 priv = soup_server_get_instance_private (server);
1154 soup_server_ensure_listening (server);
1155 g_return_val_if_fail (priv->legacy_iface != NULL, NULL);
1157 return priv->listeners ? priv->listeners->data : NULL;
1161 * soup_server_get_listeners:
1162 * @server: a #SoupServer
1164 * Gets @server's list of listening sockets.
1166 * You should treat these sockets as read-only; writing to or
1167 * modifiying any of these sockets may cause @server to malfunction.
1169 * (Beware that in contrast to the old soup_server_get_listener(), this
1170 * function returns #GSockets, not #SoupSockets.)
1172 * Return value: (transfer container) (element-type Gio.Socket): a
1173 * list of listening sockets.
1176 soup_server_get_listeners (SoupServer *server)
1178 SoupServerPrivate *priv;
1179 GSList *listeners, *iter;
1181 g_return_val_if_fail (SOUP_IS_SERVER (server), NULL);
1182 priv = soup_server_get_instance_private (server);
1185 for (iter = priv->listeners; iter; iter = iter->next)
1186 listeners = g_slist_prepend (listeners, soup_socket_get_gsocket (iter->data));
1188 /* priv->listeners has the sockets in reverse order from how
1189 * they were added, so listeners now has them back in the
1195 static void start_request (SoupServer *, SoupClientContext *);
1196 static void socket_disconnected (SoupSocket *sock, SoupClientContext *client);
1198 static SoupClientContext *
1199 soup_client_context_new (SoupServer *server, SoupSocket *sock)
1201 SoupClientContext *client = g_slice_new0 (SoupClientContext);
1203 client->server = server;
1204 client->sock = g_object_ref (sock);
1205 client->gsock = soup_socket_get_gsocket (sock);
1207 g_object_ref (client->gsock);
1208 g_signal_connect (sock, "disconnected",
1209 G_CALLBACK (socket_disconnected), client);
1210 client->ref_count = 1;
1216 soup_client_context_cleanup (SoupClientContext *client)
1218 g_clear_object (&client->auth_domain);
1219 g_clear_pointer (&client->auth_user, g_free);
1220 g_clear_object (&client->remote_addr);
1221 g_clear_object (&client->local_addr);
1226 static SoupClientContext *
1227 soup_client_context_ref (SoupClientContext *client)
1229 g_atomic_int_inc (&client->ref_count);
1234 soup_client_context_unref (SoupClientContext *client)
1236 if (!g_atomic_int_dec_and_test (&client->ref_count))
1239 soup_client_context_cleanup (client);
1241 g_signal_handlers_disconnect_by_func (client->sock, socket_disconnected, client);
1242 g_object_unref (client->sock);
1243 g_clear_object (&client->gsock);
1244 g_clear_pointer (&client->remote_ip, g_free);
1245 g_slice_free (SoupClientContext, client);
1249 request_finished (SoupMessage *msg, SoupMessageIOCompletion completion, gpointer user_data)
1251 SoupClientContext *client = user_data;
1252 SoupServer *server = client->server;
1253 SoupServerPrivate *priv = soup_server_get_instance_private (server);
1254 SoupSocket *sock = client->sock;
1257 if (completion == SOUP_MESSAGE_IO_STOLEN) {
1258 soup_client_context_unref (client);
1259 g_object_unref (msg);
1263 /* Complete the message, assuming it actually really started. */
1265 soup_message_finished (msg);
1267 failed = (completion == SOUP_MESSAGE_IO_INTERRUPTED ||
1268 msg->status_code == SOUP_STATUS_IO_ERROR);
1269 g_signal_emit (server,
1270 failed ? signals[REQUEST_ABORTED] : signals[REQUEST_FINISHED],
1274 if (completion == SOUP_MESSAGE_IO_COMPLETE &&
1275 soup_socket_is_connected (sock) &&
1276 soup_message_is_keepalive (msg) &&
1278 start_request (server, client);
1280 soup_socket_disconnect (client->sock);
1281 soup_client_context_unref (client);
1283 g_object_unref (msg);
1286 /* "" was never documented as meaning the same thing as "/", but it
1287 * effectively was. We have to special case it now or otherwise it
1288 * would match "*" too.
1290 #define NORMALIZED_PATH(path) ((path) && *(path) ? (path) : "/")
1292 static SoupServerHandler *
1293 get_handler (SoupServer *server, SoupMessage *msg)
1295 SoupServerPrivate *priv = soup_server_get_instance_private (server);
1298 uri = soup_message_get_uri (msg);
1299 return soup_path_map_lookup (priv->handlers, NORMALIZED_PATH (uri->path));
1303 call_handler (SoupServer *server, SoupServerHandler *handler,
1304 SoupClientContext *client, SoupMessage *msg,
1307 GHashTable *form_data_set;
1310 if (early && !handler->early_callback)
1312 else if (!early && !handler->callback)
1315 if (msg->status_code != 0)
1318 uri = soup_message_get_uri (msg);
1320 form_data_set = soup_form_decode (uri->query);
1322 form_data_set = NULL;
1325 (*handler->early_callback) (server, msg,
1326 uri->path, form_data_set,
1327 client, handler->early_user_data);
1329 (*handler->callback) (server, msg,
1330 uri->path, form_data_set,
1331 client, handler->user_data);
1335 g_hash_table_unref (form_data_set);
1339 got_headers (SoupMessage *msg, SoupClientContext *client)
1341 SoupServer *server = client->server;
1342 SoupServerPrivate *priv = soup_server_get_instance_private (server);
1343 SoupServerHandler *handler;
1347 SoupAuthDomain *domain;
1349 gboolean rejected = FALSE;
1352 /* Add required response headers */
1353 date = soup_date_new_from_now (0);
1354 date_string = soup_date_to_string (date, SOUP_DATE_HTTP);
1355 soup_message_headers_replace (msg->response_headers, "Date",
1357 g_free (date_string);
1358 soup_date_free (date);
1360 if (msg->status_code != 0)
1363 uri = soup_message_get_uri (msg);
1364 if ((soup_socket_is_ssl (client->sock) && !soup_uri_is_https (uri, priv->https_aliases)) ||
1365 (!soup_socket_is_ssl (client->sock) && !soup_uri_is_http (uri, priv->http_aliases))) {
1366 soup_message_set_status (msg, SOUP_STATUS_BAD_REQUEST);
1370 if (!priv->raw_paths) {
1373 decoded_path = soup_uri_decode (uri->path);
1375 if (strstr (decoded_path, "/../") ||
1376 g_str_has_suffix (decoded_path, "/..")
1379 strstr (decoded_path, "\\..\\") ||
1380 strstr (decoded_path, "/..\\") ||
1381 strstr (decoded_path, "\\../") ||
1382 g_str_has_suffix (decoded_path, "\\..")
1385 /* Introducing new ".." segments is not allowed */
1386 g_free (decoded_path);
1387 soup_message_set_status (msg, SOUP_STATUS_BAD_REQUEST);
1391 soup_uri_set_path (uri, decoded_path);
1392 g_free (decoded_path);
1395 /* Now handle authentication. (We do this here so that if
1396 * the request uses "Expect: 100-continue", we can reject it
1397 * immediately rather than waiting for the request body to
1400 for (iter = priv->auth_domains; iter; iter = iter->next) {
1401 domain = iter->data;
1403 if (soup_auth_domain_covers (domain, msg)) {
1404 auth_user = soup_auth_domain_accepts (domain, msg);
1406 client->auth_domain = g_object_ref (domain);
1407 client->auth_user = auth_user;
1415 /* If any auth domain rejected it, then it will need authentication. */
1417 for (iter = priv->auth_domains; iter; iter = iter->next) {
1418 domain = iter->data;
1420 if (soup_auth_domain_covers (domain, msg))
1421 soup_auth_domain_challenge (domain, msg);
1426 /* Otherwise, call the early handlers. */
1427 handler = get_handler (server, msg);
1429 call_handler (server, handler, client, msg, TRUE);
1433 complete_websocket_upgrade (SoupMessage *msg, gpointer user_data)
1435 SoupClientContext *client = user_data;
1436 SoupServer *server = client->server;
1437 SoupURI *uri = soup_message_get_uri (msg);
1438 SoupServerHandler *handler;
1440 SoupWebsocketConnection *conn;
1442 handler = get_handler (server, msg);
1443 if (!handler || !handler->websocket_callback)
1446 soup_client_context_ref (client);
1447 stream = soup_client_context_steal_connection (client);
1448 conn = soup_websocket_connection_new_with_extensions (stream, uri,
1449 SOUP_WEBSOCKET_CONNECTION_SERVER,
1450 soup_message_headers_get_one (msg->request_headers, "Origin"),
1451 soup_message_headers_get_one (msg->response_headers, "Sec-WebSocket-Protocol"),
1452 handler->websocket_extensions);
1453 handler->websocket_extensions = NULL;
1454 g_object_unref (stream);
1455 soup_client_context_unref (client);
1457 (*handler->websocket_callback) (server, conn, uri->path, client,
1458 handler->websocket_user_data);
1459 g_object_unref (conn);
1460 soup_client_context_unref (client);
1464 got_body (SoupMessage *msg, SoupClientContext *client)
1466 SoupServer *server = client->server;
1467 SoupServerHandler *handler;
1469 g_signal_emit (server, signals[REQUEST_READ], 0, msg, client);
1471 if (msg->status_code != 0)
1474 handler = get_handler (server, msg);
1476 soup_message_set_status (msg, SOUP_STATUS_NOT_FOUND);
1480 call_handler (server, handler, client, msg, FALSE);
1481 if (msg->status_code != 0)
1484 if (handler->websocket_callback) {
1485 SoupServerPrivate *priv;
1487 priv = soup_server_get_instance_private (server);
1488 if (soup_websocket_server_process_handshake_with_extensions (msg,
1489 handler->websocket_origin,
1490 handler->websocket_protocols,
1491 priv->websocket_extension_types,
1492 &handler->websocket_extensions)) {
1493 g_signal_connect (msg, "wrote-informational",
1494 G_CALLBACK (complete_websocket_upgrade),
1495 soup_client_context_ref (client));
1501 start_request (SoupServer *server, SoupClientContext *client)
1503 SoupServerPrivate *priv = soup_server_get_instance_private (server);
1506 soup_client_context_cleanup (client);
1508 /* Listen for another request on this connection */
1509 msg = g_object_new (SOUP_TYPE_MESSAGE,
1510 SOUP_MESSAGE_SERVER_SIDE, TRUE,
1514 if (priv->server_header) {
1515 soup_message_headers_append (msg->response_headers, "Server",
1516 priv->server_header);
1519 g_signal_connect (msg, "got_headers", G_CALLBACK (got_headers), client);
1520 g_signal_connect (msg, "got_body", G_CALLBACK (got_body), client);
1522 g_signal_emit (server, signals[REQUEST_STARTED], 0,
1525 soup_message_read_request (msg, client->sock,
1526 priv->legacy_iface == NULL,
1527 request_finished, client);
1531 socket_disconnected (SoupSocket *sock, SoupClientContext *client)
1533 SoupServerPrivate *priv = soup_server_get_instance_private (client->server);
1535 priv->clients = g_slist_remove (priv->clients, client);
1538 soup_message_set_status (client->msg, SOUP_STATUS_IO_ERROR);
1539 soup_message_io_finished (client->msg);
1544 soup_server_accept_socket (SoupServer *server,
1547 SoupServerPrivate *priv = soup_server_get_instance_private (server);
1548 SoupClientContext *client;
1550 client = soup_client_context_new (server, sock);
1551 priv->clients = g_slist_prepend (priv->clients, client);
1552 start_request (server, client);
1556 * soup_server_accept_iostream:
1557 * @server: a #SoupServer
1558 * @stream: a #GIOStream
1559 * @local_addr: (allow-none): the local #GSocketAddress associated with the @stream
1560 * @remote_addr: (allow-none): the remote #GSocketAddress associated with the @stream
1561 * @error: return location for a #GError
1563 * Add a new client stream to the @server.
1565 * Return value: %TRUE on success, %FALSE if the stream could not be
1566 * accepted or any other error occurred (in which case @error will be
1572 soup_server_accept_iostream (SoupServer *server,
1574 GSocketAddress *local_addr,
1575 GSocketAddress *remote_addr,
1579 SoupAddress *local = NULL, *remote = NULL;
1582 local = soup_address_new_from_gsockaddr (local_addr);
1584 remote = soup_address_new_from_gsockaddr (remote_addr);
1586 sock = g_initable_new (SOUP_TYPE_SOCKET, NULL, error,
1588 "local-address", local,
1589 "remote-address", remote,
1592 g_clear_object (&local);
1593 g_clear_object (&remote);
1598 soup_server_accept_socket (server, sock);
1599 g_object_unref (sock);
1605 new_connection (SoupSocket *listener, SoupSocket *sock, gpointer user_data)
1607 SoupServer *server = user_data;
1609 soup_server_accept_socket (server, sock);
1613 * soup_server_run_async:
1614 * @server: a #SoupServer
1616 * Starts @server, if you are using the old API, causing it to listen
1617 * for and process incoming connections.
1619 * The server runs in @server's #GMainContext. It will not actually
1620 * perform any processing unless the appropriate main loop is running.
1621 * In the simple case where you did not set the server's
1622 * %SOUP_SERVER_ASYNC_CONTEXT property, this means the server will run
1623 * whenever the glib main loop is running.
1625 * Deprecated: When using soup_server_listen(), etc, the server will
1626 * always listen for connections, and will process them whenever the
1627 * thread-default #GMainContext is running.
1630 soup_server_run_async (SoupServer *server)
1632 SoupServerPrivate *priv;
1633 SoupSocket *listener;
1635 g_return_if_fail (SOUP_IS_SERVER (server));
1636 priv = soup_server_get_instance_private (server);
1638 soup_server_ensure_listening (server);
1640 g_return_if_fail (priv->legacy_iface != NULL);
1642 if (!priv->listeners) {
1644 g_main_loop_unref (priv->loop);
1650 listener = priv->listeners->data;
1651 g_signal_connect (listener, "new_connection",
1652 G_CALLBACK (new_connection), server);
1659 * @server: a #SoupServer
1661 * Starts @server, if you are using the old API, causing it to listen
1662 * for and process incoming connections. Unlike
1663 * soup_server_run_async(), this creates a #GMainLoop and runs it, and
1664 * it will not return until someone calls soup_server_quit() to stop
1667 * Deprecated: When using soup_server_listen(), etc, the server will
1668 * always listen for connections, and will process them whenever the
1669 * thread-default #GMainContext is running.
1672 soup_server_run (SoupServer *server)
1674 SoupServerPrivate *priv;
1676 g_return_if_fail (SOUP_IS_SERVER (server));
1677 priv = soup_server_get_instance_private (server);
1680 priv->loop = g_main_loop_new (priv->async_context, TRUE);
1681 G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
1682 soup_server_run_async (server);
1683 G_GNUC_END_IGNORE_DEPRECATIONS;
1687 g_main_loop_run (priv->loop);
1692 * @server: a #SoupServer
1694 * Stops processing for @server, if you are using the old API. Call
1695 * this to clean up after soup_server_run_async(), or to terminate a
1696 * call to soup_server_run().
1698 * Note that messages currently in progress will continue to be
1699 * handled, if the main loop associated with the server is resumed or
1702 * @server is still in a working state after this call; you can start
1703 * and stop a server as many times as you want.
1705 * Deprecated: When using soup_server_listen(), etc, the server will
1706 * always listen for connections, and will process them whenever the
1707 * thread-default #GMainContext is running.
1710 soup_server_quit (SoupServer *server)
1712 SoupServerPrivate *priv;
1713 SoupSocket *listener;
1715 g_return_if_fail (SOUP_IS_SERVER (server));
1716 priv = soup_server_get_instance_private (server);
1717 g_return_if_fail (priv->legacy_iface != NULL);
1718 g_return_if_fail (priv->listeners != NULL);
1720 listener = priv->listeners->data;
1721 g_signal_handlers_disconnect_by_func (listener,
1722 G_CALLBACK (new_connection),
1725 g_main_loop_quit (priv->loop);
1729 * soup_server_disconnect:
1730 * @server: a #SoupServer
1732 * Closes and frees @server's listening sockets. If you are using the
1733 * old #SoupServer APIs, this also includes the effect of
1734 * soup_server_quit().
1736 * Note that if there are currently requests in progress on @server,
1737 * that they will continue to be processed if @server's #GMainContext
1740 * You can call soup_server_listen(), etc, after calling this function
1741 * if you want to start listening again.
1744 soup_server_disconnect (SoupServer *server)
1746 SoupServerPrivate *priv;
1747 GSList *listeners, *clients, *iter;
1748 SoupSocket *listener;
1749 SoupClientContext *client;
1751 g_return_if_fail (SOUP_IS_SERVER (server));
1752 priv = soup_server_get_instance_private (server);
1754 if (priv->legacy_iface) {
1755 G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
1756 soup_server_quit (server);
1757 G_GNUC_END_IGNORE_DEPRECATIONS;
1760 clients = priv->clients;
1761 priv->clients = NULL;
1762 listeners = priv->listeners;
1763 priv->listeners = NULL;
1765 for (iter = clients; iter; iter = iter->next) {
1766 client = iter->data;
1767 soup_socket_disconnect (client->sock);
1769 g_slist_free (clients);
1771 for (iter = listeners; iter; iter = iter->next) {
1772 listener = iter->data;
1773 soup_socket_disconnect (listener);
1774 g_object_unref (listener);
1776 g_slist_free (listeners);
1780 * SoupServerListenOptions:
1781 * @SOUP_SERVER_LISTEN_HTTPS: Listen for https connections rather
1783 * @SOUP_SERVER_LISTEN_IPV4_ONLY: Only listen on IPv4 interfaces.
1784 * @SOUP_SERVER_LISTEN_IPV6_ONLY: Only listen on IPv6 interfaces.
1786 * Options to pass to soup_server_listen(), etc.
1788 * %SOUP_SERVER_LISTEN_IPV4_ONLY and %SOUP_SERVER_LISTEN_IPV6_ONLY
1789 * only make sense with soup_server_listen_all() and
1790 * soup_server_listen_local(), not plain soup_server_listen() (which
1791 * simply listens on whatever kind of socket you give it). And you
1792 * cannot specify both of them in a single call.
1798 soup_server_listen_internal (SoupServer *server, SoupSocket *listener,
1799 SoupServerListenOptions options,
1802 SoupServerPrivate *priv = soup_server_get_instance_private (server);
1803 gboolean is_listening;
1805 if (options & SOUP_SERVER_LISTEN_HTTPS) {
1806 if (!priv->tls_cert) {
1807 g_set_error_literal (error,
1809 G_IO_ERROR_INVALID_ARGUMENT,
1810 _("Can’t create a TLS server without a TLS certificate"));
1814 g_object_set (G_OBJECT (listener),
1815 SOUP_SOCKET_SSL_CREDENTIALS, priv->tls_cert,
1819 g_object_get (G_OBJECT (listener),
1820 SOUP_SOCKET_IS_SERVER, &is_listening,
1822 if (!is_listening) {
1823 if (!soup_socket_listen_full (listener, error)) {
1824 SoupAddress *saddr = soup_socket_get_local_address (listener);
1826 g_prefix_error (error,
1827 _("Could not listen on address %s, port %d: "),
1828 soup_address_get_physical (saddr),
1829 soup_address_get_port (saddr));
1834 g_signal_connect (listener, "new_connection",
1835 G_CALLBACK (new_connection), server);
1837 /* Note: soup_server_listen_ipv4_ipv6() below relies on the
1838 * fact that this does g_slist_prepend().
1840 priv->listeners = g_slist_prepend (priv->listeners, g_object_ref (listener));
1845 * soup_server_listen:
1846 * @server: a #SoupServer
1847 * @address: the address of the interface to listen on
1848 * @options: listening options for this server
1849 * @error: return location for a #GError
1851 * This attempts to set up @server to listen for connections on
1854 * If @options includes %SOUP_SERVER_LISTEN_HTTPS, and @server has
1855 * been configured for TLS, then @server will listen for https
1856 * connections on this port. Otherwise it will listen for plain http.
1858 * You may call this method (along with the other "listen" methods)
1859 * any number of times on a server, if you want to listen on multiple
1860 * ports, or set up both http and https service.
1862 * After calling this method, @server will begin accepting and
1863 * processing connections as soon as the appropriate #GMainContext is
1866 * Note that #SoupServer never makes use of dual IPv4/IPv6 sockets; if
1867 * @address is an IPv6 address, it will only accept IPv6 connections.
1868 * You must configure IPv4 listening separately.
1870 * Return value: %TRUE on success, %FALSE if @address could not be
1871 * bound or any other error occurred (in which case @error will be
1877 soup_server_listen (SoupServer *server, GSocketAddress *address,
1878 SoupServerListenOptions options,
1881 SoupServerPrivate *priv;
1882 SoupSocket *listener;
1886 g_return_val_if_fail (SOUP_IS_SERVER (server), FALSE);
1887 g_return_val_if_fail (!(options & SOUP_SERVER_LISTEN_IPV4_ONLY) &&
1888 !(options & SOUP_SERVER_LISTEN_IPV6_ONLY), FALSE);
1890 priv = soup_server_get_instance_private (server);
1891 g_return_val_if_fail (priv->disposed == FALSE, FALSE);
1893 saddr = soup_address_new_from_gsockaddr (address);
1894 listener = soup_socket_new (SOUP_SOCKET_LOCAL_ADDRESS, saddr,
1895 SOUP_SOCKET_USE_THREAD_CONTEXT, TRUE,
1896 SOUP_SOCKET_IPV6_ONLY, TRUE,
1899 success = soup_server_listen_internal (server, listener, options, error);
1900 g_object_unref (listener);
1901 g_object_unref (saddr);
1907 soup_server_listen_ipv4_ipv6 (SoupServer *server,
1908 GInetAddress *iaddr4,
1909 GInetAddress *iaddr6,
1911 SoupServerListenOptions options,
1914 SoupServerPrivate *priv = soup_server_get_instance_private (server);
1915 GSocketAddress *addr4, *addr6;
1916 GError *my_error = NULL;
1920 g_return_val_if_fail (iaddr4 != NULL || iaddr6 != NULL, FALSE);
1922 options &= ~(SOUP_SERVER_LISTEN_IPV4_ONLY | SOUP_SERVER_LISTEN_IPV6_ONLY);
1926 addr4 = g_inet_socket_address_new (iaddr4, port);
1927 if (!soup_server_listen (server, addr4, options, error)) {
1928 g_object_unref (addr4);
1931 g_object_unref (addr4);
1933 v4sock = priv->listeners->data;
1934 v4port = soup_address_get_port (soup_socket_get_local_address (v4sock));
1943 addr6 = g_inet_socket_address_new (iaddr6, v4port);
1944 if (soup_server_listen (server, addr6, options, &my_error)) {
1945 g_object_unref (addr6);
1948 g_object_unref (addr6);
1950 if (v4sock && g_error_matches (my_error, G_IO_ERROR,
1951 #if GLIB_CHECK_VERSION (2, 41, 0)
1952 G_IO_ERROR_NOT_SUPPORTED
1957 /* No IPv6 support, but IPV6_ONLY wasn't specified, so just
1958 * ignore the failure.
1960 g_error_free (my_error);
1965 priv->listeners = g_slist_remove (priv->listeners, v4sock);
1966 soup_socket_disconnect (v4sock);
1967 g_object_unref (v4sock);
1970 if (port == 0 && g_error_matches (my_error, G_IO_ERROR, G_IO_ERROR_ADDRESS_IN_USE)) {
1971 /* The randomly-assigned IPv4 port was in use on the IPv6 side... Try again */
1972 g_clear_error (&my_error);
1976 g_propagate_error (error, my_error);
1981 * soup_server_listen_all:
1982 * @server: a #SoupServer
1983 * @port: the port to listen on, or 0
1984 * @options: listening options for this server
1985 * @error: return location for a #GError
1987 * This attempts to set up @server to listen for connections on all
1988 * interfaces on the system. (That is, it listens on the addresses
1989 * <literal>0.0.0.0</literal> and/or <literal>::</literal>, depending
1990 * on whether @options includes %SOUP_SERVER_LISTEN_IPV4_ONLY,
1991 * %SOUP_SERVER_LISTEN_IPV6_ONLY, or neither.) If @port is specified,
1992 * @server will listen on that port. If it is 0, @server will find an
1993 * unused port to listen on. (In that case, you can use
1994 * soup_server_get_uris() to find out what port it ended up choosing.)
1996 * See soup_server_listen() for more details.
1998 * Return value: %TRUE on success, %FALSE if @port could not be bound
1999 * or any other error occurred (in which case @error will be set).
2004 soup_server_listen_all (SoupServer *server, guint port,
2005 SoupServerListenOptions options,
2008 GInetAddress *iaddr4, *iaddr6;
2011 g_return_val_if_fail (SOUP_IS_SERVER (server), FALSE);
2012 g_return_val_if_fail (!(options & SOUP_SERVER_LISTEN_IPV4_ONLY) ||
2013 !(options & SOUP_SERVER_LISTEN_IPV6_ONLY), FALSE);
2015 if (options & SOUP_SERVER_LISTEN_IPV6_ONLY)
2018 iaddr4 = g_inet_address_new_any (G_SOCKET_FAMILY_IPV4);
2020 if (options & SOUP_SERVER_LISTEN_IPV4_ONLY)
2023 iaddr6 = g_inet_address_new_any (G_SOCKET_FAMILY_IPV6);
2025 success = soup_server_listen_ipv4_ipv6 (server, iaddr4, iaddr6,
2026 port, options, error);
2028 g_clear_object (&iaddr4);
2029 g_clear_object (&iaddr6);
2035 * soup_server_listen_local:
2036 * @server: a #SoupServer
2037 * @port: the port to listen on, or 0
2038 * @options: listening options for this server
2039 * @error: return location for a #GError
2041 * This attempts to set up @server to listen for connections on
2042 * "localhost" (that is, <literal>127.0.0.1</literal> and/or
2043 * <literal>::1</literal>, depending on whether @options includes
2044 * %SOUP_SERVER_LISTEN_IPV4_ONLY, %SOUP_SERVER_LISTEN_IPV6_ONLY, or
2045 * neither). If @port is specified, @server will listen on that port.
2046 * If it is 0, @server will find an unused port to listen on. (In that
2047 * case, you can use soup_server_get_uris() to find out what port it
2048 * ended up choosing.)
2050 * See soup_server_listen() for more details.
2052 * Return value: %TRUE on success, %FALSE if @port could not be bound
2053 * or any other error occurred (in which case @error will be set).
2058 soup_server_listen_local (SoupServer *server, guint port,
2059 SoupServerListenOptions options,
2062 GInetAddress *iaddr4, *iaddr6;
2065 g_return_val_if_fail (SOUP_IS_SERVER (server), FALSE);
2066 g_return_val_if_fail (!(options & SOUP_SERVER_LISTEN_IPV4_ONLY) ||
2067 !(options & SOUP_SERVER_LISTEN_IPV6_ONLY), FALSE);
2069 if (options & SOUP_SERVER_LISTEN_IPV6_ONLY)
2072 iaddr4 = g_inet_address_new_loopback (G_SOCKET_FAMILY_IPV4);
2074 if (options & SOUP_SERVER_LISTEN_IPV4_ONLY)
2077 iaddr6 = g_inet_address_new_loopback (G_SOCKET_FAMILY_IPV6);
2079 success = soup_server_listen_ipv4_ipv6 (server, iaddr4, iaddr6,
2080 port, options, error);
2082 g_clear_object (&iaddr4);
2083 g_clear_object (&iaddr6);
2089 * soup_server_listen_socket:
2090 * @server: a #SoupServer
2091 * @socket: a listening #GSocket
2092 * @options: listening options for this server
2093 * @error: return location for a #GError
2095 * This attempts to set up @server to listen for connections on
2098 * See soup_server_listen() for more details.
2100 * Return value: %TRUE on success, %FALSE if an error occurred (in
2101 * which case @error will be set).
2106 soup_server_listen_socket (SoupServer *server, GSocket *socket,
2107 SoupServerListenOptions options,
2110 SoupServerPrivate *priv;
2111 SoupSocket *listener;
2114 g_return_val_if_fail (SOUP_IS_SERVER (server), FALSE);
2115 g_return_val_if_fail (G_IS_SOCKET (socket), FALSE);
2116 g_return_val_if_fail (!(options & SOUP_SERVER_LISTEN_IPV4_ONLY) &&
2117 !(options & SOUP_SERVER_LISTEN_IPV6_ONLY), FALSE);
2119 priv = soup_server_get_instance_private (server);
2120 g_return_val_if_fail (priv->disposed == FALSE, FALSE);
2122 listener = g_initable_new (SOUP_TYPE_SOCKET, NULL, error,
2123 SOUP_SOCKET_GSOCKET, socket,
2124 SOUP_SOCKET_USE_THREAD_CONTEXT, TRUE,
2125 SOUP_SOCKET_IPV6_ONLY, TRUE,
2130 success = soup_server_listen_internal (server, listener, options, error);
2131 g_object_unref (listener);
2137 * soup_server_listen_fd:
2138 * @server: a #SoupServer
2139 * @fd: the file descriptor of a listening socket
2140 * @options: listening options for this server
2141 * @error: return location for a #GError
2143 * This attempts to set up @server to listen for connections on
2146 * See soup_server_listen() for more details.
2148 * Note that @server will close @fd when you free it or call
2149 * soup_server_disconnect().
2151 * Return value: %TRUE on success, %FALSE if an error occurred (in
2152 * which case @error will be set).
2157 soup_server_listen_fd (SoupServer *server, int fd,
2158 SoupServerListenOptions options,
2161 SoupServerPrivate *priv;
2162 SoupSocket *listener;
2165 g_return_val_if_fail (SOUP_IS_SERVER (server), FALSE);
2166 g_return_val_if_fail (!(options & SOUP_SERVER_LISTEN_IPV4_ONLY) &&
2167 !(options & SOUP_SERVER_LISTEN_IPV6_ONLY), FALSE);
2169 priv = soup_server_get_instance_private (server);
2170 g_return_val_if_fail (priv->disposed == FALSE, FALSE);
2172 listener = g_initable_new (SOUP_TYPE_SOCKET, NULL, error,
2174 SOUP_SOCKET_USE_THREAD_CONTEXT, TRUE,
2175 SOUP_SOCKET_IPV6_ONLY, TRUE,
2180 success = soup_server_listen_internal (server, listener, options, error);
2181 g_object_unref (listener);
2187 * soup_server_get_uris:
2188 * @server: a #SoupServer
2190 * Gets a list of URIs corresponding to the interfaces @server is
2191 * listening on. These will contain IP addresses, not hostnames, and
2192 * will also indicate whether the given listener is http or https.
2194 * Note that if you used soup_server_listen_all(), the returned URIs
2195 * will use the addresses <literal>0.0.0.0</literal> and
2196 * <literal>::</literal>, rather than actually returning separate URIs
2197 * for each interface on the system.
2199 * Return value: (transfer full) (element-type Soup.URI): a list of
2200 * #SoupURIs, which you must free when you are done with it.
2205 soup_server_get_uris (SoupServer *server)
2207 SoupServerPrivate *priv;
2209 SoupSocket *listener;
2214 g_return_val_if_fail (SOUP_IS_SERVER (server), NULL);
2215 priv = soup_server_get_instance_private (server);
2217 for (l = priv->listeners, uris = NULL; l; l = l->next) {
2219 addr = soup_socket_get_local_address (listener);
2220 g_object_get (G_OBJECT (listener), SOUP_SOCKET_SSL_CREDENTIALS, &creds, NULL);
2222 uri = soup_uri_new (NULL);
2223 soup_uri_set_scheme (uri, creds ? "https" : "http");
2224 soup_uri_set_host (uri, soup_address_get_physical (addr));
2225 soup_uri_set_port (uri, soup_address_get_port (addr));
2226 soup_uri_set_path (uri, "/");
2228 uris = g_slist_prepend (uris, uri);
2235 * soup_server_get_async_context:
2236 * @server: a #SoupServer
2238 * Gets @server's async_context, if you are using the old API. (With
2239 * the new API, the server runs in the thread's thread-default
2240 * #GMainContext, regardless of what this method returns.)
2242 * This does not add a ref to the context, so you will need to ref it
2243 * yourself if you want it to outlive its server.
2245 * Return value: (nullable) (transfer none): @server's #GMainContext,
2246 * which may be %NULL
2248 * Deprecated: If you are using soup_server_listen(), etc, then
2249 * the server listens on the thread-default #GMainContext, and this
2250 * property is ignored.
2253 soup_server_get_async_context (SoupServer *server)
2255 SoupServerPrivate *priv;
2257 g_return_val_if_fail (SOUP_IS_SERVER (server), NULL);
2258 priv = soup_server_get_instance_private (server);
2260 return priv->async_context;
2264 * SoupClientContext:
2266 * A #SoupClientContext provides additional information about the
2267 * client making a particular request. In particular, you can use
2268 * soup_client_context_get_auth_domain() and
2269 * soup_client_context_get_auth_user() to determine if HTTP
2270 * authentication was used successfully.
2272 * soup_client_context_get_remote_address() and/or
2273 * soup_client_context_get_host() can be used to get information for
2274 * logging or debugging purposes. soup_client_context_get_gsocket() may
2275 * also be of use in some situations (eg, tracking when multiple
2276 * requests are made on the same connection).
2278 G_DEFINE_BOXED_TYPE (SoupClientContext, soup_client_context, soup_client_context_ref, soup_client_context_unref)
2281 * soup_client_context_get_socket:
2282 * @client: a #SoupClientContext
2284 * Retrieves the #SoupSocket that @client is associated with.
2286 * If you are using this method to observe when multiple requests are
2287 * made on the same persistent HTTP connection (eg, as the ntlm-test
2288 * test program does), you will need to pay attention to socket
2289 * destruction as well (either by using weak references, or by
2290 * connecting to the #SoupSocket::disconnected signal), so that you do
2291 * not get fooled when the allocator reuses the memory address of a
2292 * previously-destroyed socket to represent a new socket.
2294 * Return value: (transfer none): the #SoupSocket that @client is
2297 * Deprecated: use soup_client_context_get_gsocket(), which returns
2301 soup_client_context_get_socket (SoupClientContext *client)
2303 g_return_val_if_fail (client != NULL, NULL);
2305 return client->sock;
2309 * soup_client_context_get_gsocket:
2310 * @client: a #SoupClientContext
2312 * Retrieves the #GSocket that @client is associated with.
2314 * If you are using this method to observe when multiple requests are
2315 * made on the same persistent HTTP connection (eg, as the ntlm-test
2316 * test program does), you will need to pay attention to socket
2317 * destruction as well (eg, by using weak references), so that you do
2318 * not get fooled when the allocator reuses the memory address of a
2319 * previously-destroyed socket to represent a new socket.
2321 * Return value: (nullable) (transfer none): the #GSocket that @client is
2322 * associated with, %NULL if you used soup_server_accept_iostream().
2327 soup_client_context_get_gsocket (SoupClientContext *client)
2329 g_return_val_if_fail (client != NULL, NULL);
2331 return client->gsock;
2335 * soup_client_context_get_address:
2336 * @client: a #SoupClientContext
2338 * Retrieves the #SoupAddress associated with the remote end
2341 * Return value: (nullable) (transfer none): the #SoupAddress
2342 * associated with the remote end of a connection, it may be
2343 * %NULL if you used soup_server_accept_iostream().
2345 * Deprecated: Use soup_client_context_get_remote_address(), which returns
2346 * a #GSocketAddress.
2349 soup_client_context_get_address (SoupClientContext *client)
2351 g_return_val_if_fail (client != NULL, NULL);
2353 return soup_socket_get_remote_address (client->sock);
2357 * soup_client_context_get_remote_address:
2358 * @client: a #SoupClientContext
2360 * Retrieves the #GSocketAddress associated with the remote end
2363 * Return value: (nullable) (transfer none): the #GSocketAddress
2364 * associated with the remote end of a connection, it may be
2365 * %NULL if you used soup_server_accept_iostream().
2370 soup_client_context_get_remote_address (SoupClientContext *client)
2372 g_return_val_if_fail (client != NULL, NULL);
2374 if (client->remote_addr)
2375 return client->remote_addr;
2377 client->remote_addr = client->gsock ?
2378 g_socket_get_remote_address (client->gsock, NULL) :
2379 soup_address_get_gsockaddr (soup_socket_get_remote_address (client->sock));
2381 return client->remote_addr;
2385 * soup_client_context_get_local_address:
2386 * @client: a #SoupClientContext
2388 * Retrieves the #GSocketAddress associated with the local end
2391 * Return value: (nullable) (transfer none): the #GSocketAddress
2392 * associated with the local end of a connection, it may be
2393 * %NULL if you used soup_server_accept_iostream().
2398 soup_client_context_get_local_address (SoupClientContext *client)
2400 g_return_val_if_fail (client != NULL, NULL);
2402 if (client->local_addr)
2403 return client->local_addr;
2405 client->local_addr = client->gsock ?
2406 g_socket_get_local_address (client->gsock, NULL) :
2407 soup_address_get_gsockaddr (soup_socket_get_local_address (client->sock));
2409 return client->local_addr;
2413 * soup_client_context_get_host:
2414 * @client: a #SoupClientContext
2416 * Retrieves the IP address associated with the remote end of a
2419 * Return value: (nullable): the IP address associated with the remote
2420 * end of a connection, it may be %NULL if you used
2421 * soup_server_accept_iostream().
2424 soup_client_context_get_host (SoupClientContext *client)
2426 g_return_val_if_fail (client != NULL, NULL);
2428 if (client->remote_ip)
2429 return client->remote_ip;
2431 if (client->gsock) {
2432 GSocketAddress *addr = soup_client_context_get_remote_address (client);
2433 GInetAddress *iaddr;
2435 if (!addr || !G_IS_INET_SOCKET_ADDRESS (addr))
2437 iaddr = g_inet_socket_address_get_address (G_INET_SOCKET_ADDRESS (addr));
2438 client->remote_ip = g_inet_address_to_string (iaddr);
2442 G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
2443 addr = soup_client_context_get_address (client);
2444 G_GNUC_END_IGNORE_DEPRECATIONS;
2445 client->remote_ip = g_strdup (soup_address_get_physical (addr));
2448 return client->remote_ip;
2452 * soup_client_context_get_auth_domain:
2453 * @client: a #SoupClientContext
2455 * Checks whether the request associated with @client has been
2456 * authenticated, and if so returns the #SoupAuthDomain that
2459 * Return value: (transfer none) (nullable): a #SoupAuthDomain, or
2460 * %NULL if the request was not authenticated.
2463 soup_client_context_get_auth_domain (SoupClientContext *client)
2465 g_return_val_if_fail (client != NULL, NULL);
2467 return client->auth_domain;
2471 * soup_client_context_get_auth_user:
2472 * @client: a #SoupClientContext
2474 * Checks whether the request associated with @client has been
2475 * authenticated, and if so returns the username that the client
2478 * Return value: (nullable): the authenticated-as user, or %NULL if
2479 * the request was not authenticated.
2482 soup_client_context_get_auth_user (SoupClientContext *client)
2484 g_return_val_if_fail (client != NULL, NULL);
2486 return client->auth_user;
2490 * soup_client_context_steal_connection:
2491 * @client: a #SoupClientContext
2493 * "Steals" the HTTP connection associated with @client from its
2494 * #SoupServer. This happens immediately, regardless of the current
2495 * state of the connection; if the response to the current
2496 * #SoupMessage has not yet finished being sent, then it will be
2497 * discarded; you can steal the connection from a
2498 * #SoupMessage:wrote-informational or #SoupMessage:wrote-body signal
2499 * handler if you need to wait for part or all of the response to be
2502 * Note that when calling this function from C, @client will most
2503 * likely be freed as a side effect.
2505 * Return value: (transfer full): the #GIOStream formerly associated
2506 * with @client (or %NULL if @client was no longer associated with a
2507 * connection). No guarantees are made about what kind of #GIOStream
2513 soup_client_context_steal_connection (SoupClientContext *client)
2517 g_return_val_if_fail (client != NULL, NULL);
2519 soup_client_context_ref (client);
2521 stream = soup_message_io_steal (client->msg);
2523 g_object_set_data_full (G_OBJECT (stream), "GSocket",
2524 soup_socket_steal_gsocket (client->sock),
2528 socket_disconnected (client->sock, client);
2529 soup_client_context_unref (client);
2536 * SoupServerCallback:
2537 * @server: the #SoupServer
2538 * @msg: the message being processed
2539 * @path: the path component of @msg's Request-URI
2540 * @query: (element-type utf8 utf8) (allow-none): the parsed query
2541 * component of @msg's Request-URI
2542 * @client: additional contextual information about the client
2543 * @user_data: the data passed to soup_server_add_handler() or
2544 * soup_server_add_early_handler().
2546 * A callback used to handle requests to a #SoupServer.
2548 * @path and @query contain the likewise-named components of the
2549 * Request-URI, subject to certain assumptions. By default,
2550 * #SoupServer decodes all percent-encoding in the URI path, such that
2551 * "/foo%<!-- -->2Fbar" is treated the same as "/foo/bar". If your
2552 * server is serving resources in some non-POSIX-filesystem namespace,
2553 * you may want to distinguish those as two distinct paths. In that
2554 * case, you can set the %SOUP_SERVER_RAW_PATHS property when creating
2555 * the #SoupServer, and it will leave those characters undecoded. (You
2556 * may want to call soup_uri_normalize() to decode any percent-encoded
2557 * characters that you aren't handling specially.)
2559 * @query contains the query component of the Request-URI parsed
2560 * according to the rules for HTML form handling. Although this is the
2561 * only commonly-used query string format in HTTP, there is nothing
2562 * that actually requires that HTTP URIs use that format; if your
2563 * server needs to use some other format, you can just ignore @query,
2564 * and call soup_message_get_uri() and parse the URI's query field
2567 * See soup_server_add_handler() and soup_server_add_early_handler()
2568 * for details of what handlers can/should do.
2571 static SoupServerHandler *
2572 get_or_create_handler (SoupServer *server, const char *exact_path)
2574 SoupServerPrivate *priv = soup_server_get_instance_private (server);
2575 SoupServerHandler *handler;
2577 exact_path = NORMALIZED_PATH (exact_path);
2579 handler = soup_path_map_lookup (priv->handlers, exact_path);
2580 if (handler && !strcmp (handler->path, exact_path))
2583 handler = g_slice_new0 (SoupServerHandler);
2584 handler->path = g_strdup (exact_path);
2585 soup_path_map_add (priv->handlers, exact_path, handler);
2591 * soup_server_add_handler:
2592 * @server: a #SoupServer
2593 * @path: (allow-none): the toplevel path for the handler
2594 * @callback: callback to invoke for requests under @path
2595 * @user_data: data for @callback
2596 * @destroy: destroy notifier to free @user_data
2598 * Adds a handler to @server for requests under @path. If @path is
2599 * %NULL or "/", then this will be the default handler for all
2600 * requests that don't have a more specific handler. (Note though that
2601 * if you want to handle requests to the special "*" URI, you must
2602 * explicitly register a handler for "*"; the default handler will not
2603 * be used for that case.)
2605 * For requests under @path (that have not already been assigned a
2606 * status code by a #SoupAuthDomain, an early #SoupServerHandler, or a
2607 * signal handler), @callback will be invoked after receiving the
2608 * request body; the message's #SoupMessage:method,
2609 * #SoupMessage:request-headers, and #SoupMessage:request-body fields
2610 * will be filled in.
2612 * After determining what to do with the request, the callback must at
2613 * a minimum call soup_message_set_status() (or
2614 * soup_message_set_status_full()) on the message to set the response
2615 * status code. Additionally, it may set response headers and/or fill
2616 * in the response body.
2618 * If the callback cannot fully fill in the response before returning
2619 * (eg, if it needs to wait for information from a database, or
2620 * another network server), it should call soup_server_pause_message()
2621 * to tell @server to not send the response right away. When the
2622 * response is ready, call soup_server_unpause_message() to cause it
2625 * To send the response body a bit at a time using "chunked" encoding,
2626 * first call soup_message_headers_set_encoding() to set
2627 * %SOUP_ENCODING_CHUNKED on the #SoupMessage:response-headers. Then call
2628 * soup_message_body_append() (or soup_message_body_append_buffer())
2629 * to append each chunk as it becomes ready, and
2630 * soup_server_unpause_message() to make sure it's running. (The
2631 * server will automatically pause the message if it is using chunked
2632 * encoding but no more chunks are available.) When you are done, call
2633 * soup_message_body_complete() to indicate that no more chunks are
2637 soup_server_add_handler (SoupServer *server,
2639 SoupServerCallback callback,
2641 GDestroyNotify destroy)
2643 SoupServerHandler *handler;
2645 g_return_if_fail (SOUP_IS_SERVER (server));
2646 g_return_if_fail (callback != NULL);
2648 handler = get_or_create_handler (server, path);
2649 if (handler->destroy)
2650 handler->destroy (handler->user_data);
2652 handler->callback = callback;
2653 handler->destroy = destroy;
2654 handler->user_data = user_data;
2658 * soup_server_add_early_handler:
2659 * @server: a #SoupServer
2660 * @path: (allow-none): the toplevel path for the handler
2661 * @callback: callback to invoke for requests under @path
2662 * @user_data: data for @callback
2663 * @destroy: destroy notifier to free @user_data
2665 * Adds an "early" handler to @server for requests under @path. Note
2666 * that "normal" and "early" handlers are matched up together, so if
2667 * you add a normal handler for "/foo" and an early handler for
2668 * "/foo/bar", then a request to "/foo/bar" (or any path below it)
2669 * will run only the early handler. (But if you add both handlers at
2670 * the same path, then both will get run.)
2672 * For requests under @path (that have not already been assigned a
2673 * status code by a #SoupAuthDomain or a signal handler), @callback
2674 * will be invoked after receiving the request headers, but before
2675 * receiving the request body; the message's #SoupMessage:method and
2676 * #SoupMessage:request-headers fields will be filled in.
2678 * Early handlers are generally used for processing requests with
2679 * request bodies in a streaming fashion. If you determine that the
2680 * request will contain a message body, normally you would call
2681 * soup_message_body_set_accumulate() on the message's
2682 * #SoupMessage:request-body to turn off request-body accumulation,
2683 * and connect to the message's #SoupMessage::got-chunk signal to
2684 * process each chunk as it comes in.
2686 * To complete the message processing after the full message body has
2687 * been read, you can either also connect to #SoupMessage::got-body,
2688 * or else you can register a non-early handler for @path as well. As
2689 * long as you have not set the #SoupMessage:status-code by the time
2690 * #SoupMessage::got-body is emitted, the non-early handler will be
2696 soup_server_add_early_handler (SoupServer *server,
2698 SoupServerCallback callback,
2700 GDestroyNotify destroy)
2702 SoupServerHandler *handler;
2704 g_return_if_fail (SOUP_IS_SERVER (server));
2705 g_return_if_fail (callback != NULL);
2707 handler = get_or_create_handler (server, path);
2708 if (handler->early_destroy)
2709 handler->early_destroy (handler->early_user_data);
2711 handler->early_callback = callback;
2712 handler->early_destroy = destroy;
2713 handler->early_user_data = user_data;
2717 * SoupServerWebsocketCallback:
2718 * @server: the #SoupServer
2719 * @path: the path component of @msg's Request-URI
2720 * @connection: the newly created WebSocket connection
2721 * @client: additional contextual information about the client
2722 * @user_data: the data passed to @soup_server_add_handler
2724 * A callback used to handle WebSocket requests to a #SoupServer. The
2725 * callback will be invoked after sending the handshake response back
2726 * to the client (and is only invoked if the handshake was
2729 * @path contains the path of the Request-URI, subject to the same
2730 * rules as #SoupServerCallback (qv).
2734 * soup_server_add_websocket_handler:
2735 * @server: a #SoupServer
2736 * @path: (allow-none): the toplevel path for the handler
2737 * @origin: (allow-none): the origin of the connection
2738 * @protocols: (allow-none) (array zero-terminated=1): the protocols
2739 * supported by this handler
2740 * @callback: callback to invoke for successful WebSocket requests under @path
2741 * @user_data: data for @callback
2742 * @destroy: destroy notifier to free @user_data
2744 * Adds a WebSocket handler to @server for requests under @path. (If
2745 * @path is %NULL or "/", then this will be the default handler for
2746 * all requests that don't have a more specific handler.)
2748 * When a path has a WebSocket handler registered, @server will check
2749 * incoming requests for WebSocket handshakes after all other handlers
2750 * have run (unless some earlier handler has already set a status code
2751 * on the message), and update the request's status, response headers,
2752 * and response body accordingly.
2754 * If @origin is non-%NULL, then only requests containing a matching
2755 * "Origin" header will be accepted. If @protocols is non-%NULL, then
2756 * only requests containing a compatible "Sec-WebSocket-Protocols"
2757 * header will be accepted. More complicated requirements can be
2758 * handled by adding a normal handler to @path, and having it perform
2759 * whatever checks are needed (possibly calling
2760 * soup_server_check_websocket_handshake() one or more times), and
2761 * setting a failure status code if the handshake should be rejected.
2764 soup_server_add_websocket_handler (SoupServer *server,
2768 SoupServerWebsocketCallback callback,
2770 GDestroyNotify destroy)
2772 SoupServerHandler *handler;
2774 g_return_if_fail (SOUP_IS_SERVER (server));
2775 g_return_if_fail (callback != NULL);
2777 handler = get_or_create_handler (server, path);
2778 if (handler->websocket_destroy)
2779 handler->websocket_destroy (handler->websocket_user_data);
2780 if (handler->websocket_origin)
2781 g_free (handler->websocket_origin);
2782 if (handler->websocket_protocols)
2783 g_strfreev (handler->websocket_protocols);
2784 g_list_free_full (handler->websocket_extensions, g_object_unref);
2786 handler->websocket_callback = callback;
2787 handler->websocket_destroy = destroy;
2788 handler->websocket_user_data = user_data;
2789 handler->websocket_origin = g_strdup (origin);
2790 handler->websocket_protocols = g_strdupv (protocols);
2791 handler->websocket_extensions = NULL;
2795 * soup_server_remove_handler:
2796 * @server: a #SoupServer
2797 * @path: the toplevel path for the handler
2799 * Removes all handlers (early and normal) registered at @path.
2802 soup_server_remove_handler (SoupServer *server, const char *path)
2804 SoupServerPrivate *priv;
2806 g_return_if_fail (SOUP_IS_SERVER (server));
2807 priv = soup_server_get_instance_private (server);
2809 soup_path_map_remove (priv->handlers, NORMALIZED_PATH (path));
2813 * soup_server_add_auth_domain:
2814 * @server: a #SoupServer
2815 * @auth_domain: a #SoupAuthDomain
2817 * Adds an authentication domain to @server. Each auth domain will
2818 * have the chance to require authentication for each request that
2819 * comes in; normally auth domains will require authentication for
2820 * requests on certain paths that they have been set up to watch, or
2821 * that meet other criteria set by the caller. If an auth domain
2822 * determines that a request requires authentication (and the request
2823 * doesn't contain authentication), @server will automatically reject
2824 * the request with an appropriate status (401 Unauthorized or 407
2825 * Proxy Authentication Required). If the request used the
2826 * "100-continue" Expectation, @server will reject it before the
2827 * request body is sent.
2830 soup_server_add_auth_domain (SoupServer *server, SoupAuthDomain *auth_domain)
2832 SoupServerPrivate *priv;
2834 g_return_if_fail (SOUP_IS_SERVER (server));
2835 priv = soup_server_get_instance_private (server);
2837 priv->auth_domains = g_slist_append (priv->auth_domains, auth_domain);
2838 g_object_ref (auth_domain);
2842 * soup_server_remove_auth_domain:
2843 * @server: a #SoupServer
2844 * @auth_domain: a #SoupAuthDomain
2846 * Removes @auth_domain from @server.
2849 soup_server_remove_auth_domain (SoupServer *server, SoupAuthDomain *auth_domain)
2851 SoupServerPrivate *priv;
2853 g_return_if_fail (SOUP_IS_SERVER (server));
2854 priv = soup_server_get_instance_private (server);
2856 priv->auth_domains = g_slist_remove (priv->auth_domains, auth_domain);
2857 g_object_unref (auth_domain);
2861 * soup_server_pause_message:
2862 * @server: a #SoupServer
2863 * @msg: a #SoupMessage associated with @server.
2865 * Pauses I/O on @msg. This can be used when you need to return from
2866 * the server handler without having the full response ready yet. Use
2867 * soup_server_unpause_message() to resume I/O.
2869 * This must only be called on #SoupMessages which were created by the
2870 * #SoupServer and are currently doing I/O, such as those passed into a
2871 * #SoupServerCallback or emitted in a #SoupServer::request-read signal.
2874 soup_server_pause_message (SoupServer *server,
2877 g_return_if_fail (SOUP_IS_SERVER (server));
2878 g_return_if_fail (SOUP_IS_MESSAGE (msg));
2880 soup_message_io_pause (msg);
2884 * soup_server_unpause_message:
2885 * @server: a #SoupServer
2886 * @msg: a #SoupMessage associated with @server.
2888 * Resumes I/O on @msg. Use this to resume after calling
2889 * soup_server_pause_message(), or after adding a new chunk to a
2892 * I/O won't actually resume until you return to the main loop.
2894 * This must only be called on #SoupMessages which were created by the
2895 * #SoupServer and are currently doing I/O, such as those passed into a
2896 * #SoupServerCallback or emitted in a #SoupServer::request-read signal.
2899 soup_server_unpause_message (SoupServer *server,
2902 g_return_if_fail (SOUP_IS_SERVER (server));
2903 g_return_if_fail (SOUP_IS_MESSAGE (msg));
2905 soup_message_io_unpause (msg);
2909 * soup_server_add_websocket_extension:
2910 * @server: a #SoupServer
2911 * @extension_type: a #GType
2913 * Add support for a WebSocket extension of the given @extension_type.
2914 * When a WebSocket client requests an extension of @extension_type,
2915 * a new #SoupWebsocketExtension of type @extension_type will be created
2916 * to handle the request.
2918 * You can also add support for a WebSocket extension to the server at
2919 * construct time by using the %SOUP_SERVER_ADD_WEBSOCKET_EXTENSION property.
2920 * Note that #SoupWebsocketExtensionDeflate is supported by default, use
2921 * soup_server_remove_websocket_extension() if you want to disable it.
2926 soup_server_add_websocket_extension (SoupServer *server, GType extension_type)
2928 SoupServerPrivate *priv;
2930 g_return_if_fail (SOUP_IS_SERVER (server));
2932 priv = soup_server_get_instance_private (server);
2933 if (!g_type_is_a (extension_type, SOUP_TYPE_WEBSOCKET_EXTENSION)) {
2934 g_warning ("Type '%s' is not a SoupWebsocketExtension", g_type_name (extension_type));
2938 g_ptr_array_add (priv->websocket_extension_types, g_type_class_ref (extension_type));
2942 * soup_server_remove_websocket_extension:
2943 * @server: a #SoupServer
2944 * @extension_type: a #GType
2946 * Removes support for WebSocket extension of type @extension_type (or any subclass of
2947 * @extension_type) from @server. You can also remove extensions enabled by default
2948 * from the server at construct time by using the %SOUP_SERVER_REMOVE_WEBSOCKET_EXTENSION
2954 soup_server_remove_websocket_extension (SoupServer *server, GType extension_type)
2956 SoupServerPrivate *priv;
2957 SoupWebsocketExtensionClass *extension_class;
2960 g_return_if_fail (SOUP_IS_SERVER (server));
2962 priv = soup_server_get_instance_private (server);
2963 if (!g_type_is_a (extension_type, SOUP_TYPE_WEBSOCKET_EXTENSION)) {
2964 g_warning ("Type '%s' is not a SoupWebsocketExtension", g_type_name (extension_type));
2968 extension_class = g_type_class_peek (extension_type);
2969 for (i = 0; i < priv->websocket_extension_types->len; i++) {
2970 if (priv->websocket_extension_types->pdata[i] == (gpointer)extension_class) {
2971 g_ptr_array_remove_index (priv->websocket_extension_types, i);