/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 | | |