summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDan Winship <danw@gnome.org>2009-08-04 19:34:30 -0400
committerDan Winship <danw@gnome.org>2009-08-09 10:31:54 -0400
commit280dc8568d9ebe9fb16fb13b2272169e968b3e49 (patch)
tree799dce34ba2e5c023ea45ba2cf5807a9fe0341f3
parent8cc54925bbec130acd796d96363ad31223c3a962 (diff)
downloadlibsoup-280dc8568d9ebe9fb16fb13b2272169e968b3e49.tar.gz
Support "OPTIONS *" in SoupServer
Update soup-message-server-io.c to allow "*" in a Request-Line, and update SoupServer and SoupAuthDomain methods and docs to deal with it. For backward-compatibility, requests to "*" are NOT passed to the default handler; you must explicitly register a handler for "*". http://bugzilla.gnome.org/show_bug.cgi?id=590751
-rw-r--r--libsoup/soup-auth-domain.c19
-rw-r--r--libsoup/soup-message-server-io.c21
-rw-r--r--libsoup/soup-server.c24
-rw-r--r--tests/misc-test.c95
4 files changed, 146 insertions, 13 deletions
diff --git a/libsoup/soup-auth-domain.c b/libsoup/soup-auth-domain.c
index d3949d15..62fa7724 100644
--- a/libsoup/soup-auth-domain.c
+++ b/libsoup/soup-auth-domain.c
@@ -29,7 +29,9 @@
* In order for an auth domain to have any effect, you must add one or
* more paths to it (via soup_auth_domain_add_path() or the
* %SOUP_AUTH_DOMAIN_ADD_PATH property). To require authentication for
- * all requests, add the path "/".
+ * all ordinary requests, add the path "/". (Note that this does not
+ * include the special "*" URI (eg, "OPTIONS *"), which must be added
+ * as a separate path if you want to cover it.)
*
* If you need greater control over which requests should and
* shouldn't be authenticated, add paths covering everything you
@@ -312,6 +314,10 @@ soup_auth_domain_add_path (SoupAuthDomain *domain, const char *path)
{
SoupAuthDomainPrivate *priv = SOUP_AUTH_DOMAIN_GET_PRIVATE (domain);
+ /* "" should not match "*" */
+ if (!*path)
+ path = "/";
+
soup_path_map_add (priv->paths, path, GINT_TO_POINTER (TRUE));
}
@@ -340,6 +346,10 @@ soup_auth_domain_remove_path (SoupAuthDomain *domain, const char *path)
{
SoupAuthDomainPrivate *priv = SOUP_AUTH_DOMAIN_GET_PRIVATE (domain);
+ /* "" should not match "*" */
+ if (!*path)
+ path = "/";
+
soup_path_map_add (priv->paths, path, GINT_TO_POINTER (FALSE));
}
@@ -529,8 +539,8 @@ soup_auth_domain_check_password (SoupAuthDomain *domain,
*
* Checks if @domain requires @msg to be authenticated (according to
* its paths and filter function). This does not actually look at
- * whether @msg *is* authenticated, merely whether or not is needs to
- * be.
+ * whether @msg <emphasis>is</emphasis> authenticated, merely whether
+ * or not it needs to be.
*
* This is used by #SoupServer internally and is probably of no use to
* anyone else.
@@ -560,7 +570,8 @@ soup_auth_domain_covers (SoupAuthDomain *domain, SoupMessage *msg)
*
* Checks if @msg contains appropriate authorization for @domain to
* accept it. Mirroring soup_auth_domain_covers(), this does not check
- * whether or not @domain *cares* if @msg is authorized.
+ * whether or not @domain <emphasis>cares</emphasis> if @msg is
+ * authorized.
*
* This is used by #SoupServer internally and is probably of no use to
* anyone else.
diff --git a/libsoup/soup-message-server-io.c b/libsoup/soup-message-server-io.c
index 2e769f43..56d2a6bb 100644
--- a/libsoup/soup-message-server-io.c
+++ b/libsoup/soup-message-server-io.c
@@ -56,14 +56,23 @@ parse_request_headers (SoupMessage *msg, char *headers, guint headers_len,
/* Generate correct context for request */
req_host = soup_message_headers_get_one (msg->request_headers, "Host");
+ if (strchr (req_host, '/')) {
+ g_free (req_path);
+ return SOUP_STATUS_BAD_REQUEST;
+ }
- if (*req_path != '/') {
- /* Check for absolute URI */
+ if (!strcmp (req_path, "*") && req_host) {
+ /* Eg, "OPTIONS * HTTP/1.1" */
+ url = g_strdup_printf ("%s://%s",
+ soup_socket_is_ssl (sock) ? "https" : "http",
+ req_host);
+ uri = soup_uri_new (url);
+ if (uri)
+ soup_uri_set_path (uri, "*");
+ g_free (url);
+ } else if (*req_path != '/') {
+ /* Must be an absolute URI */
uri = soup_uri_new (req_path);
- if (!uri) {
- g_free (req_path);
- return SOUP_STATUS_BAD_REQUEST;
- }
} else if (req_host) {
url = g_strdup_printf ("%s://%s%s",
soup_socket_is_ssl (sock) ? "https" : "http",
diff --git a/libsoup/soup-server.c b/libsoup/soup-server.c
index e34fffbb..b7ccef2f 100644
--- a/libsoup/soup-server.c
+++ b/libsoup/soup-server.c
@@ -40,10 +40,15 @@
* same handler, just pass "/" (or %NULL) for the path.) Any request
* that does not match any handler will automatically be returned to
* the client with a 404 (Not Found) status.
+ *
+ * If you want to handle the special "*" URI (eg, "OPTIONS *"), you
+ * must explicitly register a handler for "*"; the default handler
+ * will not be used for that case.
*
* To add authentication to some or all paths, create an appropriate
* #SoupAuthDomain (qv), and add it to the server via
- * soup_server_add_auth_domain.
+ * soup_server_add_auth_domain(). (As with handlers, you must
+ * explicitly add "*" to an auth domain if you want it to be covered.)
*
* Additional processing options are available via #SoupServer's
* signals; Connect to #SoupServer::request-started to be notified
@@ -739,6 +744,8 @@ soup_server_get_handler (SoupServer *server, const char *path)
hand = soup_path_map_lookup (priv->handlers, path);
if (hand)
return hand;
+ if (!strcmp (path, "*"))
+ return NULL;
}
return priv->default_handler;
}
@@ -1199,6 +1206,12 @@ soup_client_context_get_auth_user (SoupClientContext *client)
* Adds a handler to @server for requests under @path. See the
* documentation for #SoupServerCallback for information about
* how callbacks should behave.
+ *
+ * If @path is %NULL or "/", then this will be the default handler for
+ * all requests that don't have a more specific handler. Note though
+ * that if you want to handle requests to the special "*" URI, you
+ * must explicitly register a handler for "*"; the default handler
+ * will not be used for that case.
**/
void
soup_server_add_handler (SoupServer *server,
@@ -1214,6 +1227,13 @@ soup_server_add_handler (SoupServer *server,
g_return_if_fail (callback != NULL);
priv = SOUP_SERVER_GET_PRIVATE (server);
+ /* "" was never documented as meaning the same this as "/",
+ * but it effectively was. We have to special case it now or
+ * otherwise it would match "*" too.
+ */
+ if (path && (!*path || !strcmp (path, "/")))
+ path = NULL;
+
hand = g_slice_new0 (SoupServerHandler);
hand->path = g_strdup (path);
hand->callback = callback;
@@ -1250,7 +1270,7 @@ soup_server_remove_handler (SoupServer *server, const char *path)
g_return_if_fail (SOUP_IS_SERVER (server));
priv = SOUP_SERVER_GET_PRIVATE (server);
- if (!path) {
+ if (!path || !*path || !strcmp (path, "/")) {
if (priv->default_handler) {
unregister_handler (priv->default_handler);
free_handler (priv->default_handler);
diff --git a/tests/misc-test.c b/tests/misc-test.c
index 70415d3a..e6944777 100644
--- a/tests/misc-test.c
+++ b/tests/misc-test.c
@@ -18,6 +18,7 @@
#include "test-utils.h"
+SoupServer *server;
SoupURI *base_uri;
static gboolean
@@ -34,6 +35,16 @@ server_callback (SoupServer *server, SoupMessage *msg,
{
SoupURI *uri = soup_message_get_uri (msg);
+ soup_message_headers_append (msg->response_headers,
+ "X-Handled-By", "server_callback");
+
+ if (!strcmp (path, "*")) {
+ debug_printf (1, " default server_callback got request for '*'!\n");
+ errors++;
+ soup_message_set_status (msg, SOUP_STATUS_INTERNAL_SERVER_ERROR);
+ return;
+ }
+
if (msg->method != SOUP_METHOD_GET) {
soup_message_set_status (msg, SOUP_STATUS_NOT_IMPLEMENTED);
return;
@@ -62,6 +73,29 @@ server_callback (SoupServer *server, SoupMessage *msg,
}
}
+static void
+server_star_callback (SoupServer *server, SoupMessage *msg,
+ const char *path, GHashTable *query,
+ SoupClientContext *context, gpointer data)
+{
+ soup_message_headers_append (msg->response_headers,
+ "X-Handled-By", "star_callback");
+
+ if (strcmp (path, "*") != 0) {
+ debug_printf (1, " server_star_callback got request for '%s'!\n", path);
+ errors++;
+ soup_message_set_status (msg, SOUP_STATUS_INTERNAL_SERVER_ERROR);
+ return;
+ }
+
+ if (msg->method != SOUP_METHOD_OPTIONS) {
+ soup_message_set_status (msg, SOUP_STATUS_METHOD_NOT_ALLOWED);
+ return;
+ }
+
+ soup_message_set_status (msg, SOUP_STATUS_OK);
+}
+
/* Host header handling: client must be able to override the default
* value, server must be able to recognize different Host values.
* #539803.
@@ -283,10 +317,68 @@ do_msg_reuse_test (void)
g_free (signal_ids);
}
+static void
+do_star_test (void)
+{
+ SoupSession *session;
+ SoupMessage *msg;
+ SoupURI *star_uri;
+ const char *handled_by;
+
+ debug_printf (1, "\nOPTIONS *\n");
+
+ session = soup_test_session_new (SOUP_TYPE_SESSION_SYNC, NULL);
+ star_uri = soup_uri_copy (base_uri);
+ soup_uri_set_path (star_uri, "*");
+
+ debug_printf (1, " Testing with no handler\n");
+ msg = soup_message_new_from_uri ("OPTIONS", star_uri);
+ soup_session_send_message (session, msg);
+
+ if (msg->status_code != SOUP_STATUS_NOT_FOUND) {
+ debug_printf (1, " Unexpected response: %d %s\n",
+ msg->status_code, msg->reason_phrase);
+ errors++;
+ }
+ handled_by = soup_message_headers_get_one (msg->response_headers,
+ "X-Handled-By");
+ if (handled_by) {
+ /* Should have been rejected by SoupServer directly */
+ debug_printf (1, " Message reached handler '%s'\n",
+ handled_by);
+ errors++;
+ }
+ g_object_unref (msg);
+
+ soup_server_add_handler (server, "*", server_star_callback, NULL, NULL);
+
+ debug_printf (1, " Testing with handler\n");
+ msg = soup_message_new_from_uri ("OPTIONS", star_uri);
+ soup_session_send_message (session, msg);
+
+ if (msg->status_code != SOUP_STATUS_OK) {
+ debug_printf (1, " Unexpected response: %d %s\n",
+ msg->status_code, msg->reason_phrase);
+ errors++;
+ }
+ handled_by = soup_message_headers_get_one (msg->response_headers,
+ "X-Handled-By");
+ if (!handled_by) {
+ debug_printf (1, " Message did not reach handler!\n");
+ errors++;
+ } else if (strcmp (handled_by, "star_callback") != 0) {
+ debug_printf (1, " Message reached incorrect handler '%s'\n",
+ handled_by);
+ errors++;
+ }
+ g_object_unref (msg);
+
+ soup_test_session_abort_unref (session);
+}
+
int
main (int argc, char **argv)
{
- SoupServer *server;
SoupAuthDomain *auth_domain;
test_init (argc, argv, NULL);
@@ -307,6 +399,7 @@ main (int argc, char **argv)
do_host_test ();
do_callback_unref_test ();
do_msg_reuse_test ();
+ do_star_test ();
soup_uri_free (base_uri);