diff options
author | Dan Winship <danw@gnome.org> | 2009-08-04 19:34:30 -0400 |
---|---|---|
committer | Dan Winship <danw@gnome.org> | 2009-08-09 10:31:54 -0400 |
commit | 280dc8568d9ebe9fb16fb13b2272169e968b3e49 (patch) | |
tree | 799dce34ba2e5c023ea45ba2cf5807a9fe0341f3 | |
parent | 8cc54925bbec130acd796d96363ad31223c3a962 (diff) | |
download | libsoup-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.c | 19 | ||||
-rw-r--r-- | libsoup/soup-message-server-io.c | 21 | ||||
-rw-r--r-- | libsoup/soup-server.c | 24 | ||||
-rw-r--r-- | tests/misc-test.c | 95 |
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); |