libwebsockets/minimal-examples-lowlevel/api-tests/api-test-lws_tokenize/main.c
Andy Green 047fb7bb21 tokenize: enhance to support chunked parsing
Add EXPECT_MORE flag to indicate that running out of input is not (yet)
indicating the end of the document.  The caller should remove this flag
when it identifies that it does not have the chunk with the end of the
document: the last chunk may be zero length.

Track line numbers so the caller can infer CR, absorb CRLF -> CR.

Also add COLON_NONTERM needed for ipv6 literal addresses.
2022-04-10 06:56:12 +01:00

1109 lines
27 KiB
C

/*
* lws-api-test-lws_tokenize
*
* Written in 2010-2021 by Andy Green <andy@warmcat.com>
*
* This file is made available under the Creative Commons CC0 1.0
* Universal Public Domain Dedication.
*
* This demonstrates the most minimal http server you can make with lws.
*
* To keep it simple, it serves stuff from the subdirectory
* "./mount-origin" of the directory it was started in.
* You can change that by changing mount.origin below.
*/
#include <libwebsockets.h>
#include <string.h>
#include <stdio.h>
struct expected {
lws_tokenize_elem e;
const char *value;
size_t len;
};
struct tests {
const char *string;
struct expected *exp;
int count;
int flags;
};
struct expected expected1[] = {
{ LWS_TOKZE_TOKEN, "protocol-1", 10 },
{ LWS_TOKZE_DELIMITER, ",", 1},
{ LWS_TOKZE_TOKEN, "protocol_2", 10 },
{ LWS_TOKZE_DELIMITER, ",", 1},
{ LWS_TOKZE_TOKEN, "protocol3", 9 },
{ LWS_TOKZE_ENDED, NULL, 0 },
},
expected2[] = {
{ LWS_TOKZE_TOKEN_NAME_COLON, "Accept-Language", 15 },
{ LWS_TOKZE_TOKEN, "fr-CH", 5 },
{ LWS_TOKZE_DELIMITER, ",", 1 },
{ LWS_TOKZE_TOKEN, "fr", 2 },
{ LWS_TOKZE_DELIMITER, ";", 1},
{ LWS_TOKZE_TOKEN_NAME_EQUALS, "q", 1 },
{ LWS_TOKZE_FLOAT, "0.9", 3 },
{ LWS_TOKZE_DELIMITER, ",", 1 },
{ LWS_TOKZE_TOKEN, "en", 2 },
{ LWS_TOKZE_DELIMITER, ";", 1},
{ LWS_TOKZE_TOKEN_NAME_EQUALS, "q", 1 },
{ LWS_TOKZE_FLOAT, "0.8", 3 },
{ LWS_TOKZE_DELIMITER, ",", 1 },
{ LWS_TOKZE_TOKEN, "de", 2 },
{ LWS_TOKZE_DELIMITER, ";", 1},
{ LWS_TOKZE_TOKEN_NAME_EQUALS, "q", 1 },
{ LWS_TOKZE_FLOAT, "0.7", 3 },
{ LWS_TOKZE_DELIMITER, ",", 1 },
{ LWS_TOKZE_DELIMITER, "*", 1 },
{ LWS_TOKZE_DELIMITER, ";", 1 },
{ LWS_TOKZE_TOKEN_NAME_EQUALS, "q", 1 },
{ LWS_TOKZE_FLOAT, "0.5", 3 },
{ LWS_TOKZE_ENDED, NULL, 0 },
},
expected3[] = {
{ LWS_TOKZE_TOKEN_NAME_EQUALS, "quoted", 6 },
{ LWS_TOKZE_QUOTED_STRING, "things:", 7 },
{ LWS_TOKZE_DELIMITER, ",", 1 },
{ LWS_TOKZE_INTEGER, "1234", 4 },
{ LWS_TOKZE_ENDED, NULL, 0 },
},
expected4[] = {
{ LWS_TOKZE_ERR_COMMA_LIST, ",", 1 },
},
expected5[] = {
{ LWS_TOKZE_TOKEN, "brokenlist2", 11 },
{ LWS_TOKZE_DELIMITER, ",", 1 },
{ LWS_TOKZE_ERR_COMMA_LIST, ",", 1 },
},
expected6[] = {
{ LWS_TOKZE_TOKEN, "brokenlist3", 11 },
{ LWS_TOKZE_DELIMITER, ",", 1 },
{ LWS_TOKZE_ERR_COMMA_LIST, ",", 1 },
},
expected7[] = {
{ LWS_TOKZE_TOKEN, "fr", 2 },
{ LWS_TOKZE_DELIMITER, "-", 1 },
{ LWS_TOKZE_TOKEN, "CH", 2 },
{ LWS_TOKZE_DELIMITER, ",", 1 },
{ LWS_TOKZE_TOKEN, "fr", 2 },
{ LWS_TOKZE_DELIMITER, ";", 1 },
{ LWS_TOKZE_TOKEN_NAME_EQUALS, "q", 1 },
{ LWS_TOKZE_FLOAT, "0.9", 3 },
{ LWS_TOKZE_DELIMITER, ",", 1 },
{ LWS_TOKZE_TOKEN, "en", 2 },
{ LWS_TOKZE_DELIMITER, ";", 1 },
{ LWS_TOKZE_TOKEN_NAME_EQUALS, "q", 1 },
{ LWS_TOKZE_FLOAT, "0.8", 3 },
{ LWS_TOKZE_DELIMITER, ",", 1 },
{ LWS_TOKZE_TOKEN, "de", 2 },
{ LWS_TOKZE_DELIMITER, ";", 1 },
{ LWS_TOKZE_TOKEN_NAME_EQUALS, "q", 1 },
{ LWS_TOKZE_FLOAT, "0.7", 3 },
{ LWS_TOKZE_DELIMITER, ",", 1 },
{ LWS_TOKZE_TOKEN, "*", 1 },
{ LWS_TOKZE_DELIMITER, ";", 1 },
{ LWS_TOKZE_TOKEN_NAME_EQUALS, "q", 1 },
{ LWS_TOKZE_FLOAT, "0.5", 3 },
{ LWS_TOKZE_ENDED, "", 0 },
},
expected8[] = {
{ LWS_TOKZE_TOKEN, "Οὐχὶ", 10 },
{ LWS_TOKZE_TOKEN, "ταὐτὰ", 12 },
{ LWS_TOKZE_TOKEN, "παρίσταταί", 22 },
{ LWS_TOKZE_TOKEN, "μοι", 6 },
{ LWS_TOKZE_TOKEN, "γιγνώσκειν", 21 },
{ LWS_TOKZE_DELIMITER, ",", 1 },
{ LWS_TOKZE_TOKEN, "", 3 },
{ LWS_TOKZE_TOKEN, "ἄνδρες", 13 },
{ LWS_TOKZE_TOKEN, "᾿Αθηναῖοι", 20 },
{ LWS_TOKZE_DELIMITER, ",", 1 },
{ LWS_TOKZE_TOKEN, "greek", 5 },
{ LWS_TOKZE_ENDED, "", 0 },
},
expected9[] = {
/*
* because the tokenizer scans ahead for = aggregation,
* it finds the broken utf8 before reporting the token
*/
{ LWS_TOKZE_ERR_BROKEN_UTF8, "", 0 },
},
expected10[] = {
{ LWS_TOKZE_TOKEN, "badutf8-2", 9 },
{ LWS_TOKZE_TOKEN, "", 3 },
{ LWS_TOKZE_DELIMITER, ",", 1 },
{ LWS_TOKZE_ERR_BROKEN_UTF8, "", 0 },
},
expected11[] = {
{ LWS_TOKZE_TOKEN, "1.myserver", 10 },
{ LWS_TOKZE_DELIMITER, ".", 1 },
{ LWS_TOKZE_TOKEN, "com", 3 },
{ LWS_TOKZE_ENDED, "", 0 },
},
expected12[] = {
{ LWS_TOKZE_TOKEN, "1.myserver.com", 14 },
{ LWS_TOKZE_ENDED, "", 0 },
},
expected13[] = {
{ LWS_TOKZE_TOKEN, "1.myserver.com", 14 },
{ LWS_TOKZE_ENDED, "", 0 },
},
expected14[] = {
{ LWS_TOKZE_INTEGER, "1", 1 },
{ LWS_TOKZE_DELIMITER, ".", 1 },
{ LWS_TOKZE_TOKEN, "myserver", 8 },
{ LWS_TOKZE_DELIMITER, ".", 1 },
{ LWS_TOKZE_TOKEN, "com", 3 },
{ LWS_TOKZE_ENDED, "", 0 },
},
expected15[] = {
{ LWS_TOKZE_TOKEN, "close", 5 },
{ LWS_TOKZE_DELIMITER, ",", 1 },
{ LWS_TOKZE_TOKEN, "Upgrade", 7 },
{ LWS_TOKZE_ENDED, "", 0 },
},
expected16[] = {
{ LWS_TOKZE_TOKEN_NAME_EQUALS, "a", 1 },
{ LWS_TOKZE_TOKEN, "5", 1 },
{ LWS_TOKZE_ENDED, "", 0 },
},
expected17[] = {
{ LWS_TOKZE_TOKEN, "hello", 5 },
{ LWS_TOKZE_ENDED, "", 0 },
},
expected18[] = {
{ LWS_TOKZE_TOKEN, "x=y", 3 },
{ LWS_TOKZE_ENDED, "", 0 },
}
;
struct tests tests[] = {
{
" protocol-1, protocol_2\t,\tprotocol3\n",
expected1, LWS_ARRAY_SIZE(expected1),
LWS_TOKENIZE_F_MINUS_NONTERM | LWS_TOKENIZE_F_AGG_COLON
}, {
"Accept-Language: fr-CH, fr;q=0.9, en;q=0.8, de;q=0.7, *;q=0.5",
expected2, LWS_ARRAY_SIZE(expected2),
LWS_TOKENIZE_F_MINUS_NONTERM | LWS_TOKENIZE_F_AGG_COLON
}, {
"quoted = \"things:\", 1234",
expected3, LWS_ARRAY_SIZE(expected3),
LWS_TOKENIZE_F_MINUS_NONTERM | LWS_TOKENIZE_F_AGG_COLON
}, {
", brokenlist1",
expected4, LWS_ARRAY_SIZE(expected4),
LWS_TOKENIZE_F_COMMA_SEP_LIST
}, {
"brokenlist2,,",
expected5, LWS_ARRAY_SIZE(expected5),
LWS_TOKENIZE_F_COMMA_SEP_LIST
}, {
"brokenlist3,",
expected6, LWS_ARRAY_SIZE(expected6),
LWS_TOKENIZE_F_COMMA_SEP_LIST
}, {
"fr-CH, fr;q=0.9, en;q=0.8, de;q=0.7, *;q=0.5",
expected7, LWS_ARRAY_SIZE(expected7),
LWS_TOKENIZE_F_ASTERISK_NONTERM | LWS_TOKENIZE_F_RFC7230_DELIMS
},
{
" Οὐχὶ ταὐτὰ παρίσταταί μοι γιγνώσκειν, ὦ ἄνδρες ᾿Αθηναῖοι, greek",
expected8, LWS_ARRAY_SIZE(expected8),
LWS_TOKENIZE_F_RFC7230_DELIMS
},
{
"badutf8-1 \x80...",
expected9, LWS_ARRAY_SIZE(expected9),
LWS_TOKENIZE_F_MINUS_NONTERM | LWS_TOKENIZE_F_RFC7230_DELIMS
},
{
"badutf8-2 \xed\x9f\xbf,\x80...",
expected10, LWS_ARRAY_SIZE(expected10),
LWS_TOKENIZE_F_MINUS_NONTERM | LWS_TOKENIZE_F_RFC7230_DELIMS
},
{
"1.myserver.com",
expected11, LWS_ARRAY_SIZE(expected11),
0
},
{
"1.myserver.com",
expected12, LWS_ARRAY_SIZE(expected12),
LWS_TOKENIZE_F_DOT_NONTERM
},
{
"1.myserver.com",
expected13, LWS_ARRAY_SIZE(expected13),
LWS_TOKENIZE_F_DOT_NONTERM | LWS_TOKENIZE_F_NO_FLOATS
},
{
"1.myserver.com",
expected14, LWS_ARRAY_SIZE(expected14),
LWS_TOKENIZE_F_NO_FLOATS
},
{
"close, Upgrade",
expected15, LWS_ARRAY_SIZE(expected15),
LWS_TOKENIZE_F_COMMA_SEP_LIST
},
{
"a=5", expected16, LWS_ARRAY_SIZE(expected16),
LWS_TOKENIZE_F_NO_INTEGERS
},
{
"# comment1\r\nhello #comment2\r\n#comment3", expected17,
LWS_ARRAY_SIZE(expected17), LWS_TOKENIZE_F_HASH_COMMENT
},
{
"x=y", expected18,
LWS_ARRAY_SIZE(expected18), LWS_TOKENIZE_F_EQUALS_NONTERM
}
};
/*
* add LWS_TOKZE_ERRS to the element index (which may be negative by that
* amount) to index this array
*/
static const char *element_names[] = {
"LWS_TOKZE_ERR_BROKEN_TOO_LONG",
"LWS_TOKZE_ERR_BROKEN_WANT_READ",
"LWS_TOKZE_ERR_BROKEN_UTF8",
"LWS_TOKZE_ERR_UNTERM_STRING",
"LWS_TOKZE_ERR_MALFORMED_FLOAT",
"LWS_TOKZE_ERR_NUM_ON_LHS",
"LWS_TOKZE_ERR_COMMA_LIST",
"LWS_TOKZE_ENDED",
"LWS_TOKZE_DELIMITER",
"LWS_TOKZE_TOKEN",
"LWS_TOKZE_INTEGER",
"LWS_TOKZE_FLOAT",
"LWS_TOKZE_TOKEN_NAME_EQUALS",
"LWS_TOKZE_TOKEN_NAME_COLON",
"LWS_TOKZE_QUOTED_STRING",
};
int
exp_cb1(void *priv, const char *name, char *out, size_t *pos, size_t olen,
size_t *exp_ofs)
{
const char *replace = NULL;
size_t total, budget;
if (!strcmp(name, "test")) {
replace = "replacement_string";
total = strlen(replace);
goto expand;
}
return LSTRX_FATAL_NAME_UNKNOWN;
expand:
budget = olen - *pos;
total -= *exp_ofs;
if (total < budget)
budget = total;
if (out)
memcpy(out + *pos, replace + (*exp_ofs), budget);
*exp_ofs += budget;
*pos += budget;
if (budget == total)
return LSTRX_DONE;
return LSTRX_FILLED_OUT;
}
static const char *exp_inp1 = "this-is-a-${test}-for-strexp";
int main(int argc, const char **argv)
{
struct lws_context_creation_info info;
struct lws_context *cx;
struct lws_tokenize ts;
lws_tokenize_elem e;
const char *p;
char b1[22];
int n, logs = LLL_USER | LLL_ERR | LLL_WARN | LLL_NOTICE
/* for LLL_ verbosity above NOTICE to be built into lws,
* lws must have been configured and built with
* -DCMAKE_BUILD_TYPE=DEBUG instead of =RELEASE */
/* | LLL_INFO */ /* | LLL_PARSER */ /* | LLL_HEADER */
/* | LLL_EXT */ /* | LLL_CLIENT */ /* | LLL_LATENCY */
/* | LLL_DEBUG */;
int fail = 0, ok = 0, flags = 0;
char dotstar[512];
if ((p = lws_cmdline_option(argc, argv, "-d")))
logs = atoi(p);
lws_set_log_level(logs, NULL);
lwsl_user("LWS API selftest: lws_tokenize\n");
if ((p = lws_cmdline_option(argc, argv, "-f")))
flags = atoi(p);
memset(&info, 0, sizeof info);
info.options = LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT |
LWS_SERVER_OPTION_H2_JUST_FIX_WINDOW_UPDATE_OVERFLOW;
/*
* since we know this lws context is only ever going to be used with
* one client wsis / fds / sockets at a time, let lws know it doesn't
* have to use the default allocations for fd tables up to ulimit -n.
* It will just allocate for 1 internal and 1 (+ 1 http2 nwsi) that we
* will use.
*/
info.fd_limit_per_thread = 1 + 1 + 1;
#if 0
#if defined(LWS_WITH_MBEDTLS) || defined(USE_WOLFSSL)
/*
* OpenSSL uses the system trust store. mbedTLS has to be told which
* CA to trust explicitly.
*/
info.client_ssl_ca_filepath = "./warmcat.com.cer";
#endif
#endif
#if 0
n = open("./warmcat.com.cer", O_RDONLY);
if (n >= 0) {
info.client_ssl_ca_mem_len = read(n, memcert, sizeof(memcert));
info.client_ssl_ca_mem = memcert;
close(n);
n = 0;
memcert[info.client_ssl_ca_mem_len++] = '\0';
}
#endif
{
/* lws_fx_t */
lws_fx_t r, a, b;
a.whole = 1;
a.frac = 0;
b.whole = 5;
b.frac = 50000000;
lws_fx_add(&r, &a, &b);
if (r.whole != 6 || r.frac != 50000000) {
lwsl_err("%s: fixed3232: test1 fail\n", __func__);
return 1;
}
lws_fx_sub(&r, &b, &a);
if (r.whole != 4 || r.frac != 50000000) {
lwsl_err("%s: fixed3232: test2 fail\n", __func__);
return 1;
}
a.whole = -1;
a.frac = 0;
b.whole = 5;
b.frac = 50000000;
lws_fx_add(&r, &a, &b);
if (r.whole != 4 || r.frac != 50000000) {
lwsl_err("%s: fixed3232: test3 fail\n", __func__);
return 1;
}
a.whole = -1;
a.frac = 0;
b.whole = -1;
b.frac = 50000000;
lws_fx_add(&r, &a, &b);
if (r.whole != -2 || r.frac != 50000000) {
lwsl_err("%s: fixed3232: test4 fail\n", __func__);
return 1;
}
lws_fx_set(a, -1, 70000000);
lws_fx_set(b, -1, 50000000);
lws_fx_add(&r, &a, &b);
if (r.whole != -3 || r.frac != -20000000) {
lwsl_err("%s: fixed3232: test4a fail: %s\n", __func__,
lws_fx_string(&r, b1, sizeof(b1)));
return 1;
}
lws_fx_set(a, 1, 70000000);
lws_fx_set(b, -1, 50000000);
lws_fx_add(&r, &a, &b);
if (r.whole != 0 || r.frac != 20000000) {
lwsl_err("%s: fixed3232: test4b fail: %s\n", __func__,
lws_fx_string(&r, b1, sizeof(b1)));
return 1;
}
lws_fx_set(a, -1, 70000000);
lws_fx_set(b, 1, 50000000);
lws_fx_add(&r, &a, &b);
if (r.whole != 0 || r.frac != -20000000) {
lwsl_err("%s: fixed3232: test4b1 fail: %s\n", __func__,
lws_fx_string(&r, b1, sizeof(b1)));
return 1;
}
lws_fx_set(a, 3, 0);
lws_fx_set(b, 5, 10000000);
lws_fx_mul(&r, &a, &b);
if (r.whole != 15 || r.frac != 30000000) {
lwsl_err("%s: fixed3232: test5 fail: %d.%08u\n", __func__, r.whole, r.frac);
return 1;
}
lws_fx_set(a, -3, 0);
lws_fx_set(b, 5, 10000000);
lws_fx_mul(&r, &a, &b);
if (r.whole != -15 || r.frac != -30000000) {
lwsl_err("%s: fixed3232: test6 fail: %d.%08u\n", __func__, r.whole, r.frac);
return 1;
}
lws_fx_set(a, 3, 0);
lws_fx_set(b, -5, 10000000);
lws_fx_mul(&r, &a, &b);
if (r.whole != -15 || r.frac != -30000000) {
lwsl_err("%s: fixed3232: test7 fail: %d.%08d\n", __func__, r.whole, r.frac);
return 1;
}
lws_fx_set(a, -3, 0);
lws_fx_set(b, -5, 10000000);
lws_fx_mul(&r, &a, &b);
if (r.whole != 15 || r.frac != 30000000) {
lwsl_err("%s: fixed3232: test8 fail: %d.%08u\n", __func__, r.whole, r.frac);
return 1;
}
lws_fx_set(a, 3, 50000000);
lws_fx_set(b, 5, 10000000);
lws_fx_mul(&r, &a, &b);
if (r.whole != 17 || r.frac != 85000000) {
lwsl_err("%s: fixed3232: test9 fail: %d.%08u\n", __func__, r.whole, r.frac);
return 1;
}
lws_fx_set(a, -3, 50000000);
lws_fx_set(b, 5, 10000000);
lws_fx_mul(&r, &a, &b);
if (r.whole != -17 || r.frac != -85000000) {
lwsl_err("%s: fixed3232: test10 fail: %d.%08u\n", __func__, r.whole, r.frac);
return 1;
}
lws_fx_set(a, 1, 50000000);
lws_fx_set(b, 0, 10000000);
lws_fx_mul(&r, &a, &b);
if (r.whole != 0 || r.frac != 15000000) {
lwsl_err("%s: fixed3232: test10a fail: %d.%08u\n", __func__, r.whole, r.frac);
return 1;
}
lws_fx_set(a, -1, 50000000);
lws_fx_set(b, 0, 10000000);
lws_fx_mul(&r, &a, &b);
if (r.whole != 0 || r.frac != -15000000) {
lwsl_err("%s: fixed3232: test10b fail: %d.%08u\n", __func__, r.whole, r.frac);
return 1;
}
lws_fx_set(a, 1, 50000000);
lws_fx_set(b, 0, -10000000);
lws_fx_mul(&r, &a, &b);
if (r.whole != 0 || r.frac != -15000000) {
lwsl_err("%s: fixed3232: test10c fail: %d.%08u\n", __func__, r.whole, r.frac);
return 1;
}
lws_fx_set(a, 3, 50000000);
lws_fx_set(b, -5, 10000000);
lws_fx_mul(&r, &a, &b);
if (r.whole != -17 || r.frac != -85000000) {
lwsl_err("%s: fixed3232: test11 fail: %d.%08u\n", __func__, r.whole, r.frac);
return 1;
}
lws_fx_set(a, -3, 50000000);
lws_fx_set(b, -5, 10000000);
lws_fx_mul(&r, &a, &b);
if (r.whole != 17 || r.frac != 85000000) {
lwsl_err("%s: fixed3232: test12 fail: %d.%08u\n", __func__, r.whole, r.frac);
return 1;
}
lws_fx_set(a, 27, 0);
lws_fx_set(b, 9, 0);
lws_fx_div(&r, &a, &b);
if (r.whole != 3 || r.frac != 0) {
lwsl_err("%s: fixed3232: test13 fail: %d.%08u\n", __func__, r.whole, r.frac);
return 1;
}
lws_fx_set(a, 33, 33333333);
lws_fx_set(b, 11, 0);
lws_fx_div(&r, &a, &b);
if (r.whole != 3 || r.frac != 3030302) {
lwsl_err("%s: fixed3232: test14 fail: %d.%08u\n", __func__, r.whole, r.frac);
return 1;
}
lws_fx_set(a, 33, 33333333);
lws_fx_set(b, 1, 10000000);
lws_fx_div(&r, &a, &b);
if (r.whole != 30 || r.frac != 30303030) {
lwsl_err("%s: fixed3232: test15 fail: %d.%08u\n", __func__, r.whole, r.frac);
return 1;
}
lws_fx_set(a, -33, 33333333);
lws_fx_set(b, 1, 10000000);
lws_fx_div(&r, &a, &b);
if (r.whole != -30 || r.frac != -30303030) {
lwsl_err("%s: fixed3232: test16 fail: %d.%08u\n", __func__, r.whole, r.frac);
return 1;
}
a.whole = 33;
a.frac = 33333333;
b.whole = -1;
b.frac = 10000000;
lws_fx_div(&r, &a, &b);
if (r.whole != -30 || r.frac != -30303030) {
lwsl_err("%s: fixed3232: test17 fail: %d.%08u\n", __func__, r.whole, r.frac);
return 1;
}
a.whole = -33;
a.frac = 33333333;
b.whole = -1;
b.frac = 10000000;
lws_fx_div(&r, &a, &b);
if (r.whole != 30 || r.frac != 30303030) {
lwsl_err("%s: fixed3232: test18 fail: %d.%08u\n", __func__, r.whole, r.frac);
return 1;
}
a.whole = 64;
a.frac = 0;
lws_fx_sqrt(&r, &a);
if (r.whole != 8 || r.frac != 0) {
lwsl_err("%s: fixed3232: test19 fail: %d.%08u\n", __func__, r.whole, r.frac);
return 1;
}
a.whole = 16512;
a.frac = 25000000;
lws_fx_sqrt(&r, &a);
if (r.whole != 128 || r.frac != 50000000) {
lwsl_err("%s: fixed3232: test20 fail: %d.%08u\n", __func__, r.whole, r.frac);
return 1;
}
a.whole = 22;
a.frac = 80000000;
b.whole = 18;
b.frac = 0;
lws_fx_sub(&r, &a, &b);
if (r.whole != 4 || r.frac != 80000000) {
lwsl_err("%s: fixed3232: test21 fail: %d.%08u\n", __func__, r.whole, r.frac);
return 1;
}
a.whole = 2;
a.frac = 80000000;
b.whole = 18;
b.frac = 0;
lws_fx_sub(&r, &a, &b);
if (r.whole != -15 || r.frac != 20000000) {
lwsl_err("%s: fixed3232: test22 fail: %d.%08u\n", __func__, r.whole, r.frac);
return 1;
}
a.whole = 24;
a.frac = 20000000;
b.whole = 24;
b.frac = 0;
lws_fx_sub(&r, &a, &b);
if (r.whole != 0 || r.frac != 20000000) {
lwsl_err("%s: fixed3232: test23 fail: %d.%08u\n", __func__, r.whole, r.frac);
return 1;
}
}
cx = lws_create_context(&info);
/* lws_strexp */
{
size_t in_len, used_in, used_out;
lws_strexp_t exp;
char obuf[128];
const char *p;
obuf[0] = '\0';
lws_strexp_init(&exp, NULL, exp_cb1, obuf, sizeof(obuf));
n = lws_strexp_expand(&exp, exp_inp1, 28, &used_in, &used_out);
if (n != LSTRX_DONE || used_in != 28 ||
strcmp(obuf, "this-is-a-replacement_string-for-strexp")) {
lwsl_notice("%s: obuf %s\n", __func__, obuf);
lwsl_err("%s: lws_strexp test 1 failed: %d\n", __func__, n);
return 1;
}
/* as above, but don't generate output, just find the length */
lws_strexp_init(&exp, NULL, exp_cb1, NULL, (size_t)-1);
n = lws_strexp_expand(&exp, exp_inp1, 28, &used_in, &used_out);
if (n != LSTRX_DONE || used_in != 28 || used_out != 39) {
lwsl_err("%s: lws_strexp test 2 failed: %d, used_out: %d\n",
__func__, n, (int)used_out);
return 1;
}
p = exp_inp1;
in_len = strlen(p);
memset(obuf, 0, sizeof(obuf));
lws_strexp_init(&exp, NULL, exp_cb1, obuf, 16);
n = lws_strexp_expand(&exp, p, in_len, &used_in, &used_out);
if (n != LSTRX_FILLED_OUT || used_in != 16 || used_out != 16) {
lwsl_err("a\n");
return 1;
}
p += used_in;
in_len -= used_in;
memset(obuf, 0, sizeof(obuf));
lws_strexp_reset_out(&exp, obuf, 16);
n = lws_strexp_expand(&exp, p, in_len, &used_in, &used_out);
if (n != LSTRX_FILLED_OUT || used_in != 5 || used_out != 16) {
lwsl_err("b: n %d, used_in %d, used_out %d\n", n,
(int)used_in, (int)used_out);
return 2;
}
p += used_in;
in_len -= used_in;
memset(obuf, 0, sizeof(obuf));
lws_strexp_reset_out(&exp, obuf, 16);
n = lws_strexp_expand(&exp, p, in_len, &used_in, &used_out);
if (n != LSTRX_DONE || used_in != 7 || used_out != 7) {
lwsl_err("c: n %d, used_in %d, used_out %d\n", n, (int)used_in, (int)used_out);
return 2;
}
}
/* sanity check lws_strnncpy() */
lws_strnncpy(dotstar, "12345678", 4, sizeof(dotstar));
if (strcmp(dotstar, "1234")) {
lwsl_err("%s: lws_strnncpy check failed\n", __func__);
return 1;
}
lws_strnncpy(dotstar, "12345678", 8, 6);
if (strcmp(dotstar, "12345")) {
lwsl_err("%s: lws_strnncpy check failed\n", __func__);
return 1;
}
/* sanity check lws_nstrstr() */
{
static const char *t1 = "abc123456";
const char *mcp;
mcp = lws_nstrstr(t1, strlen(t1), "abc", 3);
if (mcp != t1) {
lwsl_err("%s: lws_nstrstr 1 failed\n", __func__);
return 1;
}
mcp = lws_nstrstr(t1, strlen(t1), "def", 3);
if (mcp != NULL) {
lwsl_err("%s: lws_nstrstr 2 failed\n", __func__);
return 1;
}
mcp = lws_nstrstr(t1, strlen(t1), "456", 3);
if (mcp != t1 + 6) {
lwsl_err("%s: lws_nstrstr 3 failed: %p\n", __func__, mcp);
return 1;
}
mcp = lws_nstrstr(t1, strlen(t1), "1", 1);
if (mcp != t1 + 3) {
lwsl_err("%s: lws_nstrstr 4 failed\n", __func__);
return 1;
}
mcp = lws_nstrstr(t1, strlen(t1), "abc1234567", 10);
if (mcp != NULL) {
lwsl_err("%s: lws_nstrstr 5 failed\n", __func__);
return 1;
}
}
/* sanity check lws_json_simple_find() */
{
static const char *t1 = "{\"myname1\":true,"
"\"myname2\":\"string\", "
"\"myname3\": 123}";
size_t alen;
const char *mcp;
mcp = lws_json_simple_find(t1, strlen(t1), "\"myname1\":", &alen);
if (mcp != t1 + 11 || alen != 4) {
lwsl_err("%s: lws_json_simple_find 1 failed: (%d) %s\n",
__func__, (int)alen, mcp);
return 1;
}
mcp = lws_json_simple_find(t1, strlen(t1), "\"myname2\":", &alen);
if (mcp != t1 + 27 || alen != 6) {
lwsl_err("%s: lws_json_simple_find 2 failed\n", __func__);
return 1;
}
mcp = lws_json_simple_find(t1, strlen(t1), "\"myname3\":", &alen);
if (mcp != t1 + 47 || alen != 3) {
lwsl_err("%s: lws_json_simple_find 3 failed\n", __func__);
return 1;
}
mcp = lws_json_simple_find(t1, strlen(t1), "\"nope\":", &alen);
if (mcp != NULL) {
lwsl_err("%s: lws_json_simple_find 4 failed\n", __func__);
return 1;
}
}
p = lws_cmdline_option(argc, argv, "-s");
for (n = 0; n < (int)LWS_ARRAY_SIZE(tests); n++) {
int m = 0, in_fail = fail;
struct expected *exp = tests[n].exp;
memset(&ts, 0, sizeof(ts));
ts.start = tests[n].string;
ts.len = strlen(ts.start);
ts.flags = (uint16_t)tests[n].flags;
do {
e = lws_tokenize(&ts);
lws_strnncpy(dotstar, ts.token, ts.token_len,
sizeof(dotstar));
lwsl_info("{ %s, \"%s\", %d }\n",
element_names[e + LWS_TOKZE_ERRS], dotstar,
(int)ts.token_len);
if (m == (int)tests[n].count) {
lwsl_notice("fail: expected end earlier\n");
fail++;
break;
}
if (e != exp->e) {
lwsl_notice("fail... tok %s vs expected %s\n",
element_names[e + LWS_TOKZE_ERRS],
element_names[exp->e + LWS_TOKZE_ERRS]);
fail++;
break;
}
if (e > 0 &&
(ts.token_len != exp->len ||
memcmp(exp->value, ts.token, exp->len))) {
lws_strnncpy(dotstar, ts.token, ts.token_len,
sizeof(dotstar));
lwsl_notice("fail token mismatch %d %d %s\n",
(int)ts.token_len, (int)exp->len,
dotstar);
fail++;
break;
}
m++;
exp++;
} while (e > 0);
if (fail == in_fail)
ok++;
}
if (p) {
ts.start = p;
ts.len = strlen(p);
ts.flags = (uint16_t)flags;
printf("\t{\n\t\t\"%s\",\n"
"\t\texpected%d, LWS_ARRAY_SIZE(expected%d),\n\t\t",
p, (int)LWS_ARRAY_SIZE(tests) + 1,
(int)LWS_ARRAY_SIZE(tests) + 1);
if (!flags)
printf("0\n\t},\n");
else {
if (flags & LWS_TOKENIZE_F_MINUS_NONTERM)
printf("LWS_TOKENIZE_F_MINUS_NONTERM");
if (flags & LWS_TOKENIZE_F_AGG_COLON) {
if (flags & 1)
printf(" | ");
printf("LWS_TOKENIZE_F_AGG_COLON");
}
if (flags & LWS_TOKENIZE_F_COMMA_SEP_LIST) {
if (flags & 3)
printf(" | ");
printf("LWS_TOKENIZE_F_COMMA_SEP_LIST");
}
if (flags & LWS_TOKENIZE_F_RFC7230_DELIMS) {
if (flags & 7)
printf(" | ");
printf("LWS_TOKENIZE_F_RFC7230_DELIMS");
}
if (flags & LWS_TOKENIZE_F_DOT_NONTERM) {
if (flags & 15)
printf(" | ");
printf("LWS_TOKENIZE_F_DOT_NONTERM");
}
if (flags & LWS_TOKENIZE_F_NO_FLOATS) {
if (flags & 31)
printf(" | ");
printf("LWS_TOKENIZE_F_NO_FLOATS");
}
printf("\n\t},\n");
}
printf("\texpected%d[] = {\n", (int)LWS_ARRAY_SIZE(tests) + 1);
do {
e = lws_tokenize(&ts);
lws_strnncpy(dotstar, ts.token, ts.token_len,
sizeof(dotstar));
printf("\t\t{ %s, \"%s\", %d },\n",
element_names[e + LWS_TOKZE_ERRS],
dotstar, (int)ts.token_len);
} while (e > 0);
printf("\t}\n");
}
#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
{
time_t t;
if (lws_http_date_parse_unix("Tue, 15 Nov 1994 08:12:31 GMT", 29, &t)) {
lwsl_err("%s: date parse failed\n", __func__);
fail++;
} else {
/* lwsl_notice("%s: %llu\n", __func__, (unsigned long long)t); */
if (t != (time_t)784887151) {
lwsl_err("%s: date parse wrong\n", __func__);
fail++;
} else {
char s[30];
if (lws_http_date_render_from_unix(s, sizeof(s), &t)) {
lwsl_err("%s: failed date render\n", __func__);
fail++;
} else {
if (!strcmp(s, "Tue, 15 Nov 1994 08:12:31 GMT")) {
lwsl_err("%s: date render wrong\n", __func__);
fail++;
}
}
}
}
}
#endif
{
char buf[24];
int m;
m = lws_humanize(buf, sizeof(buf), 0, humanize_schema_si);
if (m != 1 || strcmp(buf, "0")) {
lwsl_user("%s: humanize 1 fail '%s' (%d)\n", __func__, buf, m);
fail++;
}
m = lws_humanize(buf, sizeof(buf), 2, humanize_schema_si);
if (m != 1 || strcmp(buf, "2")) {
lwsl_user("%s: humanize 2 fail '%s' (%d)\n", __func__, buf, m);
fail++;
}
m = lws_humanize(buf, sizeof(buf), 999, humanize_schema_si);
if (m != 3 || strcmp(buf, "999")) {
lwsl_user("%s: humanize 3 fail '%s' (%d)\n", __func__, buf, m);
fail++;
}
m = lws_humanize(buf, sizeof(buf), 1000, humanize_schema_si);
if (m != 4 || strcmp(buf, "1000")) {
lwsl_user("%s: humanize 4 fail '%s' (%d)\n", __func__, buf, m);
fail++;
}
m = lws_humanize(buf, sizeof(buf), 1024, humanize_schema_si);
if (m != 7 || strcmp(buf, "1.000Ki")) {
lwsl_user("%s: humanize 5 fail '%s' (%d)\n", __func__, buf, m);
fail++;
}
}
if (lws_strcmp_wildcard("allied", 6, "allied", 6)) {
lwsl_user("%s: wc 1 fail\n", __func__);
fail++;
}
if (lws_strcmp_wildcard("a*", 2, "allied", 6)) {
lwsl_user("%s: wc 2 fail\n", __func__);
fail++;
}
if (lws_strcmp_wildcard("all*", 4, "allied", 6)) {
lwsl_user("%s: wc 3 fail\n", __func__);
fail++;
}
if (lws_strcmp_wildcard("all*d", 5, "allied", 6)) {
lwsl_user("%s: wc 4 fail\n", __func__);
fail++;
}
if (!lws_strcmp_wildcard("b*", 2, "allied", 6)) {
lwsl_user("%s: wc 5 fail\n", __func__);
fail++;
}
if (!lws_strcmp_wildcard("b*ed", 4, "allied", 6)) {
lwsl_user("%s: wc 6 fail\n", __func__);
fail++;
}
if (!lws_strcmp_wildcard("allie", 5, "allied", 6)) {
lwsl_user("%s: wc 7 fail\n", __func__);
fail++;
}
if (lws_strcmp_wildcard("allie*", 6, "allied", 6)) {
lwsl_user("%s: wc 8 fail\n", __func__);
fail++;
}
if (lws_strcmp_wildcard("*llie*", 6, "allied", 6)) {
lwsl_user("%s: wc 9 fail\n", __func__);
fail++;
}
if (lws_strcmp_wildcard("*llied", 6, "allied", 6)) {
lwsl_user("%s: wc 10 fail\n", __func__);
fail++;
}
if (!lws_strcmp_wildcard("*llie", 5, "allied", 6)) {
lwsl_user("%s: wc 11 fail\n", __func__);
fail++;
}
if (!lws_strcmp_wildcard("*nope", 5, "allied", 6)) {
lwsl_user("%s: wc 12 fail\n", __func__);
fail++;
}
if (lws_strcmp_wildcard("*li*", 4, "allied", 6)) {
lwsl_user("%s: wc 13 fail\n", __func__);
fail++;
}
if (lws_strcmp_wildcard("*", 1, "allied", 6)) {
lwsl_user("%s: wc 14 fail\n", __func__);
fail++;
}
if (lws_strcmp_wildcard("*abc*d", 6, "xxabyyabcdd", 11)) {
lwsl_user("%s: wc 15 fail\n", __func__);
fail++;
}
if (lws_strcmp_wildcard("ssproxy.n.cn.*", 14,
"ssproxy.n.cn.failures", 21)) {
lwsl_user("%s: wc 16 fail\n", __func__);
fail++;
}
lwsl_user("Completed: PASS: %d, FAIL: %d\n", ok, fail);
lws_context_destroy(cx);
return !(ok && !fail);
}