From: Dmitry Verenitsin Date: Tue, 26 May 2026 19:02:42 +0000 (+0500) Subject: Merge commit from fork X-Git-Tag: v1.11.1^2~7 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=33ee3663bbe634ebc7a909bec787dcaf2434f37f;p=thirdparty%2Ffreeswitch.git Merge commit from fork Cap `Content-Length` at `HTTP_POST_MAX_BODY` (10 MiB) and size the allocation to the actual body length (`content_length + 1` for the trailing NUL). Also fix `WS_BLOCK` units — `kws_raw_read` takes ms, set to 10000. --- diff --git a/src/mod/endpoints/mod_verto/mod_verto.c b/src/mod/endpoints/mod_verto/mod_verto.c index 113a21c579..e4a9dc3fda 100644 --- a/src/mod/endpoints/mod_verto/mod_verto.c +++ b/src/mod/endpoints/mod_verto/mod_verto.c @@ -41,6 +41,7 @@ SWITCH_MODULE_RUNTIME_FUNCTION(mod_verto_runtime); SWITCH_MODULE_DEFINITION(mod_verto, mod_verto_load, mod_verto_shutdown, mod_verto_runtime); #define HTTP_CHUNK_SIZE 1024 * 32 +#define HTTP_POST_MAX_BODY (10 * 1024 * 1024) /* max accepted Content-Length for form-urlencoded POST */ #define EP_NAME "verto.rtc" //#define WSS_STANDALONE 1 #include "libks/ks.h" @@ -1824,7 +1825,7 @@ new_req: char *buffer = NULL; switch_ssize_t len = 0, bytes = 0; - if (request->content_length && request->content_length > 10 * 1024 * 1024 - 1) { + if (request->content_length && request->content_length >= HTTP_POST_MAX_BODY) { char *data = "HTTP/1.1 413 Request Entity Too Large\r\n" "Content-Length: 0\r\n\r\n"; kws_raw_write(jsock->ws, data, strlen(data)); @@ -1832,16 +1833,16 @@ new_req: goto done; } - if (!(buffer = malloc(2 * 1024 * 1024))) { + if (!(buffer = malloc(request->content_length + 1))) { goto request_err; } while(bytes < (switch_ssize_t)request->content_length) { len = request->content_length - bytes; -#define WS_BLOCK 1 +#define WS_BLOCK 10000 /* ms; matches libks's internal default */ - if ((len = kws_raw_read(jsock->ws, buffer + bytes, len, WS_BLOCK)) < 0) { + if ((len = kws_raw_read(jsock->ws, buffer + bytes, len, WS_BLOCK)) <= 0) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Read error %" SWITCH_SSIZE_T_FMT"\n", len); goto done; } diff --git a/tests/unit/Makefile.am b/tests/unit/Makefile.am index 2f83bca68f..47542e34ea 100644 --- a/tests/unit/Makefile.am +++ b/tests/unit/Makefile.am @@ -6,6 +6,7 @@ noinst_PROGRAMS += switch_core_video switch_core_db switch_vad switch_packetizer noinst_PROGRAMS += switch_stun noinst_PROGRAMS += test_tts_format noinst_PROGRAMS+= switch_hold switch_sip +noinst_PROGRAMS += test_mod_verto if HAVE_PCAP noinst_PROGRAMS += switch_rtp_pcap diff --git a/tests/unit/conf_verto/freeswitch.xml b/tests/unit/conf_verto/freeswitch.xml new file mode 100644 index 0000000000..fb316ffde4 --- /dev/null +++ b/tests/unit/conf_verto/freeswitch.xml @@ -0,0 +1,47 @@ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
diff --git a/tests/unit/conf_verto/verto.conf.xml b/tests/unit/conf_verto/verto.conf.xml new file mode 100644 index 0000000000..ece12290ae --- /dev/null +++ b/tests/unit/conf_verto/verto.conf.xml @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/unit/test_mod_verto.c b/tests/unit/test_mod_verto.c new file mode 100644 index 0000000000..c3f414af07 --- /dev/null +++ b/tests/unit/test_mod_verto.c @@ -0,0 +1,316 @@ +/* + * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application + * Copyright (C) 2026, Anthony Minessale II + * + * Version: MPL 1.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application + * + * The Initial Developer of the Original Code is + * Anthony Minessale II + * Portions created by the Initial Developer are Copyright (C) + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Dmitry Verenitsin + * + * + * test_mod_verto.c -- Tests for mod_verto + * + */ + +#include +#include + +#define VERTO_TEST_HOST "127.0.0.1" +#define VERTO_TEST_PORT 33081 + +/* Must match HTTP_POST_MAX_BODY in src/mod/endpoints/mod_verto/mod_verto.c */ +#define VERTO_POST_MAX_BODY (10 * 1024 * 1024) + +static switch_status_t verto_connect(switch_socket_t **sock_out, switch_memory_pool_t *pool) +{ + switch_sockaddr_t *addr = NULL; + switch_socket_t *sock = NULL; + int attempts; + + if (switch_sockaddr_info_get(&addr, VERTO_TEST_HOST, SWITCH_UNSPEC, + VERTO_TEST_PORT, 0, pool) != SWITCH_STATUS_SUCCESS) { + return SWITCH_STATUS_FALSE; + } + + for (attempts = 0; attempts < 50; attempts++) { + if (switch_socket_create(&sock, switch_sockaddr_get_family(addr), + SOCK_STREAM, SWITCH_PROTO_TCP, pool) != SWITCH_STATUS_SUCCESS) { + return SWITCH_STATUS_FALSE; + } + switch_socket_opt_set(sock, SWITCH_SO_TCP_NODELAY, 1); + + if (switch_socket_connect(sock, addr) == SWITCH_STATUS_SUCCESS) { + *sock_out = sock; + return SWITCH_STATUS_SUCCESS; + } + + switch_socket_close(sock); + sock = NULL; + switch_yield(100000); + } + + return SWITCH_STATUS_FALSE; +} + +static switch_status_t send_all(switch_socket_t *sock, const char *buf, switch_size_t len) +{ + switch_size_t remaining = len; + const char *p = buf; + + while (remaining > 0) { + switch_size_t n = remaining; + if (switch_socket_send(sock, p, &n) != SWITCH_STATUS_SUCCESS) { + return SWITCH_STATUS_FALSE; + } + if (n == 0) { + return SWITCH_STATUS_FALSE; + } + p += n; + remaining -= n; + } + return SWITCH_STATUS_SUCCESS; +} + +static switch_size_t read_status_line(switch_socket_t *sock, char *out, switch_size_t cap) +{ + switch_size_t got = 0; + + while (got < cap - 1) { + switch_size_t want = cap - 1 - got; + if (switch_socket_recv(sock, out + got, &want) != SWITCH_STATUS_SUCCESS || want == 0) { + break; + } + got += want; + if (memchr(out, '\n', got)) break; + } + out[got] = '\0'; + return got; +} + +FST_CORE_DB_BEGIN("./conf_verto") +{ + FST_SUITE_BEGIN(test_mod_verto) + { + FST_SETUP_BEGIN() + { + fst_requires_module("mod_verto"); + switch_yield(500000); + } + FST_SETUP_END() + + FST_TEARDOWN_BEGIN() + { + } + FST_TEARDOWN_END() + + FST_TEST_BEGIN(post_at_cap_returns_413) + { + switch_memory_pool_t *pool = NULL; + switch_socket_t *sock = NULL; + char req[256]; + char resp[64] = { 0 }; + switch_size_t req_len; + + do { + if (switch_core_new_memory_pool(&pool) != SWITCH_STATUS_SUCCESS) { + fst_fail("could not allocate memory pool"); + break; + } + if (verto_connect(&sock, pool) != SWITCH_STATUS_SUCCESS) { + fst_fail("could not connect to verto listener"); + break; + } + + req_len = switch_snprintf(req, sizeof(req), + "POST / HTTP/1.1\r\n" + "Host: " VERTO_TEST_HOST "\r\n" + "Content-Type: application/x-www-form-urlencoded\r\n" + "Content-Length: %d\r\n" + "\r\n", + VERTO_POST_MAX_BODY); + + if (send_all(sock, req, req_len) != SWITCH_STATUS_SUCCESS) { + fst_fail("could not send request"); + break; + } + + read_status_line(sock, resp, sizeof(resp)); + fst_check_string_starts_with(resp, "HTTP/1.1 413"); + } while (0); + + if (sock) switch_socket_close(sock); + if (pool) switch_core_destroy_memory_pool(&pool); + } + FST_TEST_END() + + FST_TEST_BEGIN(post_small_body_parsed) + { + switch_memory_pool_t *pool = NULL; + switch_socket_t *sock = NULL; + const switch_size_t body_len = 32 * 1024; + char *body = NULL; + char req[256]; + char resp[64] = { 0 }; + switch_size_t req_len; + + do { + if (switch_core_new_memory_pool(&pool) != SWITCH_STATUS_SUCCESS) { + fst_fail("could not allocate memory pool"); + break; + } + if (verto_connect(&sock, pool) != SWITCH_STATUS_SUCCESS) { + fst_fail("could not connect to verto listener"); + break; + } + + body = malloc(body_len); + if (!body) { + fst_fail("could not allocate body buffer"); + break; + } + memset(body, 'x', body_len); + + req_len = switch_snprintf(req, sizeof(req), + "POST / HTTP/1.1\r\n" + "Host: " VERTO_TEST_HOST "\r\n" + "Content-Type: application/x-www-form-urlencoded\r\n" + "Content-Length: %" SWITCH_SIZE_T_FMT "\r\n" + "\r\n", + body_len); + + if (send_all(sock, req, req_len) != SWITCH_STATUS_SUCCESS) { + fst_fail("could not send headers"); + break; + } + if (send_all(sock, body, body_len) != SWITCH_STATUS_SUCCESS) { + fst_fail("could not send body"); + break; + } + + read_status_line(sock, resp, sizeof(resp)); + fst_check_string_starts_with(resp, "HTTP/1.1 "); + fst_xcheck(strncmp(resp, "HTTP/1.1 413", 12) != 0, + "server returned 413 below cap"); + } while (0); + + free(body); + if (sock) switch_socket_close(sock); + if (pool) switch_core_destroy_memory_pool(&pool); + } + FST_TEST_END() + + FST_TEST_BEGIN(post_large_body_no_overflow) + { + switch_memory_pool_t *pool = NULL; + switch_socket_t *sock = NULL; + const switch_size_t body_len = 8 * 1024 * 1024; + char *body = NULL; + char req[256]; + char resp[64] = { 0 }; + switch_size_t req_len; + + do { + if (switch_core_new_memory_pool(&pool) != SWITCH_STATUS_SUCCESS) { + fst_fail("could not allocate memory pool"); + break; + } + if (verto_connect(&sock, pool) != SWITCH_STATUS_SUCCESS) { + fst_fail("could not connect to verto listener"); + break; + } + + body = malloc(body_len); + if (!body) { + fst_fail("could not allocate body buffer"); + break; + } + memset(body, 'x', body_len); + + req_len = switch_snprintf(req, sizeof(req), + "POST / HTTP/1.1\r\n" + "Host: " VERTO_TEST_HOST "\r\n" + "Content-Type: application/x-www-form-urlencoded\r\n" + "Content-Length: %" SWITCH_SIZE_T_FMT "\r\n" + "\r\n", + body_len); + + if (send_all(sock, req, req_len) != SWITCH_STATUS_SUCCESS) { + fst_fail("could not send headers"); + break; + } + if (send_all(sock, body, body_len) != SWITCH_STATUS_SUCCESS) { + fst_fail("could not send body"); + break; + } + + read_status_line(sock, resp, sizeof(resp)); + fst_check_string_starts_with(resp, "HTTP/1.1 "); + fst_xcheck(strncmp(resp, "HTTP/1.1 413", 12) != 0, + "server returned 413 below cap"); + } while (0); + + free(body); + if (sock) switch_socket_close(sock); + if (pool) switch_core_destroy_memory_pool(&pool); + } + FST_TEST_END() + + FST_TEST_BEGIN(post_overflow_length_returns_413) + { + switch_memory_pool_t *pool = NULL; + switch_socket_t *sock = NULL; + char req[256]; + char resp[64] = { 0 }; + switch_size_t req_len; + + do { + if (switch_core_new_memory_pool(&pool) != SWITCH_STATUS_SUCCESS) { + fst_fail("could not allocate memory pool"); + break; + } + if (verto_connect(&sock, pool) != SWITCH_STATUS_SUCCESS) { + fst_fail("could not connect to verto listener"); + break; + } + + req_len = switch_snprintf(req, sizeof(req), + "POST / HTTP/1.1\r\n" + "Host: " VERTO_TEST_HOST "\r\n" + "Content-Type: application/x-www-form-urlencoded\r\n" + "Content-Length: 9999999999\r\n" + "\r\n"); + + if (send_all(sock, req, req_len) != SWITCH_STATUS_SUCCESS) { + fst_fail("could not send request"); + break; + } + + read_status_line(sock, resp, sizeof(resp)); + fst_check_string_starts_with(resp, "HTTP/1.1 413"); + } while (0); + + if (sock) switch_socket_close(sock); + if (pool) switch_core_destroy_memory_pool(&pool); + } + FST_TEST_END() + } + FST_SUITE_END() +} +FST_CORE_END()