parse_body.c

Go to the documentation of this file.
00001 /*
00002  * $Id$
00003  *
00004  * Copyright (C) 2008 iptelorg GmbH
00005  *
00006  * This file is part of ser, a free SIP server.
00007  *
00008  * ser is free software; you can redistribute it and/or modify
00009  * it under the terms of the GNU General Public License as published by
00010  * the Free Software Foundation; either version 2 of the License, or
00011  * (at your option) any later version
00012  *
00013  * For a license to use the ser software under conditions
00014  * other than those described here, or to purchase support for this
00015  * software, please contact iptel.org by e-mail at the following addresses:
00016  *    info@iptel.org
00017  *
00018  * ser is distributed in the hope that it will be useful,
00019  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00020  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00021  * GNU General Public License for more details.
00022  *
00023  * You should have received a copy of the GNU General Public License 
00024  * along with this program; if not, write to the Free Software 
00025  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00026  *
00027  * History:
00028  * --------
00029  *  2008-05-22  Initial version, get_body_part() is introduced (Miklos)
00030  */
00031 
00039 #include "../trim.h"
00040 #include "parser_f.h"
00041 #include "parse_content.h"
00042 #include "parse_param.h"
00043 #include "keys.h"
00044 #include "parse_body.h"
00045 
00047 static inline int get_boundary_param(struct sip_msg *msg, str *boundary)
00048 {
00049         str     s;
00050         char    *c;
00051         param_t *p, *list;
00052 
00053 #define is_boundary(c) \
00054         (((c)[0] == 'b' || (c)[0] == 'B') && \
00055         ((c)[1] == 'o' || (c)[1] == 'O') && \
00056         ((c)[2] == 'u' || (c)[2] == 'U') && \
00057         ((c)[3] == 'n' || (c)[3] == 'N') && \
00058         ((c)[4] == 'd' || (c)[4] == 'D') && \
00059         ((c)[5] == 'a' || (c)[5] == 'A') && \
00060         ((c)[6] == 'r' || (c)[6] == 'R') && \
00061         ((c)[7] == 'y' || (c)[7] == 'Y'))
00062 
00063 #define boundary_param_len (sizeof("boundary")-1)
00064 
00065         /* get the pointer to the beginning of the parameter list */
00066         s.s = msg->content_type->body.s;
00067         s.len = msg->content_type->body.len;
00068         c = find_not_quoted(&s, ';');
00069         if (!c)
00070                 return -1;
00071         c++;
00072         s.len = s.len - (c - s.s);
00073         s.s = c;
00074         trim_leading(&s);
00075 
00076         if (s.len <= 0)
00077                 return -1;
00078 
00079         /* parse the parameter list, and search for boundary */
00080         if (parse_params(&s, CLASS_ANY, NULL, &list)<0)
00081                 return -1;
00082 
00083         boundary->s = NULL;
00084         for (p = list; p; p = p->next)
00085                 if ((p->name.len == boundary_param_len) &&
00086                         is_boundary(p->name.s)
00087                 ) {
00088                         boundary->s = p->body.s;
00089                         boundary->len = p->body.len;
00090                         break;
00091                 }
00092         free_params(list);
00093         if (!boundary->s || !boundary->len)
00094                 return -1;
00095 
00096         DBG("boundary is \"%.*s\"\n",
00097                 boundary->len, boundary->s);
00098         return 0;
00099 }
00100 
00102 static inline char *search_boundary(char *buf, char *buf_end, str *boundary)
00103 {
00104         char *c;
00105 
00106         c = buf;
00107         while (c + 2 /* -- */ + boundary->len < buf_end) {
00108                 if ((*c == '-') && (*(c+1) == '-') &&
00109                         (memcmp(c+2, boundary->s, boundary->len) == 0)
00110                 )
00111                         return c; /* boundary found */
00112 
00113                 /* go to the next line */
00114                 while ((c < buf_end) && (*c != '\n')) c++;
00115                 c++;
00116         }
00117         return NULL;
00118 }
00119 
00121 inline static char *get_multipart_body(char *buf,
00122                                         char *buf_end,
00123                                         str *boundary,
00124                                         int *len)
00125 {
00126         char *beg, *end;
00127 
00128         if (buf >= buf_end)
00129                 goto error;
00130 
00131         beg = buf;
00132         while ((*beg != '\r') && (*beg != '\n')) {
00133                 while ((beg < buf_end) && (*beg != '\n'))
00134                         beg++;
00135                 beg++;
00136                 if (beg >= buf_end)
00137                         goto error;
00138         }
00139         /* CRLF delimeter found, the body begins right after it */
00140         while ((beg < buf_end) && (*beg != '\n'))
00141                 beg++;
00142         beg++;
00143         if (beg >= buf_end)
00144                 goto error;
00145 
00146         if (!(end = search_boundary(beg, buf_end, boundary)))
00147                 goto error;
00148 
00149         /* CRLF preceding the boundary belongs to the boundary
00150         and not to the body */
00151         if (*(end-1) == '\n') end--;
00152         if (*(end-1) == '\r') end--;
00153 
00154         if (end < beg)
00155                 goto error;
00156 
00157         *len = end-beg;
00158         return beg;
00159 error:
00160         ERR("failed to extract the body from the multipart mime type\n");
00161         return NULL;
00162 }
00163 
00164 
00166 #define READ(val) \
00167 (*(val + 0) + (*(val + 1) << 8) + (*(val + 2) << 16) + (*(val + 3) << 24))
00168 
00169 #define LOWER_DWORD(d) ((d) | 0x20202020)
00170 
00175 char *get_body_part(    struct sip_msg *msg,
00176                         unsigned short type, unsigned short subtype,
00177                         int *len)
00178 {
00179         int     mime;
00180         unsigned int    umime;
00181         char    *c, *c2, *buf_end;
00182         str     boundary;
00183 
00184 #define content_type_len \
00185         (sizeof("Content-Type") - 1)
00186 
00187         if ((mime = parse_content_type_hdr(msg)) <= 0)
00188                 return NULL;
00189 
00190         if (mime == ((type<<16)|subtype)) {
00191                 /* content-type is type/subtype */
00192                 c = get_body(msg);
00193                 if (c)
00194                         *len = msg->buf+msg->len - c;
00195                 return c;
00196 
00197         } else if ((mime>>16) == TYPE_MULTIPART) {
00198                 /* type is multipart/something, search for type/subtype part */
00199 
00200                 if (get_boundary_param(msg, &boundary)) {
00201                         ERR("failed to get boundary parameter\n");
00202                         return NULL;
00203                 }
00204                 if (!(c = get_body(msg)))
00205                         return NULL;
00206                 buf_end = msg->buf+msg->len;
00207 
00208                 /* check all the body parts delimated by the boundary value,
00209                 and search for the Content-Type HF with the given 
00210                 type/subtype */
00211 next_part:
00212                 while ((c = search_boundary(c, buf_end, &boundary))) {
00213                         /* skip boundary */
00214                         c += 2 + boundary.len;
00215 
00216                         if ((c+2 > buf_end) ||
00217                                 ((*c == '-') && (*(c+1) == '-'))
00218                         )
00219                                 /* end boundary, no more body part
00220                                 will follow */
00221                                 return NULL;
00222 
00223                         /* go to the next line */
00224                         while ((c < buf_end) && (*c != '\n')) c++;
00225                         c++;
00226                         if (c >= buf_end)
00227                                 return NULL;
00228 
00229                         /* try to find the content-type header */
00230                         while ((*c != '\r') && (*c != '\n')) {
00231                                 if (c + content_type_len >= buf_end)
00232                                         return NULL;
00233 
00234                                 if ((LOWER_DWORD(READ(c)) == _cont_) &&
00235                                         (LOWER_DWORD(READ(c+4)) == _ent__) &&
00236                                         (LOWER_DWORD(READ(c+8)) == _type_)
00237                                 ) {
00238                                         /* Content-Type HF found */
00239                                         c += content_type_len;
00240                                         while ((c < buf_end) &&
00241                                                 ((*c == ' ') || (*c == '\t'))
00242                                         )
00243                                                 c++;
00244 
00245                                         if (c + 1 /* : */ >= buf_end)
00246                                                 return NULL;
00247 
00248                                         if (*c != ':')
00249                                                 /* not realy a Content-Type HF */
00250                                                 goto next_hf;
00251                                         c++;
00252 
00253                                         /* search the end of the header body,
00254                                         decode_mime_type() needs it */
00255                                         c2 = c;
00256                                         while (((c2 < buf_end) && (*c2 != '\n')) ||
00257                                                 ((c2+1 < buf_end) && (*c2 == '\n') &&
00258                                                         ((*(c2+1) == ' ') || (*(c2+1) == '\t')))
00259                                         )
00260                                                 c2++;
00261 
00262                                         if (c2 >= buf_end)
00263                                                 return NULL;
00264                                         if (*(c2-1) == '\r') c2--;
00265 
00266                                         if (!decode_mime_type(c, c2 , &umime)) {
00267                                                 ERR("failed to decode the mime type\n");
00268                                                 return NULL;
00269                                         }
00270 
00271                                         /* c2 points to the CRLF at the end of the line,
00272                                         move the pointer to the beginning of the next line */
00273                                         c = c2;
00274                                         if ((c < buf_end) && (*c == '\r')) c++;
00275                                         if ((c < buf_end) && (*c == '\n')) c++;
00276 
00277                                         if (umime != ((type<<16)|subtype)) {
00278                                                 /* this is not the part we are looking for */
00279                                                 goto next_part;
00280                                         }
00281 
00282                                         /* the requested type/subtype is found! */
00283                                         return get_multipart_body(c,
00284                                                         buf_end,
00285                                                         &boundary,
00286                                                         len);
00287                                 }
00288 next_hf:
00289                                 /* go to the next line */
00290                                 while ((c < buf_end) && (*c != '\n')) c++;
00291                                 c++;
00292                         }
00293                         /* CRLF delimeter reached,
00294                         no Content-Type HF was found */
00295                 }
00296         }
00297         return NULL;
00298 }