Alexandre Lision | 8af73cb | 2013-12-10 14:11:20 -0500 | [diff] [blame] | 1 | /* $Id$ */ |
| 2 | /* |
| 3 | * Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com) |
| 4 | * |
| 5 | * This program is free software; you can redistribute it and/or modify |
| 6 | * it under the terms of the GNU General Public License as published by |
| 7 | * the Free Software Foundation; either version 2 of the License, or |
| 8 | * (at your option) any later version. |
| 9 | * |
| 10 | * This program is distributed in the hope that it will be useful, |
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 13 | * GNU General Public License for more details. |
| 14 | * |
| 15 | * You should have received a copy of the GNU General Public License |
| 16 | * along with this program; if not, write to the Free Software |
| 17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| 18 | */ |
| 19 | #include "test.h" |
| 20 | #include <pjsip.h> |
| 21 | #include <pjlib.h> |
| 22 | |
| 23 | #define THIS_FILE "" |
| 24 | |
| 25 | /* |
| 26 | * multipart tests |
| 27 | */ |
| 28 | typedef pj_status_t (*verify_ptr)(pj_pool_t*,pjsip_msg_body*); |
| 29 | |
| 30 | static pj_status_t verify1(pj_pool_t *pool, pjsip_msg_body *body); |
| 31 | |
| 32 | static struct test_t |
| 33 | { |
| 34 | char *ctype; |
| 35 | char *csubtype; |
| 36 | char *boundary; |
| 37 | const char *msg; |
| 38 | verify_ptr verify; |
| 39 | } p_tests[] = |
| 40 | { |
| 41 | { |
| 42 | /* Content-type */ |
| 43 | "multipart", "mixed", "12345", |
| 44 | |
| 45 | /* Body: */ |
| 46 | "This is the prolog, which should be ignored.\r\n" |
| 47 | "--12345\r\n" |
| 48 | "Content-Type: my/text\r\n" |
| 49 | "\r\n" |
| 50 | "Header and body\r\n" |
| 51 | "--12345 \t\r\n" |
| 52 | "Content-Type: hello/world\r\n" |
| 53 | "Content-Length: 0\r\n" |
| 54 | "\r\n" |
| 55 | "--12345\r\n" |
| 56 | "\r\n" |
| 57 | "Body only\r\n" |
| 58 | "--12345\r\n" |
| 59 | "Content-Type: multipart/mixed;boundary=6789\r\n" |
| 60 | "\r\n" |
| 61 | "Prolog of the subbody, should be ignored\r\n" |
| 62 | "--6789\r\n" |
| 63 | "\r\n" |
| 64 | "Subbody\r\n" |
| 65 | "--6789--\r\n" |
| 66 | "Epilogue of the subbody, should be ignored\r\n" |
| 67 | "--12345--\r\n" |
| 68 | "This is epilogue, which should be ignored too", |
| 69 | |
| 70 | &verify1 |
| 71 | } |
| 72 | }; |
| 73 | |
| 74 | static void init_media_type(pjsip_media_type *mt, |
| 75 | char *type, char *subtype, char *boundary) |
| 76 | { |
| 77 | static pjsip_param prm; |
| 78 | |
| 79 | pjsip_media_type_init(mt, NULL, NULL); |
| 80 | if (type) mt->type = pj_str(type); |
| 81 | if (subtype) mt->subtype = pj_str(subtype); |
| 82 | if (boundary) { |
| 83 | pj_list_init(&prm); |
| 84 | prm.name = pj_str("boundary"); |
| 85 | prm.value = pj_str(boundary); |
| 86 | pj_list_push_back(&mt->param, &prm); |
| 87 | } |
| 88 | } |
| 89 | |
| 90 | static int verify_part(pjsip_multipart_part *part, |
| 91 | char *h_content_type, |
| 92 | char *h_content_subtype, |
| 93 | char *boundary, |
| 94 | int h_content_length, |
| 95 | const char *body) |
| 96 | { |
| 97 | pjsip_ctype_hdr *ctype_hdr = NULL; |
| 98 | pjsip_clen_hdr *clen_hdr = NULL; |
| 99 | pjsip_hdr *hdr; |
| 100 | pj_str_t the_body; |
| 101 | |
| 102 | hdr = part->hdr.next; |
| 103 | while (hdr != &part->hdr) { |
| 104 | if (hdr->type == PJSIP_H_CONTENT_TYPE) |
| 105 | ctype_hdr = (pjsip_ctype_hdr*)hdr; |
| 106 | else if (hdr->type == PJSIP_H_CONTENT_LENGTH) |
| 107 | clen_hdr = (pjsip_clen_hdr*)hdr; |
| 108 | hdr = hdr->next; |
| 109 | } |
| 110 | |
| 111 | if (h_content_type) { |
| 112 | pjsip_media_type mt; |
| 113 | |
| 114 | if (ctype_hdr == NULL) |
| 115 | return -10; |
| 116 | |
| 117 | init_media_type(&mt, h_content_type, h_content_subtype, boundary); |
| 118 | |
| 119 | if (pjsip_media_type_cmp(&ctype_hdr->media, &mt, 2) != 0) |
| 120 | return -20; |
| 121 | |
| 122 | } else { |
| 123 | if (ctype_hdr) |
| 124 | return -30; |
| 125 | } |
| 126 | |
| 127 | if (h_content_length >= 0) { |
| 128 | if (clen_hdr == NULL) |
| 129 | return -50; |
| 130 | if (clen_hdr->len != h_content_length) |
| 131 | return -60; |
| 132 | } else { |
| 133 | if (clen_hdr) |
| 134 | return -70; |
| 135 | } |
| 136 | |
| 137 | the_body.ptr = (char*)part->body->data; |
| 138 | the_body.slen = part->body->len; |
| 139 | |
| 140 | if (pj_strcmp2(&the_body, body) != 0) |
| 141 | return -90; |
| 142 | |
| 143 | return 0; |
| 144 | } |
| 145 | |
| 146 | static pj_status_t verify1(pj_pool_t *pool, pjsip_msg_body *body) |
| 147 | { |
| 148 | pjsip_media_type mt; |
| 149 | pjsip_multipart_part *part; |
| 150 | int rc; |
| 151 | |
| 152 | PJ_UNUSED_ARG(pool); |
| 153 | |
| 154 | /* Check content-type: "multipart/mixed;boundary=12345" */ |
| 155 | init_media_type(&mt, "multipart", "mixed", "12345"); |
| 156 | if (pjsip_media_type_cmp(&body->content_type, &mt, 2) != 0) |
| 157 | return -200; |
| 158 | |
| 159 | /* First part: |
| 160 | "Content-Type: my/text\r\n" |
| 161 | "\r\n" |
| 162 | "Header and body\r\n" |
| 163 | */ |
| 164 | part = pjsip_multipart_get_first_part(body); |
| 165 | if (!part) |
| 166 | return -210; |
| 167 | if (verify_part(part, "my", "text", NULL, -1, "Header and body")) |
| 168 | return -220; |
| 169 | |
| 170 | /* Next part: |
| 171 | "Content-Type: hello/world\r\n" |
| 172 | "Content-Length: 0\r\n" |
| 173 | "\r\n" |
| 174 | */ |
| 175 | part = pjsip_multipart_get_next_part(body, part); |
| 176 | if (!part) |
| 177 | return -230; |
| 178 | if ((rc=verify_part(part, "hello", "world", NULL, 0, ""))!=0) { |
| 179 | PJ_LOG(3,(THIS_FILE, " err: verify_part rc=%d", rc)); |
| 180 | return -240; |
| 181 | } |
| 182 | |
| 183 | /* Next part: |
| 184 | "\r\n" |
| 185 | "Body only\r\n" |
| 186 | */ |
| 187 | part = pjsip_multipart_get_next_part(body, part); |
| 188 | if (!part) |
| 189 | return -260; |
| 190 | if (verify_part(part, NULL, NULL, NULL, -1, "Body only")) |
| 191 | return -270; |
| 192 | |
| 193 | /* Next part: |
| 194 | "Content-Type: multipart/mixed;boundary=6789\r\n" |
| 195 | "\r\n" |
| 196 | "Prolog of the subbody, should be ignored\r\n" |
| 197 | "--6789\r\n" |
| 198 | "\r\n" |
| 199 | "Subbody\r\n" |
| 200 | "--6789--\r\n" |
| 201 | "Epilogue of the subbody, should be ignored\r\n" |
| 202 | |
| 203 | */ |
| 204 | part = pjsip_multipart_get_next_part(body, part); |
| 205 | if (!part) |
| 206 | return -280; |
| 207 | if ((rc=verify_part(part, "multipart", "mixed", "6789", -1, |
| 208 | "Prolog of the subbody, should be ignored\r\n" |
| 209 | "--6789\r\n" |
| 210 | "\r\n" |
| 211 | "Subbody\r\n" |
| 212 | "--6789--\r\n" |
| 213 | "Epilogue of the subbody, should be ignored"))!=0) { |
| 214 | PJ_LOG(3,(THIS_FILE, " err: verify_part rc=%d", rc)); |
| 215 | return -290; |
| 216 | } |
| 217 | |
| 218 | return 0; |
| 219 | } |
| 220 | |
| 221 | static int parse_test(void) |
| 222 | { |
| 223 | unsigned i; |
| 224 | |
| 225 | for (i=0; i<PJ_ARRAY_SIZE(p_tests); ++i) { |
| 226 | pj_pool_t *pool; |
| 227 | pjsip_media_type ctype; |
| 228 | pjsip_msg_body *body; |
| 229 | pj_str_t str; |
| 230 | int rc; |
| 231 | |
| 232 | pool = pjsip_endpt_create_pool(endpt, NULL, 512, 512); |
| 233 | |
| 234 | init_media_type(&ctype, p_tests[i].ctype, p_tests[i].csubtype, |
| 235 | p_tests[i].boundary); |
| 236 | |
| 237 | pj_strdup2_with_null(pool, &str, p_tests[i].msg); |
| 238 | body = pjsip_multipart_parse(pool, str.ptr, str.slen, &ctype, 0); |
| 239 | if (!body) |
| 240 | return -100; |
| 241 | |
| 242 | if (p_tests[i].verify) { |
| 243 | rc = p_tests[i].verify(pool, body); |
| 244 | } else { |
| 245 | rc = 0; |
| 246 | } |
| 247 | |
| 248 | pj_pool_release(pool); |
| 249 | if (rc) |
| 250 | return rc; |
| 251 | } |
| 252 | |
| 253 | return 0; |
| 254 | } |
| 255 | |
| 256 | int multipart_test(void) |
| 257 | { |
| 258 | int rc; |
| 259 | |
| 260 | rc = parse_test(); |
| 261 | if (rc) |
| 262 | return rc; |
| 263 | |
| 264 | return rc; |
| 265 | } |
| 266 | |