mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-01-13 02:45:35 +00:00
gsturi: Add new API for storing unmodified userinfo / fragment
New API: gst_uri_from_string_escaped() Identical to gst_uri_from_string() except that the userinfo and fragment components of the URI will not be unescaped while parsing. This is needed for correctly parsing usernames or passwords with `:` in them such as reported at: https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/-/issues/831 Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/583>
This commit is contained in:
parent
5f4723d842
commit
5195ad9126
3 changed files with 134 additions and 16 deletions
74
gst/gsturi.c
74
gst/gsturi.c
|
@ -1497,19 +1497,8 @@ gst_uri_new_with_base (GstUri * base, const gchar * scheme,
|
|||
return new_uri;
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_uri_from_string:
|
||||
* @uri: The URI string to parse.
|
||||
*
|
||||
* Parses a URI string into a new #GstUri object. Will return NULL if the URI
|
||||
* cannot be parsed.
|
||||
*
|
||||
* Returns: (transfer full) (nullable): A new #GstUri object, or NULL.
|
||||
*
|
||||
* Since: 1.6
|
||||
*/
|
||||
GstUri *
|
||||
gst_uri_from_string (const gchar * uri)
|
||||
static GstUri *
|
||||
_gst_uri_from_string_internal (const gchar * uri, gboolean unescape)
|
||||
{
|
||||
const gchar *orig_uri = uri;
|
||||
GstUri *uri_obj;
|
||||
|
@ -1545,7 +1534,10 @@ gst_uri_from_string (const gchar * uri)
|
|||
/* find end of userinfo */
|
||||
eoui = strchr (uri, '@');
|
||||
if (eoui != NULL && eoui < eoa) {
|
||||
uri_obj->userinfo = g_uri_unescape_segment (uri, eoui, NULL);
|
||||
if (unescape)
|
||||
uri_obj->userinfo = g_uri_unescape_segment (uri, eoui, NULL);
|
||||
else
|
||||
uri_obj->userinfo = g_strndup (uri, eoui - uri);
|
||||
uri = eoui + 1;
|
||||
}
|
||||
/* find end of host */
|
||||
|
@ -1565,8 +1557,10 @@ gst_uri_from_string (const gchar * uri)
|
|||
reoh = eoh = eoa;
|
||||
}
|
||||
/* don't capture empty host strings */
|
||||
if (eoh != uri)
|
||||
if (eoh != uri) {
|
||||
/* always unescape hostname */
|
||||
uri_obj->host = g_uri_unescape_segment (uri, eoh, NULL);
|
||||
}
|
||||
|
||||
uri = reoh;
|
||||
if (uri < eoa) {
|
||||
|
@ -1620,13 +1614,61 @@ gst_uri_from_string (const gchar * uri)
|
|||
}
|
||||
}
|
||||
if (uri != NULL && uri[0] == '#') {
|
||||
uri_obj->fragment = g_uri_unescape_string (uri + 1, NULL);
|
||||
if (unescape)
|
||||
uri_obj->fragment = g_uri_unescape_string (uri + 1, NULL);
|
||||
else
|
||||
uri_obj->fragment = g_strdup (uri + 1);
|
||||
}
|
||||
}
|
||||
|
||||
return uri_obj;
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_uri_from_string:
|
||||
* @uri: The URI string to parse.
|
||||
*
|
||||
* Parses a URI string into a new #GstUri object. Will return NULL if the URI
|
||||
* cannot be parsed.
|
||||
*
|
||||
* Returns: (transfer full) (nullable): A new #GstUri object, or NULL.
|
||||
*
|
||||
* Since: 1.6
|
||||
*/
|
||||
GstUri *
|
||||
gst_uri_from_string (const gchar * uri)
|
||||
{
|
||||
return _gst_uri_from_string_internal (uri, TRUE);
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_uri_from_string_escaped:
|
||||
* @uri: The URI string to parse.
|
||||
*
|
||||
* Parses a URI string into a new #GstUri object. Will return NULL if the URI
|
||||
* cannot be parsed. This is identical to gst_uri_from_string() except that
|
||||
* the userinfo and fragment components of the URI will not be unescaped while
|
||||
* parsing.
|
||||
*
|
||||
* Use this when you need to extract a username and password from the userinfo
|
||||
* such as https://user:password@example.com since either may contain
|
||||
* a URI-escaped ':' character. gst_uri_from_string() will unescape the entire
|
||||
* userinfo component, which will make it impossible to know which ':'
|
||||
* delineates the username and password.
|
||||
*
|
||||
* The same applies to the fragment component of the URI, such as
|
||||
* https://example.com/path#fragment which may contain a URI-escaped '#'.
|
||||
*
|
||||
* Returns: (transfer full) (nullable): A new #GstUri object, or NULL.
|
||||
*
|
||||
* Since: 1.18
|
||||
*/
|
||||
GstUri *
|
||||
gst_uri_from_string_escaped (const gchar * uri)
|
||||
{
|
||||
return _gst_uri_from_string_internal (uri, FALSE);
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_uri_from_string_with_base:
|
||||
* @base: (transfer none)(nullable): The base URI to join the new URI with.
|
||||
|
|
|
@ -235,6 +235,9 @@ GstUri * gst_uri_new_with_base (GstUri * base,
|
|||
GST_API
|
||||
GstUri * gst_uri_from_string (const gchar * uri) G_GNUC_MALLOC;
|
||||
|
||||
GST_API
|
||||
GstUri * gst_uri_from_string_escaped (const gchar * uri) G_GNUC_MALLOC;
|
||||
|
||||
GST_API
|
||||
GstUri * gst_uri_from_string_with_base (GstUri * base,
|
||||
const gchar * uri) G_GNUC_MALLOC;
|
||||
|
|
|
@ -336,6 +336,21 @@ struct URITest
|
|||
{"scheme", "us:er:pa:ss", "hostname", 123, "/path", {{"query", NULL}, \
|
||||
{NULL, NULL}}, "frag#ment"}},
|
||||
|
||||
#define ESCAPED_URI_TESTS \
|
||||
/* Test cases for gst_uri_from_string_escaped */ \
|
||||
{"scheme://user%20info@hostname", \
|
||||
{"scheme", "user%20info", "hostname", GST_URI_NO_PORT, NULL, {{NULL, \
|
||||
NULL}}, NULL}}, \
|
||||
{"scheme://userinfo@hostname:123/path?query#frag%23ment", \
|
||||
{"scheme", "userinfo", "hostname", 123, "/path", {{"query", NULL}, \
|
||||
{NULL, NULL}}, "frag%23ment"}}, \
|
||||
{"scheme://us%3Aer:pass@hostname", \
|
||||
{"scheme", "us%3Aer:pass", "hostname", GST_URI_NO_PORT, NULL, {{NULL, \
|
||||
NULL}}, NULL}}, \
|
||||
{"scheme://us%3Aer:pa%3Ass@hostname:123/path?query#frag%23ment", \
|
||||
{"scheme", "us%3Aer:pa%3Ass", "hostname", 123, "/path", {{"query", NULL}, \
|
||||
{NULL, NULL}}, "frag%23ment"}},
|
||||
|
||||
|
||||
static const struct URITest tests[] = {
|
||||
COMMON_URI_TESTS UNESCAPED_URI_TESTS
|
||||
|
@ -400,6 +415,63 @@ GST_START_TEST (test_url_parsing)
|
|||
|
||||
GST_END_TEST;
|
||||
|
||||
|
||||
static const struct URITest escaped_tests[] = {
|
||||
COMMON_URI_TESTS ESCAPED_URI_TESTS
|
||||
};
|
||||
|
||||
GST_START_TEST (test_url_parsing_escaped)
|
||||
{
|
||||
GstUri *uri;
|
||||
GList *list;
|
||||
gchar *tmp_str;
|
||||
guint i, j;
|
||||
|
||||
for (i = 0; i < G_N_ELEMENTS (escaped_tests); i++) {
|
||||
GST_DEBUG ("Testing URI '%s'", escaped_tests[i].str);
|
||||
|
||||
uri = gst_uri_from_string_escaped (escaped_tests[i].str);
|
||||
fail_unless (uri != NULL);
|
||||
fail_unless_equals_string (gst_uri_get_scheme (uri),
|
||||
escaped_tests[i].uri.scheme);
|
||||
fail_unless_equals_string (gst_uri_get_userinfo (uri),
|
||||
escaped_tests[i].uri.userinfo);
|
||||
fail_unless_equals_string (gst_uri_get_host (uri),
|
||||
escaped_tests[i].uri.host);
|
||||
fail_unless_equals_int (gst_uri_get_port (uri), escaped_tests[i].uri.port);
|
||||
tmp_str = gst_uri_get_path (uri);
|
||||
fail_unless_equals_string (tmp_str, escaped_tests[i].uri.path);
|
||||
g_free (tmp_str);
|
||||
|
||||
for (j = 0; j < 10; j++) {
|
||||
if (!escaped_tests[i].uri.query[j].key)
|
||||
break;
|
||||
|
||||
if (escaped_tests[i].uri.query[j].value) {
|
||||
fail_unless_equals_string (gst_uri_get_query_value (uri,
|
||||
escaped_tests[i].uri.query[j].key),
|
||||
escaped_tests[i].uri.query[j].value);
|
||||
} else {
|
||||
fail_unless (gst_uri_query_has_key (uri,
|
||||
escaped_tests[i].uri.query[j].key));
|
||||
}
|
||||
}
|
||||
list = gst_uri_get_query_keys (uri);
|
||||
fail_unless_equals_int (j, g_list_length (list));
|
||||
g_list_free (list);
|
||||
gst_uri_unref (uri);
|
||||
}
|
||||
|
||||
for (i = 0; i < G_N_ELEMENTS (unparsable_uri_tests); i++) {
|
||||
GST_DEBUG ("Testing unparsable URI '%s'", unparsable_uri_tests[i]);
|
||||
|
||||
uri = gst_uri_from_string (unparsable_uri_tests[i]);
|
||||
fail_unless (uri == NULL);
|
||||
}
|
||||
}
|
||||
|
||||
GST_END_TEST;
|
||||
|
||||
static const struct URITest url_presenting_tests[] = {
|
||||
/* check all URI elements present */
|
||||
{.uri = {"scheme", "user:pass", "host", 1234, "/path/to/dir",
|
||||
|
@ -1141,6 +1213,7 @@ gst_uri_suite (void)
|
|||
tcase_add_test (tc_chain, test_win32_uri);
|
||||
#endif
|
||||
tcase_add_test (tc_chain, test_url_parsing);
|
||||
tcase_add_test (tc_chain, test_url_parsing_escaped);
|
||||
tcase_add_test (tc_chain, test_url_presenting);
|
||||
tcase_add_test (tc_chain, test_url_normalization);
|
||||
tcase_add_test (tc_chain, test_url_joining);
|
||||
|
|
Loading…
Reference in a new issue