[gmime] Fixed GMimeParser to handle header names with trailing whitespace



commit 7ee0d4263fe54b9c500271cf507a7a898836573a
Author: Jeffrey Stedfast <jestedfa microsoft com>
Date:   Sun Mar 19 22:15:59 2017 -0400

    Fixed GMimeParser to handle header names with trailing whitespace

 TODO                          |    2 -
 gmime/gmime-header.c          |   53 +++++++++++++++++++++++++++++-----------
 gmime/gmime-internal.h        |   19 ++++++++++----
 gmime/gmime-message-partial.c |    5 ++-
 gmime/gmime-object.c          |   15 +++++++----
 gmime/gmime-parser.c          |   49 +++++++++++++++++++++++++++-----------
 6 files changed, 98 insertions(+), 45 deletions(-)
---
diff --git a/TODO b/TODO
index f9e8922..87537d3 100644
--- a/TODO
+++ b/TODO
@@ -15,8 +15,6 @@ GMime 3.0 Planning:
 - Should GMimeHeader->value be decoded by GMime? i.e. work a bit more like
   MimeKit.
 
-- Fix GMimeParser to handle lwsp between header field anme and ':'
-
 - Fix GMimeParser to save mbox From markers on the GMimeMessage so
   that GMimeMessagePart::write_to_stream() can use it.
 
diff --git a/gmime/gmime-header.c b/gmime/gmime-header.c
index 3e40917..6c13905 100644
--- a/gmime/gmime-header.c
+++ b/gmime/gmime-header.c
@@ -127,12 +127,13 @@ g_mime_header_finalize (GObject *object)
  * Returns: a new #GMimeHeader with the specified values.
  **/
 static GMimeHeader *
-g_mime_header_new (const char *name, const char *value, const char *raw_value, gint64 offset)
+g_mime_header_new (const char *name, const char *value, const char *raw_name, const char *raw_value, gint64 
offset)
 {
        GMimeHeader *header;
        
        header = g_object_newv (GMIME_TYPE_HEADER, 0, NULL);
        header->raw_value = raw_value ? g_strdup (raw_value) : NULL;
+       header->raw_name = g_strdup (raw_name);
        header->value = g_strdup (value);
        header->name = g_strdup (name);
        header->offset = offset;
@@ -205,6 +206,23 @@ g_mime_header_set_value (GMimeHeader *header, const char *value)
 
 
 /**
+ * g_mime_header_get_raw_name:
+ * @header: a #GMimeHeader
+ *
+ * Gets the header's raw name.
+ *
+ * Returns: the header name.
+ **/
+const char *
+_g_mime_header_get_raw_name (GMimeHeader *header)
+{
+       //g_return_val_if_fail (GMIME_IS_HEADER (header), NULL);
+       
+       return header->raw_name;
+}
+
+
+/**
  * g_mime_header_get_raw_value:
  * @header: a #GMimeHeader
  *
@@ -215,7 +233,7 @@ g_mime_header_set_value (GMimeHeader *header, const char *value)
 const char *
 _g_mime_header_get_raw_value (GMimeHeader *header)
 {
-       g_return_val_if_fail (GMIME_IS_HEADER (header), NULL);
+       //g_return_val_if_fail (GMIME_IS_HEADER (header), NULL);
        
        return header->raw_value;
 }
@@ -231,11 +249,10 @@ _g_mime_header_get_raw_value (GMimeHeader *header)
 void
 _g_mime_header_set_raw_value (GMimeHeader *header, const char *raw_value)
 {
-       g_return_if_fail (GMIME_IS_HEADER (header));
-       g_return_if_fail (raw_value != NULL);
+       //g_return_if_fail (GMIME_IS_HEADER (header));
+       //g_return_if_fail (raw_value != NULL);
        
        g_free (header->raw_value);
-       
        header->raw_value = g_strdup (raw_value);
 }
 
@@ -302,7 +319,7 @@ g_mime_header_write_to_stream (GMimeHeaderList *headers, GMimeHeader *header,
        g_return_val_if_fail (GMIME_IS_STREAM (stream), -1);
        
        if (header->raw_value) {
-               val = g_strdup_printf ("%s:%s", header->name, header->raw_value);
+               val = g_strdup_printf ("%s:%s", header->raw_name, header->raw_value);
                nwritten = g_mime_stream_write_string (stream, val);
                g_free (val);
                
@@ -525,14 +542,15 @@ g_mime_header_list_contains (GMimeHeaderList *headers, const char *name)
 
 
 void
-_g_mime_header_list_prepend (GMimeHeaderList *headers, const char *name, const char *value, const char 
*raw_value, gint64 offset)
+_g_mime_header_list_prepend (GMimeHeaderList *headers, const char *name, const char *value,
+                            const char *raw_name, const char *raw_value, gint64 offset)
 {
        GMimeHeaderListChangedEventArgs args;
        unsigned char *dest, *src;
        GMimeHeader *header;
        guint n;
        
-       header = g_mime_header_new (name, value, raw_value, offset);
+       header = g_mime_header_new (name, value, raw_name, raw_value, offset);
        g_mime_event_add (header->changed, (GMimeEventCallback) header_changed, headers);
        g_hash_table_replace (headers->hash, header->name, header);
        
@@ -575,17 +593,18 @@ g_mime_header_list_prepend (GMimeHeaderList *headers, const char *name, const ch
        g_return_if_fail (GMIME_IS_HEADER_LIST (headers));
        g_return_if_fail (name != NULL);
        
-       _g_mime_header_list_prepend (headers, name, value, NULL, -1);
+       _g_mime_header_list_prepend (headers, name, value, name, NULL, -1);
 }
 
 
 void
-_g_mime_header_list_append (GMimeHeaderList *headers, const char *name, const char *value, const char 
*raw_value, gint64 offset)
+_g_mime_header_list_append (GMimeHeaderList *headers, const char *name, const char *value,
+                           const char *raw_name, const char *raw_value, gint64 offset)
 {
        GMimeHeaderListChangedEventArgs args;
        GMimeHeader *header;
        
-       header = g_mime_header_new (name, value, raw_value, offset);
+       header = g_mime_header_new (name, value, raw_name, raw_value, offset);
        g_mime_event_add (header->changed, (GMimeEventCallback) header_changed, headers);
        g_ptr_array_add (headers->array, header);
        
@@ -618,7 +637,7 @@ g_mime_header_list_append (GMimeHeaderList *headers, const char *name, const cha
        g_return_if_fail (GMIME_IS_HEADER_LIST (headers));
        g_return_if_fail (name != NULL);
        
-       _g_mime_header_list_append (headers, name, value, NULL, -1);
+       _g_mime_header_list_append (headers, name, value, name, NULL, -1);
 }
 
 
@@ -644,7 +663,8 @@ g_mime_header_list_get_header (GMimeHeaderList *headers, const char *name)
 
 
 void
-_g_mime_header_list_set (GMimeHeaderList *headers, const char *name, const char *value, const char 
*raw_value, gint64 offset)
+_g_mime_header_list_set (GMimeHeaderList *headers, const char *name, const char *value,
+                        const char *raw_name, const char *raw_value, gint64 offset)
 {
        GMimeHeaderListChangedEventArgs args;
        GMimeHeader *header, *hdr;
@@ -654,6 +674,9 @@ _g_mime_header_list_set (GMimeHeaderList *headers, const char *name, const char
                g_free (header->raw_value);
                header->raw_value = raw_value ? g_strdup (raw_value) : NULL;
                
+               g_free (header->raw_name);
+               header->raw_name = g_strdup (raw_name);
+               
                g_free (header->value);
                header->value = g_strdup (value);
                
@@ -678,7 +701,7 @@ _g_mime_header_list_set (GMimeHeaderList *headers, const char *name, const char
                
                g_mime_event_emit (headers->changed, &args);
        } else {
-               _g_mime_header_list_append (headers, name, value, raw_value, offset);
+               _g_mime_header_list_append (headers, name, value, raw_name, raw_value, offset);
        }
 }
 
@@ -707,7 +730,7 @@ g_mime_header_list_set (GMimeHeaderList *headers, const char *name, const char *
        g_return_if_fail (GMIME_IS_HEADER_LIST (headers));
        g_return_if_fail (name != NULL);
        
-       _g_mime_header_list_set (headers, name, value, NULL, -1);
+       _g_mime_header_list_set (headers, name, value, name, NULL, -1);
 }
 
 
diff --git a/gmime/gmime-internal.h b/gmime/gmime-internal.h
index f5a5afe..67f7a19 100644
--- a/gmime/gmime-internal.h
+++ b/gmime/gmime-internal.h
@@ -53,6 +53,7 @@ G_GNUC_INTERNAL void g_mime_parser_options_shutdown (void);
 G_GNUC_INTERNAL GMimeParserOptions *_g_mime_parser_options_clone (GMimeParserOptions *options);
 
 /* GMimeHeader */
+G_GNUC_INTERNAL const char *_g_mime_header_get_raw_name (GMimeHeader *header);
 G_GNUC_INTERNAL const char *_g_mime_header_get_raw_value (GMimeHeader *header);
 G_GNUC_INTERNAL void _g_mime_header_set_raw_value (GMimeHeader *header, const char *raw_value);
 G_GNUC_INTERNAL void _g_mime_header_set_offset (GMimeHeader *header, gint64 offset);
@@ -60,17 +61,23 @@ G_GNUC_INTERNAL void _g_mime_header_set_offset (GMimeHeader *header, gint64 offs
 /* GMimeHeaderList */
 G_GNUC_INTERNAL GMimeParserOptions *_g_mime_header_list_get_options (GMimeHeaderList *headers);
 G_GNUC_INTERNAL void _g_mime_header_list_set_options (GMimeHeaderList *headers, GMimeParserOptions *options);
-G_GNUC_INTERNAL void _g_mime_header_list_prepend (GMimeHeaderList *headers, const char *name, const char 
*value, const char *raw_value, gint64 offset);
-G_GNUC_INTERNAL void _g_mime_header_list_append (GMimeHeaderList *headers, const char *name, const char 
*value, const char *raw_value, gint64 offset);
-G_GNUC_INTERNAL void _g_mime_header_list_set (GMimeHeaderList *headers, const char *name, const char *value, 
const char *raw_value, gint64 offset);
+G_GNUC_INTERNAL void _g_mime_header_list_prepend (GMimeHeaderList *headers, const char *name, const char 
*value,
+                                                 const char *raw_name, const char *raw_value, gint64 offset);
+G_GNUC_INTERNAL void _g_mime_header_list_append (GMimeHeaderList *headers, const char *name, const char 
*value,
+                                                const char *raw_name, const char *raw_value, gint64 offset);
+G_GNUC_INTERNAL void _g_mime_header_list_set (GMimeHeaderList *headers, const char *name, const char *value,
+                                             const char *raw_name, const char *raw_value, gint64 offset);
 
 /* GMimeObject */
 G_GNUC_INTERNAL void _g_mime_object_block_header_list_changed (GMimeObject *object);
 G_GNUC_INTERNAL void _g_mime_object_unblock_header_list_changed (GMimeObject *object);
 G_GNUC_INTERNAL void _g_mime_object_set_content_type (GMimeObject *object, GMimeContentType *content_type);
-G_GNUC_INTERNAL void _g_mime_object_prepend_header (GMimeObject *object, const char *header, const char 
*value, const char *raw_value, gint64 offset);
-G_GNUC_INTERNAL void _g_mime_object_append_header (GMimeObject *object, const char *header, const char 
*value, const char *raw_value, gint64 offset);
-G_GNUC_INTERNAL void _g_mime_object_set_header (GMimeObject *object, const char *header, const char *value, 
const char *raw_value, gint64 offset);
+G_GNUC_INTERNAL void _g_mime_object_prepend_header (GMimeObject *object, const char *name, const char *value,
+                                                   const char *raw_name, const char *raw_value, gint64 
offset);
+G_GNUC_INTERNAL void _g_mime_object_append_header (GMimeObject *object, const char *name, const char *value,
+                                                  const char *raw_name, const char *raw_value, gint64 
offset);
+G_GNUC_INTERNAL void _g_mime_object_set_header (GMimeObject *object, const char *name, const char *value,
+                                               const char *raw_name, const char *raw_value, gint64 offset);
 
 /* utils */
 G_GNUC_INTERNAL char *_g_mime_utils_unstructured_header_fold (GMimeParserOptions *options, 
GMimeFormatOptions *format,
diff --git a/gmime/gmime-message-partial.c b/gmime/gmime-message-partial.c
index 14e31de..703a971 100644
--- a/gmime/gmime-message-partial.c
+++ b/gmime/gmime-message-partial.c
@@ -321,7 +321,7 @@ g_mime_message_partial_reconstruct_message (GMimeMessagePartial **partials, size
 static GMimeMessage *
 message_partial_message_new (GMimeMessage *base)
 {
-       const char *name, *value, *raw_value;
+       const char *name, *value, *raw_name, *raw_value;
        GMimeHeaderList *headers;
        GMimeMessage *message;
        GMimeHeader *header;
@@ -337,11 +337,12 @@ message_partial_message_new (GMimeMessage *base)
        for (i = 0; i < count; i++) {
                header = g_mime_header_list_get_header_at (headers, i);
                raw_value = _g_mime_header_get_raw_value (header);
+               raw_name = _g_mime_header_get_raw_name (header);
                offset = g_mime_header_get_offset (header);
                value = g_mime_header_get_value (header);
                name = g_mime_header_get_name (header);
                
-               _g_mime_object_append_header ((GMimeObject *) message, name, value, raw_value, offset);
+               _g_mime_object_append_header ((GMimeObject *) message, name, value, raw_name, raw_value, 
offset);
        }
        
        return message;
diff --git a/gmime/gmime-object.c b/gmime/gmime-object.c
index d119f8a..5e94da1 100644
--- a/gmime/gmime-object.c
+++ b/gmime/gmime-object.c
@@ -925,9 +925,10 @@ g_mime_object_get_content_id (GMimeObject *object)
 
 
 void
-_g_mime_object_prepend_header (GMimeObject *object, const char *header, const char *value, const char 
*raw_value, gint64 offset)
+_g_mime_object_prepend_header (GMimeObject *object, const char *header, const char *value,
+                              const char *raw_name, const char *raw_value, gint64 offset)
 {
-       _g_mime_header_list_prepend (object->headers, header, value, raw_value, offset);
+       _g_mime_header_list_prepend (object->headers, header, value, raw_name, raw_value, offset);
 }
 
 
@@ -952,9 +953,10 @@ g_mime_object_prepend_header (GMimeObject *object, const char *header, const cha
 
 
 void
-_g_mime_object_append_header (GMimeObject *object, const char *header, const char *value, const char 
*raw_value, gint64 offset)
+_g_mime_object_append_header (GMimeObject *object, const char *header, const char *value,
+                             const char *raw_name, const char *raw_value, gint64 offset)
 {
-       _g_mime_header_list_append (object->headers, header, value, raw_value, offset);
+       _g_mime_header_list_append (object->headers, header, value, raw_name, raw_value, offset);
 }
 
 
@@ -979,9 +981,10 @@ g_mime_object_append_header (GMimeObject *object, const char *header, const char
 
 
 void
-_g_mime_object_set_header (GMimeObject *object, const char *header, const char *value, const char 
*raw_value, gint64 offset)
+_g_mime_object_set_header (GMimeObject *object, const char *header, const char *value,
+                          const char *raw_name, const char *raw_value, gint64 offset)
 {
-       _g_mime_header_list_set (object->headers, header, value, raw_value, offset);
+       _g_mime_header_list_set (object->headers, header, value, raw_name, raw_value, offset);
 }
 
 
diff --git a/gmime/gmime-parser.c b/gmime/gmime-parser.c
index 3da3018..9e4513e 100644
--- a/gmime/gmime-parser.c
+++ b/gmime/gmime-parser.c
@@ -103,7 +103,8 @@ typedef struct _boundary_stack {
 
 typedef struct _header_raw {
        struct _header_raw *next;
-       char *name, *value, *raw_value;
+       char *raw_name, *raw_value;
+       char *name, *value;
        gint64 offset;
 } HeaderRaw;
 
@@ -289,7 +290,8 @@ header_raw_clear (HeaderRaw **headers)
                next = header->next;
                g_free (header->name);
                g_free (header->value);
-               
+               g_free (header->raw_name);
+               g_free (header->raw_value);
                g_slice_free (HeaderRaw, header);
                
                header = next;
@@ -914,10 +916,11 @@ header_parse (GMimeParser *parser, HeaderRaw **tail)
        register char *inptr;
        HeaderRaw *header;
        
-       *priv->headerptr = '\0';
+       *priv->headerptr = ':';
        inptr = priv->headerbuf;
-       while (*inptr && *inptr != ':' && !is_type (*inptr, IS_SPACE | IS_CTRL))
+       while (*inptr != ':')
                inptr++;
+       *priv->headerptr = '\0';
        
        if (*inptr != ':') {
                /* ignore invalid headers */
@@ -937,14 +940,21 @@ header_parse (GMimeParser *parser, HeaderRaw **tail)
        header = g_slice_new (HeaderRaw);
        header->next = NULL;
        
-       header->name = g_strndup (priv->headerbuf, (size_t) (inptr - priv->headerbuf));
        header->value = g_mime_strdup_trim (inptr + 1);
        
-       *priv->rawptr = '\0';
+       /* now walk backwards over lwsp characters */
+       while (inptr > priv->headerbuf && is_blank (inptr[-1]))
+               inptr--;
+       
+       header->name = g_strndup (priv->headerbuf, (size_t) (inptr - priv->headerbuf));
+       
+       *priv->rawptr = ':';
        inptr = priv->rawbuf;
        while (*inptr != ':')
                inptr++;
+       *priv->rawptr = '\0';
        
+       header->raw_name = g_strndup (priv->rawbuf, (size_t) (inptr - priv->rawbuf));
        header->raw_value = g_strdup (inptr + 1);
        header->offset = priv->header_offset;
        
@@ -1017,6 +1027,7 @@ parser_step_headers (GMimeParser *parser)
        struct _GMimeParserPrivate *priv = parser->priv;
        gboolean eoln, valid = TRUE, fieldname = TRUE;
        gboolean continuation = FALSE;
+       gboolean blank = FALSE;
        register char *inptr;
        char *start, *inend;
        ssize_t left = 0;
@@ -1053,6 +1064,7 @@ parser_step_headers (GMimeParser *parser)
                                priv->header_offset = parser_offset (priv, inptr);
                                continuation = FALSE;
                                fieldname = TRUE;
+                               blank = FALSE;
                                valid = TRUE;
                        }
                        
@@ -1064,7 +1076,12 @@ parser_step_headers (GMimeParser *parser)
                                        *inend = ':';
                                        
                                        while (*inptr != ':') {
-                                               if (is_type (*inptr, IS_SPACE | IS_CTRL)) {
+                                               /* Note: blank spaces are allowed between the field name
+                                                * and the ':', but field names themselves are not allowed
+                                                * to contain spaces. */
+                                               if (is_blank (*inptr)) {
+                                                       blank = TRUE;
+                                               } else if (blank || is_ctrl (*inptr)) {
                                                        valid = FALSE;
                                                        break;
                                                }
@@ -1696,9 +1713,8 @@ parser_scan_message_part (GMimeParser *parser, GMimeParserOptions *options, GMim
        header = priv->headers;
        while (header) {
                if (g_ascii_strncasecmp (header->name, "Content-", 8) != 0) {
-                       _g_mime_object_append_header ((GMimeObject *) message, header->name,
-                                                     header->value, header->raw_value,
-                                                     header->offset);
+                       _g_mime_object_append_header ((GMimeObject *) message, header->name, header->value,
+                                                     header->raw_name, header->raw_value, header->offset);
                }
                
                header = header->next;
@@ -1740,7 +1756,8 @@ parser_construct_leaf_part (GMimeParser *parser, GMimeParserOptions *options, Co
        while (header) {
                if (!toplevel || !g_ascii_strncasecmp (header->name, "Content-", 8)) {
                        _g_mime_object_append_header (object, header->name, header->value,
-                                                     header->raw_value, header->offset);
+                                                     header->raw_name, header->raw_value,
+                                                     header->offset);
                }
                
                header = header->next;
@@ -1883,7 +1900,8 @@ parser_construct_multipart (GMimeParser *parser, GMimeParserOptions *options, Co
        while (header) {
                if (!toplevel || !g_ascii_strncasecmp (header->name, "Content-", 8)) {
                        _g_mime_object_append_header (object, header->name, header->value,
-                                                     header->raw_value, header->offset);
+                                                     header->raw_name, header->raw_value,
+                                                     header->offset);
                }
                
                header = header->next;
@@ -2015,8 +2033,11 @@ parser_construct_message (GMimeParser *parser, GMimeParserOptions *options)
                                content_length = ULONG_MAX;
                }
                
-               if (g_ascii_strncasecmp (header->name, "Content-", 8) != 0)
-                       _g_mime_object_append_header ((GMimeObject *) message, header->name, header->value, 
header->raw_value, header->offset);
+               if (g_ascii_strncasecmp (header->name, "Content-", 8) != 0) {
+                       _g_mime_object_append_header ((GMimeObject *) message, header->name, header->value,
+                                                     header->raw_name, header->raw_value, header->offset);
+               }
+               
                header = header->next;
        }
        


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]