Coverage Report

Created: 2023-11-19 07:03

/src/opensips/parser/parse_disposition.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright (C) 2001-2003 FhG Fokus
3
 *
4
 * This file is part of opensips, a free SIP server.
5
 *
6
 * opensips is free software; you can redistribute it and/or modify
7
 * it under the terms of the GNU General Public License as published by
8
 * the Free Software Foundation; either version 2 of the License, or
9
 * (at your option) any later version
10
 *
11
 * opensips is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 * GNU General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU General Public License
17
 * along with this program; if not, write to the Free Software
18
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
19
 *
20
 * History:
21
 * 2003-09-09 created (bogdan)
22
 */
23
24
25
#include <stdio.h>
26
#include <stdlib.h>
27
#include <sys/types.h>
28
#include <unistd.h>
29
#include "../mem/mem.h"
30
#include "../dprint.h"
31
#include "../ut.h"
32
#include "../errinfo.h"
33
#include "parse_disposition.h"
34
35
36
37
/* parse a string that supposed to be a disposition and fills up the structure
38
 * Returns: -2 : parse error
39
            -1 : error
40
 *           0 : success */
41
int parse_disposition( str *s, struct disposition *disp)
42
0
{
43
0
  enum { FIND_TYPE, TYPE, END_TYPE, FIND_PARAM, PARAM, END_PARAM, FIND_VAL,
44
0
         FIND_QUOTED_VAL, QUOTED_VAL, SKIP_QUOTED_VAL, VAL, END_VAL,
45
0
         F_LF, F_CR, F_CRLF};
46
0
  struct disposition_param *disp_p;
47
0
  struct disposition_param *new_p;
48
0
  int  state;
49
0
  int  saved_state;
50
0
  char *tmp;
51
0
  char *end;
52
53
0
  state = saved_state = FIND_TYPE;
54
0
  end = s->s + s->len;
55
0
  disp_p = 0;
56
57
0
  for( tmp=s->s; tmp<end; tmp++) {
58
0
    switch(*tmp) {
59
0
      case ' ':
60
0
      case '\t':
61
0
        switch (state) {
62
0
          case FIND_QUOTED_VAL:
63
0
            disp_p->body.s = tmp;
64
0
            state = QUOTED_VAL;
65
0
            break;
66
0
          case SKIP_QUOTED_VAL:
67
0
            state = QUOTED_VAL;
68
0
            break;
69
0
          case TYPE:
70
0
            disp->type.len = tmp - disp->type.s;
71
0
            state = END_TYPE;
72
0
            break;
73
0
          case PARAM:
74
0
            disp_p->name.len = tmp - disp_p->name.s;
75
0
            state = END_PARAM;
76
0
            break;
77
0
          case VAL:
78
0
            disp_p->body.len = tmp - disp_p->body.s;
79
0
            state = END_VAL;
80
0
            break;
81
0
          case F_CRLF:
82
0
          case F_LF:
83
0
          case F_CR:
84
            /*previous=crlf and now =' '*/
85
0
            state=saved_state;
86
0
            break;
87
0
        }
88
0
        break;
89
0
      case '\n':
90
0
        switch (state) {
91
0
          case TYPE:
92
0
            disp->type.len = tmp - disp->type.s;
93
0
            saved_state = END_TYPE;
94
0
            state = F_LF;
95
0
            break;
96
0
          case PARAM:
97
0
            disp_p->name.len = tmp - disp_p->name.s;
98
0
            saved_state = END_PARAM;
99
0
            state = F_LF;
100
0
            break;
101
0
          case VAL:
102
0
            disp_p->body.len = tmp - disp_p->body.s;
103
0
            saved_state = END_VAL;
104
0
            state = F_CR;
105
0
            break;
106
0
          case FIND_TYPE:
107
0
          case FIND_PARAM:
108
0
            saved_state=state;
109
0
            state=F_LF;
110
0
            break;
111
0
          case F_CR:
112
0
            state=F_CRLF;
113
0
            break;
114
0
          default:
115
0
            LM_ERR("unexpected char [%c] in status %d: <<%.*s>>"
116
0
                ".\n", *tmp,state, (int)(tmp-s->s), s->s);
117
0
            goto parse_error;
118
0
        }
119
0
        break;
120
0
      case '\r':
121
0
        switch (state) {
122
0
          case TYPE:
123
0
            disp->type.len = tmp - disp->type.s;
124
0
            saved_state = END_TYPE;
125
0
            state = F_CR;
126
0
            break;
127
0
          case PARAM:
128
0
            disp_p->name.len = tmp - disp_p->name.s;
129
0
            saved_state = END_PARAM;
130
0
            state = F_CR;
131
0
            break;
132
0
          case VAL:
133
0
            disp_p->body.len = tmp - disp_p->body.s;
134
0
            saved_state = END_VAL;
135
0
            state = F_CR;
136
0
            break;
137
0
          case FIND_TYPE:
138
0
          case FIND_PARAM:
139
0
            saved_state=state;
140
0
            state=F_CR;
141
0
            break;
142
0
          default:
143
0
            LM_ERR("unexpected char [%c] in status %d: <<%.*s>>"
144
0
              ".\n", *tmp,state, (int)(tmp-s->s), ZSW(s->s));
145
0
            goto parse_error;
146
0
        }
147
0
        break;
148
0
      case 0:
149
0
        LM_ERR("unexpected char [%c] in status %d: <<%.*s>> .\n",
150
0
          *tmp,state, (int)(tmp-s->s), ZSW(s->s));
151
0
        goto parse_error;
152
0
        break;
153
0
      case ';':
154
0
        switch (state) {
155
0
          case FIND_QUOTED_VAL:
156
0
            disp_p->body.s = tmp;
157
0
            state = QUOTED_VAL;
158
0
            break;
159
0
          case SKIP_QUOTED_VAL:
160
0
            state = QUOTED_VAL;
161
0
          case QUOTED_VAL:
162
0
            break;
163
0
          case VAL:
164
0
            disp_p->body.len = tmp - disp_p->body.s;
165
0
            state = FIND_PARAM;
166
0
            break;
167
0
          case PARAM:
168
0
            disp_p->name.len = tmp - disp_p->name.s;
169
0
            state = FIND_PARAM;
170
0
            break;
171
0
          case TYPE:
172
0
            disp->type.len = tmp - disp->type.s;
173
            /* fall through */
174
0
          case END_TYPE:
175
0
          case END_VAL:
176
0
            state = FIND_PARAM;
177
0
            break;
178
0
          default:
179
0
            LM_ERR("unexpected char [%c] in status %d: <<%.*s>> "
180
0
              ".\n", *tmp,state, (int)(tmp-s->s), ZSW(s->s));
181
0
            goto parse_error;
182
0
        }
183
0
        break;
184
0
      case '=':
185
0
        switch (state) {
186
0
          case FIND_QUOTED_VAL:
187
0
            disp_p->body.s = tmp;
188
0
            state = QUOTED_VAL;
189
0
            break;
190
0
          case SKIP_QUOTED_VAL:
191
0
            state = QUOTED_VAL;
192
0
          case QUOTED_VAL:
193
0
            break;
194
0
          case PARAM:
195
0
            disp_p->name.len = tmp - disp_p->name.s;
196
            /* fall through */
197
0
          case END_PARAM:
198
0
            state = FIND_VAL;
199
0
            break;
200
0
          default:
201
0
            LM_ERR("unexpected char [%c] in status %d: <<%.*s>>"
202
0
              ".\n", *tmp,state, (int)(tmp-s->s), ZSW(s->s));
203
0
            goto parse_error;
204
0
        }
205
0
        break;
206
0
      case '\"':
207
0
        switch (state) {
208
0
          case SKIP_QUOTED_VAL:
209
0
            state = QUOTED_VAL;
210
0
            break;
211
0
          case FIND_VAL:
212
0
            state = FIND_QUOTED_VAL;
213
0
            break;
214
0
          case QUOTED_VAL:
215
0
            disp_p->body.len = tmp - disp_p->body.s;
216
0
            disp_p->is_quoted = 1;
217
0
            state = END_VAL;
218
0
            break;
219
0
          default:
220
0
            LM_ERR("unexpected char [%c] in status %d: <<%.*s>>"
221
0
              ".\n", *tmp,state, (int)(tmp-s->s), ZSW(s->s));
222
0
            goto parse_error;
223
0
        }
224
0
        break;
225
0
      case '\\':
226
0
        switch (state) {
227
0
          case FIND_QUOTED_VAL:
228
0
            disp_p->body.s = tmp;
229
0
            state = SKIP_QUOTED_VAL;
230
0
            break;
231
0
          case SKIP_QUOTED_VAL:
232
0
            state = QUOTED_VAL;
233
0
            break;
234
0
          case QUOTED_VAL:
235
0
            state = SKIP_QUOTED_VAL;
236
0
            break;
237
0
          default:
238
0
            LM_ERR("unexpected char [%c] in status %d: <<%.*s>>"
239
0
              ".\n", *tmp,state, (int)(tmp-s->s), ZSW(s->s));
240
0
            goto parse_error;
241
0
        }
242
0
        break;
243
0
      case '(':
244
0
      case ')':
245
0
      case '<':
246
0
      case '>':
247
0
      case '@':
248
0
      case ',':
249
0
      case ':':
250
0
      case '/':
251
0
      case '[':
252
0
      case ']':
253
0
      case '?':
254
0
      case '{':
255
0
      case '}':
256
0
        switch (state) {
257
0
          case FIND_QUOTED_VAL:
258
0
            disp_p->body.s = tmp;
259
0
            state = QUOTED_VAL;
260
0
            break;
261
0
          case SKIP_QUOTED_VAL:
262
0
            state = QUOTED_VAL;
263
0
          case QUOTED_VAL:
264
0
            break;
265
0
          default:
266
0
            LM_ERR("unexpected char [%c] in status %d: <<%.*s>>"
267
0
              ".\n", *tmp,state, (int)(tmp-s->s), ZSW(s->s));
268
0
            goto parse_error;
269
0
        }
270
0
        break;
271
0
      default:
272
0
        switch (state) {
273
0
          case SKIP_QUOTED_VAL:
274
0
            state = QUOTED_VAL;
275
0
          case QUOTED_VAL:
276
0
            break;
277
0
          case FIND_TYPE:
278
0
            disp->type.s = tmp;
279
0
            state = TYPE;
280
0
            break;
281
0
          case FIND_PARAM:
282
0
            new_p=(struct disposition_param*)pkg_malloc
283
0
              (sizeof(struct disposition_param));
284
0
            if (new_p==0) {
285
0
              LM_ERR("no more pkg mem\n");
286
0
              goto error;
287
0
            }
288
0
            memset(new_p,0,sizeof(struct disposition_param));
289
0
            if (disp_p==0)
290
0
              disp->params = new_p;
291
0
            else
292
0
              disp_p->next = new_p;
293
0
            disp_p = new_p;
294
0
            disp_p->name.s = tmp;
295
0
            state = PARAM;
296
0
            break;
297
0
          case FIND_VAL:
298
0
            disp_p->body.s = tmp;
299
0
            state = VAL;
300
0
            break;
301
0
          case FIND_QUOTED_VAL:
302
0
            disp_p->body.s = tmp;
303
0
            state = QUOTED_VAL;
304
0
            break;
305
0
        }
306
0
    }/*switch*/
307
0
  }/*for*/
308
309
  /* check which was the last parser state */
310
0
  switch (state) {
311
0
    case END_PARAM:
312
0
    case END_TYPE:
313
0
    case END_VAL:
314
0
      break;
315
0
    case TYPE:
316
0
      disp->type.len = tmp - disp->type.s;
317
0
      break;
318
0
    case PARAM:
319
0
      disp_p->name.len = tmp - disp_p->name.s;
320
0
      break;
321
0
    case VAL:
322
0
      disp_p->body.len = tmp - disp_p->body.s;
323
0
      break;
324
0
    default:
325
0
      LM_ERR("wrong final state (%d)\n", state);
326
0
      goto parse_error;
327
0
  }
328
0
  return 0;
329
330
0
parse_error:
331
0
  return -2;
332
0
error:
333
0
  return -1;
334
0
}
335
336
337
338
/* Frees the entire disposition structure (params + itself) */
339
void free_disposition( struct disposition **disp)
340
0
{
341
0
  struct disposition_param *param;
342
343
  /* free the params */
344
0
  while((*disp)->params) {
345
0
    param = (*disp)->params->next;
346
0
    pkg_free( (*disp)->params);
347
0
    (*disp)->params = param;
348
0
  }
349
0
  pkg_free( *disp );
350
0
  *disp = 0;
351
0
}
352
353
354
355
/* looks inside the message, gets the Content-Disposition hdr, parse it, builds
356
 * and fills a disposition structure for it what will be attached to hdr as
357
 * parsed link.
358
 * Returns:  -1 : error
359
 *            0 : success
360
 *            1 : hdr not found
361
 */
362
int parse_content_disposition( struct sip_msg *msg )
363
0
{
364
0
  struct disposition *disp;
365
366
  /* look for Content-Disposition header */
367
0
  if (msg->content_disposition==0) {
368
0
    if (parse_headers(msg, HDR_CONTENTDISPOSITION_F, 0)==-1)
369
0
      goto error;
370
0
    if (msg->content_disposition==0) {
371
0
      LM_DBG("hdr not found\n");
372
0
      return 1;
373
0
    }
374
0
  }
375
376
  /* now, we have the header -> look if it isn't already parsed */
377
0
  if (msg->content_disposition->parsed!=0) {
378
    /* already parsed, nothing more to be done */
379
0
    return 0;
380
0
  }
381
382
  /* parse the body */
383
0
  disp = (struct disposition*)pkg_malloc(sizeof(struct disposition));
384
0
  if (disp==0) {
385
0
    LM_ERR("no more pkg memory\n");
386
0
    goto error;
387
0
  }
388
0
  memset(disp,0,sizeof(struct disposition));
389
390
0
  switch (parse_disposition( &(msg->content_disposition->body), disp)) {
391
0
    case -2:
392
0
      set_err_info(OSER_EC_PARSER, OSER_EL_MEDIUM,
393
0
        "error parsing DISPOSITION header");
394
0
      set_err_reply(400, "bad headers");
395
      /* fall through */
396
0
    case -1:
397
      /* error when parsing the body */
398
0
      free_disposition( &disp );
399
0
      goto error;
400
0
  }
401
402
  /* attach the parsed form to the header */
403
0
  msg->content_disposition->parsed = (void*)disp;
404
405
0
  return 0;
406
0
error:
407
0
  return -1;
408
0
}
409
410
411
/* Prints recursive a disposition structure */
412
void print_disposition( struct disposition *disp)
413
0
{
414
0
  struct disposition_param *param;
415
416
0
  LM_DBG("disposition type=<%.*s>[%d]\n",
417
0
    disp->type.len,disp->type.s,disp->type.len);
418
0
  for( param=disp->params; param; param=param->next) {
419
0
    LM_DBG("disposition param: <%.*s>[%d]=<%.*s>[%d] is_quoted=%d\n",
420
0
      param->name.len,param->name.s, param->name.len,
421
0
      param->body.len,param->body.s, param->body.len,
422
0
      param->is_quoted);
423
0
  }
424
0
}
425
426