/* Copyright (c) 2008, 2017, Oracle and/or its affiliates. All rights reserved. This program 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; version 2 of the License. This program 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, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */ #include #include #include #include #include #include #include #include #include /* test helpers, to inspect data */ bool read_nth_attr(const char *connect_attrs, uint connect_attrs_length, const CHARSET_INFO *connect_attrs_cs, uint ordinal, char *attr_name, uint max_attr_name, uint *attr_name_length, char *attr_value, uint max_attr_value, uint *attr_value_length); void test_blob_parser() { char name[100], value[4096]; unsigned char packet[10000], *ptr; uint name_len, value_len, idx, packet_length; bool result; const CHARSET_INFO *cs= &my_charset_utf8_bin; diag("test_blob_parser"); result= read_nth_attr("", 0, cs, 0, name, 32, &name_len, value, 1024, &value_len); ok(result == false, "zero length blob"); result= read_nth_attr("\x1", 1, cs, 0, name, 32, &name_len, value, 1024, &value_len); ok(result == false, "invalid key length"); result= read_nth_attr("\x2k1\x1", 4, cs, 0, name, 32, &name_len, value, 1024, &value_len); ok(result == false, "invalid value length"); result= read_nth_attr("\x2k1\x2v1", 6, cs, 0, name, 32, &name_len, value, 1024, &value_len); ok(result == true, "one pair return"); ok(name_len == 2, "one pair attr name length"); ok(!strncmp(name, "k1", name_len), "one pair attr name"); ok(value_len == 2, "one pair value length"); ok(!strncmp(value, "v1", value_len), "one pair value"); result= read_nth_attr("\x2k1\x2v1", 6, cs, 1, name, 32, &name_len, value, 1024, &value_len); ok(result == false, "no second arg"); result= read_nth_attr("\x2k1\x2v1\x2k2\x2v2", 12, cs, 1, name, 32, &name_len, value, 1024, &value_len); ok(result == true, "two pairs return"); ok(name_len == 2, "two pairs attr name length"); ok(!strncmp(name, "k2", name_len), "two pairs attr name"); ok(value_len == 2, "two pairs value length"); ok(!strncmp(value, "v2", value_len), "two pairs value"); result= read_nth_attr("\x2k1\xff\x2k2\x2v2", 12, cs, 1, name, 32, &name_len, value, 1024, &value_len); ok(result == false, "two pairs first value bad return"); result= read_nth_attr("\x2k1\x2v1\x2k2\x2v2", 10, cs, 1, name, 32, &name_len, value, 1024, &value_len); ok(result == false, "two pairs wrong global length"); result= read_nth_attr("\x21z123456789z123456789z123456789z12\x2v1", 37, cs, 0, name, 32, &name_len, value, 1024, &value_len); ok(result == true, "attr name overflow"); ok(name_len == 32, "attr name overflow length"); ok(!strncmp(name, "z123456789z123456789z123456789z1", name_len), "attr name overflow name"); ok(value_len == 2, "attr name overflow value length"); ok(!strncmp(value, "v1", value_len), "attr name overflow value"); packet[0]= 2; packet[1]= 'k'; packet[2]= '1'; ptr= net_store_length(packet + 3, 1025); for (idx= 0; idx < 1025; idx++) *ptr++= '0' + (idx % 10); packet_length= (uint) (ptr - packet); result= read_nth_attr((char *) packet, packet_length, cs, 0, name, 32, &name_len, value, 1024, &value_len); ok(result == true, "attr value overflow"); ok(name_len == 2, "attr value overflow length"); ok(!strncmp(name, "k1", name_len), "attr value overflow name"); ok(value_len == 1024, "attr value overflow value length"); for (idx= 0; idx < 1024; idx++) { if (value[idx] != (char) ('0' + (idx % 10))) break; } ok (idx == 1024, "attr value overflow value"); result= read_nth_attr("\x21z123456789z123456789z123456789z12\x2v1\x2k2\x2v2", 43, cs, 1, name, 32, &name_len, value, 1024, &value_len); ok(result == true, "prev attr name overflow"); ok(name_len == 2, "prev attr name overflow length"); ok(!strncmp(name, "k2", name_len), "prev attr name overflow name"); ok(value_len == 2, "prev attr name overflow value length"); ok(!strncmp(value, "v2", value_len), "prev attr name overflow value"); packet[1]= 'k'; packet[2]= '1'; packet[3]= 2; packet[4]= 'v'; packet[5]= '1'; for(idx= 251; idx < 256; idx++) { packet[0]= idx; result= read_nth_attr((char *) packet, 6, cs, 0, name, 32, &name_len, value, 1024, &value_len); ok(result == false, "invalid string length %d", idx); } memset(packet, 0, sizeof(packet)); for (idx=0; idx < 1660 /* *6 = 9960 */; idx++) memcpy(packet + idx * 6, "\x2k1\x2v1", 6); result= read_nth_attr((char *) packet, 8192, cs, 1364, name, 32, &name_len, value, 1024, &value_len); ok(result == true, "last valid attribute %d", 1364); result= read_nth_attr((char *) packet, 8192, cs, 1365, name, 32, &name_len, value, 1024, &value_len); ok(result == false, "first attribute that's cut %d", 1365); } void test_multibyte_lengths() { char name[100], value[4096]; uint name_len, value_len; bool result; const CHARSET_INFO *cs= &my_charset_utf8_bin; unsigned char var_len_packet[] = { 252, 2, 0, 'k', '1', 253, 2, 0, 0, 'v', '1', 254, 2, 0, 0, 0, 0, 0, 0, 0, 'k', '2', 254, 2, 0, 0, 0, 0, 0, 0, 0, 'v', '2' }; result= read_nth_attr((char *) var_len_packet, sizeof(var_len_packet), cs, 0, name, 32, &name_len, value, 1024, &value_len); ok(result == true, "multibyte lengths return"); ok(name_len == 2, "multibyte lengths name length"); ok(!strncmp(name, "k1", name_len), "multibyte lengths attr name"); ok(value_len == 2, "multibyte lengths value length"); ok(!strncmp(value, "v1", value_len), "multibyte lengths value"); result= read_nth_attr((char *) var_len_packet, sizeof(var_len_packet), cs, 1, name, 32, &name_len, value, 1024, &value_len); ok(result == true, "multibyte lengths second attr return"); ok(name_len == 2, "multibyte lengths second attr name length"); ok(!strncmp(name, "k2", name_len), "multibyte lengths second attr attr name"); ok(value_len == 2, "multibyte lengths value length"); ok(!strncmp(value, "v2", value_len), "multibyte lengths second attr value"); } void test_utf8_parser() { /* utf8 max byte length per character is 6 */ char name[33 * 6], value[1024 * 6], packet[1500 * 6], *ptr; uint name_len, value_len; bool result; const CHARSET_INFO *cs= &my_charset_utf8_bin; /* note : this is encoded in utf-8 */ const char *attr1= "Георги"; const char *val1= "Кодинов"; const char *attr2= "Пловдив"; const char *val2= "България"; ptr= packet; *ptr++= strlen(attr1); memcpy(ptr, attr1, strlen(attr1)); ptr+= strlen(attr1); *ptr++= strlen(val1); memcpy(ptr, val1, strlen(val1)); ptr+= strlen(val1); *ptr++= strlen(attr2); memcpy(ptr, attr2, strlen(attr2)); ptr+= strlen(attr2); *ptr++= strlen(val2); memcpy(ptr, val2, strlen(val2)); ptr+= strlen(val2); diag("test_utf8_parser attr pair #1"); result= read_nth_attr((char *) packet, ptr - packet, cs, 0, name, sizeof(name), &name_len, value, sizeof(value), &value_len); ok(result == true, "return"); ok(name_len == strlen(attr1), "name length"); ok(!strncmp(name, attr1, name_len), "attr name"); ok(value_len == strlen(val1), "value length"); ok(!strncmp(value, val1, value_len), "value"); diag("test_utf8_parser attr pair #2"); result= read_nth_attr((char *) packet, ptr - packet, cs, 1, name, sizeof(name), &name_len, value, sizeof(value), &value_len); ok(result == true, "return"); ok(name_len == strlen(attr2), "name length"); ok(!strncmp(name, attr2, name_len), "attr name"); ok(value_len == strlen(val2), "value length"); ok(!strncmp(value, val2, value_len), "value"); } void test_utf8_parser_bad_encoding() { /* utf8 max byte length per character is 3*/ char name[33 * 3], value[1024 * 3], packet[1500 * 3], *ptr; uint name_len, value_len; bool result; const CHARSET_INFO *cs= &my_charset_utf8_bin; /* note : this is encoded in utf-8 */ const char *attr= "Георги"; const char *val= "Кодинов"; ptr= packet; *ptr++= strlen(attr); memcpy(ptr, attr, strlen(attr)); ptr[0]= 0xFA; // invalid UTF-8 char ptr+= strlen(attr); *ptr++= strlen(val); memcpy(ptr, val, strlen(val)); ptr+= strlen(val); diag("test_utf8_parser_bad_encoding"); result= read_nth_attr((char *) packet, ptr - packet, cs, 0, name, sizeof(name), &name_len, value, sizeof(value), &value_len); ok(result == false, "return"); } const CHARSET_INFO *cs_cp1251; void test_cp1251_parser() { /* utf8 max byte length per character is 3*/ char name[33 * 3], value[1024 * 3], packet[1500 * 3], *ptr; uint name_len, value_len; bool result; /* note : this is Георги in windows-1251 */ const char *attr1= "\xc3\xe5\xee\xf0\xe3\xe8"; /* note : this is Кодинов in windows-1251 */ const char *val1= "\xca\xee\xe4\xe8\xed\xee\xe2"; /* note : this is Пловдив in windows-1251 */ const char *attr2= "\xcf\xeb\xee\xe2\xe4\xe8\xe2"; /* note : this is България in windows-1251 */ const char *val2= "\xc1\xfa\xeb\xe3\xe0\xf0\xe8\xff"; ptr= packet; *ptr++= strlen(attr1); memcpy(ptr, attr1, strlen(attr1)); ptr+= strlen(attr1); *ptr++= strlen(val1); memcpy(ptr, val1, strlen(val1)); ptr+= strlen(val1); *ptr++= strlen(attr2); memcpy(ptr, attr2, strlen(attr2)); ptr+= strlen(attr2); *ptr++= strlen(val2); memcpy(ptr, val2, strlen(val2)); ptr+= strlen(val2); diag("test_cp1251_parser attr pair #1"); result= read_nth_attr((char *) packet, ptr - packet, cs_cp1251, 0, name, sizeof(name), &name_len, value, sizeof(value), &value_len); ok(result == true, "return"); /* need to compare to the UTF-8 equivalents */ ok(name_len == strlen("Георги"), "name length"); ok(!strncmp(name, "Георги", name_len), "attr name"); ok(value_len == strlen("Кодинов"), "value length"); ok(!strncmp(value, "Кодинов", value_len), "value"); diag("test_cp1251_parser attr pair #2"); result= read_nth_attr((char *) packet, ptr - packet, cs_cp1251, 1, name, sizeof(name), &name_len, value, sizeof(value), &value_len); ok(result == true, "return"); /* need to compare to the UTF-8 equivalents */ ok(name_len == strlen("Пловдив"), "name length"); ok(!strncmp(name, "Пловдив", name_len), "attr name"); ok(value_len == strlen("България"), "value length"); ok(!strncmp(value, "България", value_len), "value"); } void do_all_tests() { test_blob_parser(); test_multibyte_lengths(); test_utf8_parser(); test_utf8_parser_bad_encoding(); test_cp1251_parser(); } int main(int, char **) { MY_INIT("pfs_connect_attr-t"); cs_cp1251= get_charset_by_csname("cp1251", MY_CS_PRIMARY, MYF(0)); if (!cs_cp1251) diag("skipping the cp1251 tests : missing character set"); plan(59 + (cs_cp1251 ? 10 : 0)); do_all_tests(); return (exit_status()); }