[libsoup] Force some SoupMessages to use a fresh SoupConnection
- From: Dan Winship <danw src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [libsoup] Force some SoupMessages to use a fresh SoupConnection
- Date: Thu, 22 Dec 2011 20:47:13 +0000 (UTC)
commit ff0797686c3a893ef2a5b6950356336a0712da27
Author: Dan Winship <danw gnome org>
Date: Wed Dec 7 16:53:26 2011 -0500
Force some SoupMessages to use a fresh SoupConnection
Add a new SOUP_MESSAGE_NEW_CONNECTION flag, and insist on getting a
brand new SoupConnection for any message that has that flag set, or
that uses a non-idempotent method.
Add a test to misc-test for this.
https://bugzilla.gnome.org/show_bug.cgi?id=578990
libsoup/soup-auth-manager-ntlm.c | 4 ++
libsoup/soup-message.c | 4 ++
libsoup/soup-message.h | 3 +-
libsoup/soup-session.c | 20 ++++++++++-
tests/misc-test.c | 75 ++++++++++++++++++++++++++++++++++++--
5 files changed, 100 insertions(+), 6 deletions(-)
---
diff --git a/libsoup/soup-auth-manager-ntlm.c b/libsoup/soup-auth-manager-ntlm.c
index a1b76c7..33043e7 100644
--- a/libsoup/soup-auth-manager-ntlm.c
+++ b/libsoup/soup-auth-manager-ntlm.c
@@ -449,6 +449,7 @@ ntlm_authorize_post (SoupMessage *msg, gpointer ntlm)
SoupNTLMConnection *conn;
const char *username = NULL, *password = NULL;
char *slash, *domain = NULL;
+ SoupMessageFlags flags;
conn = get_connection_for_msg (priv, msg);
if (!conn || !conn->auth)
@@ -496,6 +497,9 @@ ssofailure:
conn->response_header = soup_ntlm_response (conn->nonce,
username, password,
NULL, domain);
+
+ flags = soup_message_get_flags (msg);
+ soup_message_set_flags (msg, flags & ~SOUP_MESSAGE_NEW_CONNECTION);
soup_session_requeue_message (priv->session, msg);
done:
diff --git a/libsoup/soup-message.c b/libsoup/soup-message.c
index dc99f38..6186087 100644
--- a/libsoup/soup-message.c
+++ b/libsoup/soup-message.c
@@ -1430,6 +1430,10 @@ soup_message_cleanup_response (SoupMessage *req)
* @SOUP_MESSAGE_CERTIFICATE_TRUSTED: if set after an https response
* has been received, indicates that the server's SSL certificate is
* trusted according to the session's CA.
+ * @SOUP_MESSAGE_NEW_CONNECTION: The message should be sent on a
+ * newly-created connection, not reusing an existing persistent
+ * connection. Note that messages with non-idempotent
+ * #SoupMessage:method<!-- -->s behave this way by default.
*
* Various flags that can be set on a #SoupMessage to alter its
* behavior.
diff --git a/libsoup/soup-message.h b/libsoup/soup-message.h
index f1a8c6d..d3c7e3c 100644
--- a/libsoup/soup-message.h
+++ b/libsoup/soup-message.h
@@ -118,7 +118,8 @@ typedef enum {
SOUP_MESSAGE_OVERWRITE_CHUNKS = (1 << 3),
#endif
SOUP_MESSAGE_CONTENT_DECODED = (1 << 4),
- SOUP_MESSAGE_CERTIFICATE_TRUSTED = (1 << 5)
+ SOUP_MESSAGE_CERTIFICATE_TRUSTED = (1 << 5),
+ SOUP_MESSAGE_NEW_CONNECTION = (1 << 6)
} SoupMessageFlags;
void soup_message_set_flags (SoupMessage *msg,
diff --git a/libsoup/soup-session.c b/libsoup/soup-session.c
index 32c1b30..e0d540c 100644
--- a/libsoup/soup-session.c
+++ b/libsoup/soup-session.c
@@ -1509,11 +1509,22 @@ auth_manager_authenticate (SoupAuthManager *manager, SoupMessage *msg,
session, msg, auth, retrying);
}
+/* At some point it might be possible to mark additional methods
+ * safe or idempotent...
+ */
#define SOUP_METHOD_IS_SAFE(method) (method == SOUP_METHOD_GET || \
method == SOUP_METHOD_HEAD || \
method == SOUP_METHOD_OPTIONS || \
method == SOUP_METHOD_PROPFIND)
+#define SOUP_METHOD_IS_IDEMPOTENT(method) (method == SOUP_METHOD_GET || \
+ method == SOUP_METHOD_HEAD || \
+ method == SOUP_METHOD_OPTIONS || \
+ method == SOUP_METHOD_PROPFIND || \
+ method == SOUP_METHOD_PUT || \
+ method == SOUP_METHOD_DELETE)
+
+
#define SOUP_SESSION_WOULD_REDIRECT_AS_GET(session, msg) \
((msg)->status_code == SOUP_STATUS_SEE_OTHER || \
((msg)->status_code == SOUP_STATUS_FOUND && \
@@ -1850,17 +1861,22 @@ soup_session_get_connection (SoupSession *session,
GSList *conns;
int num_pending = 0;
SoupURI *uri;
+ gboolean need_new_connection;
if (item->conn) {
g_return_val_if_fail (soup_connection_get_state (item->conn) != SOUP_CONNECTION_DISCONNECTED, FALSE);
return TRUE;
}
+ need_new_connection =
+ (soup_message_get_flags (item->msg) & SOUP_MESSAGE_NEW_CONNECTION) ||
+ !SOUP_METHOD_IS_IDEMPOTENT (item->msg->method);
+
g_mutex_lock (&priv->host_lock);
host = get_host_for_message (session, item->msg);
for (conns = host->connections; conns; conns = conns->next) {
- if (soup_connection_get_state (conns->data) == SOUP_CONNECTION_IDLE) {
+ if (!need_new_connection && soup_connection_get_state (conns->data) == SOUP_CONNECTION_IDLE) {
soup_connection_set_state (conns->data, SOUP_CONNECTION_IN_USE);
g_mutex_unlock (&priv->host_lock);
item->conn = g_object_ref (conns->data);
@@ -1879,6 +1895,8 @@ soup_session_get_connection (SoupSession *session,
}
if (host->num_conns >= priv->max_conns_per_host) {
+ if (need_new_connection)
+ *try_pruning = TRUE;
g_mutex_unlock (&priv->host_lock);
return FALSE;
}
diff --git a/tests/misc-test.c b/tests/misc-test.c
index 332e938..9637dcb 100644
--- a/tests/misc-test.c
+++ b/tests/misc-test.c
@@ -136,7 +136,7 @@ server_callback (SoupServer *server, SoupMessage *msg,
return;
}
- if (msg->method != SOUP_METHOD_GET) {
+ if (msg->method != SOUP_METHOD_GET && msg->method != SOUP_METHOD_POST) {
soup_message_set_status (msg, SOUP_STATUS_NOT_IMPLEMENTED);
return;
}
@@ -748,8 +748,8 @@ do_accept_language_test (void)
}
static void
-timeout_test_request_started (SoupSession *session, SoupMessage *msg,
- SoupSocket *socket, gpointer user_data)
+request_started_socket_collector (SoupSession *session, SoupMessage *msg,
+ SoupSocket *socket, gpointer user_data)
{
SoupSocket **sockets = user_data;
int i;
@@ -782,7 +782,7 @@ do_timeout_test_for_session (SoupSession *session)
int i;
g_signal_connect (session, "request-started",
- G_CALLBACK (timeout_test_request_started),
+ G_CALLBACK (request_started_socket_collector),
&sockets);
debug_printf (1, " First message\n");
@@ -1103,6 +1103,72 @@ do_aliases_test (void)
soup_test_session_abort_unref (session);
}
+static void
+do_non_persistent_test_for_session (SoupSession *session)
+{
+ SoupMessage *msg;
+ SoupSocket *sockets[4] = { NULL, NULL, NULL, NULL };
+ int i;
+
+ g_signal_connect (session, "request-started",
+ G_CALLBACK (request_started_socket_collector),
+ &sockets);
+
+ debug_printf (2, " GET\n");
+ msg = soup_message_new_from_uri ("GET", base_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++;
+ }
+ if (sockets[1]) {
+ debug_printf (1, " Message was retried??\n");
+ errors++;
+ sockets[1] = sockets[2] = sockets[3] = NULL;
+ }
+ g_object_unref (msg);
+
+ debug_printf (2, " POST\n");
+ msg = soup_message_new_from_uri ("POST", base_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++;
+ }
+ if (sockets[1] == sockets[0]) {
+ debug_printf (1, " Message was sent on existing connection!\n");
+ errors++;
+ }
+ if (sockets[2]) {
+ debug_printf (1, " Too many connections used...\n");
+ errors++;
+ }
+ g_object_unref (msg);
+
+ for (i = 0; sockets[i]; i++)
+ g_object_unref (sockets[i]);
+}
+
+static void
+do_non_persistent_connection_test (void)
+{
+ SoupSession *session;
+
+ debug_printf (1, "\nNon-idempotent methods are always sent on new connections\n");
+
+ debug_printf (1, " Async session\n");
+ session = soup_test_session_new (SOUP_TYPE_SESSION_ASYNC, NULL);
+ do_non_persistent_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, NULL);
+ do_non_persistent_test_for_session (session);
+ soup_test_session_abort_unref (session);
+}
+
int
main (int argc, char **argv)
{
@@ -1139,6 +1205,7 @@ main (int argc, char **argv)
do_max_conns_test ();
do_cancel_while_reading_test ();
do_aliases_test ();
+ do_non_persistent_connection_test ();
soup_uri_free (base_uri);
soup_uri_free (ssl_base_uri);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]