diff options
author | Dan Winship <danw@gnome.org> | 2013-05-25 10:31:12 -0300 |
---|---|---|
committer | Dan Winship <danw@gnome.org> | 2013-05-25 10:31:12 -0300 |
commit | 756417e57a216cffbecd09d2f67469b6b3a501e2 (patch) | |
tree | fa590d0001e146f6e4f95baba8acf27a273e4e37 | |
parent | 1e48dc8f9a8a90e8e644ce78882c9468ca1d298b (diff) | |
download | libsoup-badconnect.tar.gz |
wipbadconnect
-rw-r--r-- | libsoup/soup-message-server-io.c | 28 | ||||
-rw-r--r-- | tests/connection-test.c | 93 |
2 files changed, 112 insertions, 9 deletions
diff --git a/libsoup/soup-message-server-io.c b/libsoup/soup-message-server-io.c index e85896b3..1a148b08 100644 --- a/libsoup/soup-message-server-io.c +++ b/libsoup/soup-message-server-io.c @@ -9,6 +9,7 @@ #include "config.h" #endif +#include <stdlib.h> #include <string.h> #include <glib/gi18n-lib.h> @@ -17,6 +18,28 @@ #include "soup-message-private.h" #include "soup-misc-private.h" +static SoupURI * +parse_connect_authority (const char *req_path) +{ + SoupURI *uri; + char *fake_uri; + + fake_uri = g_strdup_printf ("https://%s", req_path); + uri = soup_uri_new (fake_uri); + g_free (fake_uri); + + if (uri->user || uri->password || + uri->query || uri->fragment || + !uri->host || + (uri->port == 0) || + (strcmp (uri->path, "/") != 0)) { + soup_uri_free (uri); + return NULL; + } + + return uri; +} + static guint parse_request_headers (SoupMessage *msg, char *headers, guint headers_len, SoupEncoding *encoding, gpointer sock, GError **error) @@ -73,8 +96,11 @@ parse_request_headers (SoupMessage *msg, char *headers, guint headers_len, if (uri) soup_uri_set_path (uri, "*"); g_free (url); + } else if (msg->method == SOUP_METHOD_CONNECT) { + /* Authority */ + uri = parse_connect_authority (req_path); } else if (*req_path != '/') { - /* Must be an absolute URI */ + /* Absolute URI */ uri = soup_uri_new (req_path); } else if (req_host) { url = g_strdup_printf ("%s://%s%s", diff --git a/tests/connection-test.c b/tests/connection-test.c index cdc4cced..dee0ef15 100644 --- a/tests/connection-test.c +++ b/tests/connection-test.c @@ -98,6 +98,8 @@ server_callback (SoupServer *server, SoupMessage *msg, const char *path, GHashTable *query, SoupClientContext *context, gpointer data) { + SoupSocket *sock = soup_client_context_get_socket (context); + /* The way this gets used in the tests, we don't actually * need to hold it through the whole function, so it's simpler * to just release it right away. @@ -105,6 +107,18 @@ server_callback (SoupServer *server, SoupMessage *msg, g_mutex_lock (&server_mutex); g_mutex_unlock (&server_mutex); + if (msg->method == SOUP_METHOD_CONNECT) { + int sockfd; + + /* Close-during-CONNECT test; see close_socket() above */ + sockfd = soup_socket_get_fd (sock); +#ifdef G_OS_WIN32 + shutdown (sockfd, SD_SEND); +#else + shutdown (sockfd, SHUT_WR); +#endif + } + if (msg->method != SOUP_METHOD_GET && msg->method != SOUP_METHOD_POST) { soup_message_set_status (msg, SOUP_STATUS_NOT_IMPLEMENTED); return; @@ -123,14 +137,11 @@ server_callback (SoupServer *server, SoupMessage *msg, "Connection", "close"); if (too_long) { - SoupSocket *sock; - /* soup-message-io will wait for us to add * another chunk after the first, to fill out * the declared Content-Length. Instead, we * forcibly close the socket at that point. */ - sock = soup_client_context_get_socket (context); g_signal_connect (msg, "wrote-chunk", G_CALLBACK (close_socket), sock); } else if (no_close) { @@ -145,12 +156,8 @@ server_callback (SoupServer *server, SoupMessage *msg, return; } - if (!strcmp (path, "/timeout-persistent")) { - SoupSocket *sock; - - sock = soup_client_context_get_socket (context); + if (!strcmp (path, "/timeout-persistent")) setup_timeout_persistent (server, sock); - } soup_message_set_status (msg, SOUP_STATUS_OK); soup_message_set_response (msg, "text/plain", @@ -683,6 +690,75 @@ do_non_idempotent_connection_test (void) soup_test_session_abort_unref (session); } +static void +do_tunnel_close_test_for_session (SoupSession *session) +{ + SoupMessage *msg; + SoupRequest *req; + GInputStream *stream; + GError *error = NULL; + + debug_printf (1, " SoupMessage\n"); + msg = soup_message_new ("GET", "https://example.com/"); + soup_session_send_message (session, msg); + if (msg->status_code != SOUP_STATUS_SSL_FAILED) { + debug_printf (1, " Unexpected response: %d %s\n", + msg->status_code, msg->reason_phrase); + errors++; + } + g_object_unref (msg); + + if (SOUP_IS_SESSION_SYNC (session)) + return; + + debug_printf (1, " SoupRequest\n"); + req = soup_session_request (session, "https://example.com/", NULL); + stream = soup_test_request_send (req, NULL, 0, &error); + if (stream) { + msg = soup_request_http_get_message (SOUP_REQUEST_HTTP (req)); + debug_printf (1, " Request unexpectedly succeeded (%d %s)!\n", + msg->status_code, msg->reason_phrase); + g_object_unref (msg); + errors++; + soup_test_request_close_stream (req, stream, NULL, NULL); + g_object_unref (stream); + } else { + debug_printf (1, " EXPECTED error: %s\n", error->message); + g_clear_error (&error); + } + g_object_unref (req); +} + +static void +do_tunnel_close_test (void) +{ + SoupSession *session; + + debug_printf (1, "\nTest when proxy closes connection during CONNECT\n"); + + debug_printf (1, " Async session\n"); + session = soup_test_session_new (SOUP_TYPE_SESSION_ASYNC, + SOUP_SESSION_PROXY_URI, base_uri, + SOUP_SESSION_USE_THREAD_CONTEXT, TRUE, + NULL); + do_tunnel_close_test_for_session (session); + soup_test_session_abort_unref (session); + + debug_printf (1, " Sync session\n"); + session = soup_test_session_new (SOUP_TYPE_SESSION_SYNC, + SOUP_SESSION_PROXY_URI, base_uri, + NULL); + do_tunnel_close_test_for_session (session); + soup_test_session_abort_unref (session); + + debug_printf (1, " Plain session\n"); + session = soup_test_session_new (SOUP_TYPE_SESSION, + SOUP_SESSION_PROXY_URI, base_uri, + NULL); + do_tunnel_close_test_for_session (session); + soup_test_session_abort_unref (session); +} + #ifdef HAVE_APACHE #define HTTP_SERVER "http://127.0.0.1:47524" @@ -952,6 +1028,7 @@ main (int argc, char **argv) do_max_conns_test (); do_non_persistent_connection_test (); do_non_idempotent_connection_test (); + do_tunnel_close_test (); #ifdef HAVE_APACHE do_connection_state_test (); do_connection_event_test (); |