summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCarlos Garcia Campos <cgarcia@igalia.com>2022-07-27 15:19:00 +0200
committerCarlos Garcia Campos <cgarcia@igalia.com>2022-08-12 12:20:02 +0200
commit261cbad7cf9134ba5b63983ccbc61834724ae5ab (patch)
treeeb59de7994aef8aeeadb3851d558be86640d126e
parent5fb25e7810498170dd3458c9509035cef945e299 (diff)
downloadlibsoup-261cbad7cf9134ba5b63983ccbc61834724ae5ab.tar.gz
tests: use SoupServer instead of quart for HTTP/2 tests
-rw-r--r--.gitlab-ci/Dockerfile2
-rw-r--r--meson.build21
-rw-r--r--meson_options.txt6
-rwxr-xr-xtests/http2-server.py126
-rw-r--r--tests/http2-test.c407
-rw-r--r--tests/meson.build11
-rw-r--r--tests/test-utils.c74
-rw-r--r--tests/test-utils.h6
8 files changed, 311 insertions, 342 deletions
diff --git a/.gitlab-ci/Dockerfile b/.gitlab-ci/Dockerfile
index eae603e3..394123e9 100644
--- a/.gitlab-ci/Dockerfile
+++ b/.gitlab-ci/Dockerfile
@@ -33,7 +33,7 @@ RUN dnf update -y \
&& dnf clean all \
&& python2.7 -m ensurepip \
&& pip2.7 install virtualenv autobahntestsuite \
- && pip3 install quart gi-docgen
+ && pip3 install gi-docgen
# We need glib 2.70
RUN git clone https://gitlab.gnome.org/GNOME/glib.git \
diff --git a/meson.build b/meson.build
index e7db3a25..9509f813 100644
--- a/meson.build
+++ b/meson.build
@@ -285,27 +285,9 @@ else
have_autobahn = find_program('wstest', required: get_option('autobahn')).found()
endif
-# Quart server used for HTTP/2 tests
-quart_found = false
-
-if not get_option('http2_tests').disabled()
- pymod = import('python')
- python = pymod.find_installation('python3')
- if python.found()
- ret = run_command(python, '-c', 'import importlib\nassert(importlib.find_loader("quart"))', check: false)
- if ret.returncode() == 0
- quart_found = true
- endif
- endif
- message('Python module quart found: @0@'.format(quart_found.to_string('YES', 'NO')))
- if get_option('http2_tests').enabled() and not quart_found
- error('quart is required for http2 tests')
- endif
-endif
-
gnutls_dep = dependency('gnutls', version: '>= 3.6.0', required : get_option('pkcs11_tests'))
-if not have_apache or not quart_found or not have_autobahn or not gnutls_dep.found()
+if not have_apache or not have_autobahn or not gnutls_dep.found()
warning('Some regression tests will not be compiled due to missing libraries or modules. Please check the logs for more details.')
endif
@@ -431,7 +413,6 @@ summary({
summary({
'All tests' : get_option('tests'),
'Tests requiring Apache' : have_apache,
- 'Tests requiring Quart' : quart_found,
'Documentation tests' : get_option('doc_tests'),
'Fuzzing tests' : get_option('fuzzing').enabled(),
'Autobahn tests' : have_autobahn,
diff --git a/meson_options.txt b/meson_options.txt
index 64c0e835..0c5d7c7d 100644
--- a/meson_options.txt
+++ b/meson_options.txt
@@ -89,12 +89,6 @@ option('fuzzing',
description: 'enable fuzzing support'
)
-option('http2_tests',
- type: 'feature',
- value: 'auto',
- description: 'enable HTTP/2 tests depending on quart'
-)
-
option('pkcs11_tests',
type: 'feature',
value: 'auto',
diff --git a/tests/http2-server.py b/tests/http2-server.py
deleted file mode 100755
index adccc2ea..00000000
--- a/tests/http2-server.py
+++ /dev/null
@@ -1,126 +0,0 @@
-#!/usr/bin/env python3
-
-import asyncio
-from functools import wraps
-import os
-from secrets import compare_digest
-import sys
-from urllib.parse import urlparse
-
-from quart import (
- request,
- make_response,
- Quart,
-)
-
-app = Quart(__name__)
-
-timer_handle = None
-loop = None
-
-def set_timeout():
- global timer_handle
-
- # ASAN is very slow, just don't have a timer.
- if 'ASAN_OPTIONS' in os.environ:
- return
-
- if timer_handle:
- timer_handle.cancel()
-
- # This timeout just prevents a zombie process from
- # running even if a test crashes.
- timer_handle = loop.call_later(20, lambda: sys.exit(0))
-
-
-@app.route('/')
-async def index():
- set_timeout()
- return 'Hello world'
-
-@app.route('/slow')
-async def slow():
- set_timeout()
- await asyncio.sleep(1)
- return 'Hello world'
-
-@app.route('/timeout')
-async def timeout():
- set_timeout()
- await asyncio.sleep(4)
- return 'Hello world'
-
-@app.route('/no-content')
-async def no_content():
- set_timeout()
- return await make_response('', 204)
-
-@app.route('/large')
-async def large():
- set_timeout()
-
- async def generate_data():
- # Send increasing letters just to aid debugging
- letter = ord('A')
- bytes_pending = 1024 * 24
- while bytes_pending:
- await asyncio.sleep(0.1)
- bytes_pending -= 1024
- string = chr(letter) * 1024
- letter += 1
- yield bytes(string, 'UTF-8')
- yield b'\0'
-
- return generate_data()
-
-@app.route('/echo_query')
-async def echo_query():
- set_timeout()
- url = urlparse(request.url)
- return url.query
-
-@app.route('/echo_post', methods=['POST'])
-async def echo_post():
- set_timeout()
- data = await request.get_data()
- return data
-
-@app.route('/auth')
-async def auth():
- set_timeout()
- auth = request.authorization
-
- if (
- auth is not None and
- auth.type == "basic" and
- auth.username == 'username' and
- compare_digest(auth.password, 'password')
- ):
- return 'Authenticated'
-
- response = await make_response('Authentication Required')
- response.status_code = 401
- response.headers['WWW-Authenticate'] = 'Basic'
- return response
-
-has_been_misdirected = False
-
-@app.route('/misdirected_request')
-async def misdirected_request():
- set_timeout()
- global has_been_misdirected
-
- if not has_been_misdirected:
- has_been_misdirected = True
- response = await make_response('', 421)
- return response
-
- return 'Success!'
-
-if __name__ == '__main__':
- loop = asyncio.get_event_loop()
- set_timeout()
-
- app.run(use_reloader=False, loop=loop,
- certfile='test-cert.pem',
- keyfile='test-key.pem')
diff --git a/tests/http2-test.c b/tests/http2-test.c
index cbc6c41b..be7fc43a 100644
--- a/tests/http2-test.c
+++ b/tests/http2-test.c
@@ -20,13 +20,18 @@
#include "test-utils.h"
#include "soup-connection.h"
#include "soup-message-private.h"
+#include "soup-server-message-private.h"
#include "soup-body-input-stream-http2.h"
+static GUri *base_uri;
+
typedef struct {
SoupSession *session;
- SoupMessage *msg;
} Test;
+#define LARGE_N_CHARS 24
+#define LARGE_CHARS_REPEAT 1024
+
static void
setup_session (Test *test, gconstpointer data)
{
@@ -42,56 +47,74 @@ teardown_session (Test *test, gconstpointer data)
static void
do_basic_async_test (Test *test, gconstpointer data)
{
- test->msg = soup_message_new (SOUP_METHOD_GET, "https://127.0.0.1:5000/");
+ SoupMessage *msg;
+ GBytes *response;
GError *error = NULL;
- GBytes *response = soup_test_session_async_send (test->session, test->msg, NULL, &error);
+ msg = soup_message_new_from_uri (SOUP_METHOD_GET, base_uri);
+ g_assert_cmpuint (soup_message_get_http_version (msg), ==, SOUP_HTTP_1_1);
+
+ response = soup_test_session_async_send (test->session, msg, NULL, &error);
g_assert_no_error (error);
+ g_assert_cmpuint (soup_message_get_http_version (msg), ==, SOUP_HTTP_2_0);
g_assert_cmpstr (g_bytes_get_data (response, NULL), ==, "Hello world");
g_bytes_unref (response);
- g_object_unref (test->msg);
+ g_object_unref (msg);
}
static void
do_basic_sync_test (Test *test, gconstpointer data)
{
- test->msg = soup_message_new (SOUP_METHOD_GET, "https://127.0.0.1:5000/");
+ SoupMessage *msg;
+ GBytes *response;
GError *error = NULL;
- GBytes *response = soup_session_send_and_read (test->session, test->msg, NULL, &error);
+ msg = soup_message_new_from_uri (SOUP_METHOD_GET, base_uri);
+ g_assert_cmpuint (soup_message_get_http_version (msg), ==, SOUP_HTTP_1_1);
+ response = soup_session_send_and_read (test->session, msg, NULL, &error);
g_assert_no_error (error);
+ g_assert_cmpuint (soup_message_get_http_version (msg), ==, SOUP_HTTP_2_0);
g_assert_cmpstr (g_bytes_get_data (response, NULL), ==, "Hello world");
g_bytes_unref (response);
- g_object_unref (test->msg);
+ g_object_unref (msg);
}
static void
do_no_content_async_test (Test *test, gconstpointer data)
{
- test->msg = soup_message_new (SOUP_METHOD_GET, "https://127.0.0.1:5000/no-content");
+ GUri *uri;
+ SoupMessage *msg;
+ GBytes *response;
GError *error = NULL;
- GBytes *response = soup_test_session_async_send (test->session, test->msg, NULL, &error);
+ uri = g_uri_parse_relative (base_uri, "/no-content", SOUP_HTTP_URI_FLAGS, NULL);
+ msg = soup_message_new_from_uri (SOUP_METHOD_GET, uri);
+ response = soup_test_session_async_send (test->session, msg, NULL, &error);
g_assert_no_error (error);
- g_assert_cmpuint (soup_message_get_status (test->msg), ==, 204);
+ g_assert_cmpuint (soup_message_get_status (msg), ==, 204);
g_assert_cmpuint (g_bytes_get_size (response), ==, 0);
+ g_uri_unref (uri);
g_bytes_unref (response);
- g_object_unref (test->msg);
+ g_object_unref (msg);
}
static void
do_large_test (Test *test, gconstpointer data)
{
gboolean async = GPOINTER_TO_INT (data);
- SoupMessage *msg = soup_message_new (SOUP_METHOD_GET, "https://127.0.0.1:5000/large");
+ GUri *uri;
+ SoupMessage *msg;
GBytes *response;
GError *error = NULL;
+ uri = g_uri_parse_relative (base_uri, "/large", SOUP_HTTP_URI_FLAGS, NULL);
+ msg = soup_message_new_from_uri (SOUP_METHOD_GET, uri);
+
/* This is both large and read in chunks */
if (async)
response = soup_test_session_async_send (test->session, msg, NULL, &error);
@@ -99,9 +122,9 @@ do_large_test (Test *test, gconstpointer data)
response = soup_session_send_and_read (test->session, msg, NULL, &error);
g_assert_no_error (error);
- /* Size hardcoded to match http2-server.py's response */
- g_assert_cmpuint (g_bytes_get_size (response), ==, (1024 * 24) + 1);
+ g_assert_cmpuint (g_bytes_get_size (response), ==, (LARGE_N_CHARS * LARGE_CHARS_REPEAT) + 1);
+ g_uri_unref (uri);
g_bytes_unref (response);
g_object_unref (msg);
}
@@ -144,15 +167,18 @@ static void
do_multi_message_async_test (Test *test, gconstpointer data)
{
GMainContext *async_context = g_main_context_ref_thread_default ();
+ GUri *uri1, *uri2;
+ SoupMessage *msg1, *msg2;
+ GBytes *response1 = NULL;
+ GBytes *response2 = NULL;
- SoupMessage *msg1 = soup_message_new (SOUP_METHOD_GET, "https://127.0.0.1:5000/echo_query?body%201");
+ uri1 = g_uri_parse_relative (base_uri, "echo_query?body%201", SOUP_HTTP_URI_FLAGS, NULL);
+ msg1 = soup_message_new_from_uri (SOUP_METHOD_GET, uri1);
soup_message_set_http_version (msg1, SOUP_HTTP_2_0);
- SoupMessage *msg2 = soup_message_new (SOUP_METHOD_GET, "https://127.0.0.1:5000/echo_query?body%202");
+ uri2 = g_uri_parse_relative (base_uri, "echo_query?body%202", SOUP_HTTP_URI_FLAGS, NULL);
+ msg2 = soup_message_new_from_uri (SOUP_METHOD_GET, uri2);
soup_message_set_http_version (msg2, SOUP_HTTP_2_0);
-
- GBytes *response1 = NULL;
- GBytes *response2 = NULL;
soup_session_send_async (test->session, msg1, G_PRIORITY_DEFAULT, NULL, on_send_complete, &response1);
soup_session_send_async (test->session, msg2, G_PRIORITY_DEFAULT, NULL, on_send_complete, &response2);
@@ -173,6 +199,8 @@ do_multi_message_async_test (Test *test, gconstpointer data)
g_bytes_unref (response2);
g_object_unref (msg1);
g_object_unref (msg2);
+ g_uri_unref (uri1);
+ g_uri_unref (uri2);
g_main_context_unref (async_context);
}
@@ -208,18 +236,20 @@ on_send_and_read_complete (SoupSession *session,
static void
do_cancellation_test (Test *test, gconstpointer data)
{
+ GUri *uri;
SoupMessage *msg;
GMainContext *async_context = g_main_context_ref_thread_default ();
GCancellable *cancellable = g_cancellable_new ();
gboolean done = FALSE;
- msg = soup_message_new (SOUP_METHOD_GET, "https://127.0.0.1:5000/large");
+ uri = g_uri_parse_relative (base_uri, "/large", SOUP_HTTP_URI_FLAGS, NULL);
+ msg = soup_message_new_from_uri (SOUP_METHOD_GET, uri);
soup_session_send_and_read_async (test->session, msg, G_PRIORITY_DEFAULT, cancellable,
(GAsyncReadyCallback)on_send_and_read_cancelled_complete, &done);
/* Just iterate until a partial read is happening */
- for (guint i = 100000; i; i--)
- g_main_context_iteration (async_context, FALSE);
+ for (guint i = 10; i; i--)
+ g_main_context_iteration (async_context, TRUE);
/* Then cancel everything */
g_cancellable_cancel (cancellable);
@@ -230,13 +260,14 @@ do_cancellation_test (Test *test, gconstpointer data)
g_object_unref (msg);
done = FALSE;
- msg = soup_message_new (SOUP_METHOD_GET, "https://127.0.0.1:5000/large");
+ msg = soup_message_new_from_uri (SOUP_METHOD_GET, uri);
soup_session_send_and_read_async (test->session, msg, G_PRIORITY_DEFAULT, NULL,
(GAsyncReadyCallback)on_send_and_read_complete, &done);
while (!done)
g_main_context_iteration (async_context, FALSE);
+ g_uri_unref (uri);
g_object_unref (msg);
g_object_unref (cancellable);
g_main_context_unref (async_context);
@@ -258,7 +289,7 @@ do_one_cancel_after_send_request_test (SoupSession *session,
if (cancelled_by_session)
flags |= SOUP_TEST_REQUEST_CANCEL_BY_SESSION;
- msg = soup_message_new (SOUP_METHOD_GET, "https://127.0.0.1:5000/");
+ msg = soup_message_new_from_uri (SOUP_METHOD_GET, base_uri);
cancellable = g_cancellable_new ();
istream = soup_test_request_send (session, msg, cancellable, flags, &error);
g_assert_no_error (error);
@@ -307,13 +338,17 @@ do_cancellation_after_send_test (Test *test, gconstpointer data)
static void
do_post_sync_test (Test *test, gconstpointer data)
{
+ GUri *uri;
+ SoupMessage *msg;
+ GInputStream *response;
GBytes *bytes = g_bytes_new_static ("body 1", sizeof ("body 1"));
- test->msg = soup_message_new (SOUP_METHOD_POST, "https://127.0.0.1:5000/echo_post");
- soup_message_set_request_body_from_bytes (test->msg, "text/plain", bytes);
-
GError *error = NULL;
- GInputStream *response = soup_session_send (test->session, test->msg, NULL, &error);
+ uri = g_uri_parse_relative (base_uri, "/echo_post", SOUP_HTTP_URI_FLAGS, NULL);
+ msg = soup_message_new_from_uri (SOUP_METHOD_POST, uri);
+ soup_message_set_request_body_from_bytes (msg, "text/plain", bytes);
+
+ response = soup_session_send (test->session, msg, NULL, &error);
g_assert_no_error (error);
g_assert_nonnull (response);
@@ -323,27 +358,31 @@ do_post_sync_test (Test *test, gconstpointer data)
g_bytes_unref (response_bytes);
g_object_unref (response);
g_bytes_unref (bytes);
- g_object_unref (test->msg);
-
+ g_object_unref (msg);
+ g_uri_unref (uri);
}
static void
do_post_large_sync_test (Test *test, gconstpointer data)
{
- guint large_size = 1000000;
+ GUri *uri;
+ SoupMessage *msg;
+ GInputStream *response;
+ guint large_size = 10000;
char *large_data;
unsigned int i;
+ GError *error = NULL;
large_data = g_malloc (large_size);
for (i = 0; i < large_size; i++)
large_data[i] = i & 0xFF;
GBytes *bytes = g_bytes_new_take (large_data, large_size);
- test->msg = soup_message_new (SOUP_METHOD_POST, "https://127.0.0.1:5000/echo_post");
- soup_message_set_request_body_from_bytes (test->msg, "text/plain", bytes);
- GError *error = NULL;
- GInputStream *response = soup_session_send (test->session, test->msg, NULL, &error);
+ uri = g_uri_parse_relative (base_uri, "/echo_post", SOUP_HTTP_URI_FLAGS, NULL);
+ msg = soup_message_new_from_uri (SOUP_METHOD_POST, uri);
+ soup_message_set_request_body_from_bytes (msg, "text/plain", bytes);
+ response = soup_session_send (test->session, msg, NULL, &error);
g_assert_no_error (error);
g_assert_nonnull (response);
@@ -353,24 +392,27 @@ do_post_large_sync_test (Test *test, gconstpointer data)
g_bytes_unref (response_bytes);
g_object_unref (response);
g_bytes_unref (bytes);
- g_object_unref (test->msg);
+ g_object_unref (msg);
+ g_uri_unref (uri);
}
static void
do_post_async_test (Test *test, gconstpointer data)
{
+ GUri *uri;
+ SoupMessage *msg;
+ GBytes *response = NULL;
GMainContext *async_context = g_main_context_ref_thread_default ();
-
GBytes *bytes = g_bytes_new_static ("body 1", sizeof ("body 1"));
- test->msg = soup_message_new (SOUP_METHOD_POST, "https://127.0.0.1:5000/echo_post");
- soup_message_set_request_body_from_bytes (test->msg, "text/plain", bytes);
- GBytes *response = NULL;
- soup_session_send_async (test->session, test->msg, G_PRIORITY_DEFAULT, NULL, on_send_complete, &response);
+ uri = g_uri_parse_relative (base_uri, "/echo_post", SOUP_HTTP_URI_FLAGS, NULL);
+ msg = soup_message_new_from_uri (SOUP_METHOD_POST, uri);
+ soup_message_set_request_body_from_bytes (msg, "text/plain", bytes);
- while (!response) {
+ soup_session_send_async (test->session, msg, G_PRIORITY_DEFAULT, NULL, on_send_complete, &response);
+
+ while (!response)
g_main_context_iteration (async_context, TRUE);
- }
g_assert_cmpstr (g_bytes_get_data (response, NULL), ==, "body 1");
@@ -380,14 +422,18 @@ do_post_async_test (Test *test, gconstpointer data)
g_bytes_unref (response);
g_bytes_unref (bytes);
g_main_context_unref (async_context);
- g_object_unref (test->msg);
+ g_object_unref (msg);
+ g_uri_unref (uri);
}
static void
do_post_large_async_test (Test *test, gconstpointer data)
{
+ GUri *uri;
+ SoupMessage *msg;
+ GBytes *response = NULL;
GMainContext *async_context = g_main_context_ref_thread_default ();
- guint large_size = 1000000;
+ guint large_size = 10000;
char *large_data;
unsigned int i;
@@ -395,15 +441,15 @@ do_post_large_async_test (Test *test, gconstpointer data)
for (i = 0; i < large_size; i++)
large_data[i] = i & 0xFF;
GBytes *bytes = g_bytes_new_take (large_data, large_size);
- test->msg = soup_message_new (SOUP_METHOD_POST, "https://127.0.0.1:5000/echo_post");
- soup_message_set_request_body_from_bytes (test->msg, "text/plain", bytes);
- GBytes *response = NULL;
- soup_session_send_async (test->session, test->msg, G_PRIORITY_DEFAULT, NULL, on_send_complete, &response);
+ uri = g_uri_parse_relative (base_uri, "/echo_post", SOUP_HTTP_URI_FLAGS, NULL);
+ msg = soup_message_new_from_uri (SOUP_METHOD_POST, uri);
+ soup_message_set_request_body_from_bytes (msg, "text/plain", bytes);
- while (!response) {
+ soup_session_send_async (test->session, msg, G_PRIORITY_DEFAULT, NULL, on_send_complete, &response);
+
+ while (!response)
g_main_context_iteration (async_context, TRUE);
- }
g_assert_true (g_bytes_equal (bytes, response));
@@ -413,22 +459,26 @@ do_post_large_async_test (Test *test, gconstpointer data)
g_bytes_unref (response);
g_bytes_unref (bytes);
g_main_context_unref (async_context);
- g_object_unref (test->msg);
+ g_object_unref (msg);
+ g_uri_unref (uri);
}
static void
do_post_blocked_async_test (Test *test, gconstpointer data)
{
+ GUri *uri;
+ SoupMessage *msg;
+ GBytes *response = NULL;
GMainContext *async_context = g_main_context_ref_thread_default ();
GInputStream *in_stream = soup_body_input_stream_http2_new ();
soup_body_input_stream_http2_add_data (SOUP_BODY_INPUT_STREAM_HTTP2 (in_stream), (guint8*)"Part 1 -", 8);
- test->msg = soup_message_new (SOUP_METHOD_POST, "https://127.0.0.1:5000/echo_post");
- soup_message_set_request_body (test->msg, "text/plain", in_stream, 8 + 8);
+ uri = g_uri_parse_relative (base_uri, "/echo_post", SOUP_HTTP_URI_FLAGS, NULL);
+ msg = soup_message_new_from_uri (SOUP_METHOD_POST, uri);
+ soup_message_set_request_body (msg, "text/plain", in_stream, 8 + 8);
- GBytes *response = NULL;
- soup_session_send_async (test->session, test->msg, G_PRIORITY_DEFAULT, NULL, on_send_complete, &response);
+ soup_session_send_async (test->session, msg, G_PRIORITY_DEFAULT, NULL, on_send_complete, &response);
while (!response) {
// Let it iterate for a bit waiting on blocked data
@@ -447,23 +497,27 @@ do_post_blocked_async_test (Test *test, gconstpointer data)
g_bytes_unref (response);
g_object_unref (in_stream);
g_main_context_unref (async_context);
- g_object_unref (test->msg);
+ g_object_unref (msg);
+ g_uri_unref (uri);
}
static void
do_post_file_async_test (Test *test, gconstpointer data)
{
+ GUri *uri;
+ SoupMessage *msg;
+ GBytes *response = NULL;
GMainContext *async_context = g_main_context_ref_thread_default ();
GFile *in_file = g_file_new_for_path (g_test_get_filename (G_TEST_DIST, "test-cert.pem", NULL));
GFileInputStream *in_stream = g_file_read (in_file, NULL, NULL);
g_assert_nonnull (in_stream);
- test->msg = soup_message_new (SOUP_METHOD_POST, "https://127.0.0.1:5000/echo_post");
- soup_message_set_request_body (test->msg, "application/x-x509-ca-cert", G_INPUT_STREAM (in_stream), -1);
+ uri = g_uri_parse_relative (base_uri, "/echo_post", SOUP_HTTP_URI_FLAGS, NULL);
+ msg = soup_message_new_from_uri (SOUP_METHOD_POST, uri);
+ soup_message_set_request_body (msg, "application/x-x509-ca-cert", G_INPUT_STREAM (in_stream), -1);
- GBytes *response = NULL;
- soup_session_send_async (test->session, test->msg, G_PRIORITY_DEFAULT, NULL, on_send_complete, &response);
+ soup_session_send_async (test->session, msg, G_PRIORITY_DEFAULT, NULL, on_send_complete, &response);
while (!response)
g_main_context_iteration (async_context, TRUE);
@@ -477,7 +531,8 @@ do_post_file_async_test (Test *test, gconstpointer data)
g_object_unref (in_stream);
g_object_unref (in_file);
g_main_context_unref (async_context);
- g_object_unref (test->msg);
+ g_object_unref (msg);
+ g_uri_unref (uri);
}
static gboolean
@@ -500,18 +555,22 @@ on_authenticate (SoupMessage *msg, SoupAuth *auth, gboolean retrying, gpointer u
static void
do_paused_async_test (Test *test, gconstpointer data)
{
-
- test->msg = soup_message_new (SOUP_METHOD_GET, "https://127.0.0.1:5000/auth");
- g_signal_connect (test->msg, "authenticate", G_CALLBACK (on_authenticate), NULL);
-
+ GUri *uri;
+ SoupMessage *msg;
+ GBytes *response;
GError *error = NULL;
- GBytes *response = soup_test_session_async_send (test->session, test->msg, NULL, &error);
+
+ uri = g_uri_parse_relative (base_uri, "/auth", SOUP_HTTP_URI_FLAGS, NULL);
+ msg = soup_message_new_from_uri (SOUP_METHOD_GET, uri);
+ g_signal_connect (msg, "authenticate", G_CALLBACK (on_authenticate), NULL);
+ response = soup_test_session_async_send (test->session, msg, NULL, &error);
g_assert_no_error (error);
g_assert_cmpstr (g_bytes_get_data (response, NULL), ==, "Authenticated");
g_bytes_unref (response);
- g_object_unref (test->msg);
+ g_object_unref (msg);
+ g_uri_unref (uri);
}
static SoupConnection *last_connection;
@@ -556,6 +615,7 @@ do_connections_test (Test *test, gconstpointer data)
{
GMainContext *async_context;
guint complete_count = 0;
+ GUri *uri;
if (g_getenv ("ASAN_OPTIONS")) {
g_test_skip ("Flakey on asan GitLab runner");
@@ -564,10 +624,11 @@ do_connections_test (Test *test, gconstpointer data)
async_context = g_main_context_ref_thread_default ();
+ uri = g_uri_parse_relative (base_uri, "/slow", SOUP_HTTP_URI_FLAGS, NULL);
#define N_TESTS 100
for (unsigned int i = 0; i < N_TESTS; ++i) {
- SoupMessage *msg = soup_message_new ("GET", "https://127.0.0.1:5000/slow");
+ SoupMessage *msg = soup_message_new_from_uri (SOUP_METHOD_GET, uri);
soup_session_send_async (test->session, msg, G_PRIORITY_DEFAULT, NULL, on_send_ready, &complete_count);
g_object_unref (msg);
}
@@ -581,7 +642,7 @@ do_connections_test (Test *test, gconstpointer data)
/* After no messages reference the connection it should be IDLE and reusable */
g_assert_cmpuint (soup_connection_get_state (last_connection), ==, SOUP_CONNECTION_IDLE);
- SoupMessage *msg = soup_message_new ("GET", "https://127.0.0.1:5000/slow");
+ SoupMessage *msg = soup_message_new_from_uri (SOUP_METHOD_GET, uri);
soup_session_send_async (test->session, msg, G_PRIORITY_DEFAULT, NULL, on_send_ready, &complete_count);
g_object_unref (msg);
@@ -591,22 +652,28 @@ do_connections_test (Test *test, gconstpointer data)
while (g_main_context_pending (async_context))
g_main_context_iteration (async_context, FALSE);
+ g_uri_unref (uri);
g_main_context_unref (async_context);
}
static void
do_misdirected_request_test (Test *test, gconstpointer data)
{
- test->msg = soup_message_new (SOUP_METHOD_GET, "https://127.0.0.1:5000/misdirected_request");
+ GUri *uri;
+ SoupMessage *msg;
+ GBytes *response;
GError *error = NULL;
- GBytes *response = soup_test_session_async_send (test->session, test->msg, NULL, &error);
+ uri = g_uri_parse_relative (base_uri, "/misdirected_request", SOUP_HTTP_URI_FLAGS, NULL);
+ msg = soup_message_new_from_uri (SOUP_METHOD_GET, uri);
+ response = soup_test_session_async_send (test->session, msg, NULL, &error);
g_assert_no_error (error);
g_assert_cmpstr (g_bytes_get_data (response, NULL), ==, "Success!");
g_bytes_unref (response);
- g_object_unref (test->msg);
+ g_object_unref (msg);
+ g_uri_unref (uri);
}
static void
@@ -627,42 +694,50 @@ log_printer (SoupLogger *logger,
static void
do_logging_test (Test *test, gconstpointer data)
{
+ GUri *uri;
+ SoupMessage *msg;
+ GBytes *response;
+ GError *error = NULL;
+ GBytes *bytes = g_bytes_new_static ("Test", sizeof ("Test"));
gboolean has_logged_body = FALSE;
SoupLogger *logger = soup_logger_new (SOUP_LOGGER_LOG_BODY);
soup_logger_set_printer (logger, log_printer, &has_logged_body, NULL);
soup_session_add_feature (test->session, SOUP_SESSION_FEATURE (logger));
- GBytes *bytes = g_bytes_new_static ("Test", sizeof ("Test"));
- test->msg = soup_message_new (SOUP_METHOD_POST, "https://127.0.0.1:5000/echo_post");
- soup_message_set_request_body_from_bytes (test->msg, "text/plain", bytes);
- GError *error = NULL;
-
- GBytes *response = soup_test_session_async_send (test->session, test->msg, NULL, &error);
+ uri = g_uri_parse_relative (base_uri, "/echo_post", SOUP_HTTP_URI_FLAGS, NULL);
+ msg = soup_message_new_from_uri (SOUP_METHOD_POST, uri);
+ soup_message_set_request_body_from_bytes (msg, "text/plain", bytes);
+ response = soup_test_session_async_send (test->session, msg, NULL, &error);
g_assert_no_error (error);
g_assert_cmpstr (g_bytes_get_data (response, NULL), ==, "Test");
g_assert_true (has_logged_body);
g_bytes_unref (response);
- g_object_unref (test->msg);
+ g_object_unref (msg);
+ g_uri_unref (uri);
}
static void
do_metrics_size_test (Test *test, gconstpointer data)
{
+ GUri *uri;
+ SoupMessage *msg;
+ GBytes *response;
+ GError *error = NULL;
GBytes *bytes = g_bytes_new_static ("Test", sizeof ("Test"));
- test->msg = soup_message_new (SOUP_METHOD_POST, "https://127.0.0.1:5000/echo_post");
- soup_message_set_request_body_from_bytes (test->msg, "text/plain", bytes);
- soup_message_add_flags (test->msg, SOUP_MESSAGE_COLLECT_METRICS);
- GError *error = NULL;
- GBytes *response = soup_test_session_async_send (test->session, test->msg, NULL, &error);
+ uri = g_uri_parse_relative (base_uri, "/echo_post", SOUP_HTTP_URI_FLAGS, NULL);
+ msg = soup_message_new_from_uri (SOUP_METHOD_POST, uri);
+ soup_message_set_request_body_from_bytes (msg, "text/plain", bytes);
+ soup_message_add_flags (msg, SOUP_MESSAGE_COLLECT_METRICS);
+ response = soup_test_session_async_send (test->session, msg, NULL, &error);
g_assert_no_error (error);
g_assert_cmpstr (g_bytes_get_data (response, NULL), ==, "Test");
- SoupMessageMetrics *metrics = soup_message_get_metrics (test->msg);
+ SoupMessageMetrics *metrics = soup_message_get_metrics (msg);
g_assert_nonnull (metrics);
g_assert_cmpuint (soup_message_metrics_get_request_header_bytes_sent (metrics), >, 0);
@@ -675,7 +750,8 @@ do_metrics_size_test (Test *test, gconstpointer data)
g_bytes_unref (response);
g_bytes_unref (bytes);
- g_object_unref (test->msg);
+ g_object_unref (msg);
+ g_uri_unref (uri);
}
static void
@@ -765,7 +841,7 @@ do_one_metrics_time_test (SoupSession *session,
gboolean got_body_called = FALSE;
guint network_event_called = 0;
- msg = soup_message_new (SOUP_METHOD_GET, "https://127.0.0.1:5000/");
+ msg = soup_message_new_from_uri (SOUP_METHOD_GET, base_uri);
soup_message_add_flags (msg, SOUP_MESSAGE_COLLECT_METRICS);
g_signal_connect (msg, "starting",
G_CALLBACK (metrics_test_message_starting_cb),
@@ -837,7 +913,7 @@ static void
do_preconnect_test (Test *test, gconstpointer data)
{
GMainContext *async_context = g_main_context_ref_thread_default ();
- SoupMessage *msg = soup_message_new (SOUP_METHOD_GET, "https://127.0.0.1:5000/");
+ SoupMessage *msg = soup_message_new_from_uri (SOUP_METHOD_GET, base_uri);
GError *error = NULL;
SoupConnection *conn = NULL;
guint32 connection_id;
@@ -853,7 +929,7 @@ do_preconnect_test (Test *test, gconstpointer data)
g_assert_cmpuint (soup_connection_get_state (conn), ==, SOUP_CONNECTION_IDLE);
g_object_unref (msg);
- msg = soup_message_new (SOUP_METHOD_GET, "https://127.0.0.1:5000/");
+ msg = soup_message_new_from_uri (SOUP_METHOD_GET, base_uri);
GBytes *response = soup_test_session_async_send (test->session, msg, NULL, &error);
g_assert_no_error (error);
@@ -877,7 +953,7 @@ do_invalid_header_test (Test *test, gconstpointer data)
GBytes *body;
GError *error = NULL;
- msg = soup_message_new (SOUP_METHOD_GET, "https://127.0.0.1:5000/");
+ msg = soup_message_new_from_uri (SOUP_METHOD_GET, base_uri);
request_headers = soup_message_get_request_headers (msg);
soup_message_headers_append (request_headers, invalid_headers[i], "Value");
body = soup_test_session_async_send (test->session, msg, NULL, &error);
@@ -922,16 +998,18 @@ sniffer_test_send_ready_cb (SoupSession *session,
static void
do_one_sniffer_test (SoupSession *session,
- const char *uri,
+ const char *path,
gsize expected_size,
gboolean should_sniff,
GMainContext *async_context)
{
+ GUri *uri;
SoupMessage *msg;
GInputStream *stream = NULL;
GBytes *bytes;
- msg = soup_message_new (SOUP_METHOD_GET, uri);
+ uri = g_uri_parse_relative (base_uri, path, SOUP_HTTP_URI_FLAGS, NULL);
+ msg = soup_message_new_from_uri (SOUP_METHOD_GET, uri);
g_object_connect (msg,
"signal::got-headers", got_headers, NULL,
"signal::content-sniffed", content_sniffed, NULL,
@@ -965,6 +1043,7 @@ do_one_sniffer_test (SoupSession *session,
g_object_unref (stream);
g_bytes_unref (bytes);
g_object_unref (msg);
+ g_uri_unref (uri);
}
static void
@@ -974,9 +1053,9 @@ do_sniffer_async_test (Test *test, gconstpointer data)
soup_session_add_feature_by_type (test->session, SOUP_TYPE_CONTENT_SNIFFER);
- do_one_sniffer_test (test->session, "https://127.0.0.1:5000/", 11, TRUE, async_context);
- do_one_sniffer_test (test->session, "https://127.0.0.1:5000/large", (1024 * 24) + 1, TRUE, async_context);
- do_one_sniffer_test (test->session, "https://127.0.0.1:5000/no-content", 0, FALSE, async_context);
+ do_one_sniffer_test (test->session, "/", 11, TRUE, async_context);
+ do_one_sniffer_test (test->session, "/large", (LARGE_N_CHARS * LARGE_CHARS_REPEAT) + 1, TRUE, async_context);
+ do_one_sniffer_test (test->session, "/no-content", 0, FALSE, async_context);
while (g_main_context_pending (async_context))
g_main_context_iteration (async_context, FALSE);
@@ -989,41 +1068,158 @@ do_sniffer_sync_test (Test *test, gconstpointer data)
{
soup_session_add_feature_by_type (test->session, SOUP_TYPE_CONTENT_SNIFFER);
- do_one_sniffer_test (test->session, "https://127.0.0.1:5000/", 11, TRUE, NULL);
- do_one_sniffer_test (test->session, "https://127.0.0.1:5000/large", (1024 * 24) + 1, TRUE, NULL);
- do_one_sniffer_test (test->session, "https://127.0.0.1:5000/no-content", 0, FALSE, NULL);
+ do_one_sniffer_test (test->session, "/", 11, TRUE, NULL);
+ do_one_sniffer_test (test->session, "/large", (LARGE_N_CHARS * LARGE_CHARS_REPEAT) + 1, TRUE, NULL);
+ do_one_sniffer_test (test->session, "/no-content", 0, FALSE, NULL);
}
static void
do_timeout_test (Test *test, gconstpointer data)
{
+ GUri *uri;
SoupMessage *msg;
GBytes *response;
GError *error = NULL;
soup_session_set_timeout (test->session, 2);
- msg = soup_message_new (SOUP_METHOD_GET, "https://127.0.0.1:5000/timeout");
+ uri = g_uri_parse_relative (base_uri, "/timeout", SOUP_HTTP_URI_FLAGS, NULL);
+ msg = soup_message_new_from_uri (SOUP_METHOD_GET, uri);
response = soup_test_session_async_send (test->session, msg, NULL, &error);
g_assert_null (response);
g_assert_error (error, G_IO_ERROR, G_IO_ERROR_TIMED_OUT);
g_object_unref (msg);
+ g_uri_unref (uri);
while (g_main_context_pending (NULL))
g_main_context_iteration (NULL, FALSE);
}
+static gboolean
+unpause_message (SoupServerMessage *msg)
+{
+ soup_server_message_unpause (msg);
+ return FALSE;
+}
+
+static void
+server_handler (SoupServer *server,
+ SoupServerMessage *msg,
+ const char *path,
+ GHashTable *query,
+ gpointer user_data)
+{
+ g_assert_cmpuint (soup_server_message_get_http_version (msg), ==, SOUP_HTTP_2_0);
+
+ if (strcmp (path, "/") == 0 || strcmp (path, "/slow") == 0 || strcmp (path, "/timeout") == 0) {
+ gboolean is_slow = path[1] == 's';
+ gboolean is_timeout = path[1] == 't';
+
+ soup_server_message_set_status (msg, SOUP_STATUS_OK, NULL);
+ soup_server_message_set_response (msg, "text/plain",
+ SOUP_MEMORY_STATIC,
+ "Hello world", 11);
+ if (is_slow || is_timeout) {
+ GSource *timeout;
+
+ soup_server_message_pause (msg);
+ timeout = soup_add_timeout (g_main_context_get_thread_default (),
+ is_timeout ? 4000 : 1000,
+ (GSourceFunc)unpause_message, msg);
+ g_source_unref (timeout);
+ }
+ } else if (strcmp (path, "/no-content") == 0) {
+ soup_server_message_set_status (msg, SOUP_STATUS_NO_CONTENT, NULL);
+ } else if (strcmp (path, "/large") == 0) {
+ int i, j;
+ SoupMessageBody *response_body;
+ char letter = 'A';
+
+ /* Send increasing letters just to aid debugging */
+ response_body = soup_server_message_get_response_body (msg);
+ for (i = 0; i < LARGE_N_CHARS; i++, letter++) {
+ GString *chunk = g_string_new (NULL);
+
+ for (j = 0; j < LARGE_CHARS_REPEAT; j++)
+ chunk = g_string_append_c (chunk, letter);
+ soup_message_body_append_bytes (response_body, g_string_free_to_bytes (chunk));
+ }
+ soup_message_body_append (response_body, SOUP_MEMORY_STATIC, "\0", 1);
+
+ soup_server_message_set_status (msg, SOUP_STATUS_OK, NULL);
+ } else if (strcmp (path, "/echo_query") == 0) {
+ const char *query_str = g_uri_get_query (soup_server_message_get_uri (msg));
+
+ soup_server_message_set_status (msg, SOUP_STATUS_OK, NULL);
+ soup_server_message_set_response (msg, "text/plain",
+ SOUP_MEMORY_STATIC,
+ query_str, strlen (query_str));
+ } else if (strcmp (path, "/echo_post") == 0) {
+ SoupMessageBody *request_body;
+
+ request_body = soup_server_message_get_request_body (msg);
+ soup_server_message_set_status (msg, SOUP_STATUS_OK, NULL);
+ soup_server_message_set_response (msg, "text/plain",
+ SOUP_MEMORY_COPY,
+ request_body->data,
+ request_body->length);
+ } else if (strcmp (path, "/misdirected_request") == 0) {
+ static SoupServerConnection *conn = NULL;
+
+ if (!conn) {
+ conn = soup_server_message_get_connection (msg);
+ soup_server_message_set_status (msg, SOUP_STATUS_MISDIRECTED_REQUEST, NULL);
+ } else {
+ /* Message is retried on a different connection */
+ g_assert_false (conn == soup_server_message_get_connection (msg));
+ soup_server_message_set_status (msg, SOUP_STATUS_OK, NULL);
+ soup_server_message_set_response (msg, "text/plain",
+ SOUP_MEMORY_STATIC,
+ "Success!", 8);
+ }
+ } else if (strcmp (path, "/auth") == 0) {
+ soup_server_message_set_status (msg, SOUP_STATUS_OK, NULL);
+ soup_server_message_set_response (msg, "text/plain",
+ SOUP_MEMORY_STATIC,
+ "Authenticated", 13);
+ }
+}
+
+static gboolean
+server_basic_auth_callback (SoupAuthDomain *auth_domain,
+ SoupServerMessage *msg,
+ const char *username,
+ const char *password,
+ gpointer data)
+{
+ if (strcmp (username, "username") != 0)
+ return FALSE;
+
+ return strcmp (password, "password") == 0;
+}
+
int
main (int argc, char **argv)
{
+ SoupServer *server;
+ SoupAuthDomain *auth;
int ret;
test_init (argc, argv, NULL);
- if (!quart_init ()) {
- test_cleanup ();
- return 1;
- }
+ if (!tls_available)
+ return 0;
+
+ server = soup_test_server_new (SOUP_TEST_SERVER_IN_THREAD | SOUP_TEST_SERVER_HTTP2);
+ auth = soup_auth_domain_basic_new ("realm", "http2-test",
+ "auth-callback", server_basic_auth_callback,
+ NULL);
+ soup_auth_domain_add_path (auth, "/auth");
+ soup_server_add_auth_domain (server, auth);
+ g_object_unref (auth);
+
+ soup_server_add_handler (server, NULL, server_handler, NULL, NULL);
+ base_uri = soup_test_server_get_uri (server, "https", "127.0.0.1");
g_test_add ("/http2/basic/async", Test, NULL,
setup_session,
@@ -1128,6 +1324,9 @@ main (int argc, char **argv)
ret = g_test_run ();
+ g_uri_unref (base_uri);
+ soup_test_server_quit_unref (server);
+
test_cleanup ();
return ret;
diff --git a/tests/meson.build b/tests/meson.build
index 9f1d7aeb..9bf88bec 100644
--- a/tests/meson.build
+++ b/tests/meson.build
@@ -78,6 +78,7 @@ tests = [
{'name': 'date'},
{'name': 'forms'},
{'name': 'header-parsing'},
+ {'name': 'http2'},
{'name': 'http2-body-stream'},
{'name': 'hsts'},
{'name': 'hsts-db'},
@@ -107,16 +108,6 @@ tests = [
'dependencies': [libz_dep]},
]
-if quart_found
- configure_file(input : 'http2-server.py',
- output : 'http2-server.py',
- copy : true,
- install : installed_tests_enabled,
- install_dir : installed_tests_execdir)
-
- tests += [{'name': 'http2'}]
-endif
-
if brotlidec_dep.found()
tests += [{'name': 'brotli-decompressor'}]
diff --git a/tests/test-utils.c b/tests/test-utils.c
index c2a59dab..3f599c45 100644
--- a/tests/test-utils.c
+++ b/tests/test-utils.c
@@ -3,6 +3,7 @@
#include "test-utils.h"
#include "soup-misc.h"
#include "soup-session-private.h"
+#include "soup-server-private.h"
#include <glib/gprintf.h>
#ifdef G_OS_UNIX
@@ -114,8 +115,6 @@ test_cleanup (void)
apache_cleanup ();
#endif
- quart_cleanup ();
-
if (logger)
g_object_unref (logger);
if (index_buffer)
@@ -274,75 +273,6 @@ apache_cleanup (void)
#endif /* HAVE_APACHE */
-static GSubprocess *quart_proc;
-
-gboolean
-quart_init (void)
-{
- if (quart_proc)
- return TRUE;
-
- GSubprocessLauncher *launcher = g_subprocess_launcher_new (G_SUBPROCESS_FLAGS_STDOUT_PIPE); // | G_SUBPROCESS_FLAGS_STDERR_SILENCE
- g_subprocess_launcher_set_cwd (launcher, g_test_get_dir (G_TEST_DIST));
-
- GError *error = NULL;
- char *script = soup_test_build_filename_abs (G_TEST_DIST, "http2-server.py", NULL);
- quart_proc = g_subprocess_launcher_spawn (launcher, &error, script, NULL);
- g_free (script);
- g_object_unref (launcher);
-
- if (error) {
- g_test_message ("Failed to start quart server: %s", error->message);
- g_error_free (error);
- return FALSE;
- }
-
- GDataInputStream *in_stream = g_data_input_stream_new (g_subprocess_get_stdout_pipe (quart_proc));
-
- // We don't own the stream, don't break the pipe
- g_filter_input_stream_set_close_base_stream (G_FILTER_INPUT_STREAM (in_stream), FALSE);
-
- // Read stdout until the server says it is running
- while (TRUE) {
- char *line = g_data_input_stream_read_line_utf8 (in_stream, NULL, NULL, &error);
-
- if (error) {
- g_test_message ("Failed to start quart server: %s", error->message);
- g_error_free (error);
- g_object_unref (in_stream);
- return FALSE;
- } else if (line == NULL) {
- g_test_message ("Failed to start quart server (not installed?)");
- g_object_unref (in_stream);
- return FALSE;
- }
-
- if (g_str_has_prefix (line, " * Running")) {
- g_test_message ("Started quart server: %s", line + 3);
- g_free (line);
- g_object_unref (in_stream);
- return TRUE;
- }
- g_free (line);
- }
-}
-
-void
-quart_cleanup (void)
-{
- if (quart_proc) {
- GError *error = NULL;
- g_subprocess_force_exit (quart_proc);
- g_subprocess_wait (quart_proc, NULL, &error);
- if (error) {
- g_test_message ("Failed to stop quart server: %s", error->message);
- g_error_free (error);
- }
- }
-
- g_clear_object (&quart_proc);
-}
-
SoupSession *
soup_test_session_new (const char *propname, ...)
{
@@ -567,6 +497,8 @@ soup_test_server_new (SoupTestServerOptions options)
NULL);
g_clear_object (&cert);
+ soup_server_set_http2_enabled (server, options & SOUP_TEST_SERVER_HTTP2);
+
g_object_set_data (G_OBJECT (server), "options", GUINT_TO_POINTER (options));
if (options & SOUP_TEST_SERVER_UNIX_SOCKET) {
diff --git a/tests/test-utils.h b/tests/test-utils.h
index 762b828a..91e2752a 100644
--- a/tests/test-utils.h
+++ b/tests/test-utils.h
@@ -47,9 +47,6 @@ void apache_cleanup (void);
} G_STMT_END
#endif
-gboolean quart_init (void);
-void quart_cleanup (void);
-
gboolean have_curl (void);
typedef enum {
@@ -74,7 +71,8 @@ typedef enum {
SOUP_TEST_SERVER_DEFAULT = 0,
SOUP_TEST_SERVER_IN_THREAD = (1 << 0),
SOUP_TEST_SERVER_NO_DEFAULT_LISTENER = (1 << 1),
- SOUP_TEST_SERVER_UNIX_SOCKET = (1 << 2)
+ SOUP_TEST_SERVER_UNIX_SOCKET = (1 << 2),
+ SOUP_TEST_SERVER_HTTP2 = (1 << 3)
} SoupTestServerOptions;
SoupServer *soup_test_server_new (SoupTestServerOptions options);