mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-06-05 23:18:52 +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;
|
return new_uri;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
static GstUri *
|
||||||
* gst_uri_from_string:
|
_gst_uri_from_string_internal (const gchar * uri, gboolean unescape)
|
||||||
* @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)
|
|
||||||
{
|
{
|
||||||
const gchar *orig_uri = uri;
|
const gchar *orig_uri = uri;
|
||||||
GstUri *uri_obj;
|
GstUri *uri_obj;
|
||||||
|
@ -1545,7 +1534,10 @@ gst_uri_from_string (const gchar * uri)
|
||||||
/* find end of userinfo */
|
/* find end of userinfo */
|
||||||
eoui = strchr (uri, '@');
|
eoui = strchr (uri, '@');
|
||||||
if (eoui != NULL && eoui < eoa) {
|
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;
|
uri = eoui + 1;
|
||||||
}
|
}
|
||||||
/* find end of host */
|
/* find end of host */
|
||||||
|
@ -1565,8 +1557,10 @@ gst_uri_from_string (const gchar * uri)
|
||||||
reoh = eoh = eoa;
|
reoh = eoh = eoa;
|
||||||
}
|
}
|
||||||
/* don't capture empty host strings */
|
/* 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_obj->host = g_uri_unescape_segment (uri, eoh, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
uri = reoh;
|
uri = reoh;
|
||||||
if (uri < eoa) {
|
if (uri < eoa) {
|
||||||
|
@ -1620,13 +1614,61 @@ gst_uri_from_string (const gchar * uri)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (uri != NULL && uri[0] == '#') {
|
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;
|
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:
|
* gst_uri_from_string_with_base:
|
||||||
* @base: (transfer none)(nullable): The base URI to join the new URI with.
|
* @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
|
GST_API
|
||||||
GstUri * gst_uri_from_string (const gchar * uri) G_GNUC_MALLOC;
|
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
|
GST_API
|
||||||
GstUri * gst_uri_from_string_with_base (GstUri * base,
|
GstUri * gst_uri_from_string_with_base (GstUri * base,
|
||||||
const gchar * uri) G_GNUC_MALLOC;
|
const gchar * uri) G_GNUC_MALLOC;
|
||||||
|
|
|
@ -336,6 +336,21 @@ struct URITest
|
||||||
{"scheme", "us:er:pa:ss", "hostname", 123, "/path", {{"query", NULL}, \
|
{"scheme", "us:er:pa:ss", "hostname", 123, "/path", {{"query", NULL}, \
|
||||||
{NULL, NULL}}, "frag#ment"}},
|
{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[] = {
|
static const struct URITest tests[] = {
|
||||||
COMMON_URI_TESTS UNESCAPED_URI_TESTS
|
COMMON_URI_TESTS UNESCAPED_URI_TESTS
|
||||||
|
@ -400,6 +415,63 @@ GST_START_TEST (test_url_parsing)
|
||||||
|
|
||||||
GST_END_TEST;
|
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[] = {
|
static const struct URITest url_presenting_tests[] = {
|
||||||
/* check all URI elements present */
|
/* check all URI elements present */
|
||||||
{.uri = {"scheme", "user:pass", "host", 1234, "/path/to/dir",
|
{.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);
|
tcase_add_test (tc_chain, test_win32_uri);
|
||||||
#endif
|
#endif
|
||||||
tcase_add_test (tc_chain, test_url_parsing);
|
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_presenting);
|
||||||
tcase_add_test (tc_chain, test_url_normalization);
|
tcase_add_test (tc_chain, test_url_normalization);
|
||||||
tcase_add_test (tc_chain, test_url_joining);
|
tcase_add_test (tc_chain, test_url_joining);
|
||||||
|
|
Loading…
Reference in a new issue