123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595 |
- /*
- * Copyright (C) 2008 iptelorg GmbH
- *
- * This file is part of ser, a free SIP server.
- *
- * ser is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version
- *
- * For a license to use the ser software under conditions
- * other than those described here, or to purchase support for this
- * software, please contact iptel.org by e-mail at the following addresses:
- * [email protected]
- *
- * ser is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * History:
- * --------
- * 2008-05-22 Initial version, get_body_part() is introduced (Miklos)
- */
- /*! \file
- * \brief Parser :: Body handling
- *
- * \ingroup parser
- */
- #include "../trim.h"
- #include "parser_f.h"
- #include "parse_content.h"
- #include "parse_param.h"
- #include "keys.h"
- #include "parse_body.h"
- /*! \brief returns the value of boundary parameter from the Contect-Type HF */
- static inline int get_boundary_param(struct sip_msg *msg, str *boundary)
- {
- str s;
- char *c;
- param_t *p, *list;
- #define is_boundary(c) \
- (((c)[0] == 'b' || (c)[0] == 'B') && \
- ((c)[1] == 'o' || (c)[1] == 'O') && \
- ((c)[2] == 'u' || (c)[2] == 'U') && \
- ((c)[3] == 'n' || (c)[3] == 'N') && \
- ((c)[4] == 'd' || (c)[4] == 'D') && \
- ((c)[5] == 'a' || (c)[5] == 'A') && \
- ((c)[6] == 'r' || (c)[6] == 'R') && \
- ((c)[7] == 'y' || (c)[7] == 'Y'))
- #define boundary_param_len (sizeof("boundary")-1)
- /* get the pointer to the beginning of the parameter list */
- s.s = msg->content_type->body.s;
- s.len = msg->content_type->body.len;
- c = find_not_quoted(&s, ';');
- if (!c)
- return -1;
- c++;
- s.len = s.len - (c - s.s);
- s.s = c;
- trim_leading(&s);
- if (s.len <= 0)
- return -1;
- /* parse the parameter list, and search for boundary */
- if (parse_params(&s, CLASS_ANY, NULL, &list)<0)
- return -1;
- boundary->s = NULL;
- for (p = list; p; p = p->next)
- if ((p->name.len == boundary_param_len) &&
- is_boundary(p->name.s)
- ) {
- boundary->s = p->body.s;
- boundary->len = p->body.len;
- break;
- }
- free_params(list);
- if (!boundary->s || !boundary->len)
- return -1;
- DBG("boundary is \"%.*s\"\n",
- boundary->len, boundary->s);
- return 0;
- }
- /*! \brief search the next boundary in the buffer */
- static inline char *search_boundary(char *buf, char *buf_end, str *boundary)
- {
- char *c;
- c = buf;
- while (c + 2 /* -- */ + boundary->len < buf_end) {
- if ((*c == '-') && (*(c+1) == '-') &&
- (memcmp(c+2, boundary->s, boundary->len) == 0)
- )
- return c; /* boundary found */
- /* go to the next line */
- while ((c < buf_end) && (*c != '\n')) c++;
- c++;
- }
- return NULL;
- }
- /*! \brief extract the body of a part from a multipart SIP msg body */
- inline static char *get_multipart_body(char *buf,
- char *buf_end,
- str *boundary,
- int *len)
- {
- char *beg, *end;
- if (buf >= buf_end)
- goto error;
- beg = buf;
- while ((*beg != '\r') && (*beg != '\n')) {
- while ((beg < buf_end) && (*beg != '\n'))
- beg++;
- beg++;
- if (beg >= buf_end)
- goto error;
- }
- /* CRLF delimeter found, the body begins right after it */
- while ((beg < buf_end) && (*beg != '\n'))
- beg++;
- beg++;
- if (beg >= buf_end)
- goto error;
- if (!(end = search_boundary(beg, buf_end, boundary)))
- goto error;
- /* CRLF preceding the boundary belongs to the boundary
- and not to the body */
- if (*(end-1) == '\n') end--;
- if (*(end-1) == '\r') end--;
- if (end < beg)
- goto error;
- *len = end-beg;
- return beg;
- error:
- ERR("failed to extract the body from the multipart mime type\n");
- return NULL;
- }
- /*! \brief macros from parse_hname2.c */
- #define READ(val) \
- (*(val + 0) + (*(val + 1) << 8) + (*(val + 2) << 16) + (*(val + 3) << 24))
- #define LOWER_DWORD(d) ((d) | 0x20202020)
- /*! \brief Returns the pointer within the msg body to the given type/subtype,
- * and sets the length of the body part.
- * The result can be the whole msg body, or a part of a multipart body.
- */
- char *get_body_part( struct sip_msg *msg,
- unsigned short type, unsigned short subtype,
- int *len)
- {
- int mime;
- unsigned int umime;
- char *c, *c2, *buf_end;
- str boundary;
- #define content_type_len \
- (sizeof("Content-Type") - 1)
- if ((mime = parse_content_type_hdr(msg)) <= 0)
- return NULL;
- if (mime == ((type<<16)|subtype)) {
- /* content-type is type/subtype */
- c = get_body(msg);
- if (c)
- *len = msg->buf+msg->len - c;
- return c;
- } else if ((mime>>16) == TYPE_MULTIPART) {
- /* type is multipart/something, search for type/subtype part */
- if (get_boundary_param(msg, &boundary)) {
- ERR("failed to get boundary parameter\n");
- return NULL;
- }
- if (!(c = get_body(msg)))
- return NULL;
- buf_end = msg->buf+msg->len;
- /* check all the body parts delimated by the boundary value,
- and search for the Content-Type HF with the given
- type/subtype */
- next_part:
- while ((c = search_boundary(c, buf_end, &boundary))) {
- /* skip boundary */
- c += 2 + boundary.len;
- if ((c+2 > buf_end) ||
- ((*c == '-') && (*(c+1) == '-'))
- )
- /* end boundary, no more body part
- will follow */
- return NULL;
- /* go to the next line */
- while ((c < buf_end) && (*c != '\n')) c++;
- c++;
- if (c >= buf_end)
- return NULL;
- /* try to find the content-type header */
- while ((*c != '\r') && (*c != '\n')) {
- if (c + content_type_len >= buf_end)
- return NULL;
- if ((LOWER_DWORD(READ(c)) == _cont_) &&
- (LOWER_DWORD(READ(c+4)) == _ent__) &&
- (LOWER_DWORD(READ(c+8)) == _type_)
- ) {
- /* Content-Type HF found */
- c += content_type_len;
- while ((c < buf_end) &&
- ((*c == ' ') || (*c == '\t'))
- )
- c++;
- if (c + 1 /* : */ >= buf_end)
- return NULL;
- if (*c != ':')
- /* not realy a Content-Type HF */
- goto next_hf;
- c++;
- /* search the end of the header body,
- decode_mime_type() needs it */
- c2 = c;
- while (((c2 < buf_end) && (*c2 != '\n')) ||
- ((c2+1 < buf_end) && (*c2 == '\n') &&
- ((*(c2+1) == ' ') || (*(c2+1) == '\t')))
- )
- c2++;
- if (c2 >= buf_end)
- return NULL;
- if (*(c2-1) == '\r') c2--;
- if (!decode_mime_type(c, c2 , &umime)) {
- ERR("failed to decode the mime type\n");
- return NULL;
- }
- /* c2 points to the CRLF at the end of the line,
- move the pointer to the beginning of the next line */
- c = c2;
- if ((c < buf_end) && (*c == '\r')) c++;
- if ((c < buf_end) && (*c == '\n')) c++;
- if (umime != ((type<<16)|subtype)) {
- /* this is not the part we are looking for */
- goto next_part;
- }
- /* the requested type/subtype is found! */
- return get_multipart_body(c,
- buf_end,
- &boundary,
- len);
- }
- next_hf:
- /* go to the next line */
- while ((c < buf_end) && (*c != '\n')) c++;
- c++;
- }
- /* CRLF delimeter reached,
- no Content-Type HF was found */
- }
- }
- return NULL;
- }
- /**
- * trim_leading_hts
- *
- * trim leading all spaces ' ' and horizontal tabs '\t' characters.
- * - buffer, pointer to the beginning of the buffer.
- * - end_buffer, pointer to the end of the buffer.
- * returns
- * - pointer to the first non-match character if success.
- * - pointer to NULL if the end_buffer is reached.
- */
- char *trim_leading_hts (char *buffer, char *end_buffer)
- {
- char *cpy_buffer = buffer;
- while ((cpy_buffer < end_buffer) &&
- ((*cpy_buffer == ' ') || (*cpy_buffer == '\t'))) {
- cpy_buffer++;
- }
- return ((cpy_buffer < end_buffer) ? cpy_buffer : NULL);
- }
- /**
- * trim_leading_e_r
- *
- * trim leading characters until get a '\r'.
- * - buffer, pointer to the beginning of the buffer.
- * - end_buffer, pointer to the end of the buffer.
- *
- * returns
- * - pointer to the first '\r' character if success.
- * - pointer to NULL if the end_buffer is reached.
- */
- char *trim_leading_e_r (char *buffer, char *end_buffer)
- {
- char *cpy_buffer = buffer;
- while ((cpy_buffer < end_buffer) && (*cpy_buffer != '\r')) {
- cpy_buffer++;
- }
- return ((cpy_buffer < end_buffer) ? cpy_buffer : NULL);
- }
- /**
- * part_multipart_headers_cmp
- * trim leading characters until get a '\r'.
- * receives
- * - buffer, pointer to the beginning of the headers in a part of the multipart body.
- * - end_buffer, pointer to the end of the headers in the multipart body.
- * - content type/ content subtype.
- * if (type == 0 / subtype == 0): Content-Type: disabled in the search.
- * - content id.
- * if (id == NULL): Content-ID: disabled in the search.
- * - content length.
- * if (length == NULL) Content-Length: disabled in the search.
- *
- * returns
- * - true, if the part of the multipart body has :
- * -- Content-Type that matches content_type / content_subtype. (if Content-Type enabled) &&
- * -- Content-ID that matches content_id. (if Content-ID enabled) &&
- * -- Content-Length that matches content_length. (if Content-Length enabled)
- * - false, if any of them doesnt match.
- */
- int part_multipart_headers_cmp (char *buffer,
- char *end_buffer,
- unsigned short content_type,
- unsigned short content_subtype,
- char *content_id,
- char *content_length)
- {
- int error = 0;
- char *error_msg = NULL;
- char *cpy_c = NULL;
- char *cpy_d = NULL;
- char *value_ini = NULL;
- char *value_fin = NULL;
- unsigned int umime;
- int found = 0;
- int found_content_type = 0;
- int found_content_id = 0;
- int found_content_length = 0;
- if ((buffer == NULL) || (end_buffer == NULL)) {
- error = -1;
- error_msg = "buffer and/or end_buffer are NULL";
- } else {
- cpy_c = buffer;
- cpy_d = end_buffer;
- if ((content_type == 0) && (content_subtype == 0)) {
- found_content_type = 1;
- }
- if (content_id == NULL) {
- found_content_id = 1;
- }
- if (content_length == NULL) {
- found_content_length = 1;
- }
- found = found_content_type * found_content_id * found_content_length;
- while ((!found) && (!error) && (cpy_c < cpy_d)) {
- if ((cpy_c + 8) < cpy_d) {
- if ( (LOWER_DWORD(READ(cpy_c)) == _cont_)
- && (LOWER_DWORD(READ(cpy_c + 4)) == _ent__) ) {
- cpy_c += 8;
- if ( (!found_content_type)
- && ((cpy_c + 5) < cpy_d)
- && ((*(cpy_c + 0) == 't') || (*(cpy_c + 0) == 'T'))
- && ((*(cpy_c + 1) == 'y') || (*(cpy_c + 1) == 'Y'))
- && ((*(cpy_c + 2) == 'p') || (*(cpy_c + 2) == 'P'))
- && ((*(cpy_c + 3) == 'e') || (*(cpy_c + 3) == 'E'))
- && (*(cpy_c + 4) == ':') ) {
- cpy_c += 5;
- /* value_ has the content of the header */
- value_ini = trim_leading_hts(cpy_c, cpy_d);
- value_fin = trim_leading_e_r(cpy_c, cpy_d);
- if ((value_ini != NULL) && (value_fin != NULL)) {
- cpy_c = value_fin;
- if (decode_mime_type(value_ini, value_fin, &umime)) {
- if (umime == ((content_type<<16)|content_subtype)) {
- found_content_type = 1;
- } else {
- error = -2;
- error_msg = "MIME types mismatch";
- }
- } else {
- error = -3;
- error_msg = "Failed to decode MIME type";
- }
- } else {
- error = -4;
- error_msg = "Failed to perform trim_leading_hts || trim_leading_e_r";
- }
- } else if( (!found_content_id) && ((cpy_c + 3) < cpy_d)
- && ((*(cpy_c + 0) == 'i') || (*(cpy_c + 0) == 'I'))
- && ((*(cpy_c + 1) == 'd') || (*(cpy_c + 1) == 'D'))
- && (*(cpy_c + 2) == ':') ) {
- cpy_c += 3;
- /* value_ has the content of the header */
- value_ini = trim_leading_hts(cpy_c, cpy_d);
- value_fin = trim_leading_e_r(cpy_c, cpy_d);
- if ((value_ini != NULL) && (value_fin != NULL)) {
- cpy_c = value_fin;
- if (strncmp(content_id, value_ini, value_fin-value_ini) == 0) {
- found_content_id = 1;
- } else {
- error = -5;
- error_msg = "Content-ID mismatch";
- }
- } else {
- error = -6;
- error_msg = "Failed to perform trim_leading_hts || trim_leading_e_r";
- }
- } else if( (!found_content_length) && ((cpy_c + 7) < cpy_d)
- && ((*(cpy_c + 0) == 'l') || (*(cpy_c + 0) == 'L'))
- && ((*(cpy_c + 1) == 'e') || (*(cpy_c + 1) == 'E'))
- && ((*(cpy_c + 2) == 'n') || (*(cpy_c + 2) == 'N'))
- && ((*(cpy_c + 3) == 'g') || (*(cpy_c + 3) == 'G'))
- && ((*(cpy_c + 4) == 't') || (*(cpy_c + 4) == 'T'))
- && ((*(cpy_c + 5) == 'h') || (*(cpy_c + 5) == 'H'))
- && (*(cpy_c + 6) == ':') ) {
- cpy_c += 7;
- /* value_ has the content of the header */
- value_ini = trim_leading_hts(cpy_c, cpy_d);
- value_fin = trim_leading_e_r(cpy_c, cpy_d);
- if ((value_ini != NULL) && (value_fin != NULL)) {
- cpy_c = value_fin;
- if (strncmp(content_length, value_ini, value_fin-value_ini) == 0) {
- found_content_length = 1;
- } else {
- error = -7;
- error_msg = "Content-Length mismatch";
- }
- } else {
- error = -8;
- error_msg = "Failed to perform trim_leading_hts || trim_leading_e_r";
- }
- } else {
- /* Next characters dont match "Type:" or "ID:" or "Length:" OR
- * header already parsed (maybe duplicates?) and founded OR
- * header initially set as disabled and it doesnt need to be treated.
- * This is NOT an error. */
- ;
- }
- } else {
- /* First 8 characters dont match "Content-"
- * This is NOT an error. */
- ;
- }
- } else {
- error = -9;
- error_msg = "We reached the end of the buffer";
- }
- found = found_content_type * found_content_id * found_content_length;
- if ((!found) && (!error)) {
- value_fin = trim_leading_e_r(cpy_c, cpy_d);
- if (value_fin != NULL) {
- cpy_c = value_fin;
- if ((cpy_c + 1) < cpy_d) {
- if ((*cpy_c == '\r') && (*(cpy_c + 1) == '\n')) {
- cpy_c++;
- cpy_c++;
- } else {
- error = -10;
- error_msg = "Each line must end with a \r\n";
- }
- } else {
- error = -11;
- error_msg = "We reached the end of the buffer";
- }
- } else {
- error = -12;
- error_msg = "Failed to perform trim_leading_e_r";
- }
- }
- } /* End main while loop */
- }
- if (error < 0) {
- LM_ERR("part_multipart_headers_cmp. error. \"%i\". \"%s\".\n", error, error_msg);
- return 0;
- } else {
- return found;
- }
- }
- /**
- * get_body_part_by_filter
- *
- * Filters the multipart part from a given SIP message which matches the
- * Content-Type && || Content-ID && || Content-Length
- * receives
- * - SIP message
- * - pointer to the beginning of the headers in a part of the multipart body.
- * - pointer to the end of the headers in the multipart body.
- * - content type/ content subtype.
- * if (type == 0 / subtype == 0): Content-Type: disabled in the search.
- * - content id.
- * if (id == NULL): Content-ID: disabled in the search.
- * - content length.
- * if (length == NULL) Content-Length: disabled in the search.
- * - len. Length of the multipart message returned.
- *
- * returns
- * - pointer to the multipart if success.
- * - NULL, if none of the multiparts match.
- */
- char *get_body_part_by_filter(struct sip_msg *msg,
- unsigned short content_type,
- unsigned short content_subtype,
- char *content_id,
- char *content_length,
- int *len)
- {
- int mime;
- char*c, *d, *buf_end;
- str boundary;
- if ((mime = parse_content_type_hdr(msg)) <= 0)
- return NULL;
- if ((mime>>16) == TYPE_MULTIPART) {
- /* type is multipart/something, search for type/subtype part */
- if (get_boundary_param(msg, &boundary)) {
- ERR("failed to get boundary parameter\n");
- return NULL;
- }
- if (!(c = get_body(msg)))
- return NULL;
- buf_end = msg->buf+msg->len;
- while ((c = search_boundary(c, buf_end, &boundary))) {
- /* skip boundary */
- c += 2 + boundary.len;
- if ((c+2 > buf_end) || ((*c == '-') && (*(c+1) == '-')) )
- /* end boundary, no more body part will follow */
- return NULL;
- /* go to the next line */
- while ((c < buf_end) && (*c != '\n')) c++;
- c++;
- if (c >= buf_end)
- return NULL;
- d = get_multipart_body(c, buf_end, &boundary, len);
- if (part_multipart_headers_cmp(c, d, content_type, content_subtype,
- content_id, content_length)) {
- return d;
- }
- }
- }
- return NULL;
- }
|