rtsp: Do not split headers which should not be split.

From RFC 2068 section 4.2: "Multiple message-header fields with the same
field-name may be present in a message if and only if the entire
field-value for that header field is defined as a comma-separated list
[i.e., #(values)]." This means that we should not split other headers which
may contain a comma, e.g., Range and Date.
This commit is contained in:
Peter Kjellerstedt 2009-08-20 14:12:50 +02:00
parent 08d3fe8561
commit 607209f121
3 changed files with 126 additions and 87 deletions

View File

@ -1606,8 +1606,15 @@ parse_line (guint8 * buffer, GstRTSPMessage * msg)
if (*value == ' ') if (*value == ' ')
value++; value++;
/* for headers which may not appear multiple times, and thus may not
* contain multiple values on the same line, we can short-circuit the loop
* below and the entire value results in just one key:value pair*/
if (!gst_rtsp_header_allow_multiple (field))
next_value = value + strlen (value);
else
next_value = value;
/* find the next value, taking special care of quotes and comments */ /* find the next value, taking special care of quotes and comments */
next_value = value;
while (*next_value != '\0') { while (*next_value != '\0') {
if ((quoted || comment != 0) && *next_value == '\\' && if ((quoted || comment != 0) && *next_value == '\\' &&
next_value[1] != '\0') next_value[1] != '\0')

View File

@ -66,6 +66,12 @@ extern int h_errno;
#include <netdb.h> #include <netdb.h>
#endif #endif
struct rtsp_header
{
const gchar *name;
gboolean multiple;
};
static const gchar *rtsp_results[] = { static const gchar *rtsp_results[] = {
"OK", "OK",
/* errors */ /* errors */
@ -106,96 +112,101 @@ static const gchar *rtsp_methods[] = {
NULL NULL
}; };
static const gchar *rtsp_headers[] = { static struct rtsp_header rtsp_headers[] = {
"Accept", /* Accept R opt. entity */ {"Accept", TRUE},
"Accept-Encoding", /* Accept-Encoding R opt. entity */ {"Accept-Encoding", TRUE},
"Accept-Language", /* Accept-Language R opt. all */ {"Accept-Language", TRUE},
"Allow", /* Allow r opt. all */ {"Allow", TRUE},
"Authorization", /* Authorization R opt. all */ {"Authorization", FALSE},
"Bandwidth", /* Bandwidth R opt. all */ {"Bandwidth", FALSE},
"Blocksize", /* Blocksize R opt. all but OPTIONS, TEARDOWN */ {"Blocksize", FALSE},
"Cache-Control", /* Cache-Control g opt. SETUP */ {"Cache-Control", TRUE},
"Conference", /* Conference R opt. SETUP */ {"Conference", FALSE},
"Connection", /* Connection g req. all */ {"Connection", TRUE},
"Content-Base", /* Content-Base e opt. entity */ {"Content-Base", FALSE},
"Content-Encoding", /* Content-Encoding e req. SET_PARAMETER, DESCRIBE, ANNOUNCE */ {"Content-Encoding", TRUE},
"Content-Language", /* Content-Language e req. DESCRIBE, ANNOUNCE */ {"Content-Language", TRUE},
"Content-Length", /* Content-Length e req. SET_PARAMETER, ANNOUNCE, entity */ {"Content-Length", FALSE},
"Content-Location", /* Content-Location e opt. entity */ {"Content-Location", FALSE},
"Content-Type", /* Content-Type e req. SET_PARAMETER, ANNOUNCE, entity */ {"Content-Type", FALSE},
"CSeq", /* CSeq g req. all */ {"CSeq", FALSE},
"Date", /* Date g opt. all */ {"Date", FALSE},
"Expires", /* Expires e opt. DESCRIBE, ANNOUNCE */ {"Expires", FALSE},
"From", /* From R opt. all */ {"From", FALSE},
"If-Modified-Since", /* If-Modified-Since R opt. DESCRIBE, SETUP */ {"If-Modified-Since", FALSE},
"Last-Modified", /* Last-Modified e opt. entity */ {"Last-Modified", FALSE},
"Proxy-Authenticate", /* Proxy-Authenticate */ {"Proxy-Authenticate", TRUE},
"Proxy-Require", /* Proxy-Require R req. all */ {"Proxy-Require", TRUE},
"Public", /* Public r opt. all */ {"Public", TRUE},
"Range", /* Range Rr opt. PLAY, PAUSE, RECORD */ {"Range", FALSE},
"Referer", /* Referer R opt. all */ {"Referer", FALSE},
"Require", /* Require R req. all */ {"Require", TRUE},
"Retry-After", /* Retry-After r opt. all */ {"Retry-After", FALSE},
"RTP-Info", /* RTP-Info r req. PLAY */ {"RTP-Info", TRUE},
"Scale", /* Scale Rr opt. PLAY, RECORD */ {"Scale", FALSE},
"Session", /* Session Rr req. all but SETUP, OPTIONS */ {"Session", FALSE},
"Server", /* Server r opt. all */ {"Server", FALSE},
"Speed", /* Speed Rr opt. PLAY */ {"Speed", FALSE},
"Transport", /* Transport Rr req. SETUP */ {"Transport", FALSE},
"Unsupported", /* Unsupported r req. all */ {"Unsupported", FALSE},
"User-Agent", /* User-Agent R opt. all */ {"User-Agent", FALSE},
"Via", /* Via g opt. all */ {"Via", TRUE},
"WWW-Authenticate", /* WWW-Authenticate r opt. all */ {"WWW-Authenticate", TRUE},
/* Real extensions */ /* Real extensions */
"ClientChallenge", /* ClientChallenge */ {"ClientChallenge", FALSE},
"RealChallenge1", /* RealChallenge1 */ {"RealChallenge1", FALSE},
"RealChallenge2", /* RealChallenge2 */ {"RealChallenge2", FALSE},
"RealChallenge3", /* RealChallenge3 */ {"RealChallenge3", FALSE},
"Subscribe", /* Subscribe */ {"Subscribe", FALSE},
"Alert", /* Alert */ {"Alert", FALSE},
"ClientID", /* ClientID */ {"ClientID", FALSE},
"CompanyID", /* CompanyID */ {"CompanyID", FALSE},
"GUID", /* GUID */ {"GUID", FALSE},
"RegionData", /* RegionData */ {"RegionData", FALSE},
"SupportsMaximumASMBandwidth", /* SupportsMaximumASMBandwidth */ {"SupportsMaximumASMBandwidth", FALSE},
"Language", /* Language */ {"Language", FALSE},
"PlayerStarttime", /* PlayerStarttime */ {"PlayerStarttime", FALSE},
"Location", /* Location */ /* Since 0.10.16 */
"ETag", /* ETag */ {"Location", FALSE},
"If-Match", /* If-Match */
/* WM extensions [MS-RTSP] */ /* Since 0.10.23 */
"Accept-Charset", /* Accept-Charset */ {"ETag", FALSE},
"Supported", /* Supported */ {"If-Match", TRUE},
"Vary", /* Vary */
"X-Accelerate-Streaming", /* X-Accelerate-Streaming */
"X-Accept-Authentication", /* X-Accept-Authentication */
"X-Accept-Proxy-Authentication", /* X-Accept-Proxy-Authentication */
"X-Broadcast-Id", /* X-Broadcast-Id */
"X-Burst-Streaming", /* X-Burst-Streaming */
"X-Notice", /* X-Notice */
"X-Player-Lag-Time", /* X-Player-Lag-Time */
"X-Playlist", /* X-Playlist */
"X-Playlist-Change-Notice", /* X-Playlist-Change-Notice */
"X-Playlist-Gen-Id", /* X-Playlist-Gen-Id */
"X-Playlist-Seek-Id", /* X-Playlist-Seek-Id */
"X-Proxy-Client-Agent", /* X-Proxy-Client-Agent */
"X-Proxy-Client-Verb", /* X-Proxy-Client-Verb */
"X-Receding-PlaylistChange", /* X-Receding-PlaylistChange */
"X-RTP-Info", /* X-RTP-Info */
"X-StartupProfile", /* X-StartupProfile */
"Timestamp", /* Timestamp */ /* WM extensions [MS-RTSP] Since 0.10.23 */
{"Accept-Charset", TRUE},
{"Supported", TRUE},
{"Vary", TRUE},
{"X-Accelerate-Streaming", FALSE},
{"X-Accept-Authentication", FALSE},
{"X-Accept-Proxy-Authentication", FALSE},
{"X-Broadcast-Id", FALSE},
{"X-Burst-Streaming", FALSE},
{"X-Notice", FALSE},
{"X-Player-Lag-Time", FALSE},
{"X-Playlist", FALSE},
{"X-Playlist-Change-Notice", FALSE},
{"X-Playlist-Gen-Id", FALSE},
{"X-Playlist-Seek-Id", FALSE},
{"X-Proxy-Client-Agent", FALSE},
{"X-Proxy-Client-Verb", FALSE},
{"X-Receding-PlaylistChange", FALSE},
{"X-RTP-Info", FALSE},
{"X-StartupProfile", FALSE},
"Authentication-Info", /* Authentication-Info */ /* Since 0.10.24 */
"Host", /* Host */ {"Timestamp", FALSE},
"Pragma", /* Pragma */
"X-Server-IP-Address", /* X-Server-IP-Address */
"X-Sessioncookie", /* X-Sessioncookie */
NULL /* Since 0.10.25 */
{"Authentication-Info", FALSE},
{"Host", FALSE},
{"Pragma", TRUE},
{"X-Server-IP-Address", FALSE},
{"X-Sessioncookie", FALSE},
{NULL, FALSE}
}; };
#define DEF_STATUS(c, t) \ #define DEF_STATUS(c, t) \
@ -368,7 +379,7 @@ gst_rtsp_header_as_text (GstRTSPHeaderField field)
if (field == GST_RTSP_HDR_INVALID) if (field == GST_RTSP_HDR_INVALID)
return NULL; return NULL;
else else
return rtsp_headers[field - 1]; return rtsp_headers[field - 1].name;
} }
/** /**
@ -404,8 +415,8 @@ gst_rtsp_find_header_field (const gchar * header)
{ {
gint idx; gint idx;
for (idx = 0; rtsp_headers[idx]; idx++) { for (idx = 0; rtsp_headers[idx].name; idx++) {
if (g_ascii_strcasecmp (rtsp_headers[idx], header) == 0) { if (g_ascii_strcasecmp (rtsp_headers[idx].name, header) == 0) {
return idx + 1; return idx + 1;
} }
} }
@ -480,3 +491,22 @@ gst_rtsp_options_as_text (GstRTSPMethod options)
return g_string_free (str, FALSE); return g_string_free (str, FALSE);
} }
/**
* gst_rtsp_header_allow_multiple:
* @field: a #GstRTSPHeaderField
*
* Check whether @field may appear multiple times in a message.
*
* Returns: %TRUE if multiple headers are allowed.
*
* Since: 0.10.25
*/
gboolean
gst_rtsp_header_allow_multiple (GstRTSPHeaderField field)
{
if (field == GST_RTSP_HDR_INVALID)
return FALSE;
else
return rtsp_headers[field - 1].multiple;
}

View File

@ -389,6 +389,8 @@ gchar* gst_rtsp_options_as_text (GstRTSPMethod options);
GstRTSPHeaderField gst_rtsp_find_header_field (const gchar *header); GstRTSPHeaderField gst_rtsp_find_header_field (const gchar *header);
GstRTSPMethod gst_rtsp_find_method (const gchar *method); GstRTSPMethod gst_rtsp_find_method (const gchar *method);
gboolean gst_rtsp_header_allow_multiple (GstRTSPHeaderField field);
G_END_DECLS G_END_DECLS
#endif /* __GST_RTSP_DEFS_H__ */ #endif /* __GST_RTSP_DEFS_H__ */