From 1e9d2b827d97fa6b9925d697b371c0000b051c6a Mon Sep 17 00:00:00 2001 From: Carlos Garcia Campos Date: Wed, 8 Feb 2023 11:53:00 +0100 Subject: [PATCH] http1: fix crash when skipping respone stream with chunked enconding When skipping the response body the given buffer is NULL, which is not handled for chunked enconding when reading the trailers. Fixes #323 --- libsoup/http1/soup-body-input-stream.c | 4 +- tests/streaming-test.c | 69 ++++++++++++++++++++++++++ 2 files changed, 71 insertions(+), 2 deletions(-) diff --git a/libsoup/http1/soup-body-input-stream.c b/libsoup/http1/soup-body-input-stream.c index 28acae83..69a93c09 100644 --- a/libsoup/http1/soup-body-input-stream.c +++ b/libsoup/http1/soup-body-input-stream.c @@ -226,12 +226,12 @@ again: case SOUP_BODY_INPUT_STREAM_STATE_TRAILERS: nread = soup_filter_input_stream_read_line ( - fstream, buffer, count, blocking, + fstream, metabuf, sizeof (metabuf), blocking, &got_line, cancellable, error); if (nread <= 0) return nread; - if (strncmp (buffer, "\r\n", nread) || strncmp (buffer, "\n", nread)) { + if (strncmp (metabuf, "\r\n", nread) || strncmp (metabuf, "\n", nread)) { priv->chunked_state = SOUP_BODY_INPUT_STREAM_STATE_DONE; priv->eof = TRUE; } diff --git a/tests/streaming-test.c b/tests/streaming-test.c index 22153325..21e95aba 100644 --- a/tests/streaming-test.c +++ b/tests/streaming-test.c @@ -217,6 +217,74 @@ do_eof_test (gconstpointer data) soup_test_session_abort_unref (session); } +static void +do_skip (SoupSession *session, + GUri *base_uri, + const char *path) +{ + GUri *uri; + SoupMessage *msg; + GInputStream *stream; + SoupMessageMetrics *metrics; + guint64 body_size = 0; + guint64 response_body_bytes_received = 0; + GError *error = NULL; + + uri = g_uri_parse_relative (base_uri, path, SOUP_HTTP_URI_FLAGS, NULL); + msg = soup_message_new_from_uri ("GET", uri); + g_uri_unref (uri); + + soup_message_add_flags (msg, SOUP_MESSAGE_COLLECT_METRICS); + g_signal_connect (msg, "got-body-data", + G_CALLBACK (msg_got_body_data_cb), + &response_body_bytes_received); + + stream = soup_test_request_send (session, msg, NULL, 0, &error); + g_assert_no_error (error); + while (TRUE) { + gssize skipped; + + skipped = g_input_stream_skip (stream, 4096, NULL, &error); + g_assert_no_error (error); + if (skipped == 0) + break; + + body_size += skipped; + } + g_object_unref (stream); + + metrics = soup_message_get_metrics (msg); + g_assert_cmpint (body_size, ==, g_bytes_get_size (full_response)); + g_assert_cmpint (soup_message_metrics_get_response_body_size (metrics), ==, body_size); + g_assert_cmpuint (soup_message_metrics_get_response_body_bytes_received (metrics), ==, response_body_bytes_received); + if (g_str_equal (path, "chunked")) { + g_assert_cmpuint (soup_message_metrics_get_response_body_bytes_received (metrics), >, soup_message_metrics_get_response_body_size (metrics)); + } else { + g_assert_cmpuint (soup_message_metrics_get_response_body_bytes_received (metrics), ==, soup_message_metrics_get_response_body_size (metrics)); + } + if (g_str_equal (path, "content-length")) { + goffset content_length; + + content_length = soup_message_headers_get_content_length (soup_message_get_response_headers (msg)); + g_assert_cmpuint (content_length, ==, response_body_bytes_received); + } + + g_object_unref (msg); +} + +static void +do_skip_test (gconstpointer data) +{ + GUri *base_uri = (GUri *)data; + SoupSession *session; + + session = soup_test_session_new (NULL); + do_skip (session, base_uri, "chunked"); + do_skip (session, base_uri, "content-length"); + do_skip (session, base_uri, "eof"); + soup_test_session_abort_unref (session); +} + int main (int argc, char **argv) { @@ -241,6 +309,7 @@ main (int argc, char **argv) g_test_add_data_func ("/streaming/chunked", base_uri, do_chunked_test); g_test_add_data_func ("/streaming/content-length", base_uri, do_content_length_test); g_test_add_data_func ("/streaming/eof", base_uri, do_eof_test); + g_test_add_data_func ("/streaming/skip", base_uri, do_skip_test); ret = g_test_run (); -- GitLab