diff options
Diffstat (limited to 'libsoup/soup-server.c')
-rw-r--r-- | libsoup/soup-server.c | 167 |
1 files changed, 145 insertions, 22 deletions
diff --git a/libsoup/soup-server.c b/libsoup/soup-server.c index 1e462ea2..07d801d1 100644 --- a/libsoup/soup-server.c +++ b/libsoup/soup-server.c @@ -14,7 +14,7 @@ #include "soup-server.h" #include "soup.h" #include "soup-message-private.h" -#include "soup-marshal.h" +#include "soup-misc-private.h" #include "soup-path-map.h" /** @@ -106,6 +106,8 @@ typedef struct { GSList *auth_domains; GMainContext *async_context; + + char **http_aliases, **https_aliases; } SoupServerPrivate; #define SOUP_SERVER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), SOUP_TYPE_SERVER, SoupServerPrivate)) @@ -122,6 +124,8 @@ enum { PROP_ASYNC_CONTEXT, PROP_RAW_PATHS, PROP_SERVER_HEADER, + PROP_HTTP_ALIASES, + PROP_HTTPS_ALIASES, LAST_PROP }; @@ -142,6 +146,10 @@ soup_server_init (SoupServer *server) SoupServerPrivate *priv = SOUP_SERVER_GET_PRIVATE (server); priv->handlers = soup_path_map_new ((GDestroyNotify)free_handler); + + priv->http_aliases = g_new (char *, 2); + priv->http_aliases[0] = (char *)g_intern_string ("*"); + priv->http_aliases[1] = NULL; } static void @@ -192,6 +200,9 @@ soup_server_finalize (GObject *object) g_clear_pointer (&priv->loop, g_main_loop_unref); g_clear_pointer (&priv->async_context, g_main_context_unref); + g_free (priv->http_aliases); + g_free (priv->https_aliases); + G_OBJECT_CLASS (soup_server_parent_class)->finalize (object); } @@ -251,6 +262,29 @@ soup_server_constructor (GType type, return server; } +/* priv->http_aliases and priv->https_aliases are stored as arrays of + * *interned* strings, so we can't just use g_strdupv() to set them. + */ +static void +set_aliases (char ***variable, char **value) +{ + int len, i; + + if (*variable) + g_free (*variable); + + if (!value) { + *variable = NULL; + return; + } + + len = g_strv_length (value); + *variable = g_new (char *, len + 1); + for (i = 0; i < len; i++) + (*variable)[i] = (char *)g_intern_string (value[i]); + (*variable)[i] = NULL; +} + static void soup_server_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) @@ -305,6 +339,12 @@ soup_server_set_property (GObject *object, guint prop_id, } else priv->server_header = g_strdup (header); break; + case PROP_HTTP_ALIASES: + set_aliases (&priv->http_aliases, g_value_get_boxed (value)); + break; + case PROP_HTTPS_ALIASES: + set_aliases (&priv->https_aliases, g_value_get_boxed (value)); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -342,6 +382,12 @@ soup_server_get_property (GObject *object, guint prop_id, case PROP_SERVER_HEADER: g_value_set_string (value, priv->server_header); break; + case PROP_HTTP_ALIASES: + g_value_set_boxed (value, priv->http_aliases); + break; + case PROP_HTTPS_ALIASES: + g_value_set_boxed (value, priv->https_aliases); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -387,7 +433,7 @@ soup_server_class_init (SoupServerClass *server_class) G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (SoupServerClass, request_started), NULL, NULL, - _soup_marshal_NONE__OBJECT_POINTER, + NULL, G_TYPE_NONE, 2, SOUP_TYPE_MESSAGE, SOUP_TYPE_CLIENT_CONTEXT); @@ -412,7 +458,7 @@ soup_server_class_init (SoupServerClass *server_class) G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (SoupServerClass, request_read), NULL, NULL, - _soup_marshal_NONE__OBJECT_POINTER, + NULL, G_TYPE_NONE, 2, SOUP_TYPE_MESSAGE, SOUP_TYPE_CLIENT_CONTEXT); @@ -432,7 +478,7 @@ soup_server_class_init (SoupServerClass *server_class) G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (SoupServerClass, request_finished), NULL, NULL, - _soup_marshal_NONE__OBJECT_POINTER, + NULL, G_TYPE_NONE, 2, SOUP_TYPE_MESSAGE, SOUP_TYPE_CLIENT_CONTEXT); @@ -461,7 +507,7 @@ soup_server_class_init (SoupServerClass *server_class) G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (SoupServerClass, request_aborted), NULL, NULL, - _soup_marshal_NONE__OBJECT_POINTER, + NULL, G_TYPE_NONE, 2, SOUP_TYPE_MESSAGE, SOUP_TYPE_CLIENT_CONTEXT); @@ -629,6 +675,68 @@ soup_server_class_init (SoupServerClass *server_class) "Server header", NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); + + /** + * SoupServer:http-aliases: + * + * A %NULL-terminated array of URI schemes that should be + * considered to be aliases for "http". Eg, if this included + * <literal>"dav"</literal>, than a URI of + * <literal>dav://example.com/path</literal> would be treated + * identically to <literal>http://example.com/path</literal>. + * In particular, this is needed in cases where a client + * sends requests with absolute URIs, where those URIs do + * not use "http:". + * + * The default value is an array containing the single element + * <literal>"*"</literal>, a special value which means that + * any scheme except "https" is considered to be an alias for + * "http". + * + * See also #SoupServer:https-aliases. + * + * Since: 2.44 + */ + /** + * SOUP_SERVERI_HTTP_ALIASES: + * + * Alias for the #SoupServer:http-aliases property, qv. + * + * Since: 2.44 + */ + g_object_class_install_property ( + object_class, PROP_HTTP_ALIASES, + g_param_spec_boxed (SOUP_SERVER_HTTP_ALIASES, + "http aliases", + "URI schemes that are considered aliases for 'http'", + G_TYPE_STRV, + G_PARAM_READWRITE)); + /** + * SoupServer:https-aliases: + * + * A comma-delimited list of URI schemes that should be + * considered to be aliases for "https". See + * #SoupServer:http-aliases for more information. + * + * The default value is %NULL, meaning that no URI schemes + * are considered aliases for "https". + * + * Since: 2.44 + */ + /** + * SOUP_SERVER_HTTPS_ALIASES: + * + * Alias for the #SoupServer:https-aliases property, qv. + * + * Since: 2.44 + **/ + g_object_class_install_property ( + object_class, PROP_HTTPS_ALIASES, + g_param_spec_boxed (SOUP_SERVER_HTTPS_ALIASES, + "https aliases", + "URI schemes that are considered aliases for 'https'", + G_TYPE_STRV, + G_PARAM_READWRITE)); } /** @@ -680,7 +788,8 @@ soup_server_get_port (SoupServer *server) * * In order for a server to run https, you must set the * %SOUP_SERVER_SSL_CERT_FILE and %SOUP_SERVER_SSL_KEY_FILE properties - * to provide it with an SSL certificate to use. + * or %SOUP_SERVER_TLS_CERTIFICATE property to provide it with an SSL + * certificate to use. * * Return value: %TRUE if @server is serving https. **/ @@ -692,7 +801,7 @@ soup_server_is_https (SoupServer *server) g_return_val_if_fail (SOUP_IS_SERVER (server), 0); priv = SOUP_SERVER_GET_PRIVATE (server); - return (priv->ssl_cert_file && priv->ssl_key_file); + return priv->ssl_cert != NULL; } /** @@ -805,7 +914,7 @@ soup_server_get_handler (SoupServer *server, const char *path) } static void -got_headers (SoupMessage *req, SoupClientContext *client) +got_headers (SoupMessage *msg, SoupClientContext *client) { SoupServer *server = client->server; SoupServerPrivate *priv = SOUP_SERVER_GET_PRIVATE (server); @@ -817,17 +926,23 @@ got_headers (SoupMessage *req, SoupClientContext *client) gboolean rejected = FALSE; char *auth_user; + uri = soup_message_get_uri (msg); + if ((soup_server_is_https (server) && !soup_uri_is_https (uri, priv->https_aliases)) || + (!soup_server_is_https (server) && !soup_uri_is_http (uri, priv->http_aliases))) { + soup_message_set_status (msg, SOUP_STATUS_BAD_REQUEST); + return; + } + if (!priv->raw_paths) { char *decoded_path; - uri = soup_message_get_uri (req); decoded_path = soup_uri_decode (uri->path); if (strstr (decoded_path, "/../") || g_str_has_suffix (decoded_path, "/..")) { /* Introducing new ".." segments is not allowed */ g_free (decoded_path); - soup_message_set_status (req, SOUP_STATUS_BAD_REQUEST); + soup_message_set_status (msg, SOUP_STATUS_BAD_REQUEST); return; } @@ -838,7 +953,7 @@ got_headers (SoupMessage *req, SoupClientContext *client) /* Add required response headers */ date = soup_date_new_from_now (0); date_string = soup_date_to_string (date, SOUP_DATE_HTTP); - soup_message_headers_replace (req->response_headers, "Date", + soup_message_headers_replace (msg->response_headers, "Date", date_string); g_free (date_string); soup_date_free (date); @@ -851,8 +966,8 @@ got_headers (SoupMessage *req, SoupClientContext *client) for (iter = priv->auth_domains; iter; iter = iter->next) { domain = iter->data; - if (soup_auth_domain_covers (domain, req)) { - auth_user = soup_auth_domain_accepts (domain, req); + if (soup_auth_domain_covers (domain, msg)) { + auth_user = soup_auth_domain_accepts (domain, msg); if (auth_user) { client->auth_domain = g_object_ref (domain); client->auth_user = auth_user; @@ -870,27 +985,27 @@ got_headers (SoupMessage *req, SoupClientContext *client) for (iter = priv->auth_domains; iter; iter = iter->next) { domain = iter->data; - if (soup_auth_domain_covers (domain, req)) - soup_auth_domain_challenge (domain, req); + if (soup_auth_domain_covers (domain, msg)) + soup_auth_domain_challenge (domain, msg); } } static void -call_handler (SoupMessage *req, SoupClientContext *client) +call_handler (SoupMessage *msg, SoupClientContext *client) { SoupServer *server = client->server; SoupServerHandler *hand; SoupURI *uri; - g_signal_emit (server, signals[REQUEST_READ], 0, req, client); + g_signal_emit (server, signals[REQUEST_READ], 0, msg, client); - if (req->status_code != 0) + if (msg->status_code != 0) return; - uri = soup_message_get_uri (req); + uri = soup_message_get_uri (msg); hand = soup_server_get_handler (server, uri->path); if (!hand) { - soup_message_set_status (req, SOUP_STATUS_NOT_FOUND); + soup_message_set_status (msg, SOUP_STATUS_NOT_FOUND); return; } @@ -903,12 +1018,12 @@ call_handler (SoupMessage *req, SoupClientContext *client) form_data_set = NULL; /* Call method handler */ - (*hand->callback) (server, req, + (*hand->callback) (server, msg, uri->path, form_data_set, client, hand->user_data); if (form_data_set) - g_hash_table_destroy (form_data_set); + g_hash_table_unref (form_data_set); } } @@ -1436,6 +1551,10 @@ soup_server_remove_auth_domain (SoupServer *server, SoupAuthDomain *auth_domain) * Pauses I/O on @msg. This can be used when you need to return from * the server handler without having the full response ready yet. Use * soup_server_unpause_message() to resume I/O. + * + * This must only be called on #SoupMessages which were created by the + * #SoupServer and are currently doing I/O, such as those passed into a + * #SoupServerCallback or emitted in a #SoupServer::request-read signal. **/ void soup_server_pause_message (SoupServer *server, @@ -1457,6 +1576,10 @@ soup_server_pause_message (SoupServer *server, * chunked response. * * I/O won't actually resume until you return to the main loop. + * + * This must only be called on #SoupMessages which were created by the + * #SoupServer and are currently doing I/O, such as those passed into a + * #SoupServerCallback or emitted in a #SoupServer::request-read signal. **/ void soup_server_unpause_message (SoupServer *server, |