/* * $Id$ * * * Copyright (C) 2001-2003 FhG Fokus * * This file is part of ser, a free SIP server. * * ser is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version * * ser is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: * 2003-08-04 parse_content_type_hdr separates type from subtype inside * the mime type (bogdan) * 2003-08-04 CPL subtype added (bogdan) * 2003-08-05 parse_accept_hdr function added (bogdan) * 2008-05-23 reset the type/subtype to unknown, if the end of * tree has reached, but the type/subtype has still * some remaining characters (Miklos) */ /*! \file * \brief Parser :: Content part * * \ingroup parser */ #include #include #include #include #include "../mem/mem.h" #include "../dprint.h" #include "../str.h" #include "../ut.h" #include "parse_content.h" #define is_mime_char(_c_) \ (isalpha((int)_c_) || (_c_)=='-' || (_c_)=='+' || (_c_)=='.') #define is_char_equal(_c_,_cs_) \ ( (isalpha((int)_c_)?(((_c_)|0x20)==(_cs_)):((_c_)==(_cs_)))==1 ) /*! \brief * Node of the type's tree; this tree contains all the known types; */ typedef struct type_node_s { char c; /*!< char contained by this node */ unsigned char final; /*!< says what mime type/subtype was detected *!< if string ends at this node */ unsigned char nr_sons; /*!< the number of sub-nodes */ int next; /*!< the next sibling node */ }type_node_t; static type_node_t type_tree[] = { {'t',TYPE_UNKNOWN,1,4}, /* 0 */ {'e',TYPE_UNKNOWN,1,-1}, {'x',TYPE_UNKNOWN,1,-1}, {'t',TYPE_TEXT,0,-1}, {'m',TYPE_UNKNOWN,2,19}, /* 4 */ {'e',TYPE_UNKNOWN,1,11}, /* 5 */ {'s',TYPE_UNKNOWN,1,-1}, {'s',TYPE_UNKNOWN,1,-1}, {'a',TYPE_UNKNOWN,1,-1}, {'g',TYPE_UNKNOWN,1,-1}, {'e',TYPE_MESSAGE,0,-1}, {'u',TYPE_UNKNOWN,1,-1}, /* 11 */ {'l',TYPE_UNKNOWN,1,-1}, {'t',TYPE_UNKNOWN,1,-1}, {'i',TYPE_UNKNOWN,1,-1}, {'p',TYPE_UNKNOWN,1,-1}, {'a',TYPE_UNKNOWN,1,-1}, {'r',TYPE_UNKNOWN,1,-1}, {'t',TYPE_MULTIPART,0,-1}, {'a',TYPE_UNKNOWN,1,-1}, /* 19 */ {'p',TYPE_UNKNOWN,1,-1}, {'p',TYPE_UNKNOWN,1,-1}, {'l',TYPE_UNKNOWN,1,-1}, {'i',TYPE_UNKNOWN,1,-1}, {'c',TYPE_UNKNOWN,1,-1}, {'a',TYPE_UNKNOWN,1,-1}, {'t',TYPE_UNKNOWN,1,-1}, {'i',TYPE_UNKNOWN,1,-1}, {'o',TYPE_UNKNOWN,1,-1}, {'n',TYPE_APPLICATION,0,-1}, }; static type_node_t subtype_tree[] = { {'p',SUBTYPE_UNKNOWN,2,13}, {'l',SUBTYPE_UNKNOWN,1,5}, {'a',SUBTYPE_UNKNOWN,1,-1}, {'i',SUBTYPE_UNKNOWN,1,-1}, {'n',SUBTYPE_PLAIN,0,-1}, {'i',SUBTYPE_UNKNOWN,1,-1}, /* 5 */ {'d',SUBTYPE_UNKNOWN,1,-1}, {'f',SUBTYPE_UNKNOWN,1,-1}, {'+',TYPE_UNKNOWN,1,-1}, {'x',TYPE_UNKNOWN,1,-1}, {'m',TYPE_UNKNOWN,1,-1}, {'l',SUBTYPE_PIDFXML,0,-1}, {'l',SUBTYPE_PIDFXML,0,-1}, {'s',SUBTYPE_UNKNOWN,1,16}, /* 13 */ {'d',SUBTYPE_UNKNOWN,1,-1}, {'p',SUBTYPE_SDP,0,-1}, {'c',SUBTYPE_UNKNOWN,1,34}, /* 16 */ {'p',SUBTYPE_UNKNOWN,2,-1}, {'i',SUBTYPE_UNKNOWN,1,29}, {'m',SUBTYPE_CPIM,1,-1}, {'-',SUBTYPE_UNKNOWN,1,-1}, {'p',SUBTYPE_UNKNOWN,1,-1}, {'i',SUBTYPE_UNKNOWN,1,-1}, {'d',SUBTYPE_UNKNOWN,1,-1}, {'f',SUBTYPE_UNKNOWN,1,-1}, {'+',SUBTYPE_UNKNOWN,1,-1}, {'x',SUBTYPE_UNKNOWN,1,-1}, {'m',SUBTYPE_UNKNOWN,1,-1}, {'l',SUBTYPE_CPIM_PIDFXML,0,-1}, {'l',SUBTYPE_UNKNOWN,1,-1}, /* 29 */ {'+',TYPE_UNKNOWN,1,-1}, {'x',TYPE_UNKNOWN,1,-1}, {'m',TYPE_UNKNOWN,1,-1}, {'l',SUBTYPE_CPLXML,0,-1}, {'r',SUBTYPE_UNKNOWN,2,48}, /* 34 */ {'l',SUBTYPE_UNKNOWN,1,42},/* 35 */ {'m',SUBTYPE_UNKNOWN,1,-1}, {'i',SUBTYPE_UNKNOWN,1,-1}, {'+',TYPE_UNKNOWN,1,-1}, {'x',TYPE_UNKNOWN,1,-1}, {'m',TYPE_UNKNOWN,1,-1}, {'l',SUBTYPE_RLMIXML,0,-1}, {'e',SUBTYPE_UNKNOWN,1,-1}, /* 42 */ {'l',SUBTYPE_UNKNOWN,1,-1}, {'a',SUBTYPE_UNKNOWN,1,-1}, {'t',SUBTYPE_UNKNOWN,1,-1}, {'e',SUBTYPE_UNKNOWN,1,-1}, {'d',SUBTYPE_RELATED,0,-1}, {'l',SUBTYPE_UNKNOWN,1,57}, /* 48 */ {'p',SUBTYPE_UNKNOWN,1,-1}, {'i',SUBTYPE_UNKNOWN,1,-1}, {'d',SUBTYPE_UNKNOWN,1,-1}, {'f',SUBTYPE_UNKNOWN,1,-1}, {'+',SUBTYPE_UNKNOWN,1,-1}, {'x',SUBTYPE_UNKNOWN,1,-1}, {'m',SUBTYPE_UNKNOWN,1,-1}, {'l',SUBTYPE_LPIDFXML,0,-1}, {'w',SUBTYPE_UNKNOWN,1,72}, /* 57 */ {'a',SUBTYPE_UNKNOWN,1,-1}, {'t',SUBTYPE_UNKNOWN,1,-1}, {'c',SUBTYPE_UNKNOWN,1,-1}, {'h',SUBTYPE_UNKNOWN,1,-1}, {'e',SUBTYPE_UNKNOWN,1,-1}, {'r',SUBTYPE_UNKNOWN,1,-1}, {'i',TYPE_UNKNOWN,1,-1}, {'n',TYPE_UNKNOWN,1,-1}, {'f',TYPE_UNKNOWN,1,-1}, {'o',TYPE_UNKNOWN,1,-1}, {'+',TYPE_UNKNOWN,1,-1}, {'x',TYPE_UNKNOWN,1,-1}, {'m',TYPE_UNKNOWN,1,-1}, {'l',SUBTYPE_WATCHERINFOXML,0,-1}, {'x',SUBTYPE_UNKNOWN,2,94}, /* 72 */ {'p',SUBTYPE_UNKNOWN,1,81}, /* 73 */ {'i',SUBTYPE_UNKNOWN,1,-1}, {'d',SUBTYPE_UNKNOWN,1,-1}, {'f',SUBTYPE_UNKNOWN,1,-1}, {'+',SUBTYPE_UNKNOWN,1,-1}, {'x',SUBTYPE_UNKNOWN,1,-1}, {'m',SUBTYPE_UNKNOWN,1,-1}, {'l',SUBTYPE_XPIDFXML,0,-1}, {'m',SUBTYPE_UNKNOWN,1,-1}, /* 81 */ {'l',SUBTYPE_UNKNOWN,1,-1}, {'+',SUBTYPE_UNKNOWN,1,-1}, {'m',SUBTYPE_UNKNOWN,1,-1}, {'s',SUBTYPE_UNKNOWN,1,-1}, {'r',SUBTYPE_UNKNOWN,1,-1}, {'t',SUBTYPE_UNKNOWN,1,-1}, {'c',SUBTYPE_UNKNOWN,1,-1}, {'.',SUBTYPE_UNKNOWN,1,-1}, {'p',SUBTYPE_UNKNOWN,1,-1}, {'i',SUBTYPE_UNKNOWN,1,-1}, {'d',SUBTYPE_UNKNOWN,1,-1}, {'f',SUBTYPE_XML_MSRTC_PIDF,0,-1}, {'e',SUBTYPE_UNKNOWN,1,107}, /* 94 */ {'x',SUBTYPE_UNKNOWN,1,-1}, {'t',SUBTYPE_UNKNOWN,1,-1}, {'e',SUBTYPE_UNKNOWN,1,-1}, {'r',SUBTYPE_UNKNOWN,1,-1}, {'n',SUBTYPE_UNKNOWN,1,-1}, {'a',SUBTYPE_UNKNOWN,1,-1}, {'l',SUBTYPE_UNKNOWN,1,-1}, {'-',SUBTYPE_UNKNOWN,1,-1}, {'b',SUBTYPE_UNKNOWN,1,-1}, {'o',SUBTYPE_UNKNOWN,1,-1}, {'d',SUBTYPE_UNKNOWN,1,-1}, {'y',SUBTYPE_EXTERNAL_BODY,0,-1}, {'m',SUBTYPE_UNKNOWN,1,-1}, /* 107 */ {'i',SUBTYPE_UNKNOWN,1,-1}, {'x',SUBTYPE_UNKNOWN,1,-1}, {'e',SUBTYPE_UNKNOWN,1,-1}, {'d',SUBTYPE_MIXED,0,-1}, }; char* parse_content_length( char* buffer, char* end, int* length) { int number; char *p; int size; p = buffer; /* search the begining of the number */ while ( p='0' && *p<='9') { number = number*10 + (*p)-'0'; size ++; p++; } if (p==end || size==0) goto error; /* now we should have only spaces at the end */ while ( p eat everything to * the end or to the first ',' */ if ( p>16==TYPE_ALL && ((*mime_type)&0x00ff)!=SUBTYPE_ALL) { LOG(L_ERR,"ERROR:decode_mime_type: invalid mime format found " " <*/submime> in [%.*s]!!\n", (int)(end-start),start); return 0; } return p; error: LOG(L_ERR,"ERROR:decode_mime_type: parse error near in [%.*s] char" "[%d][%c] offset=%d\n", (int)(end-start),start,*p,*p,(int)(p-start)); return 0; } /*! \brief * \return * - > 0 mime found * - = 0 hdr not found * - =-1 error */ int parse_content_type_hdr( struct sip_msg *msg ) { char *end; char *ret; unsigned int mime; /* is the header already found? */ if ( msg->content_type==0 ) { /* if not, found it */ if ( parse_headers(msg, HDR_CONTENTTYPE_F, 0)==-1) goto error; if ( msg->content_type==0 ) { DBG("DEBUG:parse_content_type_hdr: missing Content-Type" "header\n"); return 0; } } /* maybe the header is already parsed! */ if ( msg->content_type->parsed!=0) return get_content_type(msg); /* it seams we have to parse it! :-( */ end = msg->content_type->body.s + msg->content_type->body.len; ret = decode_mime_type(msg->content_type->body.s, end , &mime); if (ret==0) goto error; if (ret!=end) { LOG(L_ERR,"ERROR:parse_content_type_hdr: CONTENT_TYPE hdr contains " "more then one mime type :-(!\n"); goto error; } if ((mime&0x00ff)==SUBTYPE_ALL || (mime>>16)==TYPE_ALL) { LOG(L_ERR,"ERROR:parse_content_type_hdr: invalid mime with wildcard " "'*' in Content-Type hdr!\n"); goto error; } msg->content_type->parsed = (void*)(unsigned long)mime; return mime; error: return -1; } int parse_accept_body(struct hdr_field *hdr) { static unsigned int mimes[MAX_MIMES_NR]; int nr_mimes; unsigned int mime; char *end; char *ret; if (!hdr) return -1; /* maybe the header is already parsed! */ if (hdr->parsed!=0) return 1; /* it seams we have to parse it! :-( */ ret = hdr->body.s; end = ret + hdr->body.len; nr_mimes = 0; while (1){ ret = decode_mime_type(ret, end , &mime); if (ret==0) goto error; /* a new mime was found -> put it into array */ if (nr_mimes==MAX_MIMES_NR) { LOG(L_ERR,"ERROR:parse_accept_hdr: Accept hdr contains more than" " %d mime type -> buffer overflow!!\n",MAX_MIMES_NR); goto error; } mimes[nr_mimes++] = mime; /* is another mime following? */ if (ret==end ) break; /* parse the mime separator ',' */ if (*ret!=',' || ret+1==end) { LOG(L_ERR,"ERROR:parse_accept_hdr: parse error between mimes at " "char <%x> (offset=%d) in <%.*s>!\n", *ret, (int)(ret-hdr->body.s), hdr->body.len, hdr->body.s); goto error; } /* skip the ',' */ ret++; } /* copy and link the mime buffer into the message */ hdr->parsed = (void*)pkg_malloc((nr_mimes+1)*sizeof(int)); if (hdr->parsed==0) { LOG(L_ERR,"ERROR:parse_accept: no more pkg memory\n"); goto error; } memcpy(hdr->parsed,mimes,nr_mimes*sizeof(int)); /* make the buffer null terminated */ ((int*)hdr->parsed)[nr_mimes] = 0; return 1; error: return -1; } /*! \brief * returns: > 0 ok * = 0 hdr not found * = -1 error */ int parse_accept_hdr( struct sip_msg *msg ) { static unsigned int mimes[MAX_MIMES_NR]; int nr_mimes; unsigned int mime; char *end; char *ret; /* is the header already found? */ if ( msg->accept==0 ) { /* if not, found it */ if ( parse_headers(msg, HDR_ACCEPT_F, 0)==-1) goto error; if ( msg->accept==0 ) { DBG("DEBUG:parse_accept_hdr: missing Accept header\n"); return 0; } } /* maybe the header is already parsed! */ if ( msg->accept->parsed!=0) return 1; /* it seams we have to parse it! :-( */ ret = msg->accept->body.s; end = ret + msg->accept->body.len; nr_mimes = 0; while (1){ ret = decode_mime_type(ret, end , &mime); if (ret==0) goto error; /* a new mime was found -> put it into array */ if (nr_mimes==MAX_MIMES_NR) { LOG(L_ERR,"ERROR:parse_accept_hdr: Accept hdr contains more than" " %d mime type -> buffer overflow!!\n",MAX_MIMES_NR); goto error; } mimes[nr_mimes++] = mime; /* is another mime following? */ if (ret==end ) break; /* parse the mime separator ',' */ if (*ret!=',' || ret+1==end) { LOG(L_ERR,"ERROR:parse_accept_hdr: parse error between mimes at " "char <%x> (offset=%d) in <%.*s>!\n", *ret, (int)(ret-msg->accept->body.s), msg->accept->body.len, msg->accept->body.s); goto error; } /* skip the ',' */ ret++; } /* copy and link the mime buffer into the message */ msg->accept->parsed = (void*)pkg_malloc((nr_mimes+1)*sizeof(int)); if (msg->accept->parsed==0) { LOG(L_ERR,"ERROR:parse_accept_hdr: no more pkg memory\n"); goto error; } memcpy(msg->accept->parsed,mimes,nr_mimes*sizeof(int)); /* make the buffer null terminated */ ((int*)msg->accept->parsed)[nr_mimes] = 0; return 1; error: return -1; }