parse_body.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595
  1. /*
  2. * Copyright (C) 2008 iptelorg GmbH
  3. *
  4. * This file is part of ser, a free SIP server.
  5. *
  6. * ser 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. * For a license to use the ser software under conditions
  12. * other than those described here, or to purchase support for this
  13. * software, please contact iptel.org by e-mail at the following addresses:
  14. * [email protected]
  15. *
  16. * ser is distributed in the hope that it will be useful,
  17. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  18. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  19. * GNU General Public License for more details.
  20. *
  21. * You should have received a copy of the GNU General Public License
  22. * along with this program; if not, write to the Free Software
  23. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  24. *
  25. * History:
  26. * --------
  27. * 2008-05-22 Initial version, get_body_part() is introduced (Miklos)
  28. */
  29. /*! \file
  30. * \brief Parser :: Body handling
  31. *
  32. * \ingroup parser
  33. */
  34. #include "../trim.h"
  35. #include "parser_f.h"
  36. #include "parse_content.h"
  37. #include "parse_param.h"
  38. #include "keys.h"
  39. #include "parse_body.h"
  40. /*! \brief returns the value of boundary parameter from the Contect-Type HF */
  41. static inline int get_boundary_param(struct sip_msg *msg, str *boundary)
  42. {
  43. str s;
  44. char *c;
  45. param_t *p, *list;
  46. #define is_boundary(c) \
  47. (((c)[0] == 'b' || (c)[0] == 'B') && \
  48. ((c)[1] == 'o' || (c)[1] == 'O') && \
  49. ((c)[2] == 'u' || (c)[2] == 'U') && \
  50. ((c)[3] == 'n' || (c)[3] == 'N') && \
  51. ((c)[4] == 'd' || (c)[4] == 'D') && \
  52. ((c)[5] == 'a' || (c)[5] == 'A') && \
  53. ((c)[6] == 'r' || (c)[6] == 'R') && \
  54. ((c)[7] == 'y' || (c)[7] == 'Y'))
  55. #define boundary_param_len (sizeof("boundary")-1)
  56. /* get the pointer to the beginning of the parameter list */
  57. s.s = msg->content_type->body.s;
  58. s.len = msg->content_type->body.len;
  59. c = find_not_quoted(&s, ';');
  60. if (!c)
  61. return -1;
  62. c++;
  63. s.len = s.len - (c - s.s);
  64. s.s = c;
  65. trim_leading(&s);
  66. if (s.len <= 0)
  67. return -1;
  68. /* parse the parameter list, and search for boundary */
  69. if (parse_params(&s, CLASS_ANY, NULL, &list)<0)
  70. return -1;
  71. boundary->s = NULL;
  72. for (p = list; p; p = p->next)
  73. if ((p->name.len == boundary_param_len) &&
  74. is_boundary(p->name.s)
  75. ) {
  76. boundary->s = p->body.s;
  77. boundary->len = p->body.len;
  78. break;
  79. }
  80. free_params(list);
  81. if (!boundary->s || !boundary->len)
  82. return -1;
  83. DBG("boundary is \"%.*s\"\n",
  84. boundary->len, boundary->s);
  85. return 0;
  86. }
  87. /*! \brief search the next boundary in the buffer */
  88. static inline char *search_boundary(char *buf, char *buf_end, str *boundary)
  89. {
  90. char *c;
  91. c = buf;
  92. while (c + 2 /* -- */ + boundary->len < buf_end) {
  93. if ((*c == '-') && (*(c+1) == '-') &&
  94. (memcmp(c+2, boundary->s, boundary->len) == 0)
  95. )
  96. return c; /* boundary found */
  97. /* go to the next line */
  98. while ((c < buf_end) && (*c != '\n')) c++;
  99. c++;
  100. }
  101. return NULL;
  102. }
  103. /*! \brief extract the body of a part from a multipart SIP msg body */
  104. inline static char *get_multipart_body(char *buf,
  105. char *buf_end,
  106. str *boundary,
  107. int *len)
  108. {
  109. char *beg, *end;
  110. if (buf >= buf_end)
  111. goto error;
  112. beg = buf;
  113. while ((*beg != '\r') && (*beg != '\n')) {
  114. while ((beg < buf_end) && (*beg != '\n'))
  115. beg++;
  116. beg++;
  117. if (beg >= buf_end)
  118. goto error;
  119. }
  120. /* CRLF delimeter found, the body begins right after it */
  121. while ((beg < buf_end) && (*beg != '\n'))
  122. beg++;
  123. beg++;
  124. if (beg >= buf_end)
  125. goto error;
  126. if (!(end = search_boundary(beg, buf_end, boundary)))
  127. goto error;
  128. /* CRLF preceding the boundary belongs to the boundary
  129. and not to the body */
  130. if (*(end-1) == '\n') end--;
  131. if (*(end-1) == '\r') end--;
  132. if (end < beg)
  133. goto error;
  134. *len = end-beg;
  135. return beg;
  136. error:
  137. ERR("failed to extract the body from the multipart mime type\n");
  138. return NULL;
  139. }
  140. /*! \brief macros from parse_hname2.c */
  141. #define READ(val) \
  142. (*(val + 0) + (*(val + 1) << 8) + (*(val + 2) << 16) + (*(val + 3) << 24))
  143. #define LOWER_DWORD(d) ((d) | 0x20202020)
  144. /*! \brief Returns the pointer within the msg body to the given type/subtype,
  145. * and sets the length of the body part.
  146. * The result can be the whole msg body, or a part of a multipart body.
  147. */
  148. char *get_body_part( struct sip_msg *msg,
  149. unsigned short type, unsigned short subtype,
  150. int *len)
  151. {
  152. int mime;
  153. unsigned int umime;
  154. char *c, *c2, *buf_end;
  155. str boundary;
  156. #define content_type_len \
  157. (sizeof("Content-Type") - 1)
  158. if ((mime = parse_content_type_hdr(msg)) <= 0)
  159. return NULL;
  160. if (mime == ((type<<16)|subtype)) {
  161. /* content-type is type/subtype */
  162. c = get_body(msg);
  163. if (c)
  164. *len = msg->buf+msg->len - c;
  165. return c;
  166. } else if ((mime>>16) == TYPE_MULTIPART) {
  167. /* type is multipart/something, search for type/subtype part */
  168. if (get_boundary_param(msg, &boundary)) {
  169. ERR("failed to get boundary parameter\n");
  170. return NULL;
  171. }
  172. if (!(c = get_body(msg)))
  173. return NULL;
  174. buf_end = msg->buf+msg->len;
  175. /* check all the body parts delimated by the boundary value,
  176. and search for the Content-Type HF with the given
  177. type/subtype */
  178. next_part:
  179. while ((c = search_boundary(c, buf_end, &boundary))) {
  180. /* skip boundary */
  181. c += 2 + boundary.len;
  182. if ((c+2 > buf_end) ||
  183. ((*c == '-') && (*(c+1) == '-'))
  184. )
  185. /* end boundary, no more body part
  186. will follow */
  187. return NULL;
  188. /* go to the next line */
  189. while ((c < buf_end) && (*c != '\n')) c++;
  190. c++;
  191. if (c >= buf_end)
  192. return NULL;
  193. /* try to find the content-type header */
  194. while ((*c != '\r') && (*c != '\n')) {
  195. if (c + content_type_len >= buf_end)
  196. return NULL;
  197. if ((LOWER_DWORD(READ(c)) == _cont_) &&
  198. (LOWER_DWORD(READ(c+4)) == _ent__) &&
  199. (LOWER_DWORD(READ(c+8)) == _type_)
  200. ) {
  201. /* Content-Type HF found */
  202. c += content_type_len;
  203. while ((c < buf_end) &&
  204. ((*c == ' ') || (*c == '\t'))
  205. )
  206. c++;
  207. if (c + 1 /* : */ >= buf_end)
  208. return NULL;
  209. if (*c != ':')
  210. /* not realy a Content-Type HF */
  211. goto next_hf;
  212. c++;
  213. /* search the end of the header body,
  214. decode_mime_type() needs it */
  215. c2 = c;
  216. while (((c2 < buf_end) && (*c2 != '\n')) ||
  217. ((c2+1 < buf_end) && (*c2 == '\n') &&
  218. ((*(c2+1) == ' ') || (*(c2+1) == '\t')))
  219. )
  220. c2++;
  221. if (c2 >= buf_end)
  222. return NULL;
  223. if (*(c2-1) == '\r') c2--;
  224. if (!decode_mime_type(c, c2 , &umime)) {
  225. ERR("failed to decode the mime type\n");
  226. return NULL;
  227. }
  228. /* c2 points to the CRLF at the end of the line,
  229. move the pointer to the beginning of the next line */
  230. c = c2;
  231. if ((c < buf_end) && (*c == '\r')) c++;
  232. if ((c < buf_end) && (*c == '\n')) c++;
  233. if (umime != ((type<<16)|subtype)) {
  234. /* this is not the part we are looking for */
  235. goto next_part;
  236. }
  237. /* the requested type/subtype is found! */
  238. return get_multipart_body(c,
  239. buf_end,
  240. &boundary,
  241. len);
  242. }
  243. next_hf:
  244. /* go to the next line */
  245. while ((c < buf_end) && (*c != '\n')) c++;
  246. c++;
  247. }
  248. /* CRLF delimeter reached,
  249. no Content-Type HF was found */
  250. }
  251. }
  252. return NULL;
  253. }
  254. /**
  255. * trim_leading_hts
  256. *
  257. * trim leading all spaces ' ' and horizontal tabs '\t' characters.
  258. * - buffer, pointer to the beginning of the buffer.
  259. * - end_buffer, pointer to the end of the buffer.
  260. * returns
  261. * - pointer to the first non-match character if success.
  262. * - pointer to NULL if the end_buffer is reached.
  263. */
  264. char *trim_leading_hts (char *buffer, char *end_buffer)
  265. {
  266. char *cpy_buffer = buffer;
  267. while ((cpy_buffer < end_buffer) &&
  268. ((*cpy_buffer == ' ') || (*cpy_buffer == '\t'))) {
  269. cpy_buffer++;
  270. }
  271. return ((cpy_buffer < end_buffer) ? cpy_buffer : NULL);
  272. }
  273. /**
  274. * trim_leading_e_r
  275. *
  276. * trim leading characters until get a '\r'.
  277. * - buffer, pointer to the beginning of the buffer.
  278. * - end_buffer, pointer to the end of the buffer.
  279. *
  280. * returns
  281. * - pointer to the first '\r' character if success.
  282. * - pointer to NULL if the end_buffer is reached.
  283. */
  284. char *trim_leading_e_r (char *buffer, char *end_buffer)
  285. {
  286. char *cpy_buffer = buffer;
  287. while ((cpy_buffer < end_buffer) && (*cpy_buffer != '\r')) {
  288. cpy_buffer++;
  289. }
  290. return ((cpy_buffer < end_buffer) ? cpy_buffer : NULL);
  291. }
  292. /**
  293. * part_multipart_headers_cmp
  294. * trim leading characters until get a '\r'.
  295. * receives
  296. * - buffer, pointer to the beginning of the headers in a part of the multipart body.
  297. * - end_buffer, pointer to the end of the headers in the multipart body.
  298. * - content type/ content subtype.
  299. * if (type == 0 / subtype == 0): Content-Type: disabled in the search.
  300. * - content id.
  301. * if (id == NULL): Content-ID: disabled in the search.
  302. * - content length.
  303. * if (length == NULL) Content-Length: disabled in the search.
  304. *
  305. * returns
  306. * - true, if the part of the multipart body has :
  307. * -- Content-Type that matches content_type / content_subtype. (if Content-Type enabled) &&
  308. * -- Content-ID that matches content_id. (if Content-ID enabled) &&
  309. * -- Content-Length that matches content_length. (if Content-Length enabled)
  310. * - false, if any of them doesnt match.
  311. */
  312. int part_multipart_headers_cmp (char *buffer,
  313. char *end_buffer,
  314. unsigned short content_type,
  315. unsigned short content_subtype,
  316. char *content_id,
  317. char *content_length)
  318. {
  319. int error = 0;
  320. char *error_msg = NULL;
  321. char *cpy_c = NULL;
  322. char *cpy_d = NULL;
  323. char *value_ini = NULL;
  324. char *value_fin = NULL;
  325. unsigned int umime;
  326. int found = 0;
  327. int found_content_type = 0;
  328. int found_content_id = 0;
  329. int found_content_length = 0;
  330. if ((buffer == NULL) || (end_buffer == NULL)) {
  331. error = -1;
  332. error_msg = "buffer and/or end_buffer are NULL";
  333. } else {
  334. cpy_c = buffer;
  335. cpy_d = end_buffer;
  336. if ((content_type == 0) && (content_subtype == 0)) {
  337. found_content_type = 1;
  338. }
  339. if (content_id == NULL) {
  340. found_content_id = 1;
  341. }
  342. if (content_length == NULL) {
  343. found_content_length = 1;
  344. }
  345. found = found_content_type * found_content_id * found_content_length;
  346. while ((!found) && (!error) && (cpy_c < cpy_d)) {
  347. if ((cpy_c + 8) < cpy_d) {
  348. if ( (LOWER_DWORD(READ(cpy_c)) == _cont_)
  349. && (LOWER_DWORD(READ(cpy_c + 4)) == _ent__) ) {
  350. cpy_c += 8;
  351. if ( (!found_content_type)
  352. && ((cpy_c + 5) < cpy_d)
  353. && ((*(cpy_c + 0) == 't') || (*(cpy_c + 0) == 'T'))
  354. && ((*(cpy_c + 1) == 'y') || (*(cpy_c + 1) == 'Y'))
  355. && ((*(cpy_c + 2) == 'p') || (*(cpy_c + 2) == 'P'))
  356. && ((*(cpy_c + 3) == 'e') || (*(cpy_c + 3) == 'E'))
  357. && (*(cpy_c + 4) == ':') ) {
  358. cpy_c += 5;
  359. /* value_ has the content of the header */
  360. value_ini = trim_leading_hts(cpy_c, cpy_d);
  361. value_fin = trim_leading_e_r(cpy_c, cpy_d);
  362. if ((value_ini != NULL) && (value_fin != NULL)) {
  363. cpy_c = value_fin;
  364. if (decode_mime_type(value_ini, value_fin, &umime)) {
  365. if (umime == ((content_type<<16)|content_subtype)) {
  366. found_content_type = 1;
  367. } else {
  368. error = -2;
  369. error_msg = "MIME types mismatch";
  370. }
  371. } else {
  372. error = -3;
  373. error_msg = "Failed to decode MIME type";
  374. }
  375. } else {
  376. error = -4;
  377. error_msg = "Failed to perform trim_leading_hts || trim_leading_e_r";
  378. }
  379. } else if( (!found_content_id) && ((cpy_c + 3) < cpy_d)
  380. && ((*(cpy_c + 0) == 'i') || (*(cpy_c + 0) == 'I'))
  381. && ((*(cpy_c + 1) == 'd') || (*(cpy_c + 1) == 'D'))
  382. && (*(cpy_c + 2) == ':') ) {
  383. cpy_c += 3;
  384. /* value_ has the content of the header */
  385. value_ini = trim_leading_hts(cpy_c, cpy_d);
  386. value_fin = trim_leading_e_r(cpy_c, cpy_d);
  387. if ((value_ini != NULL) && (value_fin != NULL)) {
  388. cpy_c = value_fin;
  389. if (strncmp(content_id, value_ini, value_fin-value_ini) == 0) {
  390. found_content_id = 1;
  391. } else {
  392. error = -5;
  393. error_msg = "Content-ID mismatch";
  394. }
  395. } else {
  396. error = -6;
  397. error_msg = "Failed to perform trim_leading_hts || trim_leading_e_r";
  398. }
  399. } else if( (!found_content_length) && ((cpy_c + 7) < cpy_d)
  400. && ((*(cpy_c + 0) == 'l') || (*(cpy_c + 0) == 'L'))
  401. && ((*(cpy_c + 1) == 'e') || (*(cpy_c + 1) == 'E'))
  402. && ((*(cpy_c + 2) == 'n') || (*(cpy_c + 2) == 'N'))
  403. && ((*(cpy_c + 3) == 'g') || (*(cpy_c + 3) == 'G'))
  404. && ((*(cpy_c + 4) == 't') || (*(cpy_c + 4) == 'T'))
  405. && ((*(cpy_c + 5) == 'h') || (*(cpy_c + 5) == 'H'))
  406. && (*(cpy_c + 6) == ':') ) {
  407. cpy_c += 7;
  408. /* value_ has the content of the header */
  409. value_ini = trim_leading_hts(cpy_c, cpy_d);
  410. value_fin = trim_leading_e_r(cpy_c, cpy_d);
  411. if ((value_ini != NULL) && (value_fin != NULL)) {
  412. cpy_c = value_fin;
  413. if (strncmp(content_length, value_ini, value_fin-value_ini) == 0) {
  414. found_content_length = 1;
  415. } else {
  416. error = -7;
  417. error_msg = "Content-Length mismatch";
  418. }
  419. } else {
  420. error = -8;
  421. error_msg = "Failed to perform trim_leading_hts || trim_leading_e_r";
  422. }
  423. } else {
  424. /* Next characters dont match "Type:" or "ID:" or "Length:" OR
  425. * header already parsed (maybe duplicates?) and founded OR
  426. * header initially set as disabled and it doesnt need to be treated.
  427. * This is NOT an error. */
  428. ;
  429. }
  430. } else {
  431. /* First 8 characters dont match "Content-"
  432. * This is NOT an error. */
  433. ;
  434. }
  435. } else {
  436. error = -9;
  437. error_msg = "We reached the end of the buffer";
  438. }
  439. found = found_content_type * found_content_id * found_content_length;
  440. if ((!found) && (!error)) {
  441. value_fin = trim_leading_e_r(cpy_c, cpy_d);
  442. if (value_fin != NULL) {
  443. cpy_c = value_fin;
  444. if ((cpy_c + 1) < cpy_d) {
  445. if ((*cpy_c == '\r') && (*(cpy_c + 1) == '\n')) {
  446. cpy_c++;
  447. cpy_c++;
  448. } else {
  449. error = -10;
  450. error_msg = "Each line must end with a \r\n";
  451. }
  452. } else {
  453. error = -11;
  454. error_msg = "We reached the end of the buffer";
  455. }
  456. } else {
  457. error = -12;
  458. error_msg = "Failed to perform trim_leading_e_r";
  459. }
  460. }
  461. } /* End main while loop */
  462. }
  463. if (error < 0) {
  464. LM_ERR("part_multipart_headers_cmp. error. \"%i\". \"%s\".\n", error, error_msg);
  465. return 0;
  466. } else {
  467. return found;
  468. }
  469. }
  470. /**
  471. * get_body_part_by_filter
  472. *
  473. * Filters the multipart part from a given SIP message which matches the
  474. * Content-Type && || Content-ID && || Content-Length
  475. * receives
  476. * - SIP message
  477. * - pointer to the beginning of the headers in a part of the multipart body.
  478. * - pointer to the end of the headers in the multipart body.
  479. * - content type/ content subtype.
  480. * if (type == 0 / subtype == 0): Content-Type: disabled in the search.
  481. * - content id.
  482. * if (id == NULL): Content-ID: disabled in the search.
  483. * - content length.
  484. * if (length == NULL) Content-Length: disabled in the search.
  485. * - len. Length of the multipart message returned.
  486. *
  487. * returns
  488. * - pointer to the multipart if success.
  489. * - NULL, if none of the multiparts match.
  490. */
  491. char *get_body_part_by_filter(struct sip_msg *msg,
  492. unsigned short content_type,
  493. unsigned short content_subtype,
  494. char *content_id,
  495. char *content_length,
  496. int *len)
  497. {
  498. int mime;
  499. char*c, *d, *buf_end;
  500. str boundary;
  501. if ((mime = parse_content_type_hdr(msg)) <= 0)
  502. return NULL;
  503. if ((mime>>16) == TYPE_MULTIPART) {
  504. /* type is multipart/something, search for type/subtype part */
  505. if (get_boundary_param(msg, &boundary)) {
  506. ERR("failed to get boundary parameter\n");
  507. return NULL;
  508. }
  509. if (!(c = get_body(msg)))
  510. return NULL;
  511. buf_end = msg->buf+msg->len;
  512. while ((c = search_boundary(c, buf_end, &boundary))) {
  513. /* skip boundary */
  514. c += 2 + boundary.len;
  515. if ((c+2 > buf_end) || ((*c == '-') && (*(c+1) == '-')) )
  516. /* end boundary, no more body part will follow */
  517. return NULL;
  518. /* go to the next line */
  519. while ((c < buf_end) && (*c != '\n')) c++;
  520. c++;
  521. if (c >= buf_end)
  522. return NULL;
  523. d = get_multipart_body(c, buf_end, &boundary, len);
  524. if (part_multipart_headers_cmp(c, d, content_type, content_subtype,
  525. content_id, content_length)) {
  526. return d;
  527. }
  528. }
  529. }
  530. return NULL;
  531. }