rtsp: Improve parse_line().
authorPeter Kjellerstedt <pkj@axis.com>
Wed, 17 Jun 2009 19:46:27 +0000 (21:46 +0200)
committerPeter Kjellerstedt <pkj@axis.com>
Mon, 24 Aug 2009 11:19:45 +0000 (13:19 +0200)
Make parse_line() handle keys with multiple values on one line correctly.

gst-libs/gst/rtsp/gstrtspconnection.c

index 2573258..b569455 100644 (file)
@@ -114,12 +114,6 @@ typedef struct
   guint coutl;
 } DecodeCtx;
 
-static GstRTSPResult read_line (GstRTSPConnection * conn, guint8 * buffer,
-    guint * idx, guint size);
-static GstRTSPResult parse_key_value (guint8 * buffer, gchar * key,
-    guint keysize, gchar ** value);
-static GstRTSPResult parse_string (gchar * dest, gint size, gchar ** src);
-
 #ifdef G_OS_WIN32
 #define READ_SOCKET(fd, buf, len) recv (fd, (char *)buf, len, 0)
 #define WRITE_SOCKET(fd, buf, len) send (fd, (const char *)buf, len, 0)
@@ -1441,21 +1435,6 @@ parse_string (gchar * dest, gint size, gchar ** src)
   return res;
 }
 
-static void
-parse_key (gchar * dest, gint size, gchar ** src)
-{
-  gint idx;
-
-  idx = 0;
-  while (**src != ':' && **src != '\0') {
-    if (idx < size - 1)
-      dest[idx++] = **src;
-    (*src)++;
-  }
-  if (size > 0)
-    dest[idx] = '\0';
-}
-
 static GstRTSPResult
 parse_protocol_version (gchar * protocol, GstRTSPMsgType * type,
     GstRTSPVersion * version)
@@ -1593,56 +1572,78 @@ parse_request_line (guint8 * buffer, GstRTSPMessage * msg)
   return res;
 }
 
+/* parsing lines means reading a Key: Value pair */
 static GstRTSPResult
-parse_key_value (guint8 * buffer, gchar * key, guint keysize, gchar ** value)
+parse_line (guint8 * buffer, GstRTSPMessage * msg)
 {
-  gchar *bptr;
+  GstRTSPHeaderField field;
+  gchar *line = (gchar *) buffer;
+  gchar *value;
 
-  bptr = (gchar *) buffer;
+  if ((value = strchr (line, ':')) == NULL || value == line)
+    goto parse_error;
 
-  /* read key */
-  parse_key (key, keysize, &bptr);
-  if (G_UNLIKELY (*bptr != ':'))
-    goto no_column;
+  /* trim space before the colon */
+  if (value[-1] == ' ')
+    value[-1] = '\0';
 
-  bptr++;
-  while (g_ascii_isspace (*bptr))
-    bptr++;
+  /* replace the colon with a NUL */
+  *value++ = '\0';
 
-  *value = bptr;
+  /* find the header */
+  field = gst_rtsp_find_header_field (line);
+  if (field == GST_RTSP_HDR_INVALID)
+    goto done;
 
-  return GST_RTSP_OK;
+  /* split up the value in multiple key:value pairs if it contains comma(s) */
+  while (*value != '\0') {
+    gchar *next_value;
+    gboolean quoted = FALSE;
+    guint comment = 0;
+
+    /* trim leading space */
+    if (*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')
+        next_value++;
+      else if (comment == 0 && *next_value == '"')
+        quoted = !quoted;
+      else if (!quoted && *next_value == '(')
+        comment++;
+      else if (comment != 0 && *next_value == ')')
+        comment--;
+      else if (!quoted && comment == 0 && *next_value == ',')
+        break;
 
-  /* ERRORS */
-no_column:
-  {
-    return GST_RTSP_EPARSE;
-  }
-}
+      next_value++;
+    }
 
-/* parsing lines means reading a Key: Value pair */
-static GstRTSPResult
-parse_line (guint8 * buffer, GstRTSPMessage * msg)
-{
-  GstRTSPResult res;
-  gchar key[32];
-  gchar *value;
-  GstRTSPHeaderField field;
+    /* trim space */
+    if (value != next_value && next_value[-1] == ' ')
+      next_value[-1] = '\0';
 
-  res = parse_key_value (buffer, key, sizeof (key), &value);
-  if (G_UNLIKELY (res != GST_RTSP_OK))
-    goto parse_error;
+    if (*next_value != '\0')
+      *next_value++ = '\0';
 
-  field = gst_rtsp_find_header_field (key);
-  if (field != GST_RTSP_HDR_INVALID)
-    gst_rtsp_message_add_header (msg, field, value);
+    /* add the key:value pair */
+    if (*value != '\0')
+      gst_rtsp_message_add_header (msg, field, value);
 
+    value = next_value;
+  }
+
+done:
   return GST_RTSP_OK;
 
   /* ERRORS */
 parse_error:
   {
-    return res;
+    return GST_RTSP_EPARSE;
   }
 }