mirror of
https://gitlab.freedesktop.org/pulseaudio/pulseaudio.git
synced 2025-11-12 13:30:10 -05:00
message-params: Allow parameter strings to contain escaped curly braces
The patch adds the possibility to escape curly braces within parameter strings and introduces several new functions that can be used for writing parameters. For writing, the structure pa_message_params, which is a wrapper for pa_strbuf has been created. Following new write functions are available: pa_message_params_new() - creates a new pa_message_params structure pa_message_params_free() - frees a pa_message_params structure pa_message_param_to_string_free() - converts a pa_message_param to string and frees the structure pa_message_params_begin_list() - starts a list pa_message_params_end_list() - ends a list pa_message_params_write_string() - writes a string to a pa_message_params structure pa_message_params_write_raw() - writes a raw string to a pa_message_params structure For string parameters that contain curly braces or backslashes, those characters will be escaped when using pa_message_params_write_string(), while write_raw() will put the string into the buffer without any changes. For reading, pa_message_params_read_string() reverts the changes that pa_message_params_write_string() might have introduced. The patch also adds more restrictions on the object path name. Now only alphanumeric characters and one of "_", ".", "-" and "/" are allowed. The path name may not end with a / or contain a double slash. If the user specifies a trailing / when sending a message, it will be silently removed. Part-of: <https://gitlab.freedesktop.org/pulseaudio/pulseaudio/-/merge_requests/51>
This commit is contained in:
parent
4a28b164d1
commit
590fd1ca69
8 changed files with 249 additions and 47 deletions
|
|
@ -29,6 +29,7 @@
|
|||
#include <pulse/rtclock.h>
|
||||
#include <pulse/timeval.h>
|
||||
#include <pulse/xmalloc.h>
|
||||
#include <pulse/message-params.h>
|
||||
|
||||
#include <pulsecore/module.h>
|
||||
#include <pulsecore/core-rtclock.h>
|
||||
|
|
@ -65,25 +66,26 @@ static void core_free(pa_object *o);
|
|||
|
||||
/* Returns a list of handlers. */
|
||||
static char *message_handler_list(pa_core *c) {
|
||||
pa_strbuf *buf;
|
||||
pa_message_params *param;
|
||||
void *state = NULL;
|
||||
struct pa_message_handler *handler;
|
||||
|
||||
buf = pa_strbuf_new();
|
||||
param = pa_message_params_new();
|
||||
|
||||
pa_strbuf_putc(buf, '{');
|
||||
pa_message_params_begin_list(param);
|
||||
PA_HASHMAP_FOREACH(handler, c->message_handlers, state) {
|
||||
pa_strbuf_putc(buf, '{');
|
||||
pa_message_params_begin_list(param);
|
||||
|
||||
pa_strbuf_printf(buf, "{%s} {", handler->object_path);
|
||||
if (handler->description)
|
||||
pa_strbuf_puts(buf, handler->description);
|
||||
/* object_path cannot contain characters that need escaping, therefore
|
||||
* pa_message_params_write_raw() can safely be used here. */
|
||||
pa_message_params_write_raw(param, handler->object_path, true);
|
||||
pa_message_params_write_string(param, handler->description);
|
||||
|
||||
pa_strbuf_puts(buf, "}}");
|
||||
pa_message_params_end_list(param);
|
||||
}
|
||||
pa_strbuf_putc(buf, '}');
|
||||
pa_message_params_end_list(param);
|
||||
|
||||
return pa_strbuf_to_string_free(buf);
|
||||
return pa_message_params_to_string_free(param);
|
||||
}
|
||||
|
||||
static int core_message_handler(const char *object_path, const char *message, char *message_parameters, char **response, void *userdata) {
|
||||
|
|
|
|||
|
|
@ -31,17 +31,36 @@
|
|||
|
||||
#include "message-handler.h"
|
||||
|
||||
/* Check if a string does not contain control characters. Currently these are
|
||||
* only "{" and "}". */
|
||||
static bool string_is_valid(const char *test_string) {
|
||||
/* Check if a path string starts with a / and only contains valid characters.
|
||||
* Also reject double slashes. */
|
||||
static bool object_path_is_valid(const char *test_string) {
|
||||
uint32_t i;
|
||||
|
||||
if (!test_string)
|
||||
return false;
|
||||
|
||||
/* Make sure the string starts with a / */
|
||||
if (test_string[0] != '/')
|
||||
return false;
|
||||
|
||||
for (i = 0; test_string[i]; i++) {
|
||||
if (test_string[i] == '{' ||
|
||||
test_string[i] == '}')
|
||||
return false;
|
||||
|
||||
if ((test_string[i] >= 'a' && test_string[i] <= 'z') ||
|
||||
(test_string[i] >= 'A' && test_string[i] <= 'Z') ||
|
||||
(test_string[i] >= '0' && test_string[i] <= '9') ||
|
||||
test_string[i] == '.' ||
|
||||
test_string[i] == '_' ||
|
||||
test_string[i] == '-' ||
|
||||
(test_string[i] == '/' && test_string[i + 1] != '/'))
|
||||
continue;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Make sure the string does not end with a / */
|
||||
if (test_string[i - 1] == '/')
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -56,13 +75,8 @@ void pa_message_handler_register(pa_core *c, const char *object_path, const char
|
|||
pa_assert(cb);
|
||||
pa_assert(userdata);
|
||||
|
||||
/* Ensure that the object path is not empty and starts with "/". */
|
||||
pa_assert(object_path[0] == '/');
|
||||
|
||||
/* Ensure that object path and description are valid strings */
|
||||
pa_assert(string_is_valid(object_path));
|
||||
if (description)
|
||||
pa_assert(string_is_valid(description));
|
||||
/* Ensure that object path is valid */
|
||||
pa_assert(object_path_is_valid(object_path));
|
||||
|
||||
handler = pa_xnew0(struct pa_message_handler, 1);
|
||||
handler->userdata = userdata;
|
||||
|
|
@ -91,7 +105,7 @@ void pa_message_handler_unregister(pa_core *c, const char *object_path) {
|
|||
int pa_message_handler_send_message(pa_core *c, const char *object_path, const char *message, const char *message_parameters, char **response) {
|
||||
struct pa_message_handler *handler;
|
||||
int ret;
|
||||
char *parameter_copy;
|
||||
char *parameter_copy, *path_copy;
|
||||
|
||||
pa_assert(c);
|
||||
pa_assert(object_path);
|
||||
|
|
@ -100,8 +114,16 @@ int pa_message_handler_send_message(pa_core *c, const char *object_path, const c
|
|||
|
||||
*response = NULL;
|
||||
|
||||
if (!(handler = pa_hashmap_get(c->message_handlers, object_path)))
|
||||
path_copy = pa_xstrdup(object_path);
|
||||
|
||||
/* Remove trailing / from path name if present */
|
||||
if (path_copy[strlen(path_copy) - 1] == '/')
|
||||
path_copy[strlen(path_copy) - 1] = 0;
|
||||
|
||||
if (!(handler = pa_hashmap_get(c->message_handlers, path_copy))) {
|
||||
pa_xfree(path_copy);
|
||||
return -PA_ERR_NOENTITY;
|
||||
}
|
||||
|
||||
parameter_copy = pa_xstrdup(message_parameters);
|
||||
|
||||
|
|
@ -110,6 +132,7 @@ int pa_message_handler_send_message(pa_core *c, const char *object_path, const c
|
|||
ret = handler->callback(handler->object_path, message, parameter_copy, response, handler->userdata);
|
||||
|
||||
pa_xfree(parameter_copy);
|
||||
pa_xfree(path_copy);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
@ -123,11 +146,6 @@ int pa_message_handler_set_description(pa_core *c, const char *object_path, cons
|
|||
if (!(handler = pa_hashmap_get(c->message_handlers, object_path)))
|
||||
return -PA_ERR_NOENTITY;
|
||||
|
||||
if (description) {
|
||||
if (!string_is_valid(description))
|
||||
return -PA_ERR_INVALID;
|
||||
}
|
||||
|
||||
pa_xfree(handler->description);
|
||||
handler->description = pa_xstrdup(description);
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue