[libsoup] Wait until IO finished before re-starting a request
- From: Carlos Garcia Campos <carlosgc src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [libsoup] Wait until IO finished before re-starting a request
- Date: Fri, 11 Jun 2021 10:25:02 +0000 (UTC)
commit 890766793f9d349c54a7437b32dba9ae79690579
Author: Carlos Garcia Campos <cgarcia igalia com>
Date: Fri Jun 11 12:04:10 2021 +0200
Wait until IO finished before re-starting a request
In case of restarting it can happen that the new request is started
before the previous one is fully completed. This is because restart
is scheduled on SoupMessage::got-body that happens right before the
stream is closed and the IO finished. In HTTP/1.x this is possible if a
new request is made in got-body callback, for example. In HTTP/2 is
easier to reproduce because we emit SoupMessage::got-body right after
SoupClientInputStream::eof. This patch adds an intermediate state
SOUP_MESSAGE_REQUEUED set by soup_session_requeue_item(). The transition
to SOUP_MESSAGE_RESTARTING happens when the message IO completes to
ensure the restarted request starts when message no longer has an active IO.
libsoup/http1/soup-client-message-io-http1.c | 2 ++
libsoup/soup-message-queue-item.h | 1 +
libsoup/soup-session.c | 9 ++++++-
tests/misc-test.c | 40 ++++++++++++++++++++++++++++
4 files changed, 51 insertions(+), 1 deletion(-)
---
diff --git a/libsoup/http1/soup-client-message-io-http1.c b/libsoup/http1/soup-client-message-io-http1.c
index ab589e43..46029612 100644
--- a/libsoup/http1/soup-client-message-io-http1.c
+++ b/libsoup/http1/soup-client-message-io-http1.c
@@ -1043,6 +1043,8 @@ soup_client_message_io_http1_send_item (SoupClientMessageIO *iface,
#ifdef HAVE_SYSPROF
msg_io->begin_time_nsec = SYSPROF_CAPTURE_CURRENT_TIME;
#endif
+ if (io->msg_io)
+ g_warn_if_reached ();
io->msg_io = msg_io;
io->is_reusable = FALSE;
diff --git a/libsoup/soup-message-queue-item.h b/libsoup/soup-message-queue-item.h
index cb483668..9a958342 100644
--- a/libsoup/soup-message-queue-item.h
+++ b/libsoup/soup-message-queue-item.h
@@ -20,6 +20,7 @@ typedef enum {
SOUP_MESSAGE_READY,
SOUP_MESSAGE_RUNNING,
SOUP_MESSAGE_CACHED,
+ SOUP_MESSAGE_REQUEUED,
SOUP_MESSAGE_RESTARTING,
SOUP_MESSAGE_FINISHING,
SOUP_MESSAGE_FINISHED
diff --git a/libsoup/soup-session.c b/libsoup/soup-session.c
index d1df9226..7380ff0a 100644
--- a/libsoup/soup-session.c
+++ b/libsoup/soup-session.c
@@ -1205,7 +1205,7 @@ soup_session_requeue_item (SoupSession *session,
retval = FALSE;
} else {
item->resend_count++;
- item->state = SOUP_MESSAGE_RESTARTING;
+ item->state = SOUP_MESSAGE_REQUEUED;
retval = TRUE;
}
@@ -1590,6 +1590,9 @@ message_completed (SoupMessage *msg, SoupMessageIOCompletion completion, gpointe
return;
}
+ if (item->state == SOUP_MESSAGE_REQUEUED)
+ item->state = SOUP_MESSAGE_RESTARTING;
+
if (item->state != SOUP_MESSAGE_RESTARTING) {
item->state = SOUP_MESSAGE_FINISHING;
@@ -1646,6 +1649,9 @@ tunnel_message_completed (SoupMessage *msg, SoupMessageIOCompletion completion,
SoupSession *session = tunnel_item->session;
guint status;
+ if (tunnel_item->state == SOUP_MESSAGE_REQUEUED)
+ tunnel_item->state = SOUP_MESSAGE_RESTARTING;
+
if (tunnel_item->state == SOUP_MESSAGE_RESTARTING) {
soup_message_restarted (msg);
if (soup_message_get_connection (tunnel_item->msg)) {
@@ -2028,6 +2034,7 @@ soup_session_process_queue_item (SoupSession *session,
case SOUP_MESSAGE_CACHED:
case SOUP_MESSAGE_TUNNELING:
+ case SOUP_MESSAGE_REQUEUED:
/* Will be handled elsewhere */
return;
diff --git a/tests/misc-test.c b/tests/misc-test.c
index 25d263ef..e32b18f5 100644
--- a/tests/misc-test.c
+++ b/tests/misc-test.c
@@ -760,6 +760,45 @@ do_remote_address_test (void)
soup_test_session_abort_unref (session);
}
+static void
+redirect_handler (SoupMessage *msg,
+ SoupSession *session)
+{
+ SoupMessage *new_msg;
+ GBytes *body;
+
+ new_msg = soup_message_new_from_uri ("GET", base_uri);
+ body = soup_test_session_async_send (session, new_msg, NULL, NULL);
+ g_assert_nonnull (body);
+ g_assert_cmpstr (g_bytes_get_data (body, NULL), ==, "index");
+ g_object_unref (new_msg);
+}
+
+static void
+do_new_request_on_redirect_test (void)
+{
+ SoupSession *session;
+ GUri *uri;
+ SoupMessage *msg;
+ GBytes *body;
+
+ session = soup_test_session_new (NULL);
+
+ uri = g_uri_parse_relative (base_uri, "/redirect", SOUP_HTTP_URI_FLAGS, NULL);
+ msg = soup_message_new_from_uri ("GET", uri);
+ g_signal_connect_after (msg, "got-body",
+ G_CALLBACK (redirect_handler),
+ session);
+ body = soup_test_session_async_send (session, msg, NULL, NULL);
+ g_assert_nonnull (body);
+ g_assert_cmpstr (g_bytes_get_data (body, NULL), ==, "index");
+
+ g_bytes_unref (body);
+ g_object_unref (msg);
+ g_uri_unref (uri);
+ soup_test_session_abort_unref (session);
+}
+
int
main (int argc, char **argv)
{
@@ -794,6 +833,7 @@ main (int argc, char **argv)
g_test_add_func ("/misc/msg-flags", do_msg_flags_test);
g_test_add_func ("/misc/connection-id", do_connection_id_test);
g_test_add_func ("/misc/remote-address", do_remote_address_test);
+ g_test_add_func ("/misc/new-request-on-redirect", do_new_request_on_redirect_test);
ret = g_test_run ();
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]