summaryrefslogtreecommitdiff
path: root/libsoup/soup-server.c
diff options
context:
space:
mode:
Diffstat (limited to 'libsoup/soup-server.c')
-rw-r--r--libsoup/soup-server.c167
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,