RDKEMW-6898: gdialserver not compatible with Libsoup3 library#203
RDKEMW-6898: gdialserver not compatible with Libsoup3 library#203balav08 wants to merge 7 commits into
Conversation
Reason for change: gdialserver not compatible with Libsoup3 library Updating gssdp to 1.6.3 provides libsoup3 compatibility . Test Procedure: Compiled and Verified Risks: Low Priority: P1 version: minor Signed-off-by: balaji velmurugan <balaji_velmurugan@comcast.com>
There was a problem hiding this comment.
Pull request overview
This PR adds libsoup 3 / GSSDP 1.6 compatibility while preserving a libsoup 2.4 build path for the GDial server.
Changes:
- Splits REST, SSDP, and shield implementations into
server/libsoup/2.4andserver/libsoup/3.0. - Updates CMake to select libsoup/GSSDP versions and corresponding source files.
- Adds libsoup3-specific handling in
gdialservice.cpp.
Reviewed changes
Copilot reviewed 5 out of 8 changed files in this pull request and generated 15 comments.
Show a summary per file
| File | Description |
|---|---|
server/CMakeLists.txt |
Selects libsoup 3 or 2.4 source sets and GSSDP dependencies. |
server/gdialservice.cpp |
Adds libsoup3-compatible callback and URI logging code paths. |
server/libsoup/3.0/gdial-rest.c |
Adds REST server implementation using libsoup3 APIs. |
server/libsoup/3.0/gdial-ssdp.c |
Adds SSDP implementation using libsoup3/GSSDP 1.6 APIs. |
server/libsoup/3.0/gdial-shield.c |
Adds request-throttling shield implementation for libsoup3. |
server/libsoup/2.4/gdial-rest.c |
Adds libsoup2.4 REST implementation in versioned path. |
server/libsoup/2.4/gdial-ssdp.c |
Adds libsoup2.4 SSDP implementation in versioned path. |
server/libsoup/2.4/gdial-shield.c |
Adds libsoup2.4 shield implementation in versioned path. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 7 out of 10 changed files in this pull request and generated 8 comments.
Comments suppressed due to low confidence (4)
server/libsoup/3.0/gdial-rest.c:494
g_uri_escape_string()returns memory allocated by GLib and must be released withg_free(), notfree(). Mixing allocators can corrupt memory on platforms where GLib is not using the system allocator.
char *tmp = g_uri_escape_string(payload, "=&", FALSE);
// note that we later g_free(payload_safe) which doesn't necessarily work with malloc'ed memory (seems to depend on glib version)
payload_safe = g_strdup(tmp);
free(tmp);
server/libsoup/3.0/gdial-rest.c:501
additional_data_url_safeis allocated byg_uri_escape_string(), so it must be released withg_free()rather thanfree(). Using the wrong deallocator risks heap corruption with non-system GLib allocators.
start_error = gdial_app_start(app, payload_safe, query_str_safe, additional_data_url_safe, gdial_rest_server);
if (query_str_safe) g_free(query_str_safe);
if (payload_safe) g_free(payload_safe);
free(additional_data_url_safe);
g_free(additional_data_url);
server/libsoup/3.0/gdial-rest.c:1015
priv->local_soup_instanceis unreffed before the registered app handlers are removed, butgdial_rest_server_registered_apps_clear()uses that same server to callsoup_server_remove_handler(). If this unref drops the last reference, dispose will use a freed SoupServer; the handlers should be removed before releasing the server references.
g_object_unref(priv->soup_instance);
g_object_unref(priv->local_soup_instance);
while (priv->registered_apps) {
priv->registered_apps = gdial_rest_server_registered_apps_clear(object, priv->registered_apps, priv->registered_apps);
server/libsoup/3.0/gdial-rest.c:940
- For a valid POST to the
dial_dataendpoint this branch only verifies the method and then falls through without callinggdial_rest_server_handle_POST_dial_data()or setting the response status/body. As a result,/.../<app>/dial_dataPOST requests from loopback are accepted but the dial data is never cached.
else {
gdial_rest_server_http_return_if_fail(soup_server_message_get_method(msg) == SOUP_METHOD_POST, msg, SOUP_STATUS_NOT_IMPLEMENTED);
| [libsoup_version="2.4"], | ||
| [PKG_CHECK_MODULES([SOUP], [libsoup-3.0], | ||
| [], | ||
| [libsoup_version="3.0"], |
| if LIBSOUP_3_0 | ||
| run_L1Tests_SOURCES += \ | ||
| $(top_srcdir)/server/libsoup/3.0/gdial-rest.c \ | ||
| $(top_srcdir)/server/libsoup/3.0/gdial-shield.c \ | ||
| $(top_srcdir)/server/libsoup/3.0/gdial-ssdp.c |
| pthread_mutex_lock(&ssdpServerEventSync); | ||
| if (ssdp_http_server_) | ||
| { | ||
| soup_server_remove_handler(ssdp_http_server_, "/dd.xml"); |
| gint instance_id = (gint)g_ascii_strtoll(instance, &endptr, 10); | ||
| if (strlen(endptr) == 0) { | ||
| app_by_instance = gdial_app_find_instance_by_instance_id(instance_id); | ||
| g_return_val_if_fail(app == app_by_instance, app); |
| GDIAL_LOGTRACE("Entering ..."); | ||
| g_return_if_fail(active_conns_ != NULL); | ||
| GDIAL_LOGINFO("gdial_shield_term: hash_table_size start= %d", g_hash_table_size(active_conns_)); | ||
| g_hash_table_iter_init(&iter, (GHashTable *)active_conns_); | ||
| while (g_hash_table_iter_next(&iter, &key, &value)) { | ||
| SoupMessage *msg = (SoupMessage *)key; | ||
| server_request_remove_callback(msg); | ||
| } |
| /* | ||
| * Any request only respond to app name that is among registered apps | ||
| */ | ||
| g_signal_emit(gdial_rest_server, gdial_rest_server_signals[SIGNAL_INVALID_URI], 0, "URI containes unregistered app name"); |
| ssdp_http_server_ = ssdp_http_server; | ||
| app_random_uuid = g_strdup(random_uuid); | ||
| gchar *dail_ssdp_handler = g_strdup_printf("/%s/%s", random_uuid,"dd.xml"); | ||
| soup_server_add_handler(ssdp_http_server_, dail_ssdp_handler, ssdp_http_server_callback, NULL, NULL); |
| [PKG_CHECK_MODULES([SOUP], [libsoup-3.0], | ||
| [libsoup_version="3.0"], | ||
| PKG_CHECK_MODULES([SOUP], [libsoup-2.4], |
| $(top_srcdir)/server/plat/gdial-plat-util.c \ | ||
| $(top_srcdir)/server/plat/gdialappcache.cpp \ | ||
| $(top_srcdir)/server/plat/gdial_app_registry.c | ||
|
|
||
| if LIBSOUP_2_4 |
| $(top_srcdir)/server/plat/gdial-plat-util.c \ | ||
| $(top_srcdir)/server/plat/gdialappcache.cpp \ | ||
| $(top_srcdir)/server/plat/gdial_app_registry.c | ||
|
|
||
| if LIBSOUP_2_4 |
| gint instance_id = (gint)g_ascii_strtoll(instance, &endptr, 10); | ||
| if (strlen(endptr) == 0) { | ||
| app_by_instance = gdial_app_find_instance_by_instance_id(instance_id); | ||
| g_return_val_if_fail(app == app_by_instance, app); |
| GHashTableIter iter; | ||
| gpointer key, value; | ||
| GDIAL_LOGTRACE("Entering ..."); | ||
| g_return_if_fail(active_conns_ != NULL); | ||
| GDIAL_LOGINFO("gdial_shield_term: hash_table_size start= %d", g_hash_table_size(active_conns_)); | ||
| g_hash_table_iter_init(&iter, (GHashTable *)active_conns_); | ||
| while (g_hash_table_iter_next(&iter, &key, &value)) { | ||
| SoupMessage *msg = (SoupMessage *)key; | ||
| server_request_remove_callback(msg); | ||
| } |
| pthread_mutex_lock(&ssdpServerEventSync); | ||
| if (ssdp_http_server_) | ||
| { | ||
| soup_server_remove_handler(ssdp_http_server_, "/dd.xml"); |
| g_string_append_printf(rbuf, " <link rel=\"run\" href=\"%s\"/>\r\n", rbuilder->link_href); | ||
| } | ||
| if (rbuilder->additionalData) { | ||
| g_string_append_printf(rbuf, " <additionalData>%s</additionalData>\r\n", ""); |
| char *tmp = g_uri_escape_string(payload, "=&", FALSE); | ||
| // note that we later g_free(payload_safe) which doesn't necessarily work with malloc'ed memory (seems to depend on glib version) | ||
| payload_safe = g_strdup(tmp); | ||
| free(tmp); |
| g_object_unref(priv->soup_instance); | ||
| g_object_unref(priv->local_soup_instance); | ||
| while (priv->registered_apps) { | ||
| priv->registered_apps = gdial_rest_server_registered_apps_clear(object, priv->registered_apps, priv->registered_apps); | ||
| } |
| if (app_random_uuid != NULL) { | ||
| g_free(app_random_uuid); | ||
| app_random_uuid = NULL; | ||
| } |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 7 out of 10 changed files in this pull request and generated 5 comments.
Comments suppressed due to low confidence (9)
tests/L1Tests/Makefile.am:109
- When libsoup-3.0 is selected, this still builds the existing L1 test sources, but those tests use libsoup-2.4-only APIs such as
SoupURI,SoupClientContext, directSoupMessagefields, andsoup_session_queue_message. Selecting the 3.0 implementation here will therefore make the L1 test target fail to compile unless the tests are ported or the libsoup3 path is excluded from this autotools test build.
if LIBSOUP_3_0
run_L1Tests_SOURCES += \
$(top_srcdir)/server/libsoup/3.0/gdial-rest.c \
$(top_srcdir)/server/libsoup/3.0/gdial-shield.c \
$(top_srcdir)/server/libsoup/3.0/gdial-ssdp.c
server/libsoup/3.0/gdial-rest.c:361
- On an instance-id mismatch this returns
appinstead ofNULL, and the callers treat any non-null return as authorization to delete or hide the app. A request for a different numeric instance can therefore pass validation and operate on the app found by name; return a failure value whenapp != app_by_instance.
if (strlen(endptr) == 0) {
app_by_instance = gdial_app_find_instance_by_instance_id(instance_id);
g_return_val_if_fail(app == app_by_instance, app);
server/libsoup/3.0/gdial-rest.c:860
- Skipping an empty path component advances
jwithout checking whether it reached the NULL terminator. For paths with a trailing slash (for example/<route>/<app>/), the next loop iteration dereferenceselements[j]when it is NULL, which can crash the server instead of returning an HTTP error.
if (strlen(elements[j]) == 0) {
j++;
continue;
}
server/libsoup/3.0/gdial-rest.c:465
additional_data_urlremains NULL when a registry disables additional data, but it is still passed tog_uri_escape_string(). That GLib API requires a non-null string, so registering an app withuse_additional_data == FALSEwill emit a critical and pass a NULL/invalid value into app launch instead of simply omitting the additional data URL.
gchar *additional_data_url = NULL;
if (app_registry->use_additional_data) {
additional_data_url = gdial_rest_server_new_additional_data_url(listening_port, app_registry->name, FALSE, app_registry->app_uri );
}
gchar *additional_data_url_safe = g_uri_escape_string(additional_data_url, NULL, FALSE);
server/libsoup/3.0/gdial-rest.c:1160
gdial_app_registry_new()duplicatesapp_nameinternally, so passingg_strdup(app_name)leaks the intermediate copy on every registration. Pass the original string here and let the registry own its internal duplicate.
GDialAppRegistry *app_registry = gdial_app_registry_new (g_strdup(app_name),
server/libsoup/3.0/gdial-ssdp.c:299
- Destroy clears
app_random_uuidbut leavesapp_friendly_name,app_manufacturer_name, andapp_model_nameallocated and still assigned. After a restart, the next SSDP instance can reuse stale override values from the previous run and leak the old strings.
if (app_random_uuid != NULL) {
g_free(app_random_uuid);
app_random_uuid = NULL;
}
server/libsoup/3.0/gdial-rest.c:968
- This fallback differs from the libsoup-2.4 implementation, which returns
SOUP_STATUS_NOT_IMPLEMENTEDfor unsupported methods on an instance URL. The libsoup3 path should preserve the same REST behavior; otherwise clients will get a 404 instead of the expected method-not-supported response only when built with libsoup3.
else {
gdial_rest_server_http_return_if_fail(FALSE, msg, SOUP_STATUS_NOT_FOUND);
}
server/libsoup/3.0/gdial-rest.c:1280
rbuilderis zeroed twice in a row, which is redundant and makes this constructor look copy-pasted. Remove the duplicatememsetto keep the initialization path clear.
GDialServerResponseBuilderGetApp *rbuilder = (GDialServerResponseBuilderGetApp *) malloc(sizeof(*rbuilder));
memset(rbuilder, 0, sizeof(*rbuilder));
memset(rbuilder, 0, sizeof(*rbuilder));
rbuilder->app_name = g_strdup(app_name);
server/libsoup/3.0/gdial-rest.c:941
- For a loopback
POSTto the documented/.../<app>/dial_dataroute, this only verifies the method and then falls through without callinggdial_rest_server_handle_POST_dial_data()or setting a response. The request can appear successful while the dial_data payload is never cached.
else {
gdial_rest_server_http_return_if_fail(soup_server_message_get_method(msg) == SOUP_METHOD_POST, msg, SOUP_STATUS_NOT_IMPLEMENTED);
}
| endif | ||
|
|
||
| if GSSDP_1_6 | ||
| AM_CPPFLAGS += -DHAVE_GSSDP_VERSION_1_6_OR_NEWER |
| pthread_mutex_lock(&ssdpServerEventSync); | ||
| if (ssdp_http_server_) | ||
| { | ||
| soup_server_remove_handler(ssdp_http_server_, "/dd.xml"); |
| GDIAL_LOGTRACE("Entering ..."); | ||
| g_return_if_fail(active_conns_ != NULL); | ||
| GDIAL_LOGINFO("gdial_shield_term: hash_table_size start= %d", g_hash_table_size(active_conns_)); | ||
| g_hash_table_iter_init(&iter, (GHashTable *)active_conns_); | ||
| while (g_hash_table_iter_next(&iter, &key, &value)) { | ||
| SoupMessage *msg = (SoupMessage *)key; | ||
| server_request_remove_callback(msg); | ||
| } |
| /* | ||
| * Any request only respond to app name that is among registered apps | ||
| */ | ||
| g_signal_emit(gdial_rest_server, gdial_rest_server_signals[SIGNAL_INVALID_URI], 0, "URI containes unregistered app name"); |
| * ORIGIN header is not present. | ||
| * 7.10.1 The ORIGIN header MUST match https://${ANY}.youtube.com or package | ||
| */ | ||
| GUri *origin_uri = g_uri_parse(header_origin, G_URI_FLAGS_NONE, NULL); |
Reason for change: gdialserver not compatible with Libsoup3 library Updating gssdp to 1.6.3 provides libsoup3 compatibility .
Test Procedure: Compiled and Verified
Risks: Low
Priority: P1
version: minor