Merge branch 'libsoup3'

Ports the soup plugin to libsoup 3.

Closes strongswan/strongswan#2788
This commit is contained in:
Tobias Brunner 2025-06-04 19:09:33 +02:00
commit b39311e19e
10 changed files with 51 additions and 111 deletions

View File

@ -1044,7 +1044,7 @@ if test x$unbound = xtrue; then
fi
if test x$soup = xtrue; then
PKG_CHECK_MODULES(soup, [libsoup-2.4])
PKG_CHECK_MODULES(soup, [libsoup-3.0])
AC_SUBST(soup_CFLAGS)
AC_SUBST(soup_LIBS)
fi

View File

@ -305,7 +305,7 @@ all|alpine|codeql|coverage|sonarcloud|no-dbg|no-testable-ke)
if [ "$TEST" = "no-testable-ke" ]; then
CONFIG="$CONFIG --without-testable-ke"
fi
DEPS="$DEPS libcurl4-gnutls-dev libsoup2.4-dev libunbound-dev libldns-dev
DEPS="$DEPS libcurl4-gnutls-dev libsoup-3.0-dev libunbound-dev libldns-dev
libmysqlclient-dev libsqlite3-dev clearsilver-dev libfcgi-dev
libldap2-dev libpcsclite-dev libpam0g-dev binutils-dev libnm-dev
libgcrypt20-dev libjson-c-dev libtspi-dev libsystemd-dev
@ -318,11 +318,11 @@ all|alpine|codeql|coverage|sonarcloud|no-dbg|no-testable-ke)
fi
if [ "$TEST" = "alpine" ]; then
# override the whole list for alpine
DEPS="git gmp-dev openldap-dev curl-dev ldns-dev unbound-dev libsoup-dev
tpm2-tss-dev tpm2-tss-sys mariadb-dev wolfssl-dev libgcrypt-dev
botan3-dev pcsc-lite-dev networkmanager-dev linux-pam-dev
iptables-dev libselinux-dev binutils-dev libunwind-dev ruby
py3-setuptools py3-build py3-tox"
DEPS="git gmp-dev openldap-dev curl-dev ldns-dev unbound-dev libsoup3-dev
libxml2-dev tpm2-tss-dev tpm2-tss-sys mariadb-dev wolfssl-dev
libgcrypt-dev botan3-dev pcsc-lite-dev networkmanager-dev
linux-pam-dev iptables-dev libselinux-dev binutils-dev libunwind-dev
ruby py3-setuptools py3-build py3-tox"
# musl does not provide backtrace(), so use libunwind
CONFIG="$CONFIG --enable-unwind-backtraces"
# alpine doesn't have systemd

View File

@ -69,12 +69,6 @@ enum fetcher_option_t {
*/
FETCH_REQUEST_HEADER,
/**
* Use HTTP Version 1.0 instead of 1.1.
* No additional argument is needed.
*/
FETCH_HTTP_VERSION_1_0,
/**
* Timeout to use for fetch, in seconds.
* Additional argument is u_int

View File

@ -103,9 +103,6 @@ METHOD(fetcher_manager_t, fetch, status_t,
good = fetcher->set_option(fetcher, opt,
va_arg(args, char*));
continue;
case FETCH_HTTP_VERSION_1_0:
good = fetcher->set_option(fetcher, opt);
continue;
case FETCH_TIMEOUT:
good = fetcher->set_option(fetcher, opt,
va_arg(args, u_int));

View File

@ -205,12 +205,6 @@ METHOD(fetcher_t, set_option, bool,
this->headers = curl_slist_append(this->headers, header);
break;
}
case FETCH_HTTP_VERSION_1_0:
{
curl_easy_setopt(this->curl, CURLOPT_HTTP_VERSION,
CURL_HTTP_VERSION_1_0);
break;
}
case FETCH_TIMEOUT:
{
this->timeout = va_arg(args, u_int);

View File

@ -55,11 +55,6 @@ struct private_soup_fetcher_t {
*/
u_int timeout;
/**
* HTTP request version
*/
SoupHTTPVersion version;
/**
* Fetcher callback function
*/
@ -71,36 +66,13 @@ struct private_soup_fetcher_t {
u_int *result;
};
/**
* Data to pass to soup callback
*/
typedef struct {
fetcher_callback_t cb;
void *user;
SoupSession *session;
} cb_data_t;
/**
* Soup callback invoking our callback
*/
static void soup_cb(SoupMessage *message, SoupBuffer *chunk, cb_data_t *data)
{
if (!data->cb(data->user, chunk_create((u_char*)chunk->data, chunk->length)))
{
soup_session_cancel_message(data->session, message,
SOUP_STATUS_CANCELLED);
}
}
METHOD(fetcher_t, fetch, status_t,
private_soup_fetcher_t *this, char *uri, void *userdata)
{
SoupMessage *message;
status_t status = FAILED;
cb_data_t data = {
.cb = this->cb,
.user = userdata,
};
GBytes *request_body, *res;
SoupSession *session;
message = soup_message_new(this->method, uri);
if (!message)
@ -113,32 +85,43 @@ METHOD(fetcher_t, fetch, status_t,
}
if (this->type)
{
soup_message_set_request(message, this->type, SOUP_MEMORY_STATIC,
this->data.ptr, this->data.len);
request_body = g_bytes_new_static(this->data.ptr, this->data.len);
soup_message_set_request_body_from_bytes(message, this->type,
request_body);
g_bytes_unref(request_body);
}
soup_message_set_http_version(message, this->version);
soup_message_body_set_accumulate(message->response_body, FALSE);
g_signal_connect(message, "got-chunk", G_CALLBACK(soup_cb), &data);
data.session = soup_session_new();
g_object_set(G_OBJECT(data.session),
SOUP_SESSION_TIMEOUT, (guint)this->timeout, NULL);
session = soup_session_new_with_options("timeout", (guint)this->timeout,
NULL);
DBG2(DBG_LIB, "sending http request to '%s'...", uri);
soup_session_send_message(data.session, message);
res = soup_session_send_and_read(session, message, NULL, NULL);
if (this->result)
{
*this->result = message->status_code;
*this->result = soup_message_get_status(message);
}
if (SOUP_STATUS_IS_SUCCESSFUL(message->status_code))
if (SOUP_STATUS_IS_SUCCESSFUL(soup_message_get_status(message)))
{
status = SUCCESS;
}
else if (!this->result)
{ /* only log an error if the code is not returned */
DBG1(DBG_LIB, "HTTP request failed: %s", message->reason_phrase);
DBG1(DBG_LIB, "HTTP request failed: %s",
soup_message_get_reason_phrase(message));
}
if (res)
{
gpointer data;
gsize data_len;
data = g_bytes_unref_to_data(res, &data_len);
if (!this->cb(userdata, chunk_create(data, data_len)))
{
status = FAILED;
}
g_free(data);
}
g_object_unref(G_OBJECT(message));
g_object_unref(G_OBJECT(data.session));
g_object_unref(G_OBJECT(session));
return status;
}
@ -158,9 +141,6 @@ METHOD(fetcher_t, set_option, bool,
case FETCH_REQUEST_TYPE:
this->type = va_arg(args, char*);
break;
case FETCH_HTTP_VERSION_1_0:
this->version = SOUP_HTTP_1_0;
break;
case FETCH_TIMEOUT:
this->timeout = va_arg(args, u_int);
break;
@ -200,7 +180,6 @@ soup_fetcher_t *soup_fetcher_create()
},
},
.method = SOUP_METHOD_GET,
.version = SOUP_HTTP_1_1,
.timeout = DEFAULT_TIMEOUT,
.cb = fetcher_default_callback,
);

View File

@ -54,11 +54,6 @@ struct private_winhttp_fetcher_t {
*/
chunk_t request;
/**
* HTTP version string to use
*/
LPWSTR version;
/**
* Optional HTTP headers, as allocated LPWSTR
*/
@ -264,7 +259,7 @@ METHOD(fetcher_t, fetch, status_t,
connection = WinHttpConnect(this->session, host, port, 0);
if (connection)
{
request = WinHttpOpenRequest(connection, method, path, this->version,
request = WinHttpOpenRequest(connection, method, path, NULL,
WINHTTP_NO_REFERER,
WINHTTP_DEFAULT_ACCEPT_TYPES, flags);
if (request)
@ -334,9 +329,6 @@ METHOD(fetcher_t, set_option, bool,
case FETCH_REQUEST_HEADER:
supported = append_header(this, va_arg(args, char*));
break;
case FETCH_HTTP_VERSION_1_0:
this->version = L"HTTP/1.0";
break;
case FETCH_TIMEOUT:
this->timeout = va_arg(args, u_int) * 1000;
break;
@ -381,7 +373,6 @@ winhttp_fetcher_t *winhttp_fetcher_create()
.destroy = _destroy,
},
},
.version = L"HTTP/1.1",
.cb = fetcher_default_callback,
.headers = linked_list_create(),
.session = WinHttpOpen(L"strongSwan WinHTTP fetcher",

View File

@ -27,8 +27,6 @@
typedef struct {
/* HTTP Method */
char *meth;
/* HTTP 1.x minor version */
int minor;
/* host to connect to */
char *host;
/* HTTP service port */
@ -117,8 +115,8 @@ static bool servicing(void *data, stream_t *stream)
switch (nr++)
{
case 0:
snprintf(hdr, sizeof(hdr), "%s %s HTTP/1.%u",
test->meth, test->path, test->minor);
snprintf(hdr, sizeof(hdr), "%s %s HTTP/1.1",
test->meth, test->path);
ck_assert_str_eq(hdr, start);
break;
default:
@ -158,7 +156,7 @@ static bool servicing(void *data, stream_t *stream)
}
/* response headers */
snprintf(buf, sizeof(buf), "HTTP/1.%u %u OK\r\n", test->minor, test->code);
snprintf(buf, sizeof(buf), "HTTP/1.1 %u OK\r\n", test->code);
ck_assert(stream->write_all(stream, buf, strlen(buf)));
/* if the response code indicates an error the following write operations
@ -188,13 +186,13 @@ static bool servicing(void *data, stream_t *stream)
}
static test_service_t gtests[] = {
{ "GET", 1, "127.0.0.1", 6543, "/a/test/?b=c", NULL,
{ "GET", "127.0.0.1", 6543, "/a/test/?b=c", NULL,
NULL, 0, "\x12\x34", 2, 0 },
{ "GET", 0, "localhost", 6543, "/", NULL,
{ "GET", "localhost", 6543, "/", NULL,
NULL, 0, NULL, 0, 0 },
{ "GET", 0, "127.0.0.1", 6543, "/largefile", NULL,
{ "GET", "127.0.0.1", 6543, "/largefile", NULL,
NULL, 0, large, sizeof(large), 0 },
{ "GET", 1, "[::1]", 6543, "/ipv6-url", NULL,
{ "GET", "[::1]", 6543, "/ipv6-url", NULL,
NULL, 0, "\x00\r\n\r\x00testdatablabla", 20, 0 },
};
@ -214,9 +212,7 @@ START_TEST(test_get)
snprintf(uri, sizeof(uri), "http://%s:%u%s",
gtests[_i].host, gtests[_i].port, gtests[_i].path);
status = lib->fetcher->fetch(lib->fetcher, uri, &data,
!gtests[_i].minor ? FETCH_HTTP_VERSION_1_0 : FETCH_END,
FETCH_END);
status = lib->fetcher->fetch(lib->fetcher, uri, &data, FETCH_END);
ck_assert_int_eq(status, SUCCESS);
expected = chunk_create(gtests[_i].res, gtests[_i].res_len);
ck_assert_msg(chunk_compare(expected, data) == 0,
@ -229,11 +225,11 @@ END_TEST
static test_service_t ptests[] = {
{ "POST", 1, "127.0.0.1", 6543, "/a/test/?b=c", "application/binary",
{ "POST", "127.0.0.1", 6543, "/a/test/?b=c", "application/binary",
"\x23\x45", 2, "\x12\x34", 2, 0 },
{ "POST", 0, "localhost", 6543, "/largefile", "application/x-large",
{ "POST", "localhost", 6543, "/largefile", "application/x-large",
large, sizeof(large), large, sizeof(large), 0 },
{ "POST", 1, "[::1]", 6543, "/ipv6-url", "text/plain",
{ "POST", "[::1]", 6543, "/ipv6-url", "text/plain",
"\x00\r\n\r\x00testdatablabla", 20, "\x00\r\n\r\x00testdatablabla", 20, 0 },
};
@ -257,7 +253,6 @@ START_TEST(test_post)
FETCH_REQUEST_TYPE, ptests[_i].type,
FETCH_REQUEST_DATA,
chunk_create(ptests[_i].req, ptests[_i].req_len),
!ptests[_i].minor ? FETCH_HTTP_VERSION_1_0 : FETCH_END,
FETCH_END);
ck_assert_int_eq(status, SUCCESS);
expected = chunk_create(ptests[_i].res, ptests[_i].res_len);
@ -271,11 +266,11 @@ END_TEST
static test_service_t rtests[] = {
{ "GET", 1, "localhost", 6544, "/", NULL, NULL, 0, NULL, 0, 200 },
{ "GET", 1, "localhost", 6544, "/", NULL, NULL, 0, NULL, 0, 204 },
{ "GET", 1, "localhost", 6544, "/", NULL, NULL, 0, NULL, 0, 400 },
{ "GET", 1, "localhost", 6544, "/", NULL, NULL, 0, NULL, 0, 404 },
{ "GET", 1, "localhost", 6544, "/", NULL, NULL, 0, NULL, 0, 500 },
{ "GET", "localhost", 6544, "/", NULL, NULL, 0, NULL, 0, 200 },
{ "GET", "localhost", 6544, "/", NULL, NULL, 0, NULL, 0, 204 },
{ "GET", "localhost", 6544, "/", NULL, NULL, 0, NULL, 0, 400 },
{ "GET", "localhost", 6544, "/", NULL, NULL, 0, NULL, 0, 404 },
{ "GET", "localhost", 6544, "/", NULL, NULL, 0, NULL, 0, 500 },
};
START_TEST(test_response_code)

View File

@ -44,7 +44,7 @@ TEST_SUITE_DEPEND(rsa_oaep_sha512_suite_create, PRIVKEY_DECRYPT, ENCRYPT_RSA_OAE
TEST_SUITE_DEPEND(certpolicy_suite_create, CERT_ENCODE, CERT_X509)
TEST_SUITE_DEPEND(certnames_suite_create, CERT_ENCODE, CERT_X509)
TEST_SUITE_DEPEND(serial_gen_suite_create, CERT_ENCODE, CERT_X509)
TEST_SUITE(serial_parse_suite_create)
TEST_SUITE_DEPEND(serial_parse_suite_create, CERT_DECODE, CERT_X509)
TEST_SUITE(host_suite_create)
TEST_SUITE(printf_suite_create)
TEST_SUITE(auth_cfg_suite_create)

View File

@ -563,16 +563,6 @@ static char *whitelist[] = {
"xmlInitParserCtxt",
/* libcurl */
"Curl_client_write",
/* libsoup */
"soup_add_timeout",
"soup_headers_parse_response",
"soup_message_headers_append",
"soup_message_headers_clear",
"soup_message_headers_get_list",
"soup_message_headers_get_one",
"soup_session_abort",
"soup_session_get_type",
"soup_session_remove_feature",
/* libldap */
"ldap_int_initialize",
/* ClearSilver */