parse_disposition.c 10 KB

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