Kannel: Open Source WAP and SMS gateway  $Revision: 5037 $
wap_push_pap_mime.c
Go to the documentation of this file.
1 /* ====================================================================
2  * The Kannel Software License, Version 1.0
3  *
4  * Copyright (c) 2001-2016 Kannel Group
5  * Copyright (c) 1998-2001 WapIT Ltd.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * 1. Redistributions of source code must retain the above copyright
13  * notice, this list of conditions and the following disclaimer.
14  *
15  * 2. Redistributions in binary form must reproduce the above copyright
16  * notice, this list of conditions and the following disclaimer in
17  * the documentation and/or other materials provided with the
18  * distribution.
19  *
20  * 3. The end-user documentation included with the redistribution,
21  * if any, must include the following acknowledgment:
22  * "This product includes software developed by the
23  * Kannel Group (http://www.kannel.org/)."
24  * Alternately, this acknowledgment may appear in the software itself,
25  * if and wherever such third-party acknowledgments normally appear.
26  *
27  * 4. The names "Kannel" and "Kannel Group" must not be used to
28  * endorse or promote products derived from this software without
29  * prior written permission. For written permission, please
30  * contact org@kannel.org.
31  *
32  * 5. Products derived from this software may not be called "Kannel",
33  * nor may "Kannel" appear in their name, without prior written
34  * permission of the Kannel Group.
35  *
36  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
37  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
38  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
39  * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS
40  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
41  * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
42  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
43  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
44  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
45  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
46  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
47  * ====================================================================
48  *
49  * This software consists of voluntary contributions made by many
50  * individuals on behalf of the Kannel Group. For more information on
51  * the Kannel Group, please see <http://www.kannel.org/>.
52  *
53  * Portions of this software are based upon software originally written at
54  * WapIT Ltd., Helsinki, Finland for the Kannel project.
55  */
56 
57 /*
58  * Implementation of a gateway oriented mime parser for pap module. This
59  * parser follows proxy rules stated in Push Message, chapter 7.
60  *
61  * By Aarno Syvšnen for Wiral Ltd and Global Networks Inc.
62  */
63 
64 #include "wap_push_pap_mime.h"
65 
66 /*****************************************************************************
67  *
68  * Prototypes for internal functions
69  */
70 
71 static int is_cr(int c);
72 static int is_lf(int c);
73 static int islwspchar(int c);
74 static long octstr_drop_leading_blanks(Octstr **header_value);
75 static void drop_separator(Octstr **header_value, long *pos);
76 static int parse_preamble(Octstr **mime_content, Octstr *boundary);
77 static long parse_transport_padding(Octstr *mime_content, long pos);
78 static long parse_terminator(Octstr *mime_content, long pos);
79 static int parse_body_part(Octstr **multipart, Octstr *boundary,
80  Octstr **body_part);
81 static int parse_encapsulation(Octstr **mime_content, Octstr *boundary,
82  Octstr **push_data, List **content_headers,
83  Octstr **rdf_content);
84 static int check_control_headers(Octstr **body_part);
86 static int drop_optional_header(Octstr **body_part, char *name, Octstr *boundary);
87 static int drop_header_true(Octstr **body_part, long content_pos);
88 static int drop_extension_headers(Octstr **mime_content, Octstr *boundary);
89 static long parse_field_value(Octstr *pap_content, long pos);
90 static long parse_field_name(Octstr *pap_content, long pos);
91 static void octstr_split_by_pos(Octstr **mime_content, Octstr **pap_content,
92  long boundary_pos);
95 static Octstr *make_start_delimiter(Octstr *dash_boundary);
96 static int pass_data_headers(Octstr **body_part, List **data_headers);
97 static int check_data_x_wap_application_id_header(Octstr **body_part, List **data_headers, Octstr *boundary);
98 static int check_data_content_type_header(Octstr **body_part, List **data_headers, Octstr *boundary);
99 static int pass_optional_header(Octstr **body_part, char *name, List **content_headers,
100  Octstr *boundary);
101 static int pass_extension_headers(Octstr **body_part, List **data_headers, Octstr *boundary);
102 static long pass_field_name(Octstr **body_part, Octstr **content_header,
103  long pos);
104 static long pass_field_value(Octstr **body_part, Octstr **content_header,
105  long pos);
106 static int parse_epilogue(Octstr **mime_content);
107 static int parse_tail(Octstr **multipart, Octstr *part_delimiter,
108  long boundary_pos, long *next_part_pos);
109 
110 /*****************************************************************************
111  *
112  * Implementation of the external function, PAP uses MIME type multipart/
113  * related to communicate a push message and related control information from
114  * pi to ppg. Mime_parse separates parts of message and in addition returns
115  * MIME-part-headers of the content entity. Preamble and epilogue of are dis-
116  * carded from control messages, but not from a multipart content entity.
117  * Already parsed parts of mime content are removed.
118  * Multipart/related content type is defined in rfc 2046, chapters 5.1, 5.1.1,
119  * and 5.1.7. Grammar is capitulated in rfc 2046 appendix A and in rfc 822,
120  * appendix D. PAP, chapter 8 defines how MIME multipart message is used by PAP
121  * protocol. Functions called by mime_parse remove parsed parts from the mime
122  * content.
123  * Input: pointer to mime boundary and mime content
124  * Output: Pointer to pap control document and push data, if parsable, NULL
125  * otherwise. If there is a capabilities document, pointer to this is return-
126  * ed, too. If there is none, pointer to NULL instead. Neither prologue nor
127  * epilogue is returned.
128  * In addition, return 1 if parsing was succesfull, 0 otherwise.
129  */
130 
131 int mime_parse(Octstr *boundary, Octstr *mime_content, Octstr **pap_content,
132  Octstr **push_data, List **content_headers,
133  Octstr **rdf_content)
134 {
135  int ret;
136 
137  *pap_content = NULL;
138  *push_data = NULL;
139  *content_headers = NULL;
140  *rdf_content = NULL;
141 
142  if (parse_preamble(&mime_content, boundary) < 0) {
143  warning(0, "erroneous preamble");
144  return 0;
145  }
146  if (parse_body_part(&mime_content, boundary, pap_content) <= 0) {
147  warning(0, "erroneous control entity");
148  return 0;
149  }
150  if (check_control_headers(pap_content) == 0) {
151  warning(0, "erroneous control headers");
152  return 0;
153  }
154 
155  ret = -1;
156  if ((ret = parse_encapsulation(&mime_content, boundary, push_data,
157  content_headers, rdf_content)) < 0) {
158  warning(0, "erroneous content entity (push message)");
159  return 0;
160  } else if (ret == 0) {
161  gw_assert(*rdf_content == NULL);
162  if (octstr_len(mime_content) != 0)
163  parse_epilogue(&mime_content);
164  return 1;
165  }
166 
167  if (check_control_headers(rdf_content) == 0) {
168  warning(0, "erroneous capacity (rdf) headers");
169  return 0;
170  }
171 
172  if (octstr_len(mime_content) != 0)
173  parse_epilogue(&mime_content);
174  gw_assert(octstr_len(mime_content) == 0);
175 
176  return 1;
177 }
178 
179 /*****************************************************************************
180  *
181  * Implementation of internal functions
182  */
183 
184 static int is_cr(int c)
185 {
186  return c == '\r';
187 }
188 
189 static int is_lf(int c)
190 {
191  return c == '\n';
192 }
193 
194 /*
195  * Lwspchar is defined in rfc 822, appendix D.
196  */
197 static int islwspchar(int c)
198 {
199  return c == '\t' || c == ' ';
200 }
201 
202 /* These thingies we after normally have after delimiters. */
203 static int parse_tail(Octstr **multipart, Octstr *delimiter,
204  long boundary_pos, long *next_part_pos)
205 {
206  *next_part_pos = parse_transport_padding(*multipart,
207  boundary_pos + octstr_len(delimiter));
208 
209  if ((*next_part_pos = parse_terminator(*multipart, *next_part_pos)) < 0)
210  return -1;
211 
212  return 0;
213 }
214 
215 
216 /*
217  * Boundary misses crlf here. This is intentional: Kannel header parsing pro-
218  * cess drops this terminator.
219  */
220 static int parse_preamble(Octstr **mime_content, Octstr *boundary)
221 {
222  long boundary_pos,
223  next_part_pos;
224  Octstr *dash_boundary;
225 
226  boundary_pos = next_part_pos = -1;
227  dash_boundary = make_start_delimiter(boundary);
228 
229  if ((boundary_pos = octstr_search(*mime_content, dash_boundary, 0)) < 0)
230  goto error;
231 
232  if (parse_tail(mime_content, dash_boundary, boundary_pos,
233  &next_part_pos) < 0)
234  goto error;
235 
236  octstr_delete(*mime_content, 0, next_part_pos);
237  octstr_destroy(dash_boundary);
238 
239  return 0;
240 
241 error:
242  octstr_destroy(dash_boundary);
243  return -1;
244 }
245 
246 static long parse_terminator(Octstr *mime_content, long pos)
247 {
248  if (is_cr(octstr_get_char(mime_content, pos)))
249  ++pos;
250  else
251  return -1;
252 
253  if (is_lf(octstr_get_char(mime_content, pos)))
254  ++pos;
255  else
256  return -1;
257 
258  return pos;
259 }
260 
261 static long parse_transport_padding(Octstr *mime_content, long pos)
262 {
263  while (islwspchar(octstr_get_char(mime_content, pos)))
264  ++pos;
265 
266  return pos;
267 }
268 
269 static long parse_close_delimiter(Octstr *close_delimiter, Octstr *mime_content,
270  long pos)
271 {
272  if (octstr_ncompare(close_delimiter, mime_content,
273  octstr_len(close_delimiter)) != 0)
274  return -1;
275  pos += octstr_len(close_delimiter);
276 
277  return pos;
278 }
279 
280 /*
281  * Splits the first body part away from the multipart message. A body part end with
282  * either with another body or with a close delimiter. We first split the body and
283  * then remove the separating stuff from the remainder. If we have the last body
284  * part, we must parse all closing stuff.
285  * Returns 1, there is still another body part in the multipart message
286  * 0, if there is none
287  * -1, when parsing error.
288  */
289 static int parse_body_part (Octstr **multipart, Octstr *boundary,
290  Octstr **body_part)
291 {
292  Octstr *part_delimiter,
293  *close_delimiter;
294  long boundary_pos, /* start of the boundary */
295  close_delimiter_pos, /* start of the close delimiter */
296  next_part_pos, /* start of the next part */
297  epilogue_pos; /* start of the epilogue */
298 
299  part_delimiter = make_part_delimiter(boundary);
300  close_delimiter = make_close_delimiter(boundary);
301 
302  if ((close_delimiter_pos = octstr_search(*multipart,
303  close_delimiter, 0)) < 0)
304  goto error;
305 
306  boundary_pos = octstr_search(*multipart, part_delimiter, 0);
307  if (boundary_pos == close_delimiter_pos) {
308  octstr_split_by_pos(multipart, body_part, close_delimiter_pos);
309  if ((epilogue_pos =
310  parse_close_delimiter(close_delimiter, *multipart, 0)) < 0)
311  goto error;
312  epilogue_pos = parse_transport_padding(*multipart, epilogue_pos);
313  octstr_delete(*multipart, 0, epilogue_pos);
314  goto last_part;
315  }
316 
317  octstr_split_by_pos(multipart, body_part, boundary_pos);
318 
319  if (parse_tail(multipart, part_delimiter, 0, &next_part_pos) < 0) {
320  goto error;
321  }
322 
323  octstr_delete(*multipart, 0, next_part_pos);
324  octstr_destroy(part_delimiter);
325  octstr_destroy(close_delimiter);
326 
327  return 1;
328 
329 error:
330  octstr_destroy(part_delimiter);
331  octstr_destroy(close_delimiter);
332  return -1;
333 
334 last_part:
335  octstr_destroy(part_delimiter);
336  octstr_destroy(close_delimiter);
337  return 0;
338 
339 }
340 
341 /*
342  * PAP, Chapter 8 states that PAP multipart message MUST have at least two
343  * parts, control entity (containing the pap control message) and content
344  * entity (containing the push message). So we must have at least one body
345  * part here, and at most two (MIME grammar in rfc 2046, appendix A sets no
346  * limitations here).
347  * Input: mime content, part boundary
348  * Output: Push content, rdf content if present, content headers. In addi-
349  * tion, modified mime content (without parsed parts).
350  * Returns 1, if rdf content was present
351  * 0, if it was absent
352  * -1, when error
353  */
354 static int parse_encapsulation(Octstr **mime_content, Octstr *boundary,
355  Octstr **push_data, List **content_headers,
356  Octstr **rdf_content)
357 {
358  int ret;
359 
360  ret = -1;
361  if ((ret = parse_body_part(mime_content, boundary, push_data)) < 0)
362  return -1;
363  if (pass_data_headers(push_data, content_headers) == 0)
364  return -1;
365 
366  if (ret == 0) {
367  *rdf_content = NULL;
368  return 0;
369  }
370 
371  if ((ret = parse_body_part(mime_content, boundary, rdf_content)) < 0 ||
372  ret > 0)
373  return -1;
374  else if (ret == 0)
375  return 1;
376 
377  return 1;
378 }
379 
380 /*
381  * Split os2 from os1, boundary being boundary_pos.
382  */
383 static void octstr_split_by_pos(Octstr **os1, Octstr **os2,
384  long boundary_pos)
385 {
386  *os2 = octstr_copy(*os1, 0, boundary_pos);
387  octstr_delete(*os1, 0, boundary_pos);
388 }
389 
391 {
392  Octstr *close_delimiter;
393 
394  close_delimiter = make_part_delimiter(boundary);
395  octstr_format_append(close_delimiter, "%s", "--");
396 
397  return close_delimiter;
398 }
399 
400 static Octstr *make_part_delimiter(Octstr *dash_boundary)
401 {
402  Octstr *part_delimiter;
403 
404  part_delimiter = octstr_create("\r\n--");
405  octstr_append(part_delimiter, dash_boundary);
406 
407  return part_delimiter;
408 }
409 
410 static Octstr *make_start_delimiter(Octstr *dash_boundary)
411 {
412  Octstr *start_delimiter;
413 
414  start_delimiter = octstr_create("--");
415  octstr_append(start_delimiter, dash_boundary);
416 
417  return start_delimiter;
418 }
419 
420 /*
421  * Control entity headers must contain Content-Type: application/xml headers.
422  * Rfc 2045, Appendix A does not specify the order of entity headers and states
423  * that all rfc 822 headers having a string "Content" in their field-name must
424  * be accepted. Rfc 822 grammar is capitulated in appendix D.
425  * Message starts after the first null line, so only something after it can be
426  * an extension header (or any header).
427  */
428 static int check_control_headers(Octstr **body_part)
429 {
430  if (check_control_content_type_header(body_part, octstr_imm("\r\n\r\n")) == 0)
431  return 0;
432  if (drop_optional_header(body_part, "Content-Transfer-Encoding:",
433  octstr_imm("\r\n\r\n")) == 0)
434  return 0;
435  if (drop_optional_header(body_part, "Content-ID:", octstr_imm("\r\n\r\n")) == 0)
436  return 0;
437  if (drop_optional_header(body_part, "Content-Description:", octstr_imm("\r\n\r\n")) == 0)
438  return 0;
439  if (drop_extension_headers(body_part, octstr_imm("\r\n\r\n")) == 0)
440  return 0;
441 
442  return 1;
443 }
444 
446 {
447  long content_pos;
448  long message_start_pos;
449 
450  message_start_pos = octstr_search(*body_part, boundary, 0);
451  if ((content_pos = octstr_case_nsearch(*body_part, octstr_imm("Content-Type:"), 0,
452  message_start_pos)) < 0 ||
453  octstr_case_search(*body_part, octstr_imm("application/xml"), 0) < 0) {
454  return 0;
455  }
456 
457  if (drop_header_true(body_part, content_pos) < 0)
458  return 0;
459 
460  return 1;
461 }
462 
463 /*
464  * This function actually removes a header (deletes corresponding part from
465  * the octet string body_part), in addition of all stuff prepending it. So
466  * deleting start from the octet 0. Content_pos tells where the header starts.
467  */
468 static int drop_header_true(Octstr **body_part, long content_pos)
469 {
470  long next_header_pos;
471 
472  next_header_pos = -1;
473  if ((next_header_pos = parse_field_value(*body_part, content_pos)) == 0)
474  return 0;
475  if ((next_header_pos = parse_terminator(*body_part, next_header_pos)) == 0)
476  return 0;
477  octstr_delete(*body_part, 0, next_header_pos);
478 
479  return 1;
480 }
481 
482 static int drop_optional_header(Octstr **body_part, char *name, Octstr *boundary)
483 {
484  long content_pos;
485  long message_start_pos;
486 
487  content_pos = -1;
488  message_start_pos = octstr_search(*body_part, boundary, 0);
489 
490  if ((content_pos = octstr_case_nsearch(*body_part, octstr_imm(name), 0, message_start_pos)) < 0)
491  return 1;
492 
493  if (drop_header_true(body_part, content_pos) < 0)
494  return 0;
495 
496  return 1;
497 }
498 
499 /*
500  * Extension headers are defined in rfc 822, Appendix D, as fields. We must
501  * parse all rfc 822 headers containing a string "Content". These headers
502  * are optional, too. For general definition of message parts see chapter 4.1.
503  * Specifically: "everything after first null line is message body".
504  */
505 static int drop_extension_headers(Octstr **body_part, Octstr *boundary)
506 {
507  long content_pos,
508  next_header_pos;
509  long next_content_part_pos;
510 
511  next_content_part_pos = octstr_case_search(*body_part, boundary, 0);
512  do {
513  if ((content_pos = octstr_case_nsearch(*body_part, octstr_imm("Content"), 0,
514  next_content_part_pos)) < 0)
515  return 1;
516  if ((next_header_pos = parse_field_name(*body_part, content_pos)) < 0)
517  return 0;
518  if ((next_header_pos = parse_field_value(*body_part,
519  next_header_pos)) < 0)
520  return 0;
521  if ((next_header_pos = parse_terminator(*body_part,
522  next_header_pos)) == 0)
523  return 0;
524  } while (islwspchar(octstr_get_char(*body_part, next_header_pos)));
525 
526  octstr_delete(*body_part, content_pos, next_header_pos - content_pos);
527 
528  return 1;
529 }
530 
531 static long parse_field_value(Octstr *pap_content, long pos)
532 {
533  int c;
534 
535  while (!is_cr(c = octstr_get_char(pap_content, pos)) &&
536  pos < octstr_len(pap_content)) {
537  ++pos;
538  }
539 
540  if (is_lf(c)) {
541  if (is_lf(octstr_get_char(pap_content, pos))) {
542  ++pos;
543  } else {
544  return -1;
545  }
546  }
547 
548  if (pos == octstr_len(pap_content)) {
549  return -1;
550  }
551 
552  return pos;
553 }
554 
555 static long parse_field_name(Octstr *content, long pos)
556 {
557  while (octstr_get_char(content, pos) != ':' &&
558  pos < octstr_len(content))
559  ++pos;
560 
561  if (pos == octstr_len(content))
562  return -1;
563 
564  return pos;
565 }
566 
567 /*
568  * Transfer entity headers of a body part (it is, from the content entity)
569  * to a header list. Push Message, chapter 6.2.1.10 states that Content-Type
570  * header is mandatory.
571  * Message proper starts after first empty line. We search only to it, and
572  * remove the line here.
573  * Return 0 when error, 1 otherwise. In addition, return the modified body
574  * part and content headers.
575  */
576 static int pass_data_headers(Octstr **body_part, List **data_headers)
577 {
578  *data_headers = http_create_empty_headers();
579 
580  /* Transform X-WAP-Application headers as per PPG 6.1.2.1.
581  * Note that missing header means that wml.ua is assumed. */
582  if (check_data_x_wap_application_id_header(body_part, data_headers, octstr_imm("\r\n\r\n")) == 0) {
583  warning(0, "MIME: %s: X-Wap-Application-Id header missing, assuming 'wml.ua'", __func__);
584  gwlist_append(*data_headers, octstr_create("X-Wap-Application-Id: wml.ua"));
585  }
586 
587  if (check_data_content_type_header(body_part, data_headers, octstr_imm("\r\n\r\n")) == 0) {
588  warning(0, "MIME: %s: Content-Type header missing", __func__);
589  return 0;
590  }
591 
592  if (pass_optional_header(body_part, "Content-Transfer-Encoding", data_headers,
593  octstr_imm("\r\n\r\n")) < 0)
594  goto operror;
595  if (pass_optional_header(body_part, "Content-ID", data_headers, octstr_imm("\r\n\r\n")) < 0)
596  goto operror;
597  if (pass_optional_header(body_part, "Content-Description", data_headers,
598  octstr_imm("\r\n\r\n")) < 0)
599  goto operror;
600  if (pass_extension_headers(body_part, data_headers, octstr_imm("\r\n\r\n")) == 0)
601  goto operror;
602 
603  /*
604  * XXX: TODO: This assumes that there are no further headers prefixing
605  * the MIME body. Which MAY not be the case. We SHOULD rather move all
606  * headers to the data_headers and ensure by this that there are no
607  * left overs.
608  */
609  octstr_delete(*body_part, 0, octstr_len(octstr_imm("\r\n")));
610 
611  return 1;
612 
613 operror:
614  warning(0, "MIME: pass_data_headers: an unparseable optional header");
615  return 0;
616 }
617 
618 /*
619  * Checks if body_part contains a X-Wap-Application-Id header. Transfers this header to
620  * a list content_headers.
621  * Return 1, when X-Wap-Application-Id header was found, 0 otherwise
622  */
623 static int check_data_x_wap_application_id_header(Octstr **body_part, List **content_headers,
624  Octstr *boundary)
625 {
626  long header_pos, next_header_pos;
628  long message_start_pos;
629 
630  header_pos = next_header_pos = -1;
631  content_header = octstr_create("X-Wap-Application-Id");
632  message_start_pos = octstr_search(*body_part, boundary, 0);
633 
634  if ((header_pos = octstr_case_nsearch(*body_part, content_header, 0,
635  message_start_pos)) < 0) {
636  goto error;
637  }
638  if ((next_header_pos = pass_field_value(body_part, &content_header,
639  header_pos + octstr_len(content_header))) < 0) {
640  goto error;
641  }
642  if ((next_header_pos = parse_terminator(*body_part, next_header_pos)) < 0) {
643  goto error;
644  }
645 
646  octstr_delete(*body_part, header_pos, next_header_pos - header_pos);
647  gwlist_append(*content_headers, octstr_duplicate(content_header));
648  octstr_destroy(content_header);
649 
650  return 1;
651 
652 error:
653  octstr_destroy(content_header);
654  return 0;
655 }
656 
657 /*
658  * Checks if body_part contains a Content-Type header. Transfers this header to
659  * a list content_headers. (Only part before 'boundary').
660  * Return 1, when Content-Type headers was found, 0 otherwise
661  */
662 static int check_data_content_type_header(Octstr **body_part, List **content_headers,
663  Octstr *boundary)
664 {
665  long header_pos, next_header_pos;
667  long message_start_pos;
668 
669  header_pos = next_header_pos = -1;
670  content_header = octstr_create("Content-Type");
671  message_start_pos = octstr_search(*body_part, boundary, 0);
672 
673  if ((header_pos = octstr_case_nsearch(*body_part, content_header, 0,
674  message_start_pos)) < 0) {
675  goto error;
676  }
677  if ((next_header_pos = pass_field_value(body_part, &content_header,
678  header_pos + octstr_len(content_header))) < 0) {
679  goto error;
680  }
681  if ((next_header_pos = parse_terminator(*body_part, next_header_pos)) < 0) {
682  goto error;
683  }
684 
685  octstr_delete(*body_part, header_pos, next_header_pos - header_pos);
686  gwlist_append(*content_headers, octstr_duplicate(content_header));
687  octstr_destroy(content_header);
688 
689  return 1;
690 
691 error:
692  octstr_destroy(content_header);
693  return 0;
694 }
695 
696 /*
697  * We try to find an optional header, so a failure to find one is not an
698  * error. Return -1 when error, 0 when header name not found, 1 otherwise.
699  * Search only until 'boundary'.
700  */
701 static int pass_optional_header(Octstr **body_part, char *name, List **content_headers,
702  Octstr *boundary)
703 {
704  long content_pos, next_header_pos;
705  Octstr *osname, *osvalue;
706  long message_start_pos;
707 
708  content_pos = next_header_pos = -1;
709  osname = octstr_create(name);
710  osvalue = octstr_create("");
711  message_start_pos = octstr_search(*body_part, boundary, 0);
712 
713  if ((content_pos = octstr_case_nsearch(*body_part, osname, 0, message_start_pos)) < 0)
714  goto noheader;
715  if ((next_header_pos = pass_field_value(body_part, &osvalue,
716  content_pos + octstr_len(osname))) < 0)
717  goto error;
718  if ((next_header_pos = parse_terminator(*body_part, next_header_pos)) == 0)
719  goto error;
720 
721  drop_separator(&osvalue, &next_header_pos);
722  http_header_add(*content_headers, name, octstr_get_cstr(osvalue));
723  octstr_delete(*body_part, content_pos, next_header_pos - content_pos);
724 
725  octstr_destroy(osname);
726  octstr_destroy(osvalue);
727  return 1;
728 
729 error:
730  octstr_destroy(osvalue);
731  octstr_destroy(osname);
732  return -1;
733 
734 noheader:
735  octstr_destroy(osvalue);
736  octstr_destroy(osname);
737  return 0;
738 }
739 
740 /*
741  * Remove ':' plus spaces from the header value
742  */
743 static void drop_separator(Octstr **header_value, long *pos)
744 {
745  long count;
746 
747  octstr_delete(*header_value, 0, 1); /* remove :*/
748  count = octstr_drop_leading_blanks(header_value);
749  pos = pos - 1 - count;
750 }
751 
752 /*
753  * Return number of spaces dropped.
754  */
755 static long octstr_drop_leading_blanks(Octstr **header_value)
756 {
757  long count;
758 
759  count = 0;
760  while (octstr_get_char(*header_value, 0) == ' ') {
761  octstr_delete(*header_value, 0, 1);
762  ++count;
763  }
764 
765  return count;
766 }
767 
768 /*
769  * Extension headers are optional, see Push Message, chapter 6.2. Field struc-
770  * ture is defined in rfc 822, chapter 3.2. Extension headers are defined in
771  * rfc 2045, chapter 9, grammar in appendix A. (Only to the next null line).
772  * Return 0 when error, 1 otherwise.
773  */
774 static int pass_extension_headers(Octstr **body_part, List **content_headers, Octstr *boundary)
775 {
776  long next_field_part_pos;
777  Octstr *header_name,
778  *header_value;
779  long next_content_part_pos;
780 
781  header_name = octstr_create("");
782  header_value = octstr_create("");
783  next_field_part_pos = 0;
784  next_content_part_pos = octstr_search(*body_part, boundary, 0);
785 
786  do {
787  if ((octstr_case_nsearch(*body_part, octstr_imm("Content"), 0,
788  next_content_part_pos)) < 0)
789  goto end;
790  if ((next_field_part_pos = pass_field_name(body_part, &header_name,
791  next_field_part_pos)) < 0)
792  goto error;
793  if ((next_field_part_pos = pass_field_value(body_part, &header_value,
794  next_field_part_pos)) < 0)
795  goto error;
796  if ((next_field_part_pos = parse_terminator(*body_part,
797  next_field_part_pos)) == 0)
798  goto error;
799  drop_separator(&header_value, &next_field_part_pos);
800  http_header_add(*content_headers, octstr_get_cstr(header_name),
801  octstr_get_cstr(header_value));
802  } while (islwspchar(octstr_get_char(*body_part, next_field_part_pos)));
803 
804  octstr_delete(*body_part, 0, next_field_part_pos);
805 
806 /*
807  * An intentional fall-through. We must eventually use a function for memory
808  * cleaning.
809  */
810 end:
811  octstr_destroy(header_name);
812  octstr_destroy(header_value);
813  return 1;
814 
815 error:
816  octstr_destroy(header_name);
817  octstr_destroy(header_value);
818  return 0;
819 }
820 
821 static long pass_field_value(Octstr **body_part, Octstr **header,
822  long pos)
823 {
824  int c;
825  long start;
826  Octstr *field = NULL;
827 
828  start = pos;
829  while (!is_cr(c = octstr_get_char(*body_part, pos)) &&
830  pos < octstr_len(*body_part)) {
831  ++pos;
832  }
833 
834  if (pos == octstr_len(*body_part)) {
835  return -1;
836  }
837 
838  field = octstr_copy(*body_part, start, pos - start);
839  octstr_append(*header, field);
840 
841  octstr_destroy(field);
842  return pos;
843 }
844 
845 static long pass_field_name(Octstr **body_part, Octstr **field_part,
846  long pos)
847 {
848  int c;
849  long start;
850  Octstr *name = NULL;
851 
852  start = pos;
853  while (((c = octstr_get_char(*body_part, pos)) != ':') &&
854  pos < octstr_len(*body_part)) {
855  ++pos;
856  }
857 
858  if (pos == octstr_len(*body_part)) {
859  return -1;
860  }
861 
862  name = octstr_copy(*body_part, start, pos - start);
863  octstr_append(*field_part, name);
864 
865  octstr_destroy(name);
866  return pos;
867 }
868 
869 /* This is actually CRLF epilogue. */
870 static int parse_epilogue(Octstr **mime_content)
871 {
872  long pos;
873 
874  if (octstr_len(*mime_content) == 0)
875  return 0;
876 
877  if ((pos = parse_terminator(*mime_content, 0)) < 0)
878  return -1;
879 
880  octstr_delete(*mime_content, 0, octstr_len(*mime_content));
881  return 0;
882 }
883 
void error(int err, const char *fmt,...)
Definition: log.c:612
static Octstr * delimiter
Definition: test_ppg.c:104
static int parse_epilogue(Octstr **mime_content)
static char ** push_data
Definition: test_ppg.c:96
void http_header_add(List *headers, char *name, char *contents)
Definition: http.c:2863
static int check_data_content_type_header(Octstr **body_part, List **data_headers, Octstr *boundary)
void gwlist_append(List *list, void *item)
Definition: list.c:179
static void octstr_split_by_pos(Octstr **mime_content, Octstr **pap_content, long boundary_pos)
void octstr_append(Octstr *ostr1, const Octstr *ostr2)
Definition: octstr.c:1502
static Octstr * make_start_delimiter(Octstr *dash_boundary)
static int islwspchar(int c)
static Octstr * make_part_delimiter(Octstr *boundary)
static char * boundary
Definition: test_ppg.c:97
long octstr_search(const Octstr *haystack, const Octstr *needle, long pos)
Definition: octstr.c:1068
static int check_data_x_wap_application_id_header(Octstr **body_part, List **data_headers, Octstr *boundary)
long octstr_case_nsearch(const Octstr *haystack, const Octstr *needle, long pos, long n)
Definition: octstr.c:1127
static void drop_separator(Octstr **header_value, long *pos)
static long parse_field_name(Octstr *pap_content, long pos)
static int check_control_headers(Octstr **body_part)
#define octstr_get_cstr(ostr)
Definition: octstr.h:233
#define octstr_copy(ostr, from, len)
Definition: octstr.h:178
static int pass_extension_headers(Octstr **body_part, List **data_headers, Octstr *boundary)
static int is_lf(int c)
static long parse_terminator(Octstr *mime_content, long pos)
static long pass_field_value(Octstr **body_part, Octstr **content_header, long pos)
static Octstr * content_header
Definition: test_ppg.c:101
static long parse_transport_padding(Octstr *mime_content, long pos)
static Octstr * make_close_delimiter(Octstr *boundary)
Octstr * octstr_imm(const char *cstr)
Definition: octstr.c:281
static int parse_body_part(Octstr **multipart, Octstr *boundary, Octstr **body_part)
static int drop_header_true(Octstr **body_part, long content_pos)
void octstr_delete(Octstr *ostr1, long pos, long len)
Definition: octstr.c:1525
List * http_create_empty_headers(void)
Definition: http.c:2849
int octstr_ncompare(const Octstr *ostr1, const Octstr *ostr2, long n)
Definition: octstr.c:950
static long octstr_drop_leading_blanks(Octstr **header_value)
#define octstr_duplicate(ostr)
Definition: octstr.h:187
long octstr_case_search(const Octstr *haystack, const Octstr *needle, long pos)
Definition: octstr.c:1100
char * name
Definition: smsc_cimd2.c:212
void warning(int err, const char *fmt,...)
Definition: log.c:624
static int drop_optional_header(Octstr **body_part, char *name, Octstr *boundary)
void octstr_destroy(Octstr *ostr)
Definition: octstr.c:322
#define octstr_create(cstr)
Definition: octstr.h:125
static long pass_field_name(Octstr **body_part, Octstr **content_header, long pos)
gw_assert(wtls_machine->packet_to_send!=NULL)
static long parse_field_value(Octstr *pap_content, long pos)
static long parse_close_delimiter(Octstr *close_delimiter, Octstr *mime_content, long pos)
static int is_cr(int c)
long octstr_len(const Octstr *ostr)
Definition: octstr.c:340
Definition: octstr.c:118
static int pass_optional_header(Octstr **body_part, char *name, List **content_headers, Octstr *boundary)
static int parse_preamble(Octstr **mime_content, Octstr *boundary)
void octstr_format_append(Octstr *os, const char *fmt,...)
Definition: octstr.c:2505
static int pass_data_headers(Octstr **body_part, List **data_headers)
int octstr_get_char(const Octstr *ostr, long pos)
Definition: octstr.c:404
static int parse_tail(Octstr **multipart, Octstr *part_delimiter, long boundary_pos, long *next_part_pos)
Definition: list.c:102
int mime_parse(Octstr *boundary, Octstr *mime_content, Octstr **pap_content, Octstr **push_data, List **content_headers, Octstr **rdf_content)
static int start
static int drop_extension_headers(Octstr **mime_content, Octstr *boundary)
static int check_control_content_type_header(Octstr **body_part, Octstr *boundary)
static int parse_encapsulation(Octstr **mime_content, Octstr *boundary, Octstr **push_data, List **content_headers, Octstr **rdf_content)
See file LICENSE for details about the license agreement for using, modifying, copying or deriving work from this software.