/* * This file is part of the Sofia-SIP package * * Copyright (C) 2005 Nokia Corporation. * * Contact: Pekka Pessi * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA * */ /**@ingroup test_msg * * @CFILE test_msg.c * * Torture tests for message parser. * * @author Pekka Pessi * * @date Created: Tue Aug 21 15:18:26 2001 ppessi */ #include "config.h" #include "test_class.h" #include "test_protos.h" #include "sofia-sip/msg.h" #include "sofia-sip/msg_addr.h" #include "sofia-sip/msg_date.h" #include "sofia-sip/msg_parser.h" #include "sofia-sip/bnf.h" #include "sofia-sip/msg_mclass.h" #include "sofia-sip/msg_mclass_hash.h" #include #include #include #include #include #include static int test_flags = 0; #define TSTFLAGS test_flags #include char const name[] = "test_msg"; static int msg_time_test(void) { char buf[32]; char const *s; char date1900[] = "Mon, 1 Jan 1900 00:00:00 GMT"; char date1900_1[] = "Mon, 01 Jan 1900 00:00:01 GMT"; char date822[] = "Thursday, 01-Jan-70 00:00:01 GMT"; char date822b[] = "Wednesday, 09-Nov-99 23:12:40 GMT"; char date822c[] = "Wednesday, 01-Sep-04 23:12:40 GMT"; char date2822[] = "Monday, 01-Jan-1900 00:00:01 GMT"; char dateasc[] = "Mon Jan 1 00:00:01 1900"; msg_time_t now = msg_now(), date = now; BEGIN(); s = date1900; TEST_1(msg_date_d(&s, &date) == 0); TEST(date, 0); TEST_SIZE(msg_date_e(buf, sizeof(buf), date), strlen(date1900)); TEST_SIZE(msg_date_e(buf, sizeof(buf), 1), strlen(date1900_1)); TEST_S(buf, date1900_1); s = date822; TEST_1(msg_date_d(&s, &date) == 0); TEST(date, 2208988801U); s = date822b; TEST_1(msg_date_d(&s, &date) == 0); TEST(date, 3151177960U); s = date822c; TEST_1(msg_date_d(&s, &date) == 0); TEST(date, 3303069160U); s = date2822; TEST_1(msg_date_d(&s, &date) == 0); TEST(date, 1); s = dateasc; TEST_1(msg_date_d(&s, &date) == 0); TEST(date, 1); { char error1[] = "Mo"; char error2[] = "Mon, 1 Jan 19100 00:00:00 GMT"; char error3[] = "Mon, 1 Jan 1900 00:00:"; char error4[] = "Mon, 1 Jan 1900 25:00:00 GMT"; char noerror5[] = "Mon, 1 Jan 1899 24:00:00 GMT"; char error6[] = "Mon, 30 Feb 1896 23:59:59 GMT"; char noerror7[] = "Mon, 29 Feb 1896 23:59:59 GMT"; char error8[] = "Mon, 32 Jan 1900 24:00:00 GMT"; char error9[] = "Mon, 27 Fev 1900 24:00:00 GMT"; s = error1; TEST_1(msg_date_d(&s, &date) < 0); s = error2; TEST_1(msg_date_d(&s, &date) < 0); s = error3; TEST_1(msg_date_d(&s, &date) < 0); s = error4; TEST_1(msg_date_d(&s, &date) < 0); s = noerror5; TEST_1(msg_date_d(&s, &date) == 0); TEST(date, 0); s = error6; TEST_1(msg_date_d(&s, &date) < 0); s = noerror7; TEST_1(msg_date_d(&s, &date) == 0); TEST(date, 0); s = error8; TEST_1(msg_date_d(&s, &date) < 0); s = error9; TEST_1(msg_date_d(&s, &date) < 0); } { char error1[] = "4294967297"; char *s; msg_numeric_t x[1]; memset(x, 0, sizeof (x)); x->x_common->h_class = test_numeric_class; TEST_1(msg_numeric_d(NULL, (msg_header_t *)x, s = error1, strlen(error1)) < 0); } END(); } static int addr_test(void) { BEGIN(); /* It *will* fail. */ /* TEST(sizeof(socklen_t), sizeof(msg_addrlen(NULL))); */ END(); } int test_header_parsing(void) { BEGIN(); { /* Test quoting/unquoting */ su_home_t home[1] = { SU_HOME_INIT(home) }; char *quoted = "\"foo \\b\\a\\r\\\"\\\\\"extra"; char *unquoted; TEST_1(unquoted = msg_unquote_dup(home, quoted)); TEST_S(unquoted, "foo bar\"\\"); su_home_deinit(home); } { /* Test parameter list */ su_home_t home[1] = { SU_HOME_INIT(home) }; msg_param_t const *params = NULL; char str[] = ";uffe;duffe = \"entten\" ; doo = [::1] ", *s = str; char const canonic[] = ";uffe;duffe=\"entten\";doo=[::1]"; char *end = str + strlen(str); char b[sizeof(canonic) + 8]; TEST_1(msg_params_d(home, &s, ¶ms) >= 0); TEST_1(params != 0); TEST_P(s, end); TEST_S(params[0], "uffe"); TEST_S(params[1], "duffe=\042entten\042"); TEST_S(params[2], "doo=[::1]"); TEST_1(params[3] == NULL); TEST_SIZE(msg_params_e(NULL, 0, params), strlen(canonic)); TEST_SIZE(msg_params_e(b, sizeof(b), params), strlen(canonic)); TEST_S(b, canonic); TEST_S(msg_params_find(params, "uffe"), ""); TEST_S(msg_params_find(params, "uffe="), ""); TEST_S(msg_params_find(params, "duffe"), "\"entten\""); TEST_S(msg_params_find(params, "duffe="), "\"entten\""); TEST_S(msg_params_find(params, "doo"), "[::1]"); TEST_S(msg_params_find(params, "doo="), "[::1]"); TEST(msg_params_remove((msg_param_t *)params, "uffe"), 1); TEST_S(params[0], "duffe=\042entten\042"); TEST_S(params[1], "doo=[::1]"); TEST_1(params[2] == NULL); TEST(msg_params_remove((msg_param_t *)params, "doo"), 1); TEST_S(params[0], "duffe=\042entten\042"); TEST_1(params[1] == NULL); su_home_deinit(home); } { /* Test that parameter list of length MSG_PARAMS_N is handled correctly */ su_home_t home[1] = { SU_HOME_INIT(home) }; msg_param_t const *params = NULL; char list1[] = ";one;two;three;four;five;six;seven;eight", *s = list1; char list2[] = ";one;two;three;four;five;six;seven"; char list3[] = ";one;two;three;four;five;six;seven, humppaa"; char *end3 = strchr(list3, ','); char list4[] = ";one;two;three;four;five;six;seven;eight;nine;ten" ";eleven;twelve;thirteen;fourteen;fiveteen;sixteen"; char list5[] = ";one;two;three;four;five;six;seven;eight;nine;ten" ";eleven;twelve;thirteen;fourteen;fiveteen"; char list6[] = ";one;two;three;four;five;six;seven;eight;nine;ten" ";eleven;twelve;thirteen;fourteen;fiveteen;sixteen;seventeen"; int i; TEST_1(msg_params_d(home, &s, ¶ms) >= 0); TEST_1(params); for (i = 0; i < 8; i++) TEST_1(params[i]); TEST_1(params[8] == NULL); s = list2, params = NULL; TEST_1(msg_params_d(home, &s, ¶ms) >= 0); TEST_1(params); for (i = 0; i < 7; i++) TEST_1(params[i]); TEST_1(params[7] == NULL); s = list3; params = NULL; TEST_1(msg_params_d(home, &s, ¶ms) >= 0); TEST_S(s, end3); TEST_1(params); for (i = 0; i < 7; i++) TEST_1(params[i]); TEST_1(params[7] == NULL); s = list4; params = NULL; TEST_1(msg_params_d(home, &s, ¶ms) >= 0); TEST_1(params); for (i = 0; i < 16; i++) TEST_1(params[i]); TEST_1(params[16] == NULL); s = list5; params = NULL; TEST_1(msg_params_d(home, &s, ¶ms) >= 0); TEST_1(params); for (i = 0; i < 15; i++) TEST_1(params[i]); TEST_1(params[15] == NULL); s = list6 ; params = NULL; TEST_1(msg_params_d(home, &s, ¶ms) >= 0); TEST_1(params); for (i = 0; i < 17; i++) TEST_1(params[i]); TEST_1(params[17] == NULL); su_home_deinit(home); } { /* Test parameter lists */ su_home_t home[1] = { SU_HOME_INIT(home) }; unsigned i, j; msg_param_t const *p = NULL; char *master = ";0", *list, *end; for (i = 1; i < 256; i++) { master = su_sprintf(home, "%s; %u", master, i); TEST_1(master); list = end = su_strdup(home, master); TEST_1(msg_params_d(home, &end, &p) >= 0); TEST_S(end, ""); TEST_1(p); for (j = 0; j <= i; j++) { char number[10]; snprintf(number, sizeof number, "%u", j); TEST_S(p[j], number); } TEST_1(p[i + 1] == NULL); su_free(home, list); su_free(home, (void *)p), p = NULL; } master = ";0"; for (i = 1; i < 256; i++) { master = su_sprintf(home, "%s; %u", master, i); TEST_1(master); list = end = su_strdup(home, master); TEST_1(msg_params_d(NULL, &end, &p) >= 0); TEST_S(end, ""); TEST_1(p); for (j = 0; j <= i; j++) { char number[10]; snprintf(number, sizeof number, "%u", j); TEST_S(p[j], number); } TEST_1(p[i + 1] == NULL); su_free(home, list); su_free(NULL, (void *)p), p = NULL; } su_home_deinit(home); } { /* Test comma-separated list */ su_home_t home[1] = { SU_HOME_INIT(home) }; msg_list_t k1[1] = {{{{ 0 }}}}; char list1[] = "foo, bar, baz zi \"baz\""; TEST_1(msg_list_d(home, (msg_header_t *)k1, list1, strlen(list1)) >= 0); TEST_1(k1->k_items); TEST_S(k1->k_items[0], "foo"); TEST_S(k1->k_items[1], "bar"); TEST_S(k1->k_items[2], "baz zi\042baz\042"); TEST_1(!k1->k_items[3]); su_home_deinit(home); } { /* Test that list of length MSG_PARAMS_N is handled correctly */ su_home_t home[1] = { SU_HOME_INIT(home) }; msg_list_t k2[1] = {{{{ 0 }}}}; char list2[] = "one, two, three, four, five, six, seven, eight"; TEST_1( msg_list_d(home, (msg_header_t *)k2, list2, strlen(list2)) >= 0); TEST_1(k2->k_items); TEST_1(k2->k_items[7]); TEST_1(k2->k_items[8] == NULL); su_home_deinit(home); } { /* Test that list longer than MSG_PARAMS_N is handled correctly */ su_home_t home[1] = { SU_HOME_INIT(home) }; msg_list_t k3[1] = {{{{ 0 }}}}; char list3[] = "one, two, three, four, five, six, seven, eight, nine"; TEST_1( msg_list_d(home, (msg_header_t *)k3, list3, strlen(list3)) >= 0); TEST_1(k3->k_items); TEST_1(k3->k_items[7]); TEST_1(k3->k_items[8]); TEST_1(k3->k_items[9] == NULL); su_home_deinit(home); } { /* Test that long lists are handled correctly */ su_home_t home[1] = { SU_HOME_INIT(home) }; msg_param_t *k = NULL; char *s; char list1[] = "one, two, three, four, five, six, seven, eight"; char list2[] = "one, two, three, four, five, six, seven, eight"; char list3[] = "one, two, three, four, five, six, seven, eight"; char list4[] = "one, two, three, four, five, six, seven, eight, nine"; s = list1; TEST_1(msg_commalist_d(home, &s, &k, msg_token_scan) >= 0); TEST_1(k); TEST_1(k[7]); TEST_1(k[8] == NULL); s = list2; TEST_1(msg_commalist_d(home, &s, &k, msg_token_scan) >= 0); s = list3; TEST_1(msg_commalist_d(home, &s, &k, msg_token_scan) >= 0); s = list4; TEST_1(msg_commalist_d(home, &s, &k, msg_token_scan) >= 0); su_home_deinit(home); } { /* Test parameter lists */ su_home_t home[1] = { SU_HOME_INIT(home) }; unsigned i, j; msg_param_t *p = NULL; char *master = "0", *list, *end; for (i = 1; i < 256; i++) { master = su_sprintf(home, "%s, %u", master, i); TEST_1(master); list = end = su_strdup(home, master); TEST_1(msg_commalist_d(home, &end, &p, msg_token_scan) >= 0); TEST_S(end, ""); TEST_1(p); for (j = 0; j <= i; j++) { char number[10]; snprintf(number, sizeof number, "%u", j); TEST_S(p[j], number); } TEST_1(p[i + 1] == NULL); su_free(home, list); su_free(home, (void *)p), p = NULL; } su_home_deinit(home); } { /* Test that errors in lists are handled correctly */ su_home_t home[1] = { SU_HOME_INIT(home) }; msg_param_t *k = NULL; char *s; char list1[] = "one, two, three, four, five, six, seven, foo=\"eight"; char list2[] = "one, two, three,,@,$ four, five, six, seven, eight"; s = list1; TEST_1(msg_commalist_d(home, &s, &k, NULL) < 0); TEST_1(k == NULL); s = list2; TEST_1(msg_commalist_d(home, &s, &k, msg_token_scan) < 0); su_home_deinit(home); } { /* Test empty parameter list */ su_home_t home[1] = { SU_HOME_INIT(home) }; msg_list_t k4[1] = {{{{ 0 }}}}; char list4[] = ", ,\t,\r\n\t, , "; TEST_1( msg_list_d(home, (msg_header_t *)k4, list4, strlen(list4)) >= 0); TEST_1(k4->k_items == NULL); su_home_deinit(home); } { /* Test authentication headers */ su_home_t home[1] = { SU_HOME_INIT(home) }; msg_auth_t au[1] = {{{{ 0 }}}}; char s[] = "Basic foo = \"bar==\" ,, bar=baari," "baz=\"bof,\\\\ \\\" baff\", base\t64/ - is== ,,"; TEST_1(msg_auth_d(home, (msg_header_t *)au, s, strlen(s)) >= 0); TEST_S(au->au_scheme, "Basic"); TEST_1(au->au_params); TEST_S(au->au_params[0], "foo=\042bar==\042"); TEST_S(au->au_params[1], "bar=baari"); TEST_S(au->au_params[2], "baz=\042bof,\\\\ \\\042 baff\042"); TEST_S(au->au_params[3], "base 64/- is=="); TEST_1(!au->au_params[4]); su_home_deinit(home); } /* Test that msg_*_format() works */ { su_home_t home[1] = { SU_HOME_INIT(home) }; msg_content_type_t *c; c = msg_content_type_format(home, "%s/%s;%s;%s;%s;%s;%s;%s", "text", "plain", "charset=iso-8859-15", "format=flowed", "q=0.999", "msg-size=782572564", "name-space-url=\"http://www.nokia.com/foo\"", "foo=bar"); su_home_deinit(home); } { /* Test parameter handling */ su_home_t home[1] = { SU_HOME_INIT(home) }; msg_content_encoding_t *ce; ce = msg_content_encoding_make(home, "zip, zap, zup, lz, zl, zz, ll"); TEST_1(ce); TEST_S(msg_header_find_param(ce->k_common, "zz"), ""); TEST_S(msg_header_find_item(ce->k_common, "zz"), "zz"); TEST_P(msg_header_find_param(ce->k_common, "k"), NULL); TEST(msg_header_add_param(home, ce->k_common, "zip"), 0); TEST(msg_header_remove_param(ce->k_common, "zip"), 1); TEST_S(msg_header_find_param(ce->k_common, "zip"), ""); TEST(msg_header_remove_param(ce->k_common, "zip"), 1); TEST_P(msg_header_find_param(ce->k_common, "zip"), NULL); TEST(msg_header_remove_param(ce->k_common, "zip"), 0); TEST(msg_header_replace_param(home, ce->k_common, "zip=zap"), 0); TEST_S(msg_header_find_param(ce->k_common, "zip=1"), "zap"); TEST(msg_header_replace_param(home, ce->k_common, "zip=zup"), 1); TEST_S(msg_header_find_param(ce->k_common, "zip"), "zup"); su_home_deinit(home); } { char b[8]; TEST(msg_unquoted_e(NULL, 0, "\"\""), 6); TEST(msg_unquoted_e(b, 0, "\"\""), 6); TEST(msg_unquoted_e(b, 4, "\"\""), 6); TEST(msg_unquoted_e(b, 6, "\"\""), 6); TEST(memcmp(b, "\"\\\"\\\"\"", 6), 0); TEST(msg_unquoted_e(b, 4, "\""), 4); memset(b, 0, sizeof b); TEST(msg_unquoted_e(b, 1, "\"kuik"), 8); TEST(memcmp(b, "\"\0", 2), 0); TEST(msg_unquoted_e(b, 3, "\"kuik"), 8); TEST(memcmp(b, "\"\\\"\0", 4), 0); TEST(msg_unquoted_e(b, 7, "\"kuik"), 8); TEST(memcmp(b, "\"\\\"kuik\0", 8), 0); } END(); } int hash_test(void) { int i, j, hash = 0; msg_mclass_t const *mc = msg_test_mclass; msg_hclass_t *hc; BEGIN(); for (i = 0; i < mc->mc_hash_size; i++) { hc = mc->mc_hash[i].hr_class; if (hc == NULL) continue; hash = msg_header_name_hash(hc->hc_name, NULL); TEST(hash, hc->hc_hash); /* Cross-check hashes */ for (j = i + 1; j < mc->mc_hash_size; j++) { if (mc->mc_hash[j].hr_class == NULL) continue; if (hc->hc_hash == mc->mc_hash[j].hr_class->hc_hash) fprintf(stderr, "\t%s and %s have same hash\n", hc->hc_name, mc->mc_hash[j].hr_class->hc_name); TEST_1(hc->hc_hash != mc->mc_hash[j].hr_class->hc_hash); } } END(); } msg_t *read_msg(char const buffer[]) { return msg_make(msg_test_mclass, MSG_DO_EXTRACT_COPY, buffer, -1); } /**Check if header chain contains any loops. * * @return * Return 0 if no loop, -1 otherwise. */ static int msg_chain_loop(msg_header_t const *h) { msg_header_t const *h2; if (!h) return 0; for (h2 = h->sh_succ; h && h2 && h2->sh_succ; h = h->sh_succ) { if (h == h2 || h == h2->sh_succ) return 1; h2 = h2->sh_succ->sh_succ; if (h == h2) return 1; } return 0; } /** Check header chain consistency. * * @return * Return 0 if consistent, number of errors otherwise. */ static int msg_chain_errors(msg_header_t const *h) { if (msg_chain_loop(h)) return -1; for (; h; h = h->sh_succ) { if (h->sh_succ && h->sh_succ->sh_prev != &h->sh_succ) return -1; if (h->sh_prev && h != (*h->sh_prev)) return -1; } return 0; } int test_msg_parsing(void) { msg_t *msg, *orig; su_home_t *home; msg_test_t *tst, *otst; msg_request_t *request; msg_status_t *status; msg_content_location_t *location; msg_content_language_t *language; msg_accept_language_t *se; msg_separator_t *separator; msg_payload_t *payload; BEGIN(); msg = read_msg("GET a-life HTTP/1.1" CRLF "Content-Length: 6" CRLF "Accept-Language: en;q=0.8, fi, se ; q = 0.6" CRLF "Foo: bar" CRLF CRLF "test" CRLF); home = msg_home(msg); tst = msg_test_public(msg); TEST_1(msg); TEST_1(home); TEST_1(tst); TEST_P(tst->msg_error, NULL); TEST_1(tst->msg_accept_language); TEST_1(status = msg_status_make(home, "HTTP/1.1 200 Ok")); TEST(msg_header_insert(msg, (msg_pub_t *)tst, (msg_header_t *)status), 0); TEST_P(tst->msg_status, status); TEST_P(tst->msg_request, NULL); TEST_1(request = msg_request_make(home, "GET a-wife HTTP/1.0")); TEST(msg_header_insert(msg, (msg_pub_t *)tst, (msg_header_t *)request), 0); TEST_P(tst->msg_request, request); TEST_P(tst->msg_status, NULL); TEST_1(separator = msg_separator_make(home, "\r\n")); TEST(msg_header_insert(msg, (msg_pub_t *)tst, (msg_header_t *)separator), 0); TEST_P(tst->msg_separator, separator); TEST_P(separator->sep_common->h_succ, tst->msg_payload); /* Try to add a new payload */ TEST_1(payload = msg_payload_make(home, "foofaa\r\n")); TEST(msg_header_insert(msg, (msg_pub_t *)tst, (msg_header_t *)payload), 0); /* It is appended */ TEST_P(tst->msg_payload->pl_next, payload); TEST_P(tst->msg_payload->pl_common->h_succ, payload); { msg_param_t vs; int vi = 0; msg_param_t foo = "foo=bar"; vs = NULL; MSG_PARAM_MATCH(vs, foo, "foo"); TEST_S(vs, "bar"); vs = NULL; MSG_PARAM_MATCH(vs, foo, "fo"); TEST_P(vs, NULL); vi = 0; MSG_PARAM_MATCH_P(vi, foo, "foo"); TEST(vi, 1); MSG_PARAM_MATCH_P(vi, foo, "fo"); TEST(vi, 1); vi = 0; MSG_PARAM_MATCH_P(vi, foo, "fo"); TEST(vi, 0); } msg_destroy(msg); /* Bug #2624: */ msg = read_msg("GET /replaces HTTP/1.1" CRLF "Accept-Encoding: gzip" CRLF "Accept-Encoding: bzip2" CRLF "Accept-Encoding: deflate" CRLF "Accept-Language: en;q=0.8, fi, se ; q = 0.6" CRLF ); TEST_1(msg); tst = msg_test_public(msg); TEST_1(tst); { msg_accept_encoding_t *gzip, *bzip2, *deflate; msg_accept_encoding_t *lzss; msg_accept_language_t *en, *fi, *se; msg_accept_language_t *de, *sv, *sv_fi; TEST_1(gzip = tst->msg_accept_encoding); TEST_1(bzip2 = gzip->aa_next); TEST_1(deflate = bzip2->aa_next); TEST_1(gzip->aa_common->h_data); TEST_1(lzss = msg_accept_encoding_make(msg_home(msg), "lzss")); TEST(msg_header_replace(msg, (msg_pub_t *)tst, (void *)bzip2, (void *)lzss), 0); TEST_1(gzip->aa_common->h_data); TEST_1(en = tst->msg_accept_language); TEST_1(fi = en->aa_next); TEST_1(se = fi->aa_next); TEST_S(en->aa_value, "en"); TEST_M(en->aa_common->h_data, "Accept-Language: en;q=0.8, fi, se ; q = 0.6" CRLF, en->aa_common->h_len); TEST_P((char *)en->aa_common->h_data + en->aa_common->h_len, fi->aa_common->h_data); TEST(fi->aa_common->h_len, 0); TEST_P((char *)en->aa_common->h_data + en->aa_common->h_len, se->aa_common->h_data); TEST(se->aa_common->h_len, 0); TEST_1(de = msg_accept_language_make(msg_home(msg), "de;q=0.3")); TEST(msg_header_replace(msg, (msg_pub_t *)tst, (void *)se, (void *)de), 0); TEST_P(en->aa_common->h_data, NULL); TEST_P(en->aa_next, fi); TEST_P(fi->aa_next, de); TEST_P(de->aa_next, NULL); TEST_P(en->aa_common->h_succ, fi); TEST_P(en->aa_common->h_prev, &deflate->aa_common->h_succ); TEST_P(fi->aa_common->h_succ, de); TEST_P(fi->aa_common->h_prev, &en->aa_common->h_succ); TEST_P(de->aa_common->h_succ, NULL); TEST_P(de->aa_common->h_prev, &fi->aa_common->h_succ); TEST_P(se->aa_next, NULL); TEST_P(se->aa_common->h_succ, NULL); TEST_P(se->aa_common->h_prev, NULL); TEST_1(sv = msg_accept_language_make(msg_home(msg), "sv;q=0.6,sv_FI;q=0.7")); TEST_1(sv_fi = sv->aa_next); TEST(msg_header_replace(msg, (msg_pub_t *)tst, (void *)fi, (void *)sv), 0); TEST_P(en->aa_next, sv); TEST_P(sv->aa_next->aa_next, de); TEST_P(de->aa_next, NULL); TEST_P(en->aa_common->h_succ, sv); TEST_P(en->aa_common->h_prev, &deflate->aa_common->h_succ); TEST_P(sv->aa_common->h_succ, sv_fi); TEST_P(sv->aa_common->h_prev, &en->aa_common->h_succ); TEST_P(sv_fi->aa_common->h_succ, de); TEST_P(sv_fi->aa_common->h_prev, &sv->aa_common->h_succ); TEST_P(de->aa_common->h_succ, NULL); TEST_P(de->aa_common->h_prev, &sv_fi->aa_common->h_succ); TEST(msg_serialize(msg, (msg_pub_t *)tst), 0); } msg_destroy(msg); /* Bug #2429 */ orig = read_msg("GET a-life HTTP/1.1" CRLF "Foo: bar" CRLF "Content-Length: 6" CRLF CRLF "test" CRLF "extra stuff" CRLF); TEST_1(orig); otst = msg_test_public(orig); TEST_1(otst); msg = msg_copy(orig); msg_destroy(orig); tst = msg_test_public(msg); TEST_1(tst); home = msg_home(msg); TEST_1(request = msg_request_make(home, "GET a-wife HTTP/1.1")); TEST(msg_header_insert(msg, (msg_pub_t *)tst, (void *)request), 0); TEST_1(location = msg_content_location_make(home, "http://localhost:8080/wife")); TEST(msg_header_insert(msg, (msg_pub_t *)tst, (void *)location), 0); TEST(msg_serialize(msg, (msg_pub_t *)tst), 0); TEST_1(msg_prepare(msg) > 0); TEST_1(language = msg_content_language_make(home, "se-FI, fi-FI, sv-FI")); TEST(msg_header_insert(msg, (msg_pub_t *)tst, (void *)language), 0); TEST_1(se = msg_accept_language_make(home, "se, fi, sv")); TEST_1(se->aa_next); TEST_1(se->aa_next->aa_next); TEST(msg_header_insert(msg, (msg_pub_t *)tst, (void *)se), 0); TEST(msg_serialize(msg, (msg_pub_t *)tst), 0); TEST_1(msg_prepare(msg) > 0); { char const encoded[] = "GET a-wife HTTP/1.1\r\n"; TEST_SIZE(request->rq_common->h_len, strlen(encoded)); TEST_M(request->rq_common->h_data, encoded, request->rq_common->h_len); } { char const encoded[] = "Content-Location: http://localhost:8080/wife\r\n"; TEST_SIZE(location->g_common->h_len, strlen(encoded)); TEST_M(location->g_common->h_data, encoded, location->g_common->h_len); } { char const encoded[] = "Content-Language: se-FI, fi-FI, sv-FI\r\n"; TEST_SIZE(language->k_common->h_len, strlen(encoded)); TEST_M(language->k_common->h_data, encoded, language->k_common->h_len); } { char const encoded[] = "Accept-Language: se, fi, sv\r\n"; TEST_SIZE(se->aa_common->h_len, strlen(encoded)); TEST_M(se->aa_common->h_data, encoded, se->aa_common->h_len); TEST_P((char *)se->aa_common->h_data + se->aa_common->h_len, se->aa_next->aa_common->h_data); TEST_P((char *)se->aa_common->h_data + se->aa_common->h_len, se->aa_next->aa_next->aa_common->h_data); } { size_t size = SIZE_MAX; char *s; char body[66 * 15 + 1]; int i; msg_payload_t *pl; /* Bug #1726034 */ for (i = 0; i < 15; i++) strcpy(body + i * 66, "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\r\n"); pl = msg_payload_make(msg_home(msg), body); TEST(msg_header_insert(msg, (msg_pub_t *)tst, (void *)pl), 0); s = msg_as_string(msg_home(msg), msg, NULL, 0, &size); TEST_S(s, "GET a-wife HTTP/1.1" CRLF "Foo: bar" CRLF "Content-Length: 6" CRLF "Content-Location: http://localhost:8080/wife\r\n" "Content-Language: se-FI, fi-FI, sv-FI\r\n" "Accept-Language: se, fi, sv\r\n" CRLF "test" CRLF "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" CRLF "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" CRLF "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" CRLF "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" CRLF "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" CRLF "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" CRLF "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" CRLF "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" CRLF "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" CRLF "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" CRLF "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" CRLF "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" CRLF "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" CRLF "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" CRLF "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" CRLF ); } msg_destroy(msg); END(); } static int test_warning(void) { msg_warning_t *w; su_home_t *home; char buf[64]; BEGIN(); TEST_1(home = su_home_new(sizeof *home)); TEST_1((w = msg_warning_make(home, "399 host:5060 \"Ok\", " "399 [::1]:39999 \"foo\\\" bar\""))); TEST(w->w_code, 399); TEST_S(w->w_host, "host"); TEST_S(w->w_port, "5060"); TEST_S(w->w_text, "Ok"); TEST_1(w = w->w_next); TEST(w->w_code, 399); TEST_S(w->w_host, "[::1]"); TEST_S(w->w_port, "39999"); TEST_S(w->w_text, "foo\" bar"); TEST_1(w->w_next == NULL); TEST_1(msg_warning_e(buf, sizeof buf, (msg_header_t *)w, 0) > 0); TEST_S(buf, "399 [::1]:39999 \"foo\\\" bar\""); su_home_unref(home); END(); } /* Test error handling */ int test_msg_error(void) { msg_t *msg; su_home_t *home; msg_test_t *tst; BEGIN(); msg = read_msg("GET a-life HTTP/1.1" CRLF "Content-Length: 6" CRLF "Content-Language: fi" CRLF "Content-Language: " CRLF "Accept-Language: en;q=0.8, fi, \"\", se ; q = 0.6" CRLF "Foo bar baf: bar" CRLF CRLF "test" CRLF); home = msg_home(msg); tst = msg_test_public(msg); TEST_1(msg); TEST_1(home); TEST_1(tst); TEST_1(tst->msg_error); msg_destroy(msg); END(); } int test_mclass(void) { msg_t *msg; su_home_t *home; msg_test_t *tst; msg_request_t *request; msg_status_t *status; msg_separator_t *separator; msg_payload_t *payload; msg_content_length_t *l; msg_content_language_t *la; msg_content_encoding_t *k0, *k; msg_unknown_t *foo; BEGIN(); /* Test that critical errors are signaled */ msg = read_msg("GET a-life HTTP/1.1" CRLF "Content-Length: 6bytes" CRLF "Content-Type: *" CRLF "Foo: bar" CRLF "Content-Encoding: identity" CRLF "Content-Language: en" CRLF "Content-Language: en-us" CRLF CRLF "test" CRLF); tst = msg_test_public(msg); TEST_1(msg); TEST_1(tst); TEST_1(MSG_HAS_ERROR(tst->msg_flags)); /* Content-Length is critical */ msg_destroy(msg); msg = read_msg("GET a-life HTTP/1.1" CRLF "Content-Length: 6" CRLF "Content-Type: *" CRLF "Foo: bar" CRLF "Content-Encoding: " CRLF /* XXX */ "Content-Language: en" CRLF "Content-Language: en-us" CRLF CRLF "test" CRLF); home = msg_home(msg); tst = msg_test_public(msg); TEST_1(msg); TEST_1(home); TEST_1(tst); TEST_SIZE(msg_iovec(msg, NULL, 0), 1); TEST_1(tst->msg_unknown); /* Foo */ TEST_1(tst->msg_content_type == NULL); TEST_1(tst->msg_error); /* Content-Type */ TEST_1(tst->msg_error->er_next == NULL); TEST_1(!MSG_HAS_ERROR(tst->msg_flags)); /* Content-type is not critical */ TEST_1(la = tst->msg_content_language); TEST_1(la->k_common->h_data); TEST_1(la->k_items); TEST_S(la->k_items[0], "en"); TEST_S(la->k_items[1], "en-us"); TEST_P(la->k_items[2], NULL); TEST_1(la->k_next); TEST_1(la->k_next->k_common->h_data); TEST_1(la->k_next->k_items == NULL); TEST(msg_header_add_make(msg, (msg_pub_t *)tst, msg_content_language_class, "en-gb"), 0); TEST_P(la, tst->msg_content_language); TEST_P(la->k_common->h_data, NULL); TEST_S(la->k_items[2], "en-gb"); TEST_P(la->k_next, NULL); TEST_1(status = msg_status_make(home, "HTTP/1.1 200 Ok")); TEST(msg_header_insert(msg, (msg_pub_t *)tst, (msg_header_t *)status), 0); TEST_P(tst->msg_status, status); TEST_P(tst->msg_request, NULL); TEST_1(request = msg_request_make(home, "GET a-wife HTTP/1.0")); TEST(msg_header_insert(msg, (msg_pub_t *)tst, (msg_header_t *)request), 0); TEST_P(tst->msg_request, request); TEST_P(tst->msg_status, NULL); TEST_1(separator = msg_separator_make(home, "\r\n")); TEST(msg_header_insert(msg, (msg_pub_t *)tst, (msg_header_t *)separator), 0); TEST_P(tst->msg_separator, separator); TEST_P(separator->sep_common->h_succ, tst->msg_payload); /* Try to add a new payload */ TEST_1(payload = msg_payload_make(home, "foofaa\r\n")); TEST(msg_header_insert(msg, (msg_pub_t *)tst, (msg_header_t *)payload), 0); /* The new payload should be appended */ TEST_P(tst->msg_payload->pl_next, payload); TEST_P(tst->msg_payload->pl_common->h_succ, payload); /* Try to add a new header */ TEST_1(l = msg_content_length_create(home, tst->msg_payload->pl_len + payload->pl_len)); TEST(msg_header_insert(msg, (msg_pub_t *)tst, (msg_header_t *)l), 0); /* The new header should be last before separator */ TEST_P(l->l_common->h_succ, separator); TEST_1(foo = tst->msg_unknown); TEST_S(foo->un_name, "Foo"); TEST_S(foo->un_value, "bar"); foo->un_value = "baz"; TEST_1(foo = msg_unknown_dup(home, foo)); TEST(msg_header_insert(msg, (msg_pub_t *)tst, (msg_header_t *)foo), 0); TEST_P(tst->msg_unknown->un_next, foo); TEST_1(k = msg_content_encoding_make(home, "gzip, compress")); k0 = tst->msg_content_encoding; TEST(msg_header_add_dup(msg, (msg_pub_t *)tst, (msg_header_t *)k), 0); TEST_P(k0, tst->msg_content_encoding); TEST_1(k0->k_items); TEST_S(k0->k_items[0], "gzip"); TEST_S(k0->k_items[1], "compress"); TEST_P(k0->k_items[2], NULL); TEST_1(k = msg_content_encoding_make(home, "gzip, deflate, compress")); TEST(msg_header_add_dup(msg, (msg_pub_t *)tst, (msg_header_t *)k), 0); TEST_P(k0, tst->msg_content_encoding); TEST_1(k0->k_items); TEST_S(k0->k_items[0], "gzip"); TEST_S(k0->k_items[1], "compress"); TEST_S(k0->k_items[2], "deflate"); TEST_P(k0->k_items[3], NULL); msg_destroy(msg); END(); } int test_copy(void) { msg_t *msg0, *msg, *msg1, *msg2; su_home_t *home; msg_test_t *tst0, *tst, *copy, *dup; msg_request_t *request; msg_common_t *h, *h_succ; msg_iovec_t iovec[8]; char const s[] = "GET /a-life HTTP/1.1" CRLF "Content-Length: 6" CRLF "Content-Type: *" CRLF "Foo: bar" CRLF "Content-Language: " CRLF CRLF "test" CRLF; BEGIN(); msg0 = read_msg(s); TEST_1(msg0); TEST_1(tst0 = msg_test_public(msg0)); TEST_SIZE(msg_iovec(msg0, iovec, 8), 1); TEST_1(msg = msg_copy(msg0)); TEST_1(copy = msg_test_public(msg)); TEST_1(copy->msg_request); TEST_1(tst0->msg_request); TEST_S(copy->msg_request->rq_url->url_path, tst0->msg_request->rq_url->url_path); TEST_S(copy->msg_request->rq_url->url_path, "a-life"); TEST_P(copy->msg_request->rq_url->url_path, tst0->msg_request->rq_url->url_path); msg_destroy(msg); TEST_1(msg = msg_dup(msg0)); TEST_1(dup = msg_test_public(msg)); TEST_1(dup->msg_request); TEST_1(tst0->msg_request); TEST_S(dup->msg_request->rq_url->url_path, tst0->msg_request->rq_url->url_path); TEST_S(dup->msg_request->rq_url->url_path, "a-life"); TEST_1(dup->msg_request->rq_url->url_path != tst0->msg_request->rq_url->url_path); msg_destroy(msg); TEST_1(msg = msg_copy(msg0)); msg_destroy(msg0); TEST_1(home = msg_home(msg)); TEST_1(tst = msg_test_public(msg)); TEST_1(tst->msg_unknown); /* Foo */ TEST_1(tst->msg_content_type == NULL); TEST_1(tst->msg_error); /* Content-Type */ TEST_1(!MSG_HAS_ERROR(tst->msg_flags)); /* Flags are not copied */ TEST_1(tst0->msg_request); TEST_1(request = tst->msg_request); TEST_P(tst0->msg_request->rq_url->url_path, request->rq_url->url_path); TEST_SIZE(msg_iovec(msg, iovec, 8), 1); TEST_S(iovec->siv_base, s); TEST_1(msg1 = msg_dup(msg)); TEST_1(tst = msg_test_public(msg1)); TEST_1(tst->msg_request); for (h = tst->msg_request->rq_common; h; h = h_succ) { if (h->h_prev) *h->h_prev = NULL; h_succ = (msg_common_t*)h->h_succ; h->h_succ = NULL; } TEST_1(msg2 = msg_copy(msg1)); msg_destroy(msg2); TEST_1(msg2 = msg_dup(msg1)); msg_destroy(msg2); msg_destroy(msg1); msg_destroy(msg); END(); } int test_mime(void) { msg_t *msg; su_home_t *home; int n; msg_test_t *tst; msg_header_t *h, *h_succ, *head; void *removed; msg_accept_t *ac, *ac0; msg_accept_charset_t *aa; msg_multipart_t *mp, *mp0, *mpX, *mpnew; msg_payload_t *pl; msg_content_type_t *c; msg_content_id_t *cid; msg_content_transfer_encoding_t *cte; char const s[] = "GET /a-life HTTP/1.1" CRLF "Accept: text/html;level=4;q=1" CRLF "Accept: text / plain;q=0.9" CRLF "Accept-Charset: *;q=0.1, iso-latin-1, utf-8;q=0.9" CRLF "Accept-Encoding: gzip;q=0.9, deflate" CRLF "Accept-Encoding: , identity ," CRLF "Accept: */*;q=0.2" CRLF "Accept-Language: en;q=0.5, es;q=0.2, fr;q=0.9, fi, x-pig-latin" CRLF "Content-Language: fi, se" CRLF "Content-Language: en, de" CRLF "Content-Disposition: render; required" CRLF "Content-Encoding: gzip, deflate" CRLF "Content-Base: http://localhost/foo" CRLF "MIME-Version: 1.0" CRLF "Content-Type: multipart/alternative ; boundary=\"LaGqGt4BI6Ho\"" CRLF /* "Content-Length: 305" CRLF */ "Content-MD5: LLO7gLaGqGt4BI6HouiWng==" CRLF CRLF "test" CRLF CRLF /* 1 */ "--LaGqGt4BI6Ho" " " CRLF CRLF /* 2 */ "part 1" CRLF /* 3 */ CRLF /* 4 */ "--LaGqGt4BI6Ho" CRLF "Content-Type: text/plain ; charset = iso-8859-1" CRLF /* 5 */ "Content-ID: " CRLF /* 6 */ "Content-Transfer-Encoding: quoted-unreadable" CRLF /* 7 */ CRLF /* 8 */ "part 2" /* 9 */ CRLF "--LaGqGt4BI6Ho" /* 10 */ "Content-Type: text/html" CRLF /* 11 */ "Content-ID: <4SP77aQZ9z6Top2dvLqKPQ@localhost>" CRLF /* 12 */ CRLF /* 13 */ #define BODY3 "part 3" CRLF BODY3 /* 14 */ CRLF "--LaGqGt4BI6Ho" /* 15 */ "c: text/html" CRLF /* 16 */ "l: 9" CRLF /* 17 */ "e: identity" CRLF /* 18 */ CRLF /* 19 */ #define BODY4 "" CRLF BODY4 /* 20 */ CRLF "--LaGqGt4BI6Ho--" /* 21 */ CRLF; BEGIN(); msg = read_msg(s); home = msg_home(msg); tst = msg_test_public(msg); TEST_1(msg); TEST_1(home); TEST_1(tst); TEST_1(tst->msg_error == NULL); TEST_1((tst->msg_flags & MSG_FLG_ERROR) == 0); TEST_1(ac = tst->msg_accept); TEST_1(ac = ac->ac_next); TEST_S(ac->ac_type, "text/plain"); TEST_S(ac->ac_q, "0.9"); TEST_1(ac = msg_accept_dup(home, ac)); TEST_S(ac->ac_type, "text/plain"); TEST_S(ac->ac_q, "0.9"); TEST_S(tst->msg_accept->ac_next->ac_q, "0.9"); TEST_1(ac->ac_q != tst->msg_accept->ac_next->ac_q); TEST_1(ac = msg_accept_make(home, "text / plain")); ac->ac_q = "1.0"; TEST_1(ac = msg_accept_dup(home, ac0 = ac)); TEST_1(ac->ac_q != ac0->ac_q); for (h = (msg_header_t *)tst->msg_request; h; h = h->sh_succ) { TEST_1(h->sh_data); if (h->sh_succ) TEST_P((char*)h->sh_data + h->sh_len, h->sh_succ->sh_data); } TEST_1(aa = tst->msg_accept_charset); TEST_S(aa->aa_value, "*"); TEST_S(aa->aa_q, "0.1"); mp = msg_multipart_parse(home, tst->msg_content_type, tst->msg_payload); TEST_1(mp0 = mp); TEST_1(mp->mp_data); TEST(memcmp(mp->mp_data, CRLF "--" "LaGqGt4BI6Ho" CRLF, mp->mp_len), 0); TEST_1(mp->mp_common->h_data); // TEST_M(mp->mp_common->h_data, CRLF "--" "LaGqGt4BI6Ho" " " CRLF, mp->mp_common->h_len); TEST_1(pl = mp->mp_payload); TEST_1(pl->pl_data); TEST_SIZE(strlen("part 1" CRLF), pl->pl_len); TEST(memcmp(pl->pl_data, "part 1" CRLF, pl->pl_len), 0); TEST_1(mp = mp->mp_next); TEST_1(mp->mp_data); TEST(memcmp(mp->mp_data, CRLF "--" "LaGqGt4BI6Ho" CR LF, mp->mp_len), 0); TEST_1(c = mp->mp_content_type); TEST_S(c->c_type, "text/plain"); TEST_S(c->c_subtype, "plain"); TEST_1(c->c_params); TEST_1(c->c_params[0]); TEST_S(c->c_params[0], "charset=iso-8859-1"); TEST_1(cid = mp->mp_content_id); TEST_1(cte = mp->mp_content_transfer_encoding); TEST_S(cte->g_string, "quoted-unreadable"); TEST_1(pl = mp->mp_payload); TEST_1(pl->pl_data); TEST_SIZE(strlen("part 2"), pl->pl_len); TEST(memcmp(pl->pl_data, "part 2", pl->pl_len), 0); TEST_1(mp = mp->mp_next); TEST_1(mp->mp_data); TEST_M(mp->mp_data, CRLF "--" "LaGqGt4BI6Ho" CRLF, mp->mp_len); TEST_1(pl = mp->mp_payload); TEST_1(pl->pl_data); TEST_SIZE(strlen(BODY3), pl->pl_len); TEST(memcmp(pl->pl_data, BODY3, pl->pl_len), 0); TEST_1(mp = mp->mp_next); TEST_1(mp->mp_data); TEST_M(mp->mp_data, CRLF "--" "LaGqGt4BI6Ho" CRLF, mp->mp_len); TEST_1(mp->mp_content_encoding); TEST_1(mp->mp_content_type); TEST_1(pl = mp->mp_payload); TEST_1(pl->pl_data); TEST_SIZE(strlen(BODY4), pl->pl_len); TEST(memcmp(pl->pl_data, BODY4, pl->pl_len), 0); mpX = mp; TEST_1(!(mp = mp->mp_next)); /* Test serialization */ head = NULL; TEST_1(h = msg_multipart_serialize(&head, mp0)); TEST_P((void *)h, mpX->mp_close_delim); TEST_1(!msg_chain_errors((msg_header_t *)mp0)); /* Remove chain */ for (h = (msg_header_t *)mp0, n = 0; h; h = h_succ, n++) { h_succ = h->sh_succ; if (h->sh_prev) *h->sh_prev = NULL; h->sh_prev = NULL; h->sh_succ = NULL; } TEST(n, 21); head = NULL; TEST_1(h = msg_multipart_serialize(&head, mp0)); TEST_P(h, mpX->mp_close_delim); TEST_1(!msg_chain_errors((msg_header_t *)mp0)); for (h = (msg_header_t *)mp0, n = 0; h; h = h_succ, n++) { h_succ = h->sh_succ; } TEST(n, 21); /* Add a new part to multipart */ mpnew = su_zalloc(home, sizeof(*mpnew)); TEST_1(mpnew); removed = mpX->mp_close_delim; mpX->mp_next = mpnew; mpX = mpnew; mpnew->mp_content_type = msg_content_type_make(home, "multipart/mixed"); TEST_1(mpnew->mp_content_type); TEST(msg_multipart_complete(msg_home(msg), tst->msg_content_type, mp0), 0); head = NULL; TEST_1(h = msg_multipart_serialize(&head, mp0)); TEST_P((void *)h, mpX->mp_close_delim); TEST_1(!msg_chain_errors((msg_header_t *)mp0)); for (h = (msg_header_t *)mp0, n = 0; h; h = h_succ, n++) { h_succ = h->sh_succ; TEST_1(h != removed); } TEST(n, 21 + 4); #define remove(h) \ (((*((msg_header_t*)(h))->sh_prev = ((msg_header_t*)(h))->sh_succ) ? \ (((msg_header_t*)(h))->sh_succ->sh_prev = ((msg_header_t*)(h))->sh_prev) \ : NULL), \ ((msg_header_t*)(h))->sh_succ = NULL, \ ((msg_header_t*)(h))->sh_prev = NULL) remove(mp0->mp_separator); remove(mp0->mp_next->mp_payload); remove(mp0->mp_next->mp_next->mp_content_type); remove(mp0->mp_next->mp_next->mp_next->mp_next->mp_close_delim); TEST_1(!msg_chain_errors((msg_header_t *)mp0)); head = NULL; TEST_1(h = msg_multipart_serialize(&head, mp0)); TEST_P(h, mpX->mp_close_delim); TEST_1(!msg_chain_errors((msg_header_t *)mp0)); for (h = (msg_header_t *)mp0, n = 0; h; h = h_succ, n++) { h_succ = h->sh_succ; if (h_succ == NULL) TEST_P(h, mpX->mp_close_delim); TEST_1(h != removed); } TEST(n, 21 + 4); /* Add an recursive multipart */ mpnew = su_zalloc(home, sizeof(*mpnew)); TEST_1(mpnew); mpX->mp_multipart = mpnew; mpnew->mp_content_type = msg_content_type_make(home, "text/plain"); TEST_1(mpnew->mp_content_type); TEST(msg_multipart_complete(msg_home(msg), tst->msg_content_type, mp0), 0); TEST_1(mpnew->mp_close_delim); head = NULL; TEST_1(h = msg_multipart_serialize(&head, mp0)); TEST_P(h, mpX->mp_close_delim); TEST_1(!msg_chain_errors((msg_header_t *)mp0)); for (h = (msg_header_t *)mp0, n = 0; h; h = h_succ, n++) h_succ = h->sh_succ; TEST(n, 21 + 9); su_home_check(home); su_home_zap(home); END(); } /** Test MIME encoding */ int test_mime2(void) { msg_t *msg; su_home_t *home; int n, m, len; msg_test_t *tst; msg_header_t *h; msg_accept_charset_t *aa; msg_multipart_t *mp; msg_content_type_t *c; msg_payload_t *pl; char const *end; char const s[] = "GET /a-life HTTP/1.1" CRLF "Accept: text/html;level=4;q=1" CRLF "Accept: text / plain;q=0.9" CRLF "Accept-Charset: *;q=0.1, iso-latin-1, utf-8;q=0.9" CRLF "Accept-Encoding: gzip;q=0.9, deflate" CRLF "Accept-Encoding: , identity ," CRLF "Accept: */*;q=0.2" CRLF "Accept-Language: en;q=0.5, es;q=0.2, fr;q=0.9, fi, x-pig-latin" CRLF "Content-Language: fi, se" CRLF "Content-Language: en, de" CRLF "Content-Disposition: render; required" CRLF "Content-Encoding: gzip, deflate" CRLF "Content-Base: http://localhost/foo" CRLF "MIME-Version: 1.0" CRLF "Content-Type: multipart/alternative ; boundary=\"LaGqGt4BI6Ho\"" CRLF "Content-MD5: LLO7gLaGqGt4BI6HouiWng==" CRLF CRLF "test" CRLF CRLF /* 1 */ "--LaGqGt4BI6Ho" " " CRLF CRLF /* 2 */ "part 1" CRLF /* 3 */ CRLF /* 4 */ "--LaGqGt4BI6Ho" CRLF "Content-Type: text/plain;charset=iso-8859-1" CRLF /* 5 */ "Content-ID: " CRLF /* 6 */ "Content-Transfer-Encoding: quoted-unreadable" CRLF /* 7 */ CRLF /* 8 */ "part 2" /* 9 */ CRLF "--LaGqGt4BI6Ho" /* 10 */ "Content-Type: text/html" CRLF /* 11 */ "Content-ID: <4SP77aQZ9z6Top2dvLqKPQ@localhost>" CRLF /* 12 */ CRLF /* 13 */ #define BODY3 "part 3" CRLF BODY3 /* 14 */ CRLF /* 15 */ "--LaGqGt4BI6Ho--" CRLF; char const part1[] = "This is text\n"; char const part2[] = "This is html"; char const part3[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; BEGIN(); msg = read_msg(s); home = msg_home(msg); tst = msg_test_public(msg); TEST_1(msg); TEST_1(home); TEST_1(tst); TEST_1(tst->msg_error == NULL); TEST_1((tst->msg_flags & MSG_FLG_ERROR) == 0); for (h = (msg_header_t *)tst->msg_request; h; h = h->sh_succ) { TEST_1(h->sh_data); if (h->sh_succ) TEST_P((char*)h->sh_data + h->sh_len, h->sh_succ->sh_data); } TEST_1(aa = tst->msg_accept_charset); TEST_S(aa->aa_value, "*"); TEST_S(aa->aa_q, "0.1"); TEST_1(c = tst->msg_content_type); TEST_1(tst->msg_payload); { su_home_t h0[1] = { SU_HOME_INIT(h0) }; pl = msg_payload_dup(h0, tst->msg_payload); TEST_1(pl); mp = msg_multipart_parse(home, c, pl); TEST_1(mp); for (n = 0, h = (msg_header_t *)mp; h; h = h->sh_succ, n++) h->sh_data = NULL, h->sh_len = 0; TEST(n, 15); n = msg_multipart_prepare(msg, mp, 0); TEST_1(end = strstr(s, "--LaGqGt4BI6Ho ")); len = strlen(end); TEST(len, n); TEST_1(mp = msg_multipart_dup(h0, mp)); su_home_check(h0); su_home_deinit(h0); } /* Test parsing without explicit boundary */ { su_home_t h0[1] = { SU_HOME_INIT(h0) }; pl = msg_payload_dup(h0, tst->msg_payload); TEST_1(pl); mp = msg_multipart_parse(h0, NULL, pl); TEST_1(mp); for (n = 0, h = (msg_header_t *)mp; h; h = h->sh_succ, n++) h->sh_data = NULL, h->sh_len = 0; TEST(n, 15); n = msg_multipart_prepare(msg, mp, 0); TEST_1(end = strstr(s, "--LaGqGt4BI6Ho ")); len = strlen(end); TEST(len, n); TEST_1(mp = msg_multipart_dup(h0, mp)); su_home_check(h0); su_home_deinit(h0); } /* Test parsing without preamble and explicit boundary */ { su_home_t h0[1] = { SU_HOME_INIT(h0) }; pl = msg_payload_dup(h0, tst->msg_payload); TEST_1(pl); n = strstr(pl->pl_data, "--LaGqGt4BI6Ho") - (char *)pl->pl_data; pl->pl_data = n + (char *)pl->pl_data; pl->pl_len -= n; len = pl->pl_len; mp = msg_multipart_parse(h0, NULL, pl); TEST_1(mp); for (n = 0, h = (msg_header_t *)mp; h; h = h->sh_succ, n++) h->sh_data = NULL, h->sh_len = 0; TEST(n, 15); n = msg_multipart_prepare(msg, mp, 0); TEST(len, n); TEST_1(mp = msg_multipart_dup(h0, mp)); su_home_check(h0); su_home_deinit(h0); } /* Test parsing without CR's */ { su_home_t h0[1] = { SU_HOME_INIT(h0) }; char *b; pl = msg_payload_dup(h0, tst->msg_payload); TEST_1(pl); /* Remove CRs */ b = pl->pl_data, len = pl->pl_len; for (n = m = 0; n < len; n++) { if ((b[m] = b[n]) != '\r') m++; } pl->pl_len = m; mp = msg_multipart_parse(h0, NULL, pl); TEST_1(mp); for (n = 0, h = (msg_header_t *)mp; h; h = h->sh_succ, n++) h->sh_data = NULL, h->sh_len = 0; TEST(n, 15); n = msg_multipart_prepare(msg, mp, 0); TEST_1(n > 0); TEST_1(mp = msg_multipart_dup(h0, mp)); su_home_check(h0); su_home_deinit(h0); } /* Create a new multipart from three parts */ TEST_1(c = msg_content_type_make(home, "multipart/related")); TEST_1(mp = msg_multipart_create(home, "text/plain", part1, strlen(part1))); TEST_1(mp->mp_next = msg_multipart_create(home, "text/html", part2, strlen(part2))); TEST_1(mp->mp_next->mp_next = msg_multipart_create(home, "application/octet-stream", part3, sizeof part3)); TEST(msg_multipart_complete(home, c, mp), 0); h = NULL; TEST_P(msg_multipart_serialize(&h, mp), mp->mp_next->mp_next->mp_close_delim); TEST_1(msg_multipart_prepare(msg, mp, 0)); TEST_1(mp = msg_multipart_dup(home, mp)); su_home_check(home); su_home_zap(home); END(); } /* Test serialization */ int test_serialize(void) { msg_t *msg; su_home_t *home; msg_test_t *tst; msg_mime_version_t *mime; msg_separator_t *sep; msg_payload_t *pl; msg_accept_encoding_t *aen; msg_accept_language_t *ala; char const s[] = "GET /a-life HTTP/1.1" CRLF "Accept-Language: fi" CRLF "Accept-Encoding: z0" CRLF "Accept-Language: se, de" CRLF "Accept-Encoding: z1, z2" CRLF "Accept-Language: en, sv" CRLF "Accept-Encoding: z3, z4" CRLF "Content-Length: 6" CRLF CRLF "test" CRLF; BEGIN(); msg = read_msg(s); TEST_1(msg); home = msg_home(msg); TEST_1(tst = msg_test_public(msg)); TEST(msg_chain_errors((msg_header_t *)tst->msg_request), 0); TEST_1(ala = tst->msg_accept_language->aa_next->aa_next); TEST(msg_header_remove(msg, (msg_pub_t *)tst, (msg_header_t *)ala), 0); TEST_S(ala->aa_value, "de"); TEST_1(ala = tst->msg_accept_language); TEST_1(ala = ala->aa_next); TEST_S(ala->aa_value, "se"); /* Make sure that cached encoding of se is reset */ TEST_1(ala->aa_common->h_data == NULL); TEST_1(ala->aa_common->h_len == 0); TEST_1(ala = ala->aa_next); TEST_S(ala->aa_value, "en"); /* Make sure that cached encoding of en is kept intact */ TEST_1(ala->aa_common->h_data != NULL); TEST_1(ala->aa_common->h_len != 0); TEST_1(aen = tst->msg_accept_encoding->aa_next->aa_next); TEST(msg_header_remove_all(msg, (msg_pub_t *)tst, (msg_header_t *)aen), 0); TEST_1(aen = tst->msg_accept_encoding); TEST_1(aen = aen->aa_next); TEST_S(aen->aa_value, "z1"); /* Make sure that cached encoding of z1 is reset */ TEST_1(aen->aa_common->h_data == NULL); TEST_1(aen->aa_common->h_len == 0); TEST_1(aen->aa_next == NULL); TEST_1(aen->aa_common->h_succ == (void *)ala); TEST_1(ala->aa_next->aa_common); TEST_1(ala->aa_next->aa_common->h_succ == (void *)tst->msg_content_length); TEST_1(mime = msg_mime_version_make(home, "1.0")); tst->msg_mime_version = mime; TEST(msg_serialize(msg, (msg_pub_t *)tst), 0); TEST(msg_chain_errors((msg_header_t *)tst->msg_request), 0); TEST_P(tst->msg_content_length->l_common->h_succ, mime); TEST_P(mime->g_common->h_succ, tst->msg_separator); msg_header_remove(msg, (msg_pub_t *)tst, (msg_header_t *)tst->msg_separator); TEST_1(sep = msg_separator_make(home, CRLF)); tst->msg_separator = sep; TEST(msg_serialize(msg, (msg_pub_t *)tst), 0); TEST(msg_chain_errors((msg_header_t *)tst->msg_request), 0); TEST_P(mime->g_common->h_succ, sep); TEST_P(sep->sep_common->h_succ, tst->msg_payload); msg_header_remove(msg, (msg_pub_t *)tst, (msg_header_t *)tst->msg_payload); TEST_1(pl = msg_payload_make(home, "foobar" CRLF)); pl->pl_next = tst->msg_payload; tst->msg_payload = pl; TEST(msg_serialize(msg, (msg_pub_t *)tst), 0); TEST(msg_chain_errors((msg_header_t *)tst->msg_request), 0); TEST_P(mime->g_common->h_succ, sep); TEST_P(sep->sep_common->h_succ, pl); TEST_P(pl->pl_common->h_succ, pl->pl_next); msg_destroy(msg); END(); } static int random_test(void) { struct { uint64_t low, mid, hi; } seed = { 0, 0, 0 }; uint8_t zeros[24] = { 0 }; uint8_t ones[24]; char token[33]; BEGIN(); memset(ones, 255, sizeof ones); TEST_SIZE(msg_random_token(token, 32, (void *)&seed, sizeof(seed)), 32); TEST_S(token, "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"); TEST_SIZE(msg_random_token(token, 32, zeros, 4), 7); TEST_S(token, "aaaaaaa"); TEST_SIZE(msg_random_token(token, 32, ones, 4), 7); /* Last char may vary.. */ token[6] = 0; TEST_S(token, "999999"); TEST_SIZE(msg_random_token(token, 32, zeros, 8), 13); TEST_S(token, "aaaaaaaaaaaaa"); TEST_SIZE(msg_random_token(token, 32, zeros, 12), 20); TEST_S(token, "aaaaaaaaaaaaaaaaaaaa"); END(); } void usage(int exitcode) { fprintf(stderr, "usage: %s [-v] [-a]\n", name); exit(exitcode); } int main(int argc, char *argv[]) { int retval = 0; int i; for (i = 1; argv[i]; i++) { if (strcmp(argv[i], "-v") == 0) test_flags |= tst_verbatim; else if (strcmp(argv[i], "-a") == 0) test_flags |= tst_abort; else usage(1); } #if HAVE_OPEN_C test_flags |= tst_verbatim; #endif retval |= msg_time_test(); fflush(stdout); retval |= addr_test(); fflush(stdout); retval |= hash_test(); fflush(stdout); retval |= random_test(); fflush(stdout); retval |= test_header_parsing(); fflush(stdout); retval |= test_msg_parsing(); fflush(stdout); retval |= test_warning(); fflush(stdout); retval |= test_msg_error(); fflush(stdout); retval |= test_mclass(); fflush(stdout); retval |= test_copy(); fflush(stdout); retval |= test_mime(); fflush(stdout); retval |= test_mime2(); fflush(stdout); retval |= test_serialize(); fflush(stdout); return retval; }