From 607209f1214ec84f720e449667d334622eccc13f Mon Sep 17 00:00:00 2001 From: Peter Kjellerstedt Date: Thu, 20 Aug 2009 14:12:50 +0200 Subject: [PATCH] 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. --- gst-libs/gst/rtsp/gstrtspconnection.c | 9 +- gst-libs/gst/rtsp/gstrtspdefs.c | 212 +++++++++++++++++++--------------- gst-libs/gst/rtsp/gstrtspdefs.h | 2 + 3 files changed, 131 insertions(+), 92 deletions(-) diff --git a/gst-libs/gst/rtsp/gstrtspconnection.c b/gst-libs/gst/rtsp/gstrtspconnection.c index 54b0d4c..8de8981 100644 --- a/gst-libs/gst/rtsp/gstrtspconnection.c +++ b/gst-libs/gst/rtsp/gstrtspconnection.c @@ -1606,8 +1606,15 @@ parse_line (guint8 * buffer, GstRTSPMessage * msg) if (*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 */ - next_value = value; while (*next_value != '\0') { if ((quoted || comment != 0) && *next_value == '\\' && next_value[1] != '\0') diff --git a/gst-libs/gst/rtsp/gstrtspdefs.c b/gst-libs/gst/rtsp/gstrtspdefs.c index cce0e3b..7b0cec5 100644 --- a/gst-libs/gst/rtsp/gstrtspdefs.c +++ b/gst-libs/gst/rtsp/gstrtspdefs.c @@ -66,6 +66,12 @@ extern int h_errno; #include #endif +struct rtsp_header +{ + const gchar *name; + gboolean multiple; +}; + static const gchar *rtsp_results[] = { "OK", /* errors */ @@ -106,96 +112,101 @@ static const gchar *rtsp_methods[] = { NULL }; -static const gchar *rtsp_headers[] = { - "Accept", /* Accept R opt. entity */ - "Accept-Encoding", /* Accept-Encoding R opt. entity */ - "Accept-Language", /* Accept-Language R opt. all */ - "Allow", /* Allow r opt. all */ - "Authorization", /* Authorization R opt. all */ - "Bandwidth", /* Bandwidth R opt. all */ - "Blocksize", /* Blocksize R opt. all but OPTIONS, TEARDOWN */ - "Cache-Control", /* Cache-Control g opt. SETUP */ - "Conference", /* Conference R opt. SETUP */ - "Connection", /* Connection g req. all */ - "Content-Base", /* Content-Base e opt. entity */ - "Content-Encoding", /* Content-Encoding e req. SET_PARAMETER, DESCRIBE, ANNOUNCE */ - "Content-Language", /* Content-Language e req. DESCRIBE, ANNOUNCE */ - "Content-Length", /* Content-Length e req. SET_PARAMETER, ANNOUNCE, entity */ - "Content-Location", /* Content-Location e opt. entity */ - "Content-Type", /* Content-Type e req. SET_PARAMETER, ANNOUNCE, entity */ - "CSeq", /* CSeq g req. all */ - "Date", /* Date g opt. all */ - "Expires", /* Expires e opt. DESCRIBE, ANNOUNCE */ - "From", /* From R opt. all */ - "If-Modified-Since", /* If-Modified-Since R opt. DESCRIBE, SETUP */ - "Last-Modified", /* Last-Modified e opt. entity */ - "Proxy-Authenticate", /* Proxy-Authenticate */ - "Proxy-Require", /* Proxy-Require R req. all */ - "Public", /* Public r opt. all */ - "Range", /* Range Rr opt. PLAY, PAUSE, RECORD */ - "Referer", /* Referer R opt. all */ - "Require", /* Require R req. all */ - "Retry-After", /* Retry-After r opt. all */ - "RTP-Info", /* RTP-Info r req. PLAY */ - "Scale", /* Scale Rr opt. PLAY, RECORD */ - "Session", /* Session Rr req. all but SETUP, OPTIONS */ - "Server", /* Server r opt. all */ - "Speed", /* Speed Rr opt. PLAY */ - "Transport", /* Transport Rr req. SETUP */ - "Unsupported", /* Unsupported r req. all */ - "User-Agent", /* User-Agent R opt. all */ - "Via", /* Via g opt. all */ - "WWW-Authenticate", /* WWW-Authenticate r opt. all */ +static struct rtsp_header rtsp_headers[] = { + {"Accept", TRUE}, + {"Accept-Encoding", TRUE}, + {"Accept-Language", TRUE}, + {"Allow", TRUE}, + {"Authorization", FALSE}, + {"Bandwidth", FALSE}, + {"Blocksize", FALSE}, + {"Cache-Control", TRUE}, + {"Conference", FALSE}, + {"Connection", TRUE}, + {"Content-Base", FALSE}, + {"Content-Encoding", TRUE}, + {"Content-Language", TRUE}, + {"Content-Length", FALSE}, + {"Content-Location", FALSE}, + {"Content-Type", FALSE}, + {"CSeq", FALSE}, + {"Date", FALSE}, + {"Expires", FALSE}, + {"From", FALSE}, + {"If-Modified-Since", FALSE}, + {"Last-Modified", FALSE}, + {"Proxy-Authenticate", TRUE}, + {"Proxy-Require", TRUE}, + {"Public", TRUE}, + {"Range", FALSE}, + {"Referer", FALSE}, + {"Require", TRUE}, + {"Retry-After", FALSE}, + {"RTP-Info", TRUE}, + {"Scale", FALSE}, + {"Session", FALSE}, + {"Server", FALSE}, + {"Speed", FALSE}, + {"Transport", FALSE}, + {"Unsupported", FALSE}, + {"User-Agent", FALSE}, + {"Via", TRUE}, + {"WWW-Authenticate", TRUE}, /* Real extensions */ - "ClientChallenge", /* ClientChallenge */ - "RealChallenge1", /* RealChallenge1 */ - "RealChallenge2", /* RealChallenge2 */ - "RealChallenge3", /* RealChallenge3 */ - "Subscribe", /* Subscribe */ - "Alert", /* Alert */ - "ClientID", /* ClientID */ - "CompanyID", /* CompanyID */ - "GUID", /* GUID */ - "RegionData", /* RegionData */ - "SupportsMaximumASMBandwidth", /* SupportsMaximumASMBandwidth */ - "Language", /* Language */ - "PlayerStarttime", /* PlayerStarttime */ - - "Location", /* Location */ - "ETag", /* ETag */ - "If-Match", /* If-Match */ - - /* WM extensions [MS-RTSP] */ - "Accept-Charset", /* Accept-Charset */ - "Supported", /* Supported */ - "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 */ - - "Authentication-Info", /* Authentication-Info */ - "Host", /* Host */ - "Pragma", /* Pragma */ - "X-Server-IP-Address", /* X-Server-IP-Address */ - "X-Sessioncookie", /* X-Sessioncookie */ - - NULL + {"ClientChallenge", FALSE}, + {"RealChallenge1", FALSE}, + {"RealChallenge2", FALSE}, + {"RealChallenge3", FALSE}, + {"Subscribe", FALSE}, + {"Alert", FALSE}, + {"ClientID", FALSE}, + {"CompanyID", FALSE}, + {"GUID", FALSE}, + {"RegionData", FALSE}, + {"SupportsMaximumASMBandwidth", FALSE}, + {"Language", FALSE}, + {"PlayerStarttime", FALSE}, + + /* Since 0.10.16 */ + {"Location", FALSE}, + + /* Since 0.10.23 */ + {"ETag", FALSE}, + {"If-Match", TRUE}, + + /* 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}, + + /* Since 0.10.24 */ + {"Timestamp", FALSE}, + + /* 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) \ @@ -368,7 +379,7 @@ gst_rtsp_header_as_text (GstRTSPHeaderField field) if (field == GST_RTSP_HDR_INVALID) return NULL; 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; - for (idx = 0; rtsp_headers[idx]; idx++) { - if (g_ascii_strcasecmp (rtsp_headers[idx], header) == 0) { + for (idx = 0; rtsp_headers[idx].name; idx++) { + if (g_ascii_strcasecmp (rtsp_headers[idx].name, header) == 0) { return idx + 1; } } @@ -480,3 +491,22 @@ gst_rtsp_options_as_text (GstRTSPMethod options) 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; +} diff --git a/gst-libs/gst/rtsp/gstrtspdefs.h b/gst-libs/gst/rtsp/gstrtspdefs.h index 17382d9..874ad5d 100644 --- a/gst-libs/gst/rtsp/gstrtspdefs.h +++ b/gst-libs/gst/rtsp/gstrtspdefs.h @@ -389,6 +389,8 @@ gchar* gst_rtsp_options_as_text (GstRTSPMethod options); GstRTSPHeaderField gst_rtsp_find_header_field (const gchar *header); GstRTSPMethod gst_rtsp_find_method (const gchar *method); +gboolean gst_rtsp_header_allow_multiple (GstRTSPHeaderField field); + G_END_DECLS #endif /* __GST_RTSP_DEFS_H__ */ -- 2.7.4