souphttpsrc: Handle non-UTF8 headers and error reasons more gracefully

Especially don't put them into GstStructures in one way or another, just
ignore them or error out cleanly depending on the importance of their
content.
This commit is contained in:
Sebastian Dröge 2016-11-28 12:00:09 +02:00
parent d0f608f60b
commit 37f991f06e

View File

@ -988,6 +988,9 @@ insert_http_header (const gchar * name, const gchar * value, gpointer user_data)
GstStructure *headers = user_data; GstStructure *headers = user_data;
const GValue *gv; const GValue *gv;
if (!g_utf8_validate (name, -1, NULL) || !g_utf8_validate (value, -1, NULL))
return;
gv = gst_structure_get_value (headers, name); gv = gst_structure_get_value (headers, name);
if (gv && GST_VALUE_HOLDS_ARRAY (gv)) { if (gv && GST_VALUE_HOLDS_ARRAY (gv)) {
GValue v = G_VALUE_INIT; GValue v = G_VALUE_INIT;
@ -1035,13 +1038,30 @@ gst_soup_http_src_got_headers (GstSoupHTTPSrc * src, SoupMessage * msg)
return; return;
if (src->automatic_redirect && SOUP_STATUS_IS_REDIRECTION (msg->status_code)) { if (src->automatic_redirect && SOUP_STATUS_IS_REDIRECTION (msg->status_code)) {
src->redirection_uri = g_strdup (soup_message_headers_get_one const gchar *location;
(msg->response_headers, "Location"));
src->redirection_permanent = location = soup_message_headers_get_one (msg->response_headers, "Location");
(msg->status_code == SOUP_STATUS_MOVED_PERMANENTLY);
GST_DEBUG_OBJECT (src, "%u redirect to \"%s\" (permanent %d)", if (location) {
msg->status_code, src->redirection_uri, src->redirection_permanent); if (!g_utf8_validate (location, -1, NULL)) {
return; GST_ELEMENT_ERROR_WITH_DETAILS (src, RESOURCE, SEEK,
(_("Corrupted HTTP response.")),
("Location header is not valid UTF-8"),
("http-status-code", G_TYPE_UINT, msg->status_code,
"http-redirection-uri", G_TYPE_STRING,
GST_STR_NULL (src->redirection_uri), NULL));
src->ret = GST_FLOW_ERROR;
return;
}
src->redirection_uri = g_strdup (location);
src->redirection_permanent =
(msg->status_code == SOUP_STATUS_MOVED_PERMANENTLY);
GST_DEBUG_OBJECT (src, "%u redirect to \"%s\" (permanent %d)",
msg->status_code, src->redirection_uri, src->redirection_permanent);
return;
}
} }
if (msg->status_code == SOUP_STATUS_UNAUTHORIZED) { if (msg->status_code == SOUP_STATUS_UNAUTHORIZED) {
@ -1110,46 +1130,70 @@ gst_soup_http_src_got_headers (GstSoupHTTPSrc * src, SoupMessage * msg)
if ((value = if ((value =
soup_message_headers_get_one (msg->response_headers, soup_message_headers_get_one (msg->response_headers,
"icy-metaint")) != NULL) { "icy-metaint")) != NULL) {
gint icy_metaint = atoi (value); gint icy_metaint;
GST_DEBUG_OBJECT (src, "icy-metaint: %s (parsed: %d)", value, icy_metaint); if (g_utf8_validate (value, -1, NULL)) {
if (icy_metaint > 0) { icy_metaint = atoi (value);
if (src->src_caps)
gst_caps_unref (src->src_caps);
src->src_caps = gst_caps_new_simple ("application/x-icy", GST_DEBUG_OBJECT (src, "icy-metaint: %s (parsed: %d)", value,
"metadata-interval", G_TYPE_INT, icy_metaint, NULL); icy_metaint);
if (icy_metaint > 0) {
if (src->src_caps)
gst_caps_unref (src->src_caps);
gst_base_src_set_caps (GST_BASE_SRC (src), src->src_caps); src->src_caps = gst_caps_new_simple ("application/x-icy",
"metadata-interval", G_TYPE_INT, icy_metaint, NULL);
gst_base_src_set_caps (GST_BASE_SRC (src), src->src_caps);
}
} }
} }
if ((value = if ((value =
soup_message_headers_get_content_type (msg->response_headers, soup_message_headers_get_content_type (msg->response_headers,
&params)) != NULL) { &params)) != NULL) {
GST_DEBUG_OBJECT (src, "Content-Type: %s", value); if (!g_utf8_validate (value, -1, NULL)) {
if (g_ascii_strcasecmp (value, "audio/L16") == 0) { GST_WARNING_OBJECT (src, "Content-Type is invalid UTF-8");
} else if (g_ascii_strcasecmp (value, "audio/L16") == 0) {
gint channels = 2; gint channels = 2;
gint rate = 44100; gint rate = 44100;
char *param; char *param;
if (src->src_caps) GST_DEBUG_OBJECT (src, "Content-Type: %s", value);
if (src->src_caps) {
gst_caps_unref (src->src_caps); gst_caps_unref (src->src_caps);
src->src_caps = NULL;
}
param = g_hash_table_lookup (params, "channels"); param = g_hash_table_lookup (params, "channels");
if (param != NULL) if (param != NULL) {
channels = atol (param); guint64 val = g_ascii_strtoull (param, NULL, 10);
if (val < 64)
channels = val;
else
channels = 0;
}
param = g_hash_table_lookup (params, "rate"); param = g_hash_table_lookup (params, "rate");
if (param != NULL) if (param != NULL) {
rate = atol (param); guint64 val = g_ascii_strtoull (param, NULL, 10);
if (val < G_MAXINT)
rate = val;
else
rate = 0;
}
src->src_caps = gst_caps_new_simple ("audio/x-unaligned-raw", if (rate > 0 && channels > 0) {
"format", G_TYPE_STRING, "S16BE", src->src_caps = gst_caps_new_simple ("audio/x-unaligned-raw",
"layout", G_TYPE_STRING, "interleaved", "format", G_TYPE_STRING, "S16BE",
"channels", G_TYPE_INT, channels, "rate", G_TYPE_INT, rate, NULL); "layout", G_TYPE_STRING, "interleaved",
"channels", G_TYPE_INT, channels, "rate", G_TYPE_INT, rate, NULL);
gst_base_src_set_caps (GST_BASE_SRC (src), src->src_caps); gst_base_src_set_caps (GST_BASE_SRC (src), src->src_caps);
}
} else { } else {
GST_DEBUG_OBJECT (src, "Content-Type: %s", value);
/* Set the Content-Type field on the caps */ /* Set the Content-Type field on the caps */
if (src->src_caps) { if (src->src_caps) {
src->src_caps = gst_caps_make_writable (src->src_caps); src->src_caps = gst_caps_make_writable (src->src_caps);
@ -1166,30 +1210,36 @@ gst_soup_http_src_got_headers (GstSoupHTTPSrc * src, SoupMessage * msg)
if ((value = if ((value =
soup_message_headers_get_one (msg->response_headers, soup_message_headers_get_one (msg->response_headers,
"icy-name")) != NULL) { "icy-name")) != NULL) {
g_free (src->iradio_name); if (g_utf8_validate (value, -1, NULL)) {
src->iradio_name = gst_soup_http_src_unicodify (value); g_free (src->iradio_name);
if (src->iradio_name) { src->iradio_name = gst_soup_http_src_unicodify (value);
gst_tag_list_add (tag_list, GST_TAG_MERGE_REPLACE, GST_TAG_ORGANIZATION, if (src->iradio_name) {
src->iradio_name, NULL); gst_tag_list_add (tag_list, GST_TAG_MERGE_REPLACE, GST_TAG_ORGANIZATION,
src->iradio_name, NULL);
}
} }
} }
if ((value = if ((value =
soup_message_headers_get_one (msg->response_headers, soup_message_headers_get_one (msg->response_headers,
"icy-genre")) != NULL) { "icy-genre")) != NULL) {
g_free (src->iradio_genre); if (g_utf8_validate (value, -1, NULL)) {
src->iradio_genre = gst_soup_http_src_unicodify (value); g_free (src->iradio_genre);
if (src->iradio_genre) { src->iradio_genre = gst_soup_http_src_unicodify (value);
gst_tag_list_add (tag_list, GST_TAG_MERGE_REPLACE, GST_TAG_GENRE, if (src->iradio_genre) {
src->iradio_genre, NULL); gst_tag_list_add (tag_list, GST_TAG_MERGE_REPLACE, GST_TAG_GENRE,
src->iradio_genre, NULL);
}
} }
} }
if ((value = soup_message_headers_get_one (msg->response_headers, "icy-url")) if ((value = soup_message_headers_get_one (msg->response_headers, "icy-url"))
!= NULL) { != NULL) {
g_free (src->iradio_url); if (g_utf8_validate (value, -1, NULL)) {
src->iradio_url = gst_soup_http_src_unicodify (value); g_free (src->iradio_url);
if (src->iradio_url) { src->iradio_url = gst_soup_http_src_unicodify (value);
gst_tag_list_add (tag_list, GST_TAG_MERGE_REPLACE, GST_TAG_LOCATION, if (src->iradio_url) {
src->iradio_url, NULL); gst_tag_list_add (tag_list, GST_TAG_MERGE_REPLACE, GST_TAG_LOCATION,
src->iradio_url, NULL);
}
} }
} }
if (!gst_tag_list_is_empty (tag_list)) { if (!gst_tag_list_is_empty (tag_list)) {
@ -1298,6 +1348,14 @@ gst_soup_http_src_parse_status (SoupMessage * msg, GstSoupHTTPSrc * src)
} else if (SOUP_STATUS_IS_CLIENT_ERROR (msg->status_code) || } else if (SOUP_STATUS_IS_CLIENT_ERROR (msg->status_code) ||
SOUP_STATUS_IS_REDIRECTION (msg->status_code) || SOUP_STATUS_IS_REDIRECTION (msg->status_code) ||
SOUP_STATUS_IS_SERVER_ERROR (msg->status_code)) { SOUP_STATUS_IS_SERVER_ERROR (msg->status_code)) {
const gchar *reason_phrase;
reason_phrase = msg->reason_phrase;
if (reason_phrase && !g_utf8_validate (reason_phrase, -1, NULL)) {
GST_ERROR_OBJECT (src, "Invalid UTF-8 in reason");
reason_phrase = "(invalid)";
}
/* Report HTTP error. */ /* Report HTTP error. */
/* when content_size is unknown and we have just finished receiving /* when content_size is unknown and we have just finished receiving
@ -1316,8 +1374,8 @@ gst_soup_http_src_parse_status (SoupMessage * msg, GstSoupHTTPSrc * src)
*/ */
if (msg->status_code == SOUP_STATUS_NOT_FOUND) { if (msg->status_code == SOUP_STATUS_NOT_FOUND) {
GST_ELEMENT_ERROR_WITH_DETAILS (src, RESOURCE, NOT_FOUND, GST_ELEMENT_ERROR_WITH_DETAILS (src, RESOURCE, NOT_FOUND,
("%s", msg->reason_phrase), ("%s", reason_phrase),
("%s (%d), URL: %s, Redirect to: %s", msg->reason_phrase, ("%s (%d), URL: %s, Redirect to: %s", reason_phrase,
msg->status_code, src->location, msg->status_code, src->location,
GST_STR_NULL (src->redirection_uri)), GST_STR_NULL (src->redirection_uri)),
("http-status-code", G_TYPE_UINT, msg->status_code, ("http-status-code", G_TYPE_UINT, msg->status_code,
@ -1328,15 +1386,15 @@ gst_soup_http_src_parse_status (SoupMessage * msg, GstSoupHTTPSrc * src)
|| msg->status_code == SOUP_STATUS_FORBIDDEN || msg->status_code == SOUP_STATUS_FORBIDDEN
|| msg->status_code == SOUP_STATUS_PROXY_AUTHENTICATION_REQUIRED) { || msg->status_code == SOUP_STATUS_PROXY_AUTHENTICATION_REQUIRED) {
GST_ELEMENT_ERROR_WITH_DETAILS (src, RESOURCE, NOT_AUTHORIZED, ("%s", GST_ELEMENT_ERROR_WITH_DETAILS (src, RESOURCE, NOT_AUTHORIZED, ("%s",
msg->reason_phrase), ("%s (%d), URL: %s, Redirect to: %s", reason_phrase), ("%s (%d), URL: %s, Redirect to: %s",
msg->reason_phrase, msg->status_code, src->location, reason_phrase, msg->status_code, src->location,
GST_STR_NULL (src->redirection_uri)), ("http-status-code", GST_STR_NULL (src->redirection_uri)), ("http-status-code",
G_TYPE_UINT, msg->status_code, "http-redirect-uri", G_TYPE_STRING, G_TYPE_UINT, msg->status_code, "http-redirect-uri", G_TYPE_STRING,
GST_STR_NULL (src->redirection_uri), NULL)); GST_STR_NULL (src->redirection_uri), NULL));
} else { } else {
GST_ELEMENT_ERROR_WITH_DETAILS (src, RESOURCE, OPEN_READ, GST_ELEMENT_ERROR_WITH_DETAILS (src, RESOURCE, OPEN_READ,
("%s", msg->reason_phrase), ("%s", reason_phrase),
("%s (%d), URL: %s, Redirect to: %s", msg->reason_phrase, ("%s (%d), URL: %s, Redirect to: %s", reason_phrase,
msg->status_code, src->location, msg->status_code, src->location,
GST_STR_NULL (src->redirection_uri)), GST_STR_NULL (src->redirection_uri)),
("http-status-code", G_TYPE_UINT, msg->status_code, ("http-status-code", G_TYPE_UINT, msg->status_code,