parse_disposition.c

Go to the documentation of this file.
00001 /*
00002  * $Id$
00003  *
00004  *
00005  * Copyright (C) 2001-2003 FhG Fokus
00006  *
00007  * This file is part of ser, a free SIP server.
00008  *
00009  * ser is free software; you can redistribute it and/or modify
00010  * it under the terms of the GNU General Public License as published by
00011  * the Free Software Foundation; either version 2 of the License, or
00012  * (at your option) any later version
00013  *
00014  * ser is distributed in the hope that it will be useful,
00015  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00016  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00017  * GNU General Public License for more details.
00018  *
00019  * You should have received a copy of the GNU General Public License 
00020  * along with this program; if not, write to the Free Software 
00021  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00022  *
00023  * History:
00024  * 2003-09-09 created (bogdan)
00025  */
00026 
00034 #include <stdio.h>
00035 #include <stdlib.h>
00036 #include <sys/types.h>
00037 #include <unistd.h>
00038 #include "../mem/mem.h"
00039 #include "../dprint.h"
00040 #include "../ut.h"
00041 #include "parse_disposition.h"
00042 
00043 
00044 
00048 int parse_disposition( str *s, struct disposition *disp)
00049 {
00050         enum { FIND_TYPE, TYPE, END_TYPE, FIND_PARAM, PARAM, END_PARAM, FIND_VAL,
00051                FIND_QUOTED_VAL, QUOTED_VAL, SKIP_QUOTED_VAL, VAL, END_VAL,
00052                F_LF, F_CR, F_CRLF};
00053         struct disposition_param *disp_p;
00054         struct disposition_param *new_p;
00055         int  state;
00056         int  saved_state;
00057         char *tmp;
00058         char *end;
00059 
00060         state = saved_state = FIND_TYPE;
00061         end = s->s + s->len;
00062         disp_p = 0;
00063 
00064         for( tmp=s->s; tmp<end; tmp++) {
00065                 switch(*tmp) {
00066                         case ' ':
00067                         case '\t':
00068                                 switch (state) {
00069                                         case FIND_QUOTED_VAL:
00070                                                 disp_p->body.s = tmp;
00071                                                 state = QUOTED_VAL;
00072                                                 break;
00073                                         case SKIP_QUOTED_VAL:
00074                                                 state = QUOTED_VAL;
00075                                                 break;
00076                                         case TYPE:
00077                                                 disp->type.len = tmp - disp->type.s;
00078                                                 state = END_TYPE;
00079                                                 break;
00080                                         case PARAM:
00081                                                 disp_p->name.len = tmp - disp_p->name.s;
00082                                                 state = END_PARAM;
00083                                                 break;
00084                                         case VAL:
00085                                                 disp_p->body.len = tmp - disp_p->body.s;
00086                                                 state = END_VAL;
00087                                                 break;
00088                                         case F_CRLF:
00089                                         case F_LF:
00090                                         case F_CR:
00091                                                 /*previous=crlf and now =' '*/
00092                                                 state=saved_state;
00093                                                 break;
00094                                 }
00095                                 break;
00096                         case '\n':
00097                                 switch (state) {
00098                                         case TYPE:
00099                                                 disp->type.len = tmp - disp->type.s;
00100                                                 saved_state = END_TYPE;
00101                                                 state = F_LF;
00102                                                 break;
00103                                         case PARAM:
00104                                                 disp_p->name.len = tmp - disp_p->name.s;
00105                                                 saved_state = END_PARAM;
00106                                                 state = F_LF;
00107                                                 break;
00108                                         case VAL:
00109                                                 disp_p->body.len = tmp - disp_p->body.s;
00110                                                 saved_state = END_VAL;
00111                                                 state = F_CR;
00112                                                 break;
00113                                         case FIND_TYPE:
00114                                         case FIND_PARAM:
00115                                                 saved_state=state;
00116                                                 state=F_LF;
00117                                                 break;
00118                                         case F_CR:
00119                                                 state=F_CRLF;
00120                                                 break;
00121                                         default:
00122                                                 LOG(L_ERR,"ERROR:parse_disposition: unexpected "
00123                                                         "char [%c] in status %d: <<%.*s>> .\n",
00124                                                         *tmp,state, (int)(tmp-s->s), s->s);
00125                                                 goto error;
00126                                 }
00127                                 break;
00128                         case '\r':
00129                                 switch (state) {
00130                                         case TYPE:
00131                                                 disp->type.len = tmp - disp->type.s;
00132                                                 saved_state = END_TYPE;
00133                                                 state = F_CR;
00134                                                 break;
00135                                         case PARAM:
00136                                                 disp_p->name.len = tmp - disp_p->name.s;
00137                                                 saved_state = END_PARAM;
00138                                                 state = F_CR;
00139                                                 break;
00140                                         case VAL:
00141                                                 disp_p->body.len = tmp - disp_p->body.s;
00142                                                 saved_state = END_VAL;
00143                                                 state = F_CR;
00144                                                 break;
00145                                         case FIND_TYPE:
00146                                         case FIND_PARAM:
00147                                                 saved_state=state;
00148                                                 state=F_CR;
00149                                                 break;
00150                                         default:
00151                                                 LOG(L_ERR,"ERROR:parse_disposition: unexpected "
00152                                                         "char [%c] in status %d: <<%.*s>> .\n",
00153                                                         *tmp,state, (int)(tmp-s->s), ZSW(s->s));
00154                                                 goto error;
00155                                 }
00156                                 break;
00157                         case 0:
00158                                 LOG(L_ERR,"ERROR:parse_disposition: unexpected "
00159                                         "char [%c] in status %d: <<%.*s>> .\n",
00160                                         *tmp,state, (int)(tmp-s->s), ZSW(s->s));
00161                                 goto error;
00162                                 break;
00163                         case ';':
00164                                 switch (state) {
00165                                         case FIND_QUOTED_VAL:
00166                                                 disp_p->body.s = tmp;
00167                                                 state = QUOTED_VAL;
00168                                                 break;
00169                                         case SKIP_QUOTED_VAL:
00170                                                 state = QUOTED_VAL;
00171                                         case QUOTED_VAL:
00172                                                 break;
00173                                         case VAL:
00174                                                 disp_p->body.len = tmp - disp_p->body.s;
00175                                                 state = FIND_PARAM;
00176                                                 break;
00177                                         case PARAM:
00178                                                 disp_p->name.len = tmp - disp_p->name.s;
00179                                                 state = FIND_PARAM;
00180                                                 break;
00181                                         case TYPE:
00182                                                 disp->type.len = tmp - disp->type.s;
00183                                         case END_TYPE:
00184                                         case END_VAL:
00185                                                 state = FIND_PARAM;
00186                                                 break;
00187                                         default:
00188                                                 LOG(L_ERR,"ERROR:parse_disposition: unexpected "
00189                                                         "char [%c] in status %d: <<%.*s>> .\n",
00190                                                         *tmp,state, (int)(tmp-s->s), ZSW(s->s));
00191                                                 goto error;
00192                                 }
00193                                 break;
00194                         case '=':
00195                                 switch (state) {
00196                                         case FIND_QUOTED_VAL:
00197                                                 disp_p->body.s = tmp;
00198                                                 state = QUOTED_VAL;
00199                                                 break;
00200                                         case SKIP_QUOTED_VAL:
00201                                                 state = QUOTED_VAL;
00202                                         case QUOTED_VAL:
00203                                                 break;
00204                                         case PARAM:
00205                                                 disp_p->name.len = tmp - disp_p->name.s;
00206                                         case END_PARAM:
00207                                                 state = FIND_VAL;
00208                                                 break;
00209                                         default:
00210                                                 LOG(L_ERR,"ERROR:parse_disposition: unexpected "
00211                                                         "char [%c] in status %d: <<%.*s>> .\n",
00212                                                         *tmp,state, (int)(tmp-s->s), ZSW(s->s));
00213                                                 goto error;
00214                                 }
00215                                 break;
00216                         case '\"':
00217                                 switch (state) {
00218                                         case SKIP_QUOTED_VAL:
00219                                                 state = QUOTED_VAL;
00220                                                 break;
00221                                         case FIND_VAL:
00222                                                 state = FIND_QUOTED_VAL;
00223                                                 break;
00224                                         case QUOTED_VAL:
00225                                                 disp_p->body.len = tmp - disp_p->body.s;
00226                                                 disp_p->is_quoted = 1;
00227                                                 state = END_VAL;
00228                                                 break;
00229                                         default:
00230                                                 LOG(L_ERR,"ERROR:parse_disposition: unexpected "
00231                                                         "char [%c] in status %d: <<%.*s>> .\n",
00232                                                         *tmp,state, (int)(tmp-s->s), ZSW(s->s));
00233                                                 goto error;
00234                                 }
00235                                 break;
00236                         case '\\':
00237                                 switch (state) {
00238                                         case FIND_QUOTED_VAL:
00239                                                 disp_p->body.s = tmp;
00240                                                 state = SKIP_QUOTED_VAL;
00241                                                 break;
00242                                         case SKIP_QUOTED_VAL:
00243                                                 state = QUOTED_VAL;
00244                                                 break;
00245                                         case QUOTED_VAL:
00246                                                 state = SKIP_QUOTED_VAL;
00247                                                 break;
00248                                         default:
00249                                                 LOG(L_ERR,"ERROR:parse_disposition: unexpected "
00250                                                         "char [%c] in status %d: <<%.*s>> .\n",
00251                                                         *tmp,state, (int)(tmp-s->s), ZSW(s->s));
00252                                                 goto error;
00253                                 }
00254                                 break;
00255                         case '(':
00256                         case ')':
00257                         case '<':
00258                         case '>':
00259                         case '@':
00260                         case ',':
00261                         case ':':
00262                         case '/':
00263                         case '[':
00264                         case ']':
00265                         case '?':
00266                         case '{':
00267                         case '}':
00268                                 switch (state) {
00269                                         case FIND_QUOTED_VAL:
00270                                                 disp_p->body.s = tmp;
00271                                                 state = QUOTED_VAL;
00272                                                 break;
00273                                         case SKIP_QUOTED_VAL:
00274                                                 state = QUOTED_VAL;
00275                                         case QUOTED_VAL:
00276                                                 break;
00277                                         default:
00278                                                 LOG(L_ERR,"ERROR:parse_disposition: unexpected "
00279                                                         "char [%c] in status %d: <<%.*s>> .\n",
00280                                                         *tmp,state, (int)(tmp-s->s), ZSW(s->s));
00281                                                 goto error;
00282                                 }
00283                                 break;
00284                         default:
00285                                 switch (state) {
00286                                         case SKIP_QUOTED_VAL:
00287                                                 state = QUOTED_VAL;
00288                                         case QUOTED_VAL:
00289                                                 break;
00290                                         case FIND_TYPE:
00291                                                 disp->type.s = tmp;
00292                                                 state = TYPE;
00293                                                 break;
00294                                         case FIND_PARAM:
00295                                                 new_p=(struct disposition_param*)pkg_malloc
00296                                                         (sizeof(struct disposition_param));
00297                                                 if (new_p==0) {
00298                                                         LOG(L_ERR,"ERROR:parse_disposition: no more "
00299                                                                 "pkg mem\n");
00300                                                         goto error;
00301                                                 }
00302                                                 memset(new_p,0,sizeof(struct disposition_param));
00303                                                 if (disp_p==0)
00304                                                         disp->params = new_p;
00305                                                 else
00306                                                         disp_p->next = new_p;
00307                                                 disp_p = new_p;
00308                                                 disp_p->name.s = tmp;
00309                                                 state = PARAM;
00310                                                 break;
00311                                         case FIND_VAL:
00312                                                 disp_p->body.s = tmp;
00313                                                 state = VAL;
00314                                                 break;
00315                                         case FIND_QUOTED_VAL:
00316                                                 disp_p->body.s = tmp;
00317                                                 state = QUOTED_VAL;
00318                                                 break;
00319                                 }
00320                 }/*switch*/
00321         }/*for*/
00322 
00323         /* check which was the last parser state */
00324         switch (state) {
00325                 case END_PARAM:
00326                 case END_TYPE:
00327                 case END_VAL:
00328                         break;
00329                 case TYPE:
00330                         disp->type.len = tmp - disp->type.s;
00331                         break;
00332                 case PARAM:
00333                         disp_p->name.len = tmp - disp_p->name.s;
00334                         break;
00335                 case VAL:
00336                         disp_p->body.len = tmp - disp_p->body.s;
00337                         break;
00338                 default:
00339                         LOG(L_ERR,"ERROR:parse_disposition: wrong final state (%d)\n",
00340                                 state);
00341                         goto error;
00342         }
00343         return 0;
00344 error:
00345         return -1;
00346 }
00347 
00348 
00349 
00351 void free_disposition( struct disposition **disp)
00352 {
00353         struct disposition_param *param;
00354 
00355         /* free the params */
00356         while((*disp)->params) {
00357                 param = (*disp)->params->next;
00358                 pkg_free( (*disp)->params);
00359                 (*disp)->params = param;
00360         }
00361         pkg_free( *disp );
00362         *disp = 0;
00363 }
00364 
00365 
00366 
00374 int parse_content_disposition( struct sip_msg *msg )
00375 {
00376         struct disposition *disp;
00377 
00378         /* look for Content-Disposition header */
00379         if (msg->content_disposition==0) {
00380                 if (parse_headers(msg, HDR_CONTENTDISPOSITION_F, 0)==-1)
00381                         goto error;
00382                 if (msg->content_disposition==0) {
00383                         DBG("DEBUG:parse_content_disposition: hdr not found\n");
00384                         return 1;
00385                 }
00386         }
00387 
00388         /* now, we have the header -> look if it isn't already parsed */
00389         if (msg->content_disposition->parsed!=0) {
00390                 /* already parsed, nothing more to be done */
00391                 return 0;
00392         }
00393 
00394         /* parse the body */
00395         disp = (struct disposition*)pkg_malloc(sizeof(struct disposition));
00396         if (disp==0) {
00397                 LOG(L_ERR,"ERROR:parse_content_disposition: no more pkg memory\n");
00398                 goto error;
00399         }
00400         memset(disp,0,sizeof(struct disposition));
00401 
00402         if (parse_disposition( &(msg->content_disposition->body), disp)==-1) {
00403                 /* error when parsing the body */
00404                 free_disposition( &disp );
00405                 goto error;
00406         }
00407 
00408         /* attach the parsed form to the header */
00409         msg->content_disposition->parsed = (void*)disp;
00410 
00411         return 0;
00412 error:
00413         return -1;
00414 }
00415 
00416 
00418 void print_disposition( struct disposition *disp)
00419 {
00420         struct disposition_param *param;
00421 
00422         DBG("*** Disposition type=<%.*s>[%d]\n",
00423                 disp->type.len,disp->type.s,disp->type.len);
00424         for( param=disp->params; param; param=param->next) {
00425                 DBG("*** Disposition param: <%.*s>[%d]=<%.*s>[%d] is_quoted=%d\n",
00426                         param->name.len,param->name.s, param->name.len,
00427                         param->body.len,param->body.s, param->body.len,
00428                         param->is_quoted);
00429         }
00430 }
00431 
00432