mpdparser: validate representation set identifier

It must have no whitespace, and must comply with RFC 1738 when
used to build a URL.

https://bugzilla.gnome.org/show_bug.cgi?id=750852
This commit is contained in:
Vincent Penquerc'h 2015-09-29 16:17:03 +01:00
parent 704d49b9c7
commit b8df6cc316
2 changed files with 105 additions and 5 deletions

View file

@ -33,6 +33,9 @@
#define GST_CAT_DEFAULT gst_dash_demux_debug
/* Property parsing */
static gboolean gst_mpdparser_get_xml_prop_validated_string (xmlNode * a_node,
const gchar * property_name, gchar ** property_value,
gboolean (*validator) (const char *));
static gboolean gst_mpdparser_get_xml_prop_string (xmlNode * a_node,
const gchar * property_name, gchar ** property_value);
static gboolean gst_mpdparser_get_xml_ns_prop_string (xmlNode * a_node,
@ -253,14 +256,20 @@ static const struct GstMpdParserUtcTimingMethod
/* functions to parse node namespaces, content and properties */
static gboolean
gst_mpdparser_get_xml_prop_string (xmlNode * a_node,
const gchar * property_name, gchar ** property_value)
gst_mpdparser_get_xml_prop_validated_string (xmlNode * a_node,
const gchar * property_name, gchar ** property_value,
gboolean (*validate) (const char *))
{
xmlChar *prop_string;
gboolean exists = FALSE;
prop_string = xmlGetProp (a_node, (const xmlChar *) property_name);
if (prop_string) {
if (validate && !(*validate) ((const char *) prop_string)) {
GST_WARNING ("Validation failure: %s", prop_string);
xmlFree (prop_string);
return FALSE;
}
*property_value = (gchar *) prop_string;
exists = TRUE;
GST_LOG (" - %s: %s", property_name, prop_string);
@ -288,6 +297,28 @@ gst_mpdparser_get_xml_ns_prop_string (xmlNode * a_node,
return exists;
}
static gboolean
gst_mpdparser_get_xml_prop_string (xmlNode * a_node,
const gchar * property_name, gchar ** property_value)
{
return gst_mpdparser_get_xml_prop_validated_string (a_node, property_name,
property_value, NULL);
}
static gboolean
gst_mpdparser_validate_no_whitespace (const char *s)
{
return !strpbrk (s, "\r\n\t ");
}
static gboolean
gst_mpdparser_get_xml_prop_string_no_whitespace (xmlNode * a_node,
const gchar * property_name, gchar ** property_value)
{
return gst_mpdparser_get_xml_prop_validated_string (a_node, property_name,
property_value, gst_mpdparser_validate_no_whitespace);
}
static gboolean
gst_mpdparser_get_xml_prop_string_vector_type (xmlNode * a_node,
const gchar * property_name, gchar *** property_value)
@ -1571,7 +1602,8 @@ gst_mpdparser_parse_representation_node (GList ** list, xmlNode * a_node,
*list = g_list_append (*list, new_representation);
GST_LOG ("attributes of Representation node:");
gst_mpdparser_get_xml_prop_string (a_node, "id", &new_representation->id);
gst_mpdparser_get_xml_prop_string_no_whitespace (a_node, "id",
&new_representation->id);
gst_mpdparser_get_xml_prop_unsigned_integer (a_node, "bandwidth", 0,
&new_representation->bandwidth);
gst_mpdparser_get_xml_prop_unsigned_integer (a_node, "qualityRanking", 0,
@ -2868,6 +2900,26 @@ promote_format_to_uint64 (const gchar * format)
return promoted_format;
}
static gboolean
gst_mpdparser_validate_rfc1738_url (const char *s)
{
while (*s) {
if (!strchr
(";:@&=aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ0123456789$-_.+!*'(),%",
*s))
return FALSE;
if (*s == '%') {
/* g_ascii_isdigit returns FALSE for NUL, and || is a short circuiting
operator, so this is safe for strings ending before two hex digits */
if (!g_ascii_isxdigit (s[1]) || !g_ascii_isxdigit (s[2]))
return FALSE;
s += 2;
}
s++;
}
return TRUE;
}
static gchar *
gst_mpdparser_build_URL_from_template (const gchar * url_template,
const gchar * id, guint number, guint bandwidth, guint64 time)
@ -2891,6 +2943,11 @@ gst_mpdparser_build_URL_from_template (const gchar * url_template,
format = default_format;
if (!g_strcmp0 (token, "RepresentationID")) {
if (!gst_mpdparser_validate_rfc1738_url (id)) {
GST_WARNING ("String '%s' has characters invalid in an RFC 1738 URL",
id);
goto invalid_format;
}
tokens[i] = g_strdup_printf ("%s", id);
g_free (token);
last_token_par = TRUE;

View file

@ -2016,7 +2016,7 @@ GST_START_TEST (dash_mpdparser_period_adaptationSet_representation)
" profiles=\"urn:mpeg:dash:profile:isoff-main:2011\">"
" <Period>"
" <AdaptationSet>"
" <Representation id=\"Test Id\""
" <Representation id=\"Test_Id\""
" bandwidth=\"100\""
" qualityRanking=\"200\""
" dependencyId=\"one two three\""
@ -2033,7 +2033,7 @@ GST_START_TEST (dash_mpdparser_period_adaptationSet_representation)
adaptationSet = (GstAdaptationSetNode *) periodNode->AdaptationSets->data;
representation = (GstRepresentationNode *)
adaptationSet->Representations->data;
assert_equals_string (representation->id, "Test Id");
assert_equals_string (representation->id, "Test_Id");
assert_equals_uint64 (representation->bandwidth, 100);
assert_equals_uint64 (representation->qualityRanking, 200);
assert_equals_string (representation->dependencyId[0], "one");
@ -4447,6 +4447,44 @@ GST_START_TEST
GST_END_TEST;
GST_START_TEST (dash_mpdparser_whitespace_strings)
{
fail_unless (gst_mpdparser_validate_no_whitespace ("") == TRUE);
fail_unless (gst_mpdparser_validate_no_whitespace ("/") == TRUE);
fail_unless (gst_mpdparser_validate_no_whitespace (" ") == FALSE);
fail_unless (gst_mpdparser_validate_no_whitespace ("aaaaaaaa ") == FALSE);
fail_unless (gst_mpdparser_validate_no_whitespace ("a\ta") == FALSE);
fail_unless (gst_mpdparser_validate_no_whitespace ("a\ra") == FALSE);
fail_unless (gst_mpdparser_validate_no_whitespace ("a\na") == FALSE);
}
GST_END_TEST;
GST_START_TEST (dash_mpdparser_rfc1738_strings)
{
fail_unless (gst_mpdparser_validate_rfc1738_url ("/") == FALSE);
fail_unless (gst_mpdparser_validate_rfc1738_url (" ") == FALSE);
fail_unless (gst_mpdparser_validate_rfc1738_url ("aaaaaaaa ") == FALSE);
fail_unless (gst_mpdparser_validate_rfc1738_url ("") == TRUE);
fail_unless (gst_mpdparser_validate_rfc1738_url ("a") == TRUE);
fail_unless (gst_mpdparser_validate_rfc1738_url
(";:@&=aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ0123456789$-_.+!*'(),%AA")
== TRUE);
fail_unless (gst_mpdparser_validate_rfc1738_url
(";:@&=aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ0123456789$-_.+!*'(),% ")
== FALSE);
fail_unless (gst_mpdparser_validate_rfc1738_url ("%AA") == TRUE);
fail_unless (gst_mpdparser_validate_rfc1738_url ("%A") == FALSE);
fail_unless (gst_mpdparser_validate_rfc1738_url ("%") == FALSE);
fail_unless (gst_mpdparser_validate_rfc1738_url ("%XA") == FALSE);
fail_unless (gst_mpdparser_validate_rfc1738_url ("%AX") == FALSE);
fail_unless (gst_mpdparser_validate_rfc1738_url ("%XX") == FALSE);
fail_unless (gst_mpdparser_validate_rfc1738_url ("\001") == FALSE);
}
GST_END_TEST;
/*
* create a test suite containing all dash testcases
*/
@ -4457,6 +4495,7 @@ dash_suite (void)
TCase *tc_simpleMPD = tcase_create ("simpleMPD");
TCase *tc_complexMPD = tcase_create ("complexMPD");
TCase *tc_negativeTests = tcase_create ("negativeTests");
TCase *tc_stringTests = tcase_create ("stringTests");
GST_DEBUG_CATEGORY_INIT (gst_dash_demux_debug, "gst_dash_demux_debug", 0,
"mpeg dash tests");
@ -4605,9 +4644,13 @@ dash_suite (void)
tcase_add_test (tc_negativeTests,
dash_mpdparser_wrong_period_duration_inferred_from_next_mediaPresentationDuration);
tcase_add_test (tc_stringTests, dash_mpdparser_whitespace_strings);
tcase_add_test (tc_stringTests, dash_mpdparser_rfc1738_strings);
suite_add_tcase (s, tc_simpleMPD);
suite_add_tcase (s, tc_complexMPD);
suite_add_tcase (s, tc_negativeTests);
suite_add_tcase (s, tc_stringTests);
return s;
}