rtsp: Do not split headers which should not be split.
authorPeter Kjellerstedt <pkj@axis.com>
Thu, 20 Aug 2009 12:12:50 +0000 (14:12 +0200)
committerPeter Kjellerstedt <pkj@axis.com>
Mon, 24 Aug 2009 11:19:45 +0000 (13:19 +0200)
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
gst-libs/gst/rtsp/gstrtspdefs.c
gst-libs/gst/rtsp/gstrtspdefs.h

index 54b0d4c..8de8981 100644 (file)
@@ -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')
index cce0e3b..7b0cec5 100644 (file)
@@ -66,6 +66,12 @@ extern int h_errno;
 #include <netdb.h>
 #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;
+}
index 17382d9..874ad5d 100644 (file)
@@ -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__ */