diff --git a/CHANGELOG.md b/CHANGELOG.md index b502ad420..993e8e277 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -32,7 +32,7 @@ SPDX-License-Identifier: GPL-3.0-or-later - api: fix parsing of date/times with timezone offset in function util_parse_time - irc: fix warning on creation of irc.msgbuffer option when the server name contains upper case letters ([#2281](https://github.com/weechat/weechat/issues/2281)) - relay/api: fix crash when an invalid HTTP request is received from a client -- relay/api: return an error 400 when URL parameter "colors" has an invalid value +- relay/api: return an error 400 when URL parameters "colors", "nicks", "lines" and "lines_free" have an invalid value ## Version 4.7.1 (2025-08-16) diff --git a/src/plugins/relay/api/relay-api-protocol.c b/src/plugins/relay/api/relay-api-protocol.c index 9184cc588..38428f178 100644 --- a/src/plugins/relay/api/relay-api-protocol.c +++ b/src/plugins/relay/api/relay-api-protocol.c @@ -579,7 +579,13 @@ RELAY_API_PROTOCOL_CALLBACK(buffers) } } - nicks = relay_http_get_param_boolean (client->http_req, "nicks", 0); + if (!relay_http_get_param_boolean (client->http_req, "nicks", 0, &nicks)) + { + relay_api_msg_send_error_json (client, RELAY_HTTP_400_BAD_REQUEST, NULL, + "Invalid parameter \"%s\"", + "nicks"); + return RELAY_API_PROTOCOL_RC_OK; + } colors = RELAY_API_COLORS_ANSI; ptr_colors = weechat_hashtable_get (client->http_req->params, "colors"); if (ptr_colors) @@ -623,7 +629,16 @@ RELAY_API_PROTOCOL_CALLBACK(buffers) } else { - lines = relay_http_get_param_long (client->http_req, "lines", LONG_MAX); + if (!relay_http_get_param_long (client->http_req, "lines", LONG_MAX, &lines)) + { + relay_api_msg_send_error_json ( + client, + RELAY_HTTP_400_BAD_REQUEST, + NULL, + "Invalid query string parameter \"%s\"", + "lines"); + return RELAY_API_PROTOCOL_RC_OK; + } json = relay_api_msg_lines_to_json (ptr_buffer, lines, colors); if (json) { @@ -655,10 +670,29 @@ RELAY_API_PROTOCOL_CALLBACK(buffers) } else { - lines = relay_http_get_param_long (client->http_req, "lines", 0L); - lines_free = relay_http_get_param_long (client->http_req, - "lines_free", - (lines == 0) ? 0 : LONG_MAX); + if (!relay_http_get_param_long (client->http_req, "lines", 0L, &lines)) + { + relay_api_msg_send_error_json ( + client, + RELAY_HTTP_400_BAD_REQUEST, + NULL, + "Invalid query string parameter \"%s\"", + "lines"); + return RELAY_API_PROTOCOL_RC_OK; + } + if (!relay_http_get_param_long (client->http_req, + "lines_free", + (lines == 0) ? 0 : LONG_MAX, + &lines_free)) + { + relay_api_msg_send_error_json ( + client, + RELAY_HTTP_400_BAD_REQUEST, + NULL, + "Invalid query string parameter \"%s\"", + "lines_free"); + return RELAY_API_PROTOCOL_RC_OK; + } if (ptr_buffer) { json = relay_api_msg_buffer_to_json (ptr_buffer, lines, lines_free, diff --git a/src/plugins/relay/relay-http.c b/src/plugins/relay/relay-http.c index bc2d68a8b..711a81087 100644 --- a/src/plugins/relay/relay-http.c +++ b/src/plugins/relay/relay-http.c @@ -170,45 +170,65 @@ relay_http_url_decode (const char *url) } /* - * Returns value of an URL parameter as boolean (0 or 1), using a default value - * if the parameter is not set. + * Reads value of an URL parameter as boolean (0 or 1) into *value. + * If the parameter is not in URL, the default value is used. + * + * Returns: + * 1: OK, *value is set + * 0: error (URL parameter has invalid format) */ int relay_http_get_param_boolean (struct t_relay_http_request *request, - const char *name, int default_value) + const char *name, int default_value, + int *value) { const char *ptr_value; - ptr_value = weechat_hashtable_get (request->params, name); - if (!ptr_value) - return default_value; + if (!value) + return 0; - return weechat_config_string_to_boolean (ptr_value); + ptr_value = weechat_hashtable_get (request->params, name); + *value = (ptr_value) ? + weechat_config_string_to_boolean (ptr_value) : default_value; + + return 1; } /* - * Returns value of an URL parameter as long, using a default value if the - * parameter is not set or if it's not a valid long integer. + * Reads value of an URL parameter as long into *value. + * If the parameter is not in URL, the default value is used. + * + * Returns: + * 1: OK, *value is set + * 0: error (URL parameter has invalid format) */ -long +int relay_http_get_param_long (struct t_relay_http_request *request, - const char *name, long default_value) + const char *name, long default_value, + long *value) { const char *ptr_value; char *error; long number; + if (!value) + return 0; + ptr_value = weechat_hashtable_get (request->params, name); - if (!ptr_value) - return default_value; - - number = strtol (ptr_value, &error, 10); - if (error && !error[0]) - return number; - - return default_value; + if (ptr_value) + { + number = strtol (ptr_value, &error, 10); + if (!error || error[0]) + return 0; + *value = number; + } + else + { + *value = default_value; + } + return 1; } /* diff --git a/src/plugins/relay/relay-http.h b/src/plugins/relay/relay-http.h index 17b70ef20..4bb8f0a0d 100644 --- a/src/plugins/relay/relay-http.h +++ b/src/plugins/relay/relay-http.h @@ -94,9 +94,11 @@ struct t_relay_http_response extern void relay_http_request_reinit (struct t_relay_http_request *request); extern struct t_relay_http_request *relay_http_request_alloc (void); extern int relay_http_get_param_boolean (struct t_relay_http_request *request, - const char *name, int default_value); -extern long relay_http_get_param_long (struct t_relay_http_request *request, - const char *name, long default_value); + const char *name, int default_value, + int *value); +extern int relay_http_get_param_long (struct t_relay_http_request *request, + const char *name, long default_value, + long *value); extern int relay_http_parse_method_path (struct t_relay_http_request *request, const char *method_path); extern int relay_http_check_auth (struct t_relay_client *client); diff --git a/tests/unit/plugins/relay/test-relay-http.cpp b/tests/unit/plugins/relay/test-relay-http.cpp index bf0700ee4..e901cc3ea 100644 --- a/tests/unit/plugins/relay/test-relay-http.cpp +++ b/tests/unit/plugins/relay/test-relay-http.cpp @@ -193,18 +193,31 @@ TEST(RelayHttp, UrlDecode) TEST(RelayHttp, GetParamBoolean) { struct t_relay_http_request *request; + int value; request = relay_http_request_alloc (); CHECK(request); relay_http_parse_method_path (request, "GET /api/test?key1=true&key2=1&key3=off"); - LONGS_EQUAL(1, relay_http_get_param_boolean (request, "key1", 0)); - LONGS_EQUAL(1, relay_http_get_param_boolean (request, "key1", 1)); - LONGS_EQUAL(1, relay_http_get_param_boolean (request, "key2", 0)); - LONGS_EQUAL(1, relay_http_get_param_boolean (request, "key2", 1)); - LONGS_EQUAL(0, relay_http_get_param_boolean (request, "key3", 0)); - LONGS_EQUAL(0, relay_http_get_param_boolean (request, "key3", 1)); - LONGS_EQUAL(0, relay_http_get_param_boolean (request, "xxx", 0)); - LONGS_EQUAL(1, relay_http_get_param_boolean (request, "xxx", 1)); + + LONGS_EQUAL(0, relay_http_get_param_boolean (request, "key1", 0, NULL)); + + LONGS_EQUAL(1, relay_http_get_param_boolean (request, "key1", 0, &value)); + LONGS_EQUAL(1, value); + LONGS_EQUAL(1, relay_http_get_param_boolean (request, "key1", 1, &value)); + LONGS_EQUAL(1, value); + LONGS_EQUAL(1, relay_http_get_param_boolean (request, "key2", 0, &value)); + LONGS_EQUAL(1, value); + LONGS_EQUAL(1, relay_http_get_param_boolean (request, "key2", 1, &value)); + LONGS_EQUAL(1, value); + LONGS_EQUAL(1, relay_http_get_param_boolean (request, "key3", 0, &value)); + LONGS_EQUAL(0, value); + LONGS_EQUAL(1, relay_http_get_param_boolean (request, "key3", 1, &value)); + LONGS_EQUAL(0, value); + LONGS_EQUAL(1, relay_http_get_param_boolean (request, "xxx", 0, &value)); + LONGS_EQUAL(0, value); + LONGS_EQUAL(1, relay_http_get_param_boolean (request, "xxx", 1, &value)); + LONGS_EQUAL(1, value); + relay_http_request_free (request); } @@ -216,14 +229,22 @@ TEST(RelayHttp, GetParamBoolean) TEST(RelayHttp, GetParamLong) { struct t_relay_http_request *request; + long value; request = relay_http_request_alloc (); CHECK(request); relay_http_parse_method_path (request, "GET /api/test?key1=123&key2=-4&key3=abc"); - LONGS_EQUAL(123, relay_http_get_param_long (request, "key1", 8)); - LONGS_EQUAL(-4, relay_http_get_param_long (request, "key2", 8)); - LONGS_EQUAL(8, relay_http_get_param_long (request, "key3", 8)); - LONGS_EQUAL(99, relay_http_get_param_long (request, "xxx", 99)); + + LONGS_EQUAL(0, relay_http_get_param_long (request, "key1", 0, NULL)); + LONGS_EQUAL(0, relay_http_get_param_long (request, "key3", 8, &value)); + + LONGS_EQUAL(1, relay_http_get_param_long (request, "key1", 8, &value)); + LONGS_EQUAL(123, value); + LONGS_EQUAL(1, relay_http_get_param_long (request, "key2", 8, &value)); + LONGS_EQUAL(-4, value); + LONGS_EQUAL(1, relay_http_get_param_long (request, "xxx", 99, &value)); + LONGS_EQUAL(99, value); + relay_http_request_free (request); }