summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDan Winship <danw@gnome.org>2013-05-25 10:31:12 -0300
committerDan Winship <danw@gnome.org>2013-05-25 10:31:12 -0300
commit756417e57a216cffbecd09d2f67469b6b3a501e2 (patch)
treefa590d0001e146f6e4f95baba8acf27a273e4e37
parent1e48dc8f9a8a90e8e644ce78882c9468ca1d298b (diff)
downloadlibsoup-badconnect.tar.gz
-rw-r--r--libsoup/soup-message-server-io.c28
-rw-r--r--tests/connection-test.c93
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 ();