[PATCH] sloppy mime parsing patch

Aarno Syvänen <[email protected]>
Newsgroups gmane.comp.mobile.kannel.devel
Message-ID <[email protected]>
Hi List,

This is patching changing Kannel mime parsing so that it
accepts lf instead of crlf as a separator, but only if this is
configured (strict-parsing=no).

I send the patch, because Paul vetoed the first one. Now
he can check does this one work properly.

Patch has three parts:

a) Kannel read configuration directive strict-parsing and
     parses mime multipart accordingly.
b) test_ppg accepts binary content  and sends mime
     content with different separators (crlf or lf).
c) There are two new octstr functions.

aarno
cvs.diff (application/octet-stream, 41 KB)
Index: gw/wap_push_pap_compiler.c
===================================================================
RCS file: /home/cvs/gateway/gw/wap_push_pap_compiler.c,v
retrieving revision 1.28
diff -u -r1.28 wap_push_pap_compiler.c
--- gw/wap_push_pap_compiler.c	28 Mar 2003 13:03:49 -0000	1.28
+++ gw/wap_push_pap_compiler.c	7 Apr 2003 09:56:12 -0000
@@ -23,7 +23,7 @@
  * ing some defaults (however, relying on them is quite a bad policy). In 
  * addition changing undefined values (any) to defined ones.
  *
- * By  Aarno Syvänen for Wapit Ltd and for Wiral Ltd.
+ * By  Aarno Syvänen for Wapit Ltd, Wiral Ltd and Global Network Inc.
  */
 
 #include <libxml/xmlmemory.h>
Index: gw/wap_push_pap_mime.c
===================================================================
RCS file: /home/cvs/gateway/gw/wap_push_pap_mime.c,v
retrieving revision 1.5
diff -u -r1.5 wap_push_pap_mime.c
--- gw/wap_push_pap_mime.c	4 Sep 2002 09:05:06 -0000	1.5
+++ gw/wap_push_pap_mime.c	7 Apr 2003 09:56:12 -0000
@@ -2,7 +2,7 @@
  * Implementation of a gateway oriented mime parser for pap module. This 
  * parser follows proxy rules stated in Push Message, chapter 7.
  *
- * By Aarno Syvänen for Wiral Ltd
+ * By Aarno Syvänen for Wiral Ltd and Global Networks Inc.
  */
 
 #include "wap_push_pap_mime.h"
@@ -17,39 +17,41 @@
 static int islwspchar(int c);
 static long octstr_drop_leading_blanks(Octstr **header_value);
 static void drop_separator(Octstr **header_value, long *pos);
-static int parse_preamble(Octstr **mime_content, Octstr *boundary);
+static int parse_preamble(Octstr **mime_content, Octstr *boundary, int strict_parsing);
 static long parse_transport_padding(Octstr *mime_content, long pos);
-static long parse_terminator(Octstr *mime_content, long pos);
+static long parse_terminator(Octstr *mime_content, long pos, 
+                             int strict_parsing);
 static int parse_body_part(Octstr **multipart, Octstr *boundary, 
-                            Octstr **body_part);
+                            Octstr **body_part, int strict_parsing);
 static int parse_encapsulation(Octstr **mime_content, Octstr *boundary, 
                                Octstr **push_data, List **content_headers,
-			       Octstr **rdf_content);
-static int check_control_headers(Octstr **body_part);
-static int check_control_content_type_header(Octstr **body_part);
-static int drop_optional_header(Octstr **body_part, char *name);
-static int drop_header_true(Octstr **body_part, long content_pos);
-static int drop_extension_headers(Octstr **mime_content);
-static long parse_field_value(Octstr *pap_content, long pos);
+			       Octstr **rdf_content, int strict_parsing);
+static int check_control_headers(Octstr **body_part, int strict_parsing);
+static int check_control_content_type_header(Octstr **body_part, int strict_parsing);
+static int drop_optional_header(Octstr **body_part, char *name, int strict_parsing);
+static int drop_header_true(Octstr **body_part, long content_pos, int strict_parsing);
+static int drop_extension_headers(Octstr **mime_content, int strict_parsing);
+static long parse_field_value(Octstr *pap_content, long pos, int strict_parsing);
 static long parse_field_name(Octstr *pap_content, long pos);
 static void octstr_split_by_pos(Octstr **mime_content, Octstr **pap_content, 
                                 long boundary_pos);
-static Octstr *make_close_delimiter(Octstr *boundary);
-static Octstr *make_part_delimiter(Octstr *boundary);
+static Octstr *make_close_delimiter(Octstr *boundary, int strict_parsing);
+static Octstr *make_part_delimiter(Octstr *boundary, int strict_parsing);
 static Octstr *make_start_delimiter(Octstr *dash_boundary);
-static int pass_data_headers(Octstr **body_part, List **data_headers);
-static int check_data_content_type_header(Octstr **body_part, 
-                                          List **data_headers);
+static int pass_data_headers(Octstr **body_part, List **data_headers, int strict_parsing);
+static int check_data_content_type_header(Octstr **body_part, List **data_headers,
+                                          int strict_parsing);
 static int pass_optional_header(Octstr **body_part, char *name, 
-                                List **content_headers);
-static int pass_extension_headers(Octstr **body_part, List **data_headers);
+                                List **content_headers, int strict_parsing);
+static int pass_extension_headers(Octstr **body_part, List **data_headers, 
+                                  int strict_parsing);
 static long pass_field_name(Octstr **body_part, Octstr **content_header, 
 			    long pos);
 static long pass_field_value(Octstr **body_part, Octstr **content_header, 
-                             long pos);
+                             long pos, int strict_parsing);
 static void parse_epilogue(Octstr **mime_content);
 static int parse_tail(Octstr **multipart, Octstr *part_delimiter, 
-                      long boundary_pos, long *next_part_pos);
+                      long boundary_pos, long *next_part_pos, int strict_parsing);
 
 /*****************************************************************************
  *
@@ -64,17 +66,18 @@
  * appendix D. PAP, chapter 8 defines how MIME multipart message is used by PAP
  * protocol. Functions called by mime_parse remove parsed parts from the mime
  * content. 
- * Input: pointer to mime boundary and mime content
+ * Input: pointer to mime boundary and mime content and the parsing
+ * directive (is separator crlf or lf).
  * Output: Pointer to pap control document and push data, if parsable, NULL
  * otherwise. If there is a capabilities document, pointer to this is return-
  * ed, too. If there is none, pointer to NULL instead. Neither prologue nor 
  * epilogue is returned. 
- * In addition, return 1 if parsing was succesfull, 0 otherwise.
+ * In addition, return 1 if parsing was succesful, 0 otherwise.
  */
 
 int mime_parse(Octstr *boundary, Octstr *mime_content, Octstr **pap_content, 
                Octstr **push_data, List **content_headers, 
-               Octstr **rdf_content)
+               Octstr **rdf_content, int strict_parsing)
 {
     int ret;
 
@@ -83,22 +86,23 @@
     *content_headers = NULL;
     *rdf_content = NULL;
 
-    if (parse_preamble(&mime_content, boundary) < 0) {
+    if (parse_preamble(&mime_content, boundary, strict_parsing) < 0) {
         warning(0, "erroneous preamble");
         return 0;
     }
-    if (parse_body_part(&mime_content, boundary, pap_content) <= 0) {
+    if (parse_body_part(&mime_content, boundary, pap_content, strict_parsing) <= 0) {
         warning(0, "erroneous control entity");
         return 0;
     }
-    if (check_control_headers(pap_content) == 0) {
+    if (check_control_headers(pap_content, strict_parsing) == 0) {
         warning(0, "erroneous control headers");
         return 0;
     }
-
+    
     ret = -1;
     if ((ret = parse_encapsulation(&mime_content, boundary, push_data, 
-                                   content_headers, rdf_content)) < 0) {
+                                   content_headers, rdf_content,
+                                   strict_parsing)) < 0) {
         warning(0, "erroneous content entity (push message)");
         return 0;
     } else if (ret == 0) {
@@ -108,7 +112,7 @@
         return 1;
     }
 
-    if (check_control_headers(rdf_content) == 0) {
+    if (check_control_headers(rdf_content, strict_parsing) == 0) {
         warning(0, "erroneous capacity (rdf) headers");
         return 0;
     }
@@ -142,22 +146,21 @@
 }
 
 static int parse_tail(Octstr **multipart, Octstr *delimiter, 
-                      long boundary_pos, long *next_part_pos)
+                      long boundary_pos, long *next_part_pos,
+                      int strict_parsing)
 {
     *next_part_pos = parse_transport_padding(*multipart, 
          boundary_pos + octstr_len(delimiter));
 
-    if ((*next_part_pos = parse_terminator(*multipart, *next_part_pos)) < 0)
+    if ((*next_part_pos = 
+         parse_terminator(*multipart, *next_part_pos, strict_parsing)) < 0)
         return -1;
     
     return 0;
 }
 
-/*
- * Boundary misses crlf here. This is intentional: Kannel header parsing pro-
- * cess drops this terminator.
- */
-static int parse_preamble(Octstr **mime_content, Octstr *boundary)
+
+static int parse_preamble(Octstr **mime_content, Octstr *boundary, int strict_parsing)
 {
     long boundary_pos,
          next_part_pos;
@@ -170,7 +173,7 @@
         goto error;
 
     if (parse_tail(mime_content, dash_boundary, boundary_pos, 
-            &next_part_pos) < 0) 
+            &next_part_pos, strict_parsing) < 0) 
         goto error;
 
     octstr_delete(*mime_content, 0, next_part_pos);
@@ -182,9 +185,21 @@
     octstr_destroy(dash_boundary);
     return -1;
 }
-    
-static long parse_terminator(Octstr *mime_content, long pos)
+
+/*
+ * We can have two types of terminators: crlf or plain lf (if parsing
+ * is sloppy).
+ */    
+static long parse_terminator(Octstr *mime_content, long pos, 
+                             int strict_parsing)
 {
+    /* Was it lf? Test this only if we allow sloppy parsing. */
+    if (!strict_parsing && is_lf(octstr_get_char(mime_content, pos))) {
+        ++pos;
+        return pos;
+    }
+
+    /* So we must try crlf. */
     if (is_cr(octstr_get_char(mime_content, pos)))
         ++pos;
     else 
@@ -192,7 +207,7 @@
 
     if (is_lf(octstr_get_char(mime_content, pos)))
         ++pos;
-    else 
+    else
         return -1;
 
     return pos;
@@ -217,7 +232,7 @@
  *         -1, when parsing error.
  */
 static int parse_body_part (Octstr **multipart, Octstr *boundary, 
-                            Octstr **body_part)
+                            Octstr **body_part, int strict_parsing)
 {
     Octstr *part_delimiter,
            *close_delimiter;
@@ -226,8 +241,8 @@
          end_pos,               /* end of the message */
          next_part_pos;         /* start of the next part */
  
-    part_delimiter = make_part_delimiter(boundary);
-    close_delimiter = make_close_delimiter(boundary);
+    part_delimiter = make_part_delimiter(boundary, strict_parsing);
+    close_delimiter = make_close_delimiter(boundary, strict_parsing);
 
     if ((close_delimiter_pos = octstr_search(*multipart, 
             close_delimiter, 0)) < 0) 
@@ -236,7 +251,7 @@
     boundary_pos = octstr_search(*multipart, part_delimiter, 0);
     if (boundary_pos == close_delimiter_pos) {
         if (parse_tail(multipart, close_delimiter, close_delimiter_pos,
-                       &end_pos) < 0) {
+                       &end_pos, strict_parsing) < 0) {
             goto error;
         } else {
             octstr_delete(*multipart, close_delimiter_pos, 
@@ -250,7 +265,7 @@
     *body_part = octstr_create("");
     octstr_split_by_pos(multipart, body_part, boundary_pos);
 
-    if (parse_tail(multipart, part_delimiter, 0, &next_part_pos) < 0) {
+    if (parse_tail(multipart, part_delimiter, 0, &next_part_pos, strict_parsing) < 0) {
         goto error;
     }
 
@@ -284,14 +299,14 @@
  */
 static int parse_encapsulation(Octstr **mime_content, Octstr *boundary, 
                                Octstr **push_data, List **content_headers,
-                               Octstr **rdf_content)
+                               Octstr **rdf_content, int strict_parsing)
 {
     int ret;
 
     ret = -1;
-    if ((ret = parse_body_part(mime_content, boundary, push_data)) < 0)
+    if ((ret = parse_body_part(mime_content, boundary, push_data, strict_parsing)) < 0)
         return -1;
-    if (pass_data_headers(push_data, content_headers) == 0)
+    if (pass_data_headers(push_data, content_headers, strict_parsing) == 0)
         return -1;
 
     if (ret == 0) {
@@ -299,8 +314,8 @@
         return 0;
     }
 
-    if ((ret = parse_body_part(mime_content, boundary, rdf_content)) < 0 || 
-            ret > 0)
+    if ((ret = parse_body_part(mime_content, boundary, rdf_content, 
+                               strict_parsing)) < 0 || ret > 0)
         return -1;
     else if (ret == 0)
         return 1;
@@ -325,22 +340,24 @@
     }
 }
 
-static Octstr *make_close_delimiter(Octstr *boundary) 
+static Octstr *make_close_delimiter(Octstr *boundary, int strict_parsing) 
 {
     Octstr *close_delimiter;
 
-    close_delimiter = make_part_delimiter(boundary);
+    close_delimiter = make_part_delimiter(boundary, strict_parsing);
     octstr_format_append(close_delimiter, "%s", "--");
 
     return close_delimiter;
 }
 
-static Octstr *make_part_delimiter(Octstr *dash_boundary)
+static Octstr *make_part_delimiter(Octstr *dash_boundary, 
+                                   int strict_parsing)
 {
     Octstr *part_delimiter;
 
     part_delimiter = octstr_create("");
-    octstr_format_append(part_delimiter, "%c", '\r');
+    if (strict_parsing)
+        octstr_format_append(part_delimiter, "%c", '\r');
     octstr_format_append(part_delimiter, "%c", '\n');
     octstr_format_append(part_delimiter, "%s", "--");
     octstr_append(part_delimiter, dash_boundary);
@@ -353,6 +370,7 @@
     Octstr *start_delimiter;
 
     start_delimiter = octstr_create("");
+    octstr_format_append(start_delimiter, "%c", '\n');
     octstr_format_append(start_delimiter, "%s", "--");
     octstr_append(start_delimiter, dash_boundary);
 
@@ -365,23 +383,24 @@
  * that all rfc 822 headers having a string "Content" in their field-name must
  * be accepted. Rfc 822 grammar is capitulated in appendix D.
  */
-static int check_control_headers(Octstr **body_part)
+static int check_control_headers(Octstr **body_part, int strict_parsing)
 {
-    if (check_control_content_type_header(body_part) == 0)
+    if (check_control_content_type_header(body_part, strict_parsing) == 0)
         return 0;
-    if (drop_optional_header(body_part, "Content-Transfer-Encoding:") == 0)
+    if (drop_optional_header(body_part, "Content-Transfer-Encoding:",
+                             strict_parsing) == 0)
         return 0;
-    if (drop_optional_header(body_part, "Content-ID:") == 0)
+    if (drop_optional_header(body_part, "Content-ID:", strict_parsing) == 0)
         return 0;
-    if (drop_optional_header(body_part, "Content-Description:") == 0)
+    if (drop_optional_header(body_part, "Content-Description:", strict_parsing) == 0)
         return 0;
-    if (drop_extension_headers(body_part) == 0)
+    if (drop_extension_headers(body_part, strict_parsing) == 0)
         return 0;
 
     return 1;
 }
 
-static int check_control_content_type_header(Octstr **body_part)
+static int check_control_content_type_header(Octstr **body_part, int strict_parsing)
 {
     long content_pos;
 
@@ -392,7 +411,7 @@
         return 0;
     }
 
-    if (drop_header_true(body_part, content_pos) < 0)
+    if (drop_header_true(body_part, content_pos, strict_parsing) < 0)
         return 0;
     
     return 1;
@@ -403,21 +422,20 @@
  * the octet string body_part), in addition of all stuff prepending it. So
  * deleting start from the octet 0. Content_pos tells where the header starts.
  */
-static int drop_header_true(Octstr **body_part, long content_pos) 
+static int drop_header_true(Octstr **body_part, long content_pos, int strict_parsing) 
 {
     long next_header_pos;
 
     next_header_pos = -1;
-    if ((next_header_pos = parse_field_value(*body_part, content_pos)) == 0)
-        return 0;
-    if ((next_header_pos = parse_terminator(*body_part, next_header_pos)) == 0)
+    if ((next_header_pos = parse_field_value(*body_part, content_pos, 
+                                             strict_parsing)) == 0)
         return 0;
     octstr_delete(*body_part, 0, next_header_pos);
 
     return 1;
 }
 
-static int drop_optional_header(Octstr **body_part, char *name)
+static int drop_optional_header(Octstr **body_part, char *name, int strict_parsing)
 {
     long content_pos;
          
@@ -426,7 +444,7 @@
              octstr_imm(name), 0)) < 0)
         return 1;
     
-    if (drop_header_true(body_part, content_pos) < 0)
+    if (drop_header_true(body_part, content_pos, strict_parsing) < 0)
         return 0;
 
     return 1;
@@ -437,7 +455,7 @@
  * parse all rfc 822 headers containing a string "Content". These headers 
  * are optional, too.
  */
-static int drop_extension_headers(Octstr **body_part)
+static int drop_extension_headers(Octstr **body_part, int strict_parsing)
 {
     long content_pos,
          next_header_pos;  
@@ -449,10 +467,10 @@
         if ((next_header_pos = parse_field_name(*body_part, content_pos)) < 0)
             return 0;
         if ((next_header_pos = parse_field_value(*body_part, 
-                 next_header_pos)) < 0)
+                 next_header_pos, strict_parsing)) < 0)
 	    return 0;
         if ((next_header_pos = parse_terminator(*body_part, 
-                 next_header_pos)) == 0)
+                 next_header_pos, strict_parsing)) == 0)
             return 0;
     } while (islwspchar(octstr_get_char(*body_part, next_header_pos)));
 
@@ -461,17 +479,28 @@
     return 1;
 }
 
-static long parse_field_value(Octstr *pap_content, long pos)
+static long parse_field_value(Octstr *pap_content, long pos,
+                              int strict_parsing)
 {
     int c;
 
-    while (!is_cr(c = octstr_get_char(pap_content, pos)) &&
-	     pos < octstr_len(pap_content)) {
+    /* We accept lf as a terminator, if parsing is sloppy. 
+     * (Otherwise it would be crlf.) */
+    c = -1;
+    while (pos < octstr_len(pap_content)) {
+         c = octstr_get_char(pap_content, pos);
+         if (is_cr(c))
+             break;
+         if (!strict_parsing && is_lf(c))
+             break;
          ++pos;
     }
  
-    if (is_lf(c)) {
-        if (is_lf(octstr_get_char(pap_content, pos))) {
+    /* If we had cr, we must have lf, too. */
+    if (is_cr(c)) {
+        ++pos;
+        c = octstr_get_char(pap_content, pos);
+        if (is_lf(c)) {
 	    ++pos;
         } else {
 	    return -1;
@@ -504,24 +533,25 @@
  * Return 0 when error, 1 otherwise. In addition, return the modified body
  * part and content headers.
  */
-static int pass_data_headers(Octstr **body_part, List **data_headers)
+static int pass_data_headers(Octstr **body_part, List **data_headers, 
+                             int strict_parsing)
 {
     *data_headers = http_create_empty_headers();
 
-    if (check_data_content_type_header(body_part, data_headers) == 0) {
+    if (check_data_content_type_header(body_part, data_headers, strict_parsing) == 0) {
         warning(0, "MIME: pass_data_headers: Content-Type header missing"); 
         return 0;
     }
         
     if (pass_optional_header(body_part, "Content-Transfer-Encoding", 
-                             data_headers) < 0)
+                             data_headers, strict_parsing) < 0)
         goto operror;
-    if (pass_optional_header(body_part, "Content-ID", data_headers) < 0)
+    if (pass_optional_header(body_part, "Content-ID", data_headers, strict_parsing) < 0)
         goto operror;
     if (pass_optional_header(body_part, "Content-Description", 
-                         data_headers) < 0)
+                             data_headers, strict_parsing) < 0)
         goto operror;
-    if (pass_extension_headers(body_part, data_headers) == 0)
+    if (pass_extension_headers(body_part, data_headers, strict_parsing) == 0)
         goto operror;
    
     return 1;
@@ -536,25 +566,27 @@
  * a list content_headers.
  * Return 1, when Content-Type headers was found, 0 otherwise
  */
-static int check_data_content_type_header(Octstr **body_part, 
-                                          List **content_headers)
+static int check_data_content_type_header(Octstr **body_part, List **content_headers,
+                                          int strict_parsing)
 {
     long header_pos,
          next_header_pos;
     Octstr *content_header;
+    long hdrlen;
 
     header_pos = next_header_pos = -1;
     content_header = octstr_create("Content-Type");
-    
+    hdrlen = octstr_len(content_header);    
+
     if ((header_pos = octstr_case_search(*body_part, content_header, 0)) < 0) {
         goto error;
     }
     if ((next_header_pos = pass_field_value(body_part, &content_header, 
-	    header_pos + octstr_len(content_header))) < 0) {
+	    header_pos + hdrlen, strict_parsing)) < 0) {
         goto error;
     }
     if ((next_header_pos = 
-	     parse_terminator(*body_part, next_header_pos)) < 0) {
+	     parse_terminator(*body_part, next_header_pos, strict_parsing)) < 0) {
         goto error;
     }
 
@@ -574,7 +606,7 @@
  * error. Return -1 when error, 0 when header name not found, 1 otherwise.
  */
 static int pass_optional_header(Octstr **body_part, char *name, 
-                                List **content_headers)
+                                List **content_headers, int strict_parsing)
 {
     long content_pos,
          next_header_pos;
@@ -588,10 +620,10 @@
     if ((content_pos = octstr_case_search(*body_part, osname, 0)) < 0) 
         goto noheader;
     if ((next_header_pos = pass_field_value(body_part, &osvalue, 
-	     content_pos + octstr_len(osname))) < 0)
+	     content_pos + octstr_len(osname), strict_parsing)) < 0)
         goto error;   
     if ((next_header_pos = 
-	     parse_terminator(*body_part, next_header_pos)) == 0)
+	     parse_terminator(*body_part, next_header_pos, strict_parsing)) == 0)
         goto error;
 
     drop_separator(&osvalue, &next_header_pos);
@@ -647,7 +679,8 @@
  * rfc 2045, chapter 9, grammar in appendix A.
  * Return 0 when error, 1 otherwise.
  */
-static int pass_extension_headers(Octstr **body_part, List **content_headers)
+static int pass_extension_headers(Octstr **body_part, List **content_headers,
+                                  int strict_parsing)
 {
     long next_field_part_pos,
          count;  
@@ -666,10 +699,10 @@
                  next_field_part_pos)) < 0)
             goto error;
         if ((next_field_part_pos = pass_field_value(body_part, &header_value, 
-                 next_field_part_pos)) < 0)
+                 next_field_part_pos, strict_parsing)) < 0)
             goto error;
         if ((next_field_part_pos = parse_terminator(*body_part, 
-                 next_field_part_pos)) == 0)
+                 next_field_part_pos, strict_parsing)) == 0)
             goto error;
         drop_separator(&header_value, &next_field_part_pos);
         http_header_add(*content_headers, octstr_get_cstr(header_name), 
@@ -694,14 +727,20 @@
 }
 
 static long pass_field_value(Octstr **body_part, Octstr **header, 
-                             long pos)
+                             long pos, int strict_parsing)
 {
     int c;
-
-    while (!is_cr(c = octstr_get_char(*body_part, pos)) &&
-             pos < octstr_len(*body_part)) {
+    
+    /* We accept lf as a terminator, if we accept sloppy parsing, too. */
+    c = octstr_get_char(*body_part, pos);
+    while (pos < octstr_len(*body_part)) {
+        if (is_cr(c))
+            break;
+        if (!strict_parsing && is_lf(c))
+            break;
         octstr_format_append(*header, "%c", c);
         ++pos;
+        c = octstr_get_char(*body_part, pos);
     }
  
     if (pos == octstr_len(*body_part))
Index: gw/wap_push_pap_mime.h
===================================================================
RCS file: /home/cvs/gateway/gw/wap_push_pap_mime.h,v
retrieving revision 1.2
diff -u -r1.2 wap_push_pap_mime.h
--- gw/wap_push_pap_mime.h	15 Aug 2001 12:45:16 -0000	1.2
+++ gw/wap_push_pap_mime.h	7 Apr 2003 09:56:12 -0000
@@ -21,7 +21,8 @@
  * and 5.1.7. Grammar is capitulated in rfc 2046 appendix A and in rfc 822, 
  * appendix D. Functions called by mime_parse remove parsed parts from the mime
  * content. 
- * Input: pointer to mime boundary and mime content
+ * Input: pointer to mime boundary and mime content and the parsing directive
+ * (is parsing sloppy or strict).
  * Output: in all cases, pointer to pap control document and push data. If 
  * there is a capabilities document, pointer to this is returned, too. If there
  * is none, pointer to NULL instead.
@@ -30,6 +31,6 @@
 
 int mime_parse(Octstr *boundary, Octstr *mime_content, Octstr **pap_content, 
                Octstr **push_data, List **content_headers, 
-               Octstr **rdf_content);
+               Octstr **rdf_content, int strict_parsing);
 
 #endif
Index: gw/wap_push_ppg.c
===================================================================
RCS file: /home/cvs/gateway/gw/wap_push_ppg.c,v
retrieving revision 1.53
diff -u -r1.53 wap_push_ppg.c
--- gw/wap_push_ppg.c	20 Mar 2003 14:11:49 -0000	1.53
+++ gw/wap_push_ppg.c	7 Apr 2003 09:56:12 -0000
@@ -56,6 +56,11 @@
 
 #define DEFAULT_PPG_URL "/wappush"
 
+enum {
+    STRICT_PARSING_OFF = 0,
+    STRICT_PARSING_ON = 1
+};
+
 /*****************************************************************************
  *
  * Internal data structures
@@ -144,7 +149,7 @@
 static Octstr *ssl_server_cert_file = NULL;
 static Octstr *ssl_server_key_file = NULL;
 #endif
-
+static int strict_parsing = STRICT_PARSING_ON;
 
 struct PAPEvent {
     HTTPClient *client;
@@ -463,7 +468,9 @@
      if ((global_sender = cfg_get(grp, octstr_imm("global-sender"))) == NULL)
          global_sender = octstr_imm("1234");
      ppg_default_smsc = cfg_get(grp, octstr_imm("default-smsc"));
-   
+     if (cfg_get_bool(&strict_parsing, grp, octstr_imm("strict-parsing")) == -1)
+         strict_parsing = STRICT_PARSING_ON;
+     
 #ifdef HAVE_LIBSSL
      cfg_get_integer(&ppg_ssl_port, grp, octstr_imm("ppg-ssl-port"));
      ssl_server_cert_file = cfg_get(grp, octstr_imm("ssl-server-cert-file"));
@@ -767,7 +774,7 @@
 
         gw_assert(mime_content);
         if (!mime_parse(boundary, mime_content, &pap_content, &push_data, 
-                        &content_headers, &rdf_content)) {
+                        &content_headers, &rdf_content, strict_parsing)) {
             send_bad_message_response(&client, mime_content, PAP_BAD_REQUEST,
                                       http_status);
             if (client == NULL)
Index: gwlib/cfg.def
===================================================================
RCS file: /home/cvs/gateway/gwlib/cfg.def,v
retrieving revision 1.85
diff -u -r1.85 cfg.def
--- gwlib/cfg.def	3 Apr 2003 12:18:18 -0000	1.85
+++ gwlib/cfg.def	7 Apr 2003 09:56:13 -0000
@@ -100,6 +100,7 @@
     OCTSTR(ssl-server-key-file)
     OCTSTR(global-sender)
     OCTSTR(default-smsc)
+    OCTSTR(strict-parsing)
 )
 
 
Index: gwlib/octstr.c
===================================================================
RCS file: /home/cvs/gateway/gwlib/octstr.c,v
retrieving revision 1.142
diff -u -r1.142 octstr.c
--- gwlib/octstr.c	9 Mar 2003 22:36:48 -0000	1.142
+++ gwlib/octstr.c	7 Apr 2003 09:56:13 -0000
@@ -2234,6 +2234,23 @@
     }
 }
 
+void octstr_delete_matching(Octstr *haystack, Octstr *needle)
+{
+    int p = -1;
+    long len;
+
+    seems_valid(haystack);
+    seems_valid(needle);
+    gw_assert(!haystack->immutable);
+    len = octstr_len(needle);
+
+    while ((p = octstr_search(haystack, needle, p + 1)) != -1) {
+        octstr_delete(haystack, p, len);
+        p -= len;
+    }
+}
+
+
 int octstr_symbolize(Octstr *ostr)
 {
     long len, i;
@@ -2257,3 +2274,18 @@
     return 1;
 }
 
+int octstr_all_hex(Octstr *os)      
+{
+    long len, i;
+    int ch;
+
+    seems_valid(os);
+    len = octstr_len(os);
+    for (i = 0; i < len; ++i) {
+        ch = octstr_get_char(os, i);
+        if (!gw_isxdigit(ch))
+            return 0;
+    }
+
+    return 1;
+}
Index: gwlib/octstr.h
===================================================================
RCS file: /home/cvs/gateway/gwlib/octstr.h,v
retrieving revision 1.72
diff -u -r1.72 octstr.h
--- gwlib/octstr.h	17 Mar 2003 13:22:00 -0000	1.72
+++ gwlib/octstr.h	7 Apr 2003 09:56:13 -0000
@@ -612,6 +612,15 @@
  * Symbolize hex string '78797a' becomes '%78%79%7a'
  */
 int octstr_symbolize(Octstr *ostr);
-                                                    
+
+/*
+ * Remove all occurrences of 'needle' within 'haystack'.
+ */
+void octstr_delete_matching(Octstr *haystack, Octstr *needle);
+
+/*
+ * Return 1, if octstr 'os' contains only hex chars, 0 otherwise.
+ */
+int octstr_all_hex(Octstr *os);                                                    
 
 #endif
Index: test/test_mime.c
===================================================================
RCS file: /home/cvs/gateway/test/test_mime.c,v
retrieving revision 1.1
diff -u -r1.1 test_mime.c
--- test/test_mime.c	15 Aug 2001 12:43:35 -0000	1.1
+++ test/test_mime.c	7 Apr 2003 09:56:13 -0000
@@ -99,6 +99,8 @@
     info(0, "Default write it to the file.");
 }
 
+enum { STRICT_PARSING_ON = 1 };
+
 int main(int argc, char **argv)
 {
     Octstr *mime_content,
@@ -211,7 +213,7 @@
     append_crlf(mime_content);
     
     ret = mime_parse(boundary, mime_content, &pap_content, &push_data, 
-                     &content_headers, &rdf_content);
+                     &content_headers, &rdf_content, STRICT_PARSING_ON);
     if (ret == 0) {
         error(0, "Mime_parse returned 0, cannot continue");
         goto error;
Index: test/test_ppg.c
===================================================================
RCS file: /home/cvs/gateway/test/test_ppg.c,v
retrieving revision 1.21
diff -u -r1.21 test_ppg.c
--- test/test_ppg.c	4 Sep 2002 09:15:36 -0000	1.21
+++ test/test_ppg.c	7 Apr 2003 09:56:13 -0000
@@ -27,7 +27,8 @@
            num_urls = 0,
            wait = 0,
            use_headers = 0,
-           use_config = 0;
+           use_config = 0,
+           accept_binary = 0;
 static double wait_seconds = 0.0;
 static Counter *counter = NULL;
 static char **push_data = NULL;
@@ -36,6 +37,7 @@
 static Octstr *appid_flag = NULL;
 static Octstr *content_transfer_encoding = NULL;
 static Octstr *connection = NULL;
+static Octstr *delimiter = NULL;
 
 enum { SSL_CONNECTION_OFF = 0,
        DEFAULT_NUMBER_OF_RELOGS = 2};
@@ -90,6 +92,15 @@
     cfg_destroy(cfg);
 }
 
+static void add_delimiter(Octstr **content)
+{
+    if (octstr_compare(delimiter, octstr_imm("crlf")) == 0) {
+        octstr_format_append(*content, "%c", '\r');
+    }
+
+    octstr_format_append(*content, "%c", '\n');
+}
+
 static void add_push_application_id(List **push_headers, Octstr *appid_flag)
 {
     if (octstr_compare(appid_flag, octstr_imm("any")) == 0)
@@ -110,33 +121,37 @@
 {
     if (octstr_compare(content_flag, octstr_imm("wml")) == 0)
         *wap_content = octstr_format("%s", 
-            "Content-Type: text/vnd.wap.wml\r\n");
+            "Content-Type: text/vnd.wap.wml");
     else if (octstr_compare(content_flag, octstr_imm("si")) == 0)
 	    *wap_content = octstr_format("%s",
-            "Content-Type: text/vnd.wap.si\r\n");
+            "Content-Type: text/vnd.wap.si");
     else if (octstr_compare(content_flag, octstr_imm("sl")) == 0)
 	    *wap_content = octstr_format("%s",
-            "Content-Type: text/vnd.wap.sl\r\n");
+            "Content-Type: text/vnd.wap.sl");
     else if (octstr_compare(content_flag, octstr_imm("multipart")) == 0)
         *wap_content = octstr_format("%s",
             "Content-Type: multipart/related; boundary=fsahgwruijkfldsa\r\n");
     else if (octstr_compare(content_flag, octstr_imm("mms")) == 0) 
         *wap_content = octstr_format("%s", 
-            "Content-Type: application/vnd.wap.mms-message\r\n"); 
+            "Content-Type: application/vnd.wap.mms-message"); 
     else if (octstr_compare(content_flag, octstr_imm("scrap")) == 0)
-        *wap_content = octstr_format("%s", "no type at all\r\n"); 
+        *wap_content = octstr_format("%s", "no type at all"); 
     else if (octstr_compare(content_flag, octstr_imm("nil")) == 0)
         *wap_content = octstr_create("");
+    if (octstr_len(*wap_content) > 0)
+        add_delimiter(wap_content);
 }
 
 static void add_content_transfer_encoding_type(Octstr *content_flag, 
                                                Octstr *wap_content)
 {
     if (!content_flag)
-	     return;
+	return;
 
     if (octstr_compare(content_flag, octstr_imm("base64")) == 0)
-	    octstr_append_cstr(wap_content, "Content-transfer-encoding: base64\r\n");
+	octstr_append_cstr(wap_content, "Content-transfer-encoding: base64");
+
+    add_delimiter(&wap_content);
 }
 
 static void add_connection_header(Octstr *connection, Octstr *wap_content)
@@ -145,18 +160,20 @@
         return;
 
     if (octstr_compare(connection, octstr_imm("close")) == 0)
-        octstr_format_append(wap_content, "%s", "Connection: close\r\n");
+        octstr_format_append(wap_content, "%s", "Connection: close");
     else if (octstr_compare(connection, octstr_imm("keep-alive")) == 0) 
-        octstr_format_append(wap_content, "%s", "Connection: keep-alive\r\n");
+        octstr_format_append(wap_content, "%s", "Connection: keep-alive");
+
+    add_delimiter(&wap_content);
 }
 
 static void transfer_encode (Octstr *cte, Octstr *content)
 {
     if (!cte)
-	    return;
+	return;
     
     if (octstr_compare(cte, octstr_imm("base64")) == 0) {
-	    octstr_binary_to_base64(content);
+       octstr_binary_to_base64(content);
     }
 }
 
@@ -180,12 +197,10 @@
     Octstr *part_delimiter;
 
     part_delimiter = octstr_create("");
-    octstr_format_append(part_delimiter, "%c", '\r');
-    octstr_format_append(part_delimiter, "%c", '\n');
+    add_delimiter(&part_delimiter);
     octstr_format_append(part_delimiter, "%s", "--");
     octstr_append(part_delimiter, boundary);
-    octstr_format_append(part_delimiter, "%c", '\r');
-    octstr_format_append(part_delimiter, "%c", '\n');
+    add_delimiter(&part_delimiter);
     
     return part_delimiter;
 }
@@ -195,14 +210,11 @@
     Octstr *close_delimiter;
 
     close_delimiter = octstr_create("");
-    octstr_format_append(close_delimiter, "%c", '\r');
-    octstr_format_append(close_delimiter, "%c", '\n');
+    add_delimiter(&close_delimiter);
     octstr_format_append(close_delimiter, "%s", "--");
     octstr_append(close_delimiter, boundary);
     octstr_format_append(close_delimiter, "%s", "--");
-    octstr_format_append(close_delimiter, "%c", '\r');
-    octstr_format_append(close_delimiter, "%c", '\n');
-    
+    add_delimiter(&close_delimiter);
 
     return close_delimiter;
 }
@@ -288,18 +300,30 @@
                                            wap_content);
         add_connection_header(connection, wap_content);
 
+        /* Read the content file. (To be pushed)*/
         if ((wap_file_content = 
                 octstr_read_file(octstr_get_cstr(content_file))) == NULL)
 	         panic(0, "Stopping");
+        if (accept_binary) {
+            octstr_delete_matching(wap_file_content, octstr_imm(" "));
+            octstr_delete_matching(wap_file_content, octstr_imm("\n"));
+            octstr_delete_matching(wap_file_content, octstr_imm("\r"));
+            if (!octstr_all_hex(wap_file_content))
+                panic(0, "non-hex chars in the content file, cannot continue");
+            octstr_hex_to_binary(wap_file_content);            
+        }
 
-	    transfer_encode (content_transfer_encoding, wap_file_content);
+	transfer_encode (content_transfer_encoding, wap_file_content);
         octstr_append(wap_content, wap_file_content);
         octstr_destroy(wap_file_content);
 
-        pap_content = octstr_format("%s", "Content-Type: application/xml\r\n");
+        /* Read the control file. (To control pushing)*/
+        pap_content = octstr_format("%s", "Content-Type: application/xml");
+        add_delimiter(&pap_content);
         if ((pap_file_content = 
                 octstr_read_file(octstr_get_cstr(pap_file))) ==  NULL)
 	        panic(0, "Stopping");
+        
         octstr_append(pap_content, pap_file_content);
         octstr_destroy(pap_file_content);
 
@@ -309,6 +333,8 @@
         push_content = octstr_create("");
         octstr_append(push_content, 
             bpos = make_part_delimiter(octstr_imm(boundary)));
+        /*octstr_append(push_content, octstr_imm("\r\n"));*/ /* Do we accept an additional 
+                                                          * clrf ? */
         octstr_append(push_content, pap_content);
         octstr_append(push_content, bpos);
         octstr_destroy(bpos);
@@ -598,6 +624,12 @@
     info(0, "Default: read components from files");
     info(0, "-t");
     info(0, "number of threads, maximum 1024, default 1");
+    info(0, "-B");
+    info(0, "accept binary push content. Default: off.");
+    info(0, "Binary content consist of hex numbers. In addition, crs, lfs and");
+    info(0, "spaces are accepted, and ignored.");
+    info(0, "-d value");
+    info(0, "set delimiter to be used. Accepted values crlf and lf. Default crlf.");
 }
 
 int main(int argc, char **argv)
@@ -614,7 +646,7 @@
     gwlib_init();
     num_threads = 1;
 
-    while ((opt = getopt(argc, argv, "Hhbv:qr:t:c:a:i:e:k:")) != EOF) {
+    while ((opt = getopt(argc, argv, "HhBbv:qr:t:c:a:i:e:k:d:")) != EOF) {
         switch(opt) {
 	    case 'v':
 	        log_set_output_level(atoi(optarg));
@@ -630,13 +662,13 @@
             
 	    case 'i': 
 	        wait = 1;
-            wait_seconds = atof(optarg);
+                wait_seconds = atof(optarg);
 	    break;
 
-        case 't': 
+            case 't': 
 	        num_threads = atoi(optarg);
-            if (num_threads > MAX_THREADS)
-		        num_threads = MAX_THREADS;
+                if (num_threads > MAX_THREADS)
+		    num_threads = MAX_THREADS;
 	    break;
 
 	    case 'H': 
@@ -652,51 +684,48 @@
                     octstr_compare(content_flag, octstr_imm("mms")) != 0 &&
                     octstr_compare(content_flag, octstr_imm("scrap")) != 0 &&
                     octstr_compare(content_flag, 
-                    octstr_imm("multipart")) != 0){
-		        octstr_destroy(content_flag);
-		        error(0, "TEST_PPG: Content type not known");
-		        help();
+                    octstr_imm("multipart")) != 0) {
+	        octstr_destroy(content_flag);
+		error(0, "TEST_PPG: Content type not known");
+		help();
                 exit(1);
             }
 	    break;
 
 	    case 'a':
 	        appid_flag = octstr_create(optarg);
-            if (octstr_compare(appid_flag, octstr_imm("any")) != 0 && 
-                    octstr_compare(appid_flag, octstr_imm("ua")) != 0 &&
-                    octstr_compare(appid_flag, octstr_imm("mms")) != 0 &&
-                    octstr_compare(appid_flag, octstr_imm("nil")) != 0 &&
-                    octstr_compare(appid_flag, octstr_imm("scrap")) != 0) {
-		        octstr_destroy(appid_flag);
-		        error(0, "TEST_PPG: Push application id not known");
-		        help();
+                if (octstr_compare(appid_flag, octstr_imm("any")) != 0 && 
+                        octstr_compare(appid_flag, octstr_imm("ua")) != 0 &&
+                        octstr_compare(appid_flag, octstr_imm("mms")) != 0 &&
+                        octstr_compare(appid_flag, octstr_imm("nil")) != 0 &&
+                        octstr_compare(appid_flag, octstr_imm("scrap")) != 0) {
+		octstr_destroy(appid_flag);
+		error(0, "TEST_PPG: Push application id not known");
+		help();
                 exit(1);
            }
 	    break;
 
 	    case 'e':
-		    content_transfer_encoding = octstr_create(optarg);
-            if (octstr_compare(content_transfer_encoding, 
-                               octstr_imm("base64")) != 0) {
-		        octstr_destroy(content_transfer_encoding);
-		        error(0, "TEST_PPG: unknown content transfer" 
-                      " encoding \"%s\"",
-			          octstr_get_cstr(content_transfer_encoding));
-		        help();
-                exit(1);
-		    }
+		content_transfer_encoding = octstr_create(optarg);
+                if (octstr_compare(content_transfer_encoding, octstr_imm("base64")) != 0) {
+	            octstr_destroy(content_transfer_encoding);
+		    error(0, "TEST_PPG: unknown content transfer" 
+                      " encoding \"%s\"", octstr_get_cstr(content_transfer_encoding));
+		    help();
+                    exit(1);
+		}
 	    break;
 
 	    case 'k':
 	        connection = octstr_create(optarg);
-            if (octstr_compare(connection, octstr_imm("close")) != 0 && 
-                    octstr_compare(connection, 
-                        octstr_imm("keep-alive")) != 0) {
-		        octstr_destroy(connection);
-		        error(0, "TEST_PPG: Connection-header unacceptable");
-		        help();
-                exit(1);
-           }
+                if (octstr_compare(connection, octstr_imm("close")) != 0 && 
+                        octstr_compare(connection, octstr_imm("keep-alive")) != 0) {
+	            octstr_destroy(connection);
+		    error(0, "TEST_PPG: Connection-header unacceptable");
+		    help();
+                    exit(1);
+                }
 	    break;
 
 	    case 'h':
@@ -707,6 +736,21 @@
 	        use_headers = 1;
 	    break;
 
+            case 'B':
+                accept_binary = 1;
+            break;
+
+            case 'd':
+                delimiter = octstr_create(optarg);
+                if (octstr_compare(delimiter, octstr_imm("crlf")) != 0 &&
+                        octstr_compare(delimiter, octstr_imm("lf")) != 0) {
+                    octstr_destroy(delimiter);
+                    error(0, "illegal d value");
+                    help();
+                    exit(1);
+                }
+            break;
+
 	    case '?':
 	    default:
 	        error(0, "TEST_PPG: Invalid option %c", opt);
@@ -730,6 +774,9 @@
     if (appid_flag == NULL)
         appid_flag = octstr_imm("ua");
 
+    if (delimiter == NULL)
+        delimiter = octstr_imm("crlf");
+
     if (use_hardcoded) {
         username = octstr_imm("troo");
         password = octstr_imm("far");
@@ -792,6 +839,7 @@
     octstr_destroy(password);
     octstr_destroy(push_url);
     octstr_destroy(connection);
+    octstr_destroy(delimiter);
     counter_destroy(counter);
     gwlib_shutdown();
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.