diff --git a/subprojects/gstreamer/gst/gsturi.c b/subprojects/gstreamer/gst/gsturi.c index a3ca53f3f8..8c88b3e664 100644 --- a/subprojects/gstreamer/gst/gsturi.c +++ b/subprojects/gstreamer/gst/gsturi.c @@ -1994,10 +1994,13 @@ gst_uri_make_writable (GstUri * uri) } /** - * gst_uri_to_string: - * @uri: This #GstUri to convert to a string. + * gst_uri_to_string_with_keys: + * @uri: (nullable): This #GstUri to convert to a string. + * @keys: (transfer none) (nullable) (element-type utf8): A GList containing + * the query argument key strings. * - * Convert the URI to a string. + * Convert the URI to a string, with the query arguments in a specific order. + * Only the keys in the @keys list will be added to the resulting string. * * Returns the URI as held in this object as a #gchar* nul-terminated string. * The caller should g_free() the string once they are finished with it. @@ -2005,10 +2008,10 @@ gst_uri_make_writable (GstUri * uri) * * Returns: (transfer full): The string version of the URI. * - * Since: 1.6 + * Since: 1.24 */ gchar * -gst_uri_to_string (const GstUri * uri) +gst_uri_to_string_with_keys (const GstUri * uri, const GList * keys) { GString *uri_str; gchar *escaped; @@ -2052,10 +2055,15 @@ gst_uri_to_string (const GstUri * uri) } if (uri->query) { - g_string_append (uri_str, "?"); - escaped = gst_uri_get_query_string (uri); - g_string_append (uri_str, escaped); - g_free (escaped); + if (keys != NULL) + escaped = gst_uri_get_query_string_ordered (uri, keys); + else + escaped = gst_uri_get_query_string (uri); + if (escaped) { + g_string_append (uri_str, "?"); + g_string_append (uri_str, escaped); + g_free (escaped); + } } if (uri->fragment != NULL) { @@ -2067,6 +2075,26 @@ gst_uri_to_string (const GstUri * uri) return g_string_free (uri_str, FALSE); } +/** + * gst_uri_to_string: + * @uri: This #GstUri to convert to a string. + * + * Convert the URI to a string. + * + * Returns the URI as held in this object as a #gchar* nul-terminated string. + * The caller should g_free() the string once they are finished with it. + * The string is put together as described in RFC 3986. + * + * Returns: (transfer full): The string version of the URI. + * + * Since: 1.6 + */ +gchar * +gst_uri_to_string (const GstUri * uri) +{ + return gst_uri_to_string_with_keys (uri, NULL); +} + /** * gst_uri_is_normalized: * @uri: (nullable): The #GstUri to test to see if it is normalized. @@ -2636,6 +2664,67 @@ gst_uri_set_query_string (GstUri * uri, const gchar * query) return TRUE; } +/** + * gst_uri_get_query_string_ordered: + * @uri: (nullable): The #GstUri to get the query string from. + * @keys: (transfer none) (nullable) (element-type utf8): A GList containing the + * query argument key strings. + * + * Get a percent encoded URI query string from the @uri, with query parameters + * in the order provided by the @keys list. Only parameter keys in the list will + * be added to the resulting URI string. This method can be used by retrieving + * the keys with gst_uri_get_query_keys() and then sorting the list, for + * example. + * + * Returns: (transfer full) (nullable): A percent encoded query string. Use + * g_free() when no longer needed. + * + * Since: 1.24 + */ +gchar * +gst_uri_get_query_string_ordered (const GstUri * uri, const GList * keys) +{ + const gchar *sep = ""; + gchar *escaped; + GString *ret = NULL; + const GList *key; + + if (!uri) + return NULL; + g_return_val_if_fail (GST_IS_URI (uri), NULL); + if (!uri->query) + return NULL; + + for (key = keys; key; key = key->next) { + const gchar *query_key = key->data; + const gchar *arg; + + /* Key isn't present, skip */ + if (!g_hash_table_contains (uri->query, query_key)) + continue; + + if (ret == NULL) + ret = g_string_new (NULL); + + /* Append the key */ + g_string_append (ret, sep); + escaped = _gst_uri_escape_http_query_element (query_key); + g_string_append (ret, escaped); + g_free (escaped); + + if ((arg = g_hash_table_lookup (uri->query, query_key))) { + /* Append the argument */ + escaped = _gst_uri_escape_http_query_element (arg); + g_string_append_printf (ret, "=%s", escaped); + g_free (escaped); + } + sep = "&"; + } + + /* If no keys were seen, return NULL string instead of empty string */ + return ret ? g_string_free (ret, FALSE) : NULL; +} + /** * gst_uri_get_query_table: * @uri: (nullable): The #GstUri to get the query table from. diff --git a/subprojects/gstreamer/gst/gsturi.h b/subprojects/gstreamer/gst/gsturi.h index 8c5881bec8..543718d630 100644 --- a/subprojects/gstreamer/gst/gsturi.h +++ b/subprojects/gstreamer/gst/gsturi.h @@ -259,6 +259,9 @@ GstUri * gst_uri_make_writable (GstUri * uri) G_GNUC_WARN_UNUSED_RESULT; GST_API gchar * gst_uri_to_string (const GstUri * uri) G_GNUC_MALLOC; +GST_API +gchar * gst_uri_to_string_with_keys (const GstUri * uri, const GList *keys); + GST_API gboolean gst_uri_is_normalized (const GstUri * uri); @@ -316,6 +319,9 @@ gboolean gst_uri_append_path_segment (GstUri * uri, GST_API gchar * gst_uri_get_query_string (const GstUri * uri); +GST_API +gchar * gst_uri_get_query_string_ordered (const GstUri * uri, const GList *keys); + GST_API gboolean gst_uri_set_query_string (GstUri * uri, const gchar * query); diff --git a/subprojects/gstreamer/tests/check/gst/gsturi.c b/subprojects/gstreamer/tests/check/gst/gsturi.c index 92511b3061..47ebd3686b 100644 --- a/subprojects/gstreamer/tests/check/gst/gsturi.c +++ b/subprojects/gstreamer/tests/check/gst/gsturi.c @@ -1043,6 +1043,55 @@ GST_START_TEST (test_url_get_set) "//example.com/path/to/file/there/segment?key=value&query#fragment"); g_free (tmp_str); + /* query string (full) */ + tmp_str = gst_uri_get_query_string (url); + fail_unless_equals_string (tmp_str, "key=value&query"); + g_free (tmp_str); + + /* query string (single key, no value) */ + tmp_list = g_list_append (NULL, g_strdup ("query")); + tmp_str = gst_uri_get_query_string_ordered (url, tmp_list); + fail_unless_equals_string (tmp_str, "query"); + g_free (tmp_str); + tmp_str = gst_uri_to_string_with_keys (url, tmp_list); + fail_unless_equals_string (tmp_str, + "//example.com/path/to/file/there/segment?query#fragment"); + g_free (tmp_str); + g_list_free_full (tmp_list, g_free); + + /* query string (single key, with value) */ + tmp_list = g_list_append (NULL, g_strdup ("key")); + tmp_str = gst_uri_get_query_string_ordered (url, tmp_list); + fail_unless_equals_string (tmp_str, "key=value"); + g_free (tmp_str); + tmp_str = gst_uri_to_string_with_keys (url, tmp_list); + fail_unless_equals_string (tmp_str, + "//example.com/path/to/file/there/segment?key=value#fragment"); + g_free (tmp_str); + g_list_free_full (tmp_list, g_free); + + /* query string (key not present) */ + tmp_list = g_list_append (NULL, g_strdup ("absent")); + tmp_str = gst_uri_get_query_string_ordered (url, tmp_list); + fail_if (tmp_str != NULL); + tmp_str = gst_uri_to_string_with_keys (url, tmp_list); + fail_unless_equals_string (tmp_str, + "//example.com/path/to/file/there/segment#fragment"); + g_free (tmp_str); + g_list_free_full (tmp_list, g_free); + + /* query string (both keys, inverse order) */ + tmp_list = g_list_append (NULL, g_strdup ("query")); + tmp_list = g_list_append (tmp_list, g_strdup ("key")); + tmp_str = gst_uri_get_query_string_ordered (url, tmp_list); + fail_unless_equals_string (tmp_str, "query&key=value"); + g_free (tmp_str); + tmp_str = gst_uri_to_string_with_keys (url, tmp_list); + fail_unless_equals_string (tmp_str, + "//example.com/path/to/file/there/segment?query&key=value#fragment"); + g_free (tmp_str); + g_list_free_full (tmp_list, g_free); + fail_unless (gst_uri_set_query_value (url, "key", NULL)); tmp_str = gst_uri_to_string (url); fail_unless_equals_string (tmp_str,