diff options
Diffstat (limited to 'web/server/h2o/libh2o/t/00unit/lib/common')
-rw-r--r-- | web/server/h2o/libh2o/t/00unit/lib/common/cache.c | 84 | ||||
-rw-r--r-- | web/server/h2o/libh2o/t/00unit/lib/common/hostinfo.c | 53 | ||||
-rw-r--r-- | web/server/h2o/libh2o/t/00unit/lib/common/multithread.c | 157 | ||||
-rw-r--r-- | web/server/h2o/libh2o/t/00unit/lib/common/serverutil.c | 95 | ||||
-rw-r--r-- | web/server/h2o/libh2o/t/00unit/lib/common/socket.c | 171 | ||||
-rw-r--r-- | web/server/h2o/libh2o/t/00unit/lib/common/string.c | 335 | ||||
-rw-r--r-- | web/server/h2o/libh2o/t/00unit/lib/common/time.c | 48 | ||||
-rw-r--r-- | web/server/h2o/libh2o/t/00unit/lib/common/url.c | 662 |
8 files changed, 1605 insertions, 0 deletions
diff --git a/web/server/h2o/libh2o/t/00unit/lib/common/cache.c b/web/server/h2o/libh2o/t/00unit/lib/common/cache.c new file mode 100644 index 000000000..ea18cbc45 --- /dev/null +++ b/web/server/h2o/libh2o/t/00unit/lib/common/cache.c @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2014-2016 DeNA Co., Ltd., Kazuho Oku + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ +#include "../../test.h" +#include "../../../../lib/common/cache.c" + +static size_t bytes_destroyed; + +static void on_destroy(h2o_iovec_t vec) +{ + bytes_destroyed += vec.len; +} + +void test_lib__common__cache_c(void) +{ + h2o_cache_t *cache = h2o_cache_create(H2O_CACHE_FLAG_EARLY_UPDATE, 1024, 1000, on_destroy); + uint64_t now = 0; + h2o_iovec_t key = {H2O_STRLIT("key")}; + h2o_cache_ref_t *ref; + + /* fetch "key" */ + ref = h2o_cache_fetch(cache, now, key, 0); + ok(ref == NULL); + + /* set "key" => "value" */ + h2o_cache_set(cache, now, key, 0, h2o_iovec_init(H2O_STRLIT("value"))); + + /* delete "key" */ + h2o_cache_delete(cache, now, key, 0); + ref = h2o_cache_fetch(cache, now, key, 0); + ok(ref == NULL); + + /* set "key" => "value" */ + h2o_cache_set(cache, now, key, 0, h2o_iovec_init(H2O_STRLIT("value"))); + + /* fetch "key" */ + ref = h2o_cache_fetch(cache, now, key, 0); + ok(h2o_memis(ref->value.base, ref->value.len, H2O_STRLIT("value"))); + h2o_cache_release(cache, ref); + + /* proceed 999ms */ + now += 999; + + /* should fail to fetch "key" */ + ref = h2o_cache_fetch(cache, now, key, 0); + ok(ref == NULL); + + /* refetch should succeed */ + ref = h2o_cache_fetch(cache, now, key, 0); + ok(h2o_memis(ref->value.base, ref->value.len, H2O_STRLIT("value"))); + h2o_cache_release(cache, ref); + + /* set "key" to "value2" */ + h2o_cache_set(cache, now, key, 0, h2o_iovec_init(H2O_STRLIT("value2"))); + + /* fetch */ + ref = h2o_cache_fetch(cache, now, key, 0); + ok(h2o_memis(ref->value.base, ref->value.len, H2O_STRLIT("value2"))); + h2o_cache_release(cache, ref); + + ok(bytes_destroyed == 10); + + h2o_cache_destroy(cache); + + ok(bytes_destroyed == 16); +} diff --git a/web/server/h2o/libh2o/t/00unit/lib/common/hostinfo.c b/web/server/h2o/libh2o/t/00unit/lib/common/hostinfo.c new file mode 100644 index 000000000..9d8e5fe7c --- /dev/null +++ b/web/server/h2o/libh2o/t/00unit/lib/common/hostinfo.c @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2014 DeNA Co., Ltd. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ +#include <arpa/inet.h> +#include "../../test.h" +#include "../../../../lib/common/hostinfo.c" + +static void test_aton(void) +{ + struct in_addr addr; + + memset(&addr, 0x55, sizeof(addr)); + ok(h2o_hostinfo_aton((h2o_iovec_t){H2O_STRLIT("127.0.0.1")}, &addr) == 0); + ok(ntohl(addr.s_addr) == 0x7f000001); + + memset(&addr, 0x55, sizeof(addr)); + ok(h2o_hostinfo_aton((h2o_iovec_t){"127.0.0.12", sizeof("127.0.0.1") - 1}, &addr) == 0); + ok(ntohl(addr.s_addr) == 0x7f000001); + + memset(&addr, 0x55, sizeof(addr)); + ok(h2o_hostinfo_aton((h2o_iovec_t){H2O_STRLIT("255.001.002.128")}, &addr) == 0); + ok(ntohl(addr.s_addr) == 0xff010280); + + ok(h2o_hostinfo_aton((h2o_iovec_t){H2O_STRLIT("127.0.0.z")}, &addr) != 0); + ok(h2o_hostinfo_aton((h2o_iovec_t){H2O_STRLIT("256.0.0.0")}, &addr) != 0); + ok(h2o_hostinfo_aton((h2o_iovec_t){H2O_STRLIT("0001.0.0.0")}, &addr) != 0); + ok(h2o_hostinfo_aton((h2o_iovec_t){H2O_STRLIT("0.0..1")}, &addr) != 0); + ok(h2o_hostinfo_aton((h2o_iovec_t){H2O_STRLIT("1.0.0.0.")}, &addr) != 0); +} + +void test_lib__common__hostinfo_c(void) +{ + /* TODO add tests for h2o_hostinfo_getaddr and related */ + subtest("aton", test_aton); +} diff --git a/web/server/h2o/libh2o/t/00unit/lib/common/multithread.c b/web/server/h2o/libh2o/t/00unit/lib/common/multithread.c new file mode 100644 index 000000000..683e489a5 --- /dev/null +++ b/web/server/h2o/libh2o/t/00unit/lib/common/multithread.c @@ -0,0 +1,157 @@ +/* + * Copyright (c) 2014 DeNA Co., Ltd. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ +#include <stdlib.h> +#include "../../test.h" +#include "../../../../lib/common/multithread.c" + +struct st_thread_t { + h2o_loop_t *loop; + h2o_multithread_queue_t *queue; +}; + +struct { + h2o_loop_t *loop; + h2o_multithread_queue_t *queue; + h2o_multithread_receiver_t pong_receiver; + h2o_multithread_receiver_t shutdown_receiver; + int received_shutdown; +} main_thread; + +struct { + h2o_loop_t *loop; + h2o_multithread_queue_t *queue; + h2o_multithread_receiver_t ping_receiver; + size_t num_ping_received; + int should_exit; +} worker_thread; + +static void send_empty_message(h2o_multithread_receiver_t *receiver) +{ + h2o_multithread_message_t *message = h2o_mem_alloc(sizeof(*message)); + *message = (h2o_multithread_message_t){{NULL}}; + h2o_multithread_send_message(receiver, message); +} + +static void pop_empty_message(h2o_linklist_t *list) +{ + h2o_multithread_message_t *message = H2O_STRUCT_FROM_MEMBER(h2o_multithread_message_t, link, list->next); + h2o_linklist_unlink(&message->link); + free(message); +} + +static void on_ping(h2o_multithread_receiver_t *receiver, h2o_linklist_t *list) +{ + while (!h2o_linklist_is_empty(list)) { + pop_empty_message(list); + if (++worker_thread.num_ping_received < 100) { + send_empty_message(&main_thread.pong_receiver); + } else { + send_empty_message(&main_thread.shutdown_receiver); + worker_thread.should_exit = 1; + } + } +} + +static void on_pong(h2o_multithread_receiver_t *receiver, h2o_linklist_t *list) +{ + while (!h2o_linklist_is_empty(list)) { + pop_empty_message(list); + send_empty_message(&worker_thread.ping_receiver); + } +} + +static void on_shutdown(h2o_multithread_receiver_t *receiver, h2o_linklist_t *list) +{ + while (!h2o_linklist_is_empty(list)) + pop_empty_message(list); + main_thread.received_shutdown = 1; +} + +#if H2O_USE_LIBUV +static h2o_loop_t *create_loop(void) +{ + h2o_loop_t *loop = h2o_mem_alloc(sizeof(*loop)); + uv_loop_init(loop); + return loop; +} + +static void destroy_loop(h2o_loop_t *loop) +{ + uv_run(loop, UV_RUN_NOWAIT); + uv_loop_close(loop); + free(loop); +} +#else +#define create_loop h2o_evloop_create +#define destroy_loop(loop) (0) /* FIXME */ +#endif + +static void *worker_main(void *_unused) +{ + while (!worker_thread.should_exit) { +#if H2O_USE_LIBUV + uv_run(worker_thread.loop, UV_RUN_ONCE); +#else + h2o_evloop_run(worker_thread.loop, INT32_MAX); +#endif + } + + return NULL; +} + +void test_lib__common__multithread_c(void) +{ + pthread_t tid; + + main_thread.loop = create_loop(); + main_thread.queue = h2o_multithread_create_queue(main_thread.loop); + h2o_multithread_register_receiver(main_thread.queue, &main_thread.pong_receiver, on_pong); + h2o_multithread_register_receiver(main_thread.queue, &main_thread.shutdown_receiver, on_shutdown); + worker_thread.loop = create_loop(); + worker_thread.queue = h2o_multithread_create_queue(worker_thread.loop); + h2o_multithread_register_receiver(worker_thread.queue, &worker_thread.ping_receiver, on_ping); + + pthread_create(&tid, NULL, worker_main, NULL); + + /* send first message */ + send_empty_message(&worker_thread.ping_receiver); + + while (!main_thread.received_shutdown) { +#if H2O_USE_LIBUV + uv_run(main_thread.loop, UV_RUN_ONCE); +#else + h2o_evloop_run(main_thread.loop, INT32_MAX); +#endif + } + + pthread_join(tid, NULL); + + h2o_multithread_unregister_receiver(worker_thread.queue, &worker_thread.ping_receiver); + h2o_multithread_destroy_queue(worker_thread.queue); + destroy_loop(worker_thread.loop); + h2o_multithread_unregister_receiver(main_thread.queue, &main_thread.pong_receiver); + h2o_multithread_unregister_receiver(main_thread.queue, &main_thread.shutdown_receiver); + h2o_multithread_destroy_queue(main_thread.queue); + destroy_loop(main_thread.loop); + + ok(1); +} diff --git a/web/server/h2o/libh2o/t/00unit/lib/common/serverutil.c b/web/server/h2o/libh2o/t/00unit/lib/common/serverutil.c new file mode 100644 index 000000000..dfbb27156 --- /dev/null +++ b/web/server/h2o/libh2o/t/00unit/lib/common/serverutil.c @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2014 DeNA Co., Ltd. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ +#include <stdlib.h> +#include "../../test.h" +#include "../../../../lib/common/serverutil.c" + +static void test_server_starter(void) +{ + int *fds; + size_t num_fds; + + unsetenv("SERVER_STARTER_PORT"); + num_fds = h2o_server_starter_get_fds(&fds); + ok(num_fds == 0); + + setenv("SERVER_STARTER_PORT", "0.0.0.0:80=3", 1); + num_fds = h2o_server_starter_get_fds(&fds); + ok(num_fds == 1); + ok(fds[0] == 3); + + setenv("SERVER_STARTER_PORT", "0.0.0.0:80=3;/tmp/foo.sock=4", 1); + num_fds = h2o_server_starter_get_fds(&fds); + ok(num_fds == 2); + ok(fds[0] == 3); + ok(fds[1] == 4); + + setenv("SERVER_STARTER_PORT", "0.0.0.0:80=foo", 1); + num_fds = h2o_server_starter_get_fds(&fds); + ok(num_fds == SIZE_MAX); + + /* without bind address */ + setenv("SERVER_STARTER_PORT", "50908=4", 1); + num_fds = h2o_server_starter_get_fds(&fds); + ok(num_fds == 1); + ok(fds[0] == 4); +} + +static void test_read_command(void) +{ + char *argv[] = {"t/00unit/assets/read_command.pl", "hello", NULL}; + h2o_buffer_t *resp; + int ret, status; + + /* success */ + ret = h2o_read_command(argv[0], argv, &resp, &status); + ok(ret == 0); + if (ret == 0) { + ok(WIFEXITED(status)); + ok(WEXITSTATUS(status) == 0); + ok(h2o_memis(resp->bytes, resp->size, H2O_STRLIT("hello"))); + h2o_buffer_dispose(&resp); + } + + /* exit status */ + setenv("READ_COMMAND_EXIT_STATUS", "75", 1); + ret = h2o_read_command(argv[0], argv, &resp, &status); + ok(ret == 0); + if (ret == 0) { + ok(WIFEXITED(status)); + ok(WEXITSTATUS(status) == 75); + ok(h2o_memis(resp->bytes, resp->size, H2O_STRLIT("hello"))); + h2o_buffer_dispose(&resp); + } + unsetenv("READ_COMMAND_EXIT_STATUS"); + + /* command not an executable */ + argv[0] = "t/00unit/assets"; + ret = h2o_read_command(argv[0], argv, &resp, &status); + ok(ret != 0 || (ret == 0 && WIFEXITED(status) && WEXITSTATUS(status) == 127)); +} + +void test_lib__common__serverutil_c(void) +{ + subtest("server-starter", test_server_starter); + subtest("read-command", test_read_command); +} diff --git a/web/server/h2o/libh2o/t/00unit/lib/common/socket.c b/web/server/h2o/libh2o/t/00unit/lib/common/socket.c new file mode 100644 index 000000000..89aae515c --- /dev/null +++ b/web/server/h2o/libh2o/t/00unit/lib/common/socket.c @@ -0,0 +1,171 @@ +/* + * Copyright (c) 2015 DeNA Co., Ltd. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ +#include <stdlib.h> +#include "../../test.h" +#include "../../../../lib/common/socket.c" + +static void test_on_alpn_select(void) +{ + static const h2o_iovec_t protocols[] = {{H2O_STRLIT("h2")}, {H2O_STRLIT("h2-16")}, {H2O_STRLIT("h2-14")}, {NULL}}; + const unsigned char *out; + unsigned char outlen; + int ret; + + ret = on_alpn_select(NULL, &out, &outlen, (const unsigned char *)H2O_STRLIT("\3foo"), (void *)protocols); + ok(ret == SSL_TLSEXT_ERR_NOACK); + + ret = on_alpn_select(NULL, &out, &outlen, (const unsigned char *)H2O_STRLIT("\2h2"), (void *)protocols); + ok(ret == SSL_TLSEXT_ERR_OK); + ok(h2o_memis(out, outlen, H2O_STRLIT("h2"))); + + ret = on_alpn_select(NULL, &out, &outlen, (const unsigned char *)H2O_STRLIT("\5h2-14\5h2-16\2h2"), (void *)protocols); + ok(ret == SSL_TLSEXT_ERR_OK); + ok(h2o_memis(out, outlen, H2O_STRLIT("h2"))); + + ret = on_alpn_select(NULL, &out, &outlen, (const unsigned char *)H2O_STRLIT("\5h2-14\5h2-16"), (void *)protocols); + ok(ret == SSL_TLSEXT_ERR_OK); + ok(h2o_memis(out, outlen, H2O_STRLIT("h2-16"))); +} + +static void test_sliding_counter(void) +{ + h2o_sliding_counter_t counter = {0}; + size_t i; + + h2o_sliding_counter_start(&counter, 100); + h2o_sliding_counter_stop(&counter, 80 + 100); + ok(counter.average == 10); + + for (i = 0; i != 7; ++i) { + h2o_sliding_counter_start(&counter, 1); + h2o_sliding_counter_stop(&counter, 81); + } + ok(counter.average == 80); + + h2o_sliding_counter_start(&counter, 1000); + h2o_sliding_counter_stop(&counter, 1000 + 1000 * 8 - 80 * 7); + ok(counter.average == 1000); + + for (i = 0; i != 8; ++i) { + h2o_sliding_counter_start(&counter, 1); + h2o_sliding_counter_stop(&counter, 11); + } + ok(counter.average == 10); +} + +static struct { + struct { + int ret; + } fetch_tcp_info; + struct { + int ret; + unsigned cur; + size_t call_cnt; + } minimize_notsent_lowat; + struct { + unsigned long ret; + } get_cipher; +} cb_ret_vars; + +static int test_adjust_notsent_lowat(h2o_socket_t *sock, unsigned notsent_lowat) +{ + cb_ret_vars.minimize_notsent_lowat.cur = notsent_lowat; + ++cb_ret_vars.minimize_notsent_lowat.call_cnt; + return cb_ret_vars.minimize_notsent_lowat.ret; +} + +static void test_prepare_for_latency_optimization(void) +{ + struct st_h2o_socket_ssl_t sock_ssl = {NULL, NULL, NULL, 5 + 8 + 16 /* GCM overhead */}; + h2o_socket_t sock = {NULL, &sock_ssl}; + h2o_socket_latency_optimization_conditions_t cond = {UINT_MAX, 10, 65535}; + + /* option disabled, or if rtt is too small */ + memset(&sock._latency_optimization, 0, sizeof(sock._latency_optimization)); + memset(&cb_ret_vars, 0, sizeof(cb_ret_vars)); + cb_ret_vars.fetch_tcp_info.ret = 0; + cb_ret_vars.get_cipher.ret = TLS1_CK_RSA_WITH_AES_128_GCM_SHA256; + prepare_for_latency_optimized_write(&sock, &cond, 50000 /* rtt */, 1400 /* mss */, 10 /* cwnd_size */, 6 /* cwnd_avail */, 4, + test_adjust_notsent_lowat); + ok(sock._latency_optimization.state == H2O_SOCKET_LATENCY_OPTIMIZATION_STATE_DISABLED); + ok(sock._latency_optimization.suggested_tls_payload_size == 16384); + ok(sock._latency_optimization.suggested_write_size == SIZE_MAX); + ok(cb_ret_vars.minimize_notsent_lowat.call_cnt == 0); + + /* trigger optimiziation */ + memset(&sock._latency_optimization, 0, sizeof(sock._latency_optimization)); + cond.min_rtt = 25; /* 25 ms */ + prepare_for_latency_optimized_write(&sock, &cond, 50000 /* rtt */, 1400 /* mss */, 10 /* cwnd_size */, 6 /* cwnd_avail */, 4, + test_adjust_notsent_lowat); + ok(sock._latency_optimization.state == H2O_SOCKET_LATENCY_OPTIMIZATION_STATE_DETERMINED); + ok(sock._latency_optimization.suggested_tls_payload_size == 1400 - (5 + 8 + 16)); + ok(sock._latency_optimization.suggested_write_size == (1400 - (5 + 8 + 16)) * (10 - 5 + 1)); + ok(cb_ret_vars.minimize_notsent_lowat.call_cnt == 1); + ok(cb_ret_vars.minimize_notsent_lowat.cur == 1); + + /* recalculate with an updated cwnd,unacked */ + sock._latency_optimization.state = H2O_SOCKET_LATENCY_OPTIMIZATION_STATE_NEEDS_UPDATE; + prepare_for_latency_optimized_write(&sock, &cond, 50000 /* rtt */, 1400 /* mss */, 14 /* cwnd_size */, 12 /* cwnd_avail */, 4, + test_adjust_notsent_lowat); + ok(sock._latency_optimization.state == H2O_SOCKET_LATENCY_OPTIMIZATION_STATE_DETERMINED); + ok(sock._latency_optimization.suggested_tls_payload_size == 1400 - (5 + 8 + 16)); + ok(sock._latency_optimization.suggested_write_size == (1400 - (5 + 8 + 16)) * (14 - 3 + 1)); + ok(cb_ret_vars.minimize_notsent_lowat.call_cnt == 1); + ok(cb_ret_vars.minimize_notsent_lowat.cur == 1); + + /* switches to B/W optimization when CWND becomes greater */ + sock._latency_optimization.state = H2O_SOCKET_LATENCY_OPTIMIZATION_STATE_NEEDS_UPDATE; + prepare_for_latency_optimized_write(&sock, &cond, 50000 /* rtt */, 1400 /* mss */, (65535 / 1400) + 1 /* cwnd_size */, + (65535 / 1400) + 1 /* cwnd_avail */, 4, test_adjust_notsent_lowat); + ok(sock._latency_optimization.state == H2O_SOCKET_LATENCY_OPTIMIZATION_STATE_DETERMINED); + ok(sock._latency_optimization.suggested_tls_payload_size == 16384); + ok(sock._latency_optimization.suggested_write_size == SIZE_MAX); + ok(cb_ret_vars.minimize_notsent_lowat.call_cnt == 2); + ok(cb_ret_vars.minimize_notsent_lowat.cur == 0); + + /* switches back to latency optimization when CWND becomes small */ + sock._latency_optimization.state = H2O_SOCKET_LATENCY_OPTIMIZATION_STATE_NEEDS_UPDATE; + prepare_for_latency_optimized_write(&sock, &cond, 50000 /* rtt */, 1400 /* mss */, 8 /* cwnd_size */, 6 /* cwnd_avail */, 4, + test_adjust_notsent_lowat); + ok(sock._latency_optimization.state == H2O_SOCKET_LATENCY_OPTIMIZATION_STATE_DETERMINED); + ok(sock._latency_optimization.suggested_tls_payload_size == 1400 - (5 + 8 + 16)); + ok(sock._latency_optimization.suggested_write_size == (1400 - (5 + 8 + 16)) * (8 - 3 + 1)); + ok(cb_ret_vars.minimize_notsent_lowat.call_cnt == 3); + ok(cb_ret_vars.minimize_notsent_lowat.cur == 1); + + /* switches back to B/W optimization when loop time becomes greater than threshold */ + sock._latency_optimization.state = H2O_SOCKET_LATENCY_OPTIMIZATION_STATE_NEEDS_UPDATE; + prepare_for_latency_optimized_write(&sock, &cond, 50000 /* rtt */, 1400 /* mss */, 8 /* cwnd_size */, 6 /* cwnd_avail */, 6, + test_adjust_notsent_lowat); + ok(sock._latency_optimization.state == H2O_SOCKET_LATENCY_OPTIMIZATION_STATE_DISABLED); + ok(sock._latency_optimization.suggested_tls_payload_size == 16384); + ok(sock._latency_optimization.suggested_write_size == SIZE_MAX); + ok(cb_ret_vars.minimize_notsent_lowat.call_cnt == 4); + ok(cb_ret_vars.minimize_notsent_lowat.cur == 0); +} + +void test_lib__common__socket_c(void) +{ + subtest("on_alpn_select", test_on_alpn_select); + subtest("sliding_counter", test_sliding_counter); + subtest("prepare_for_latency_optimization", test_prepare_for_latency_optimization); +} diff --git a/web/server/h2o/libh2o/t/00unit/lib/common/string.c b/web/server/h2o/libh2o/t/00unit/lib/common/string.c new file mode 100644 index 000000000..464506e3c --- /dev/null +++ b/web/server/h2o/libh2o/t/00unit/lib/common/string.c @@ -0,0 +1,335 @@ +/* + * Copyright (c) 2014 DeNA Co., Ltd. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ +#include "../../test.h" +#include "../../../../lib/common/string.c" + +static void test_strstr(void) +{ + ok(h2o_strstr("abcd", 4, "bc", 2) == 1); + ok(h2o_strstr("abcd", 3, "bc", 2) == 1); + ok(h2o_strstr("abcd", 2, "bc", 2) == -1); +} + +static void test_stripws(void) +{ + h2o_iovec_t t; + + t = h2o_str_stripws(H2O_STRLIT("")); + ok(h2o_memis(t.base, t.len, H2O_STRLIT(""))); + t = h2o_str_stripws(H2O_STRLIT("hello world")); + ok(h2o_memis(t.base, t.len, H2O_STRLIT("hello world"))); + t = h2o_str_stripws(H2O_STRLIT(" hello world")); + ok(h2o_memis(t.base, t.len, H2O_STRLIT("hello world"))); + t = h2o_str_stripws(H2O_STRLIT("hello world ")); + ok(h2o_memis(t.base, t.len, H2O_STRLIT("hello world"))); + t = h2o_str_stripws(H2O_STRLIT(" hello world ")); + ok(h2o_memis(t.base, t.len, H2O_STRLIT("hello world"))); + t = h2o_str_stripws(H2O_STRLIT(" ")); + ok(h2o_memis(t.base, t.len, H2O_STRLIT(""))); +} + +static void test_get_filext(void) +{ + h2o_iovec_t ext; + + ext = h2o_get_filext(H2O_STRLIT("/abc.txt")); + ok(h2o_memis(ext.base, ext.len, H2O_STRLIT("txt"))); + ext = h2o_get_filext(H2O_STRLIT("/abc.txt.gz")); + ok(h2o_memis(ext.base, ext.len, H2O_STRLIT("gz"))); + ext = h2o_get_filext(H2O_STRLIT("/abc.")); + ok(h2o_memis(ext.base, ext.len, H2O_STRLIT(""))); + ext = h2o_get_filext(H2O_STRLIT("/abc")); + ok(ext.base == NULL); + ext = h2o_get_filext(H2O_STRLIT("/abc.def/abc")); + ok(ext.base == NULL); + ext = h2o_get_filext(H2O_STRLIT("/abc.def/")); + ok(ext.base == NULL); +} + +static void test_next_token(void) +{ + h2o_iovec_t iter; + const char *token; + size_t token_len; + +#define NEXT() \ + if ((token = h2o_next_token(&iter, ',', &token_len, NULL)) == NULL) { \ + ok(0); \ + return; \ + } + + iter = h2o_iovec_init(H2O_STRLIT("public, max-age=86400, must-revalidate")); + NEXT(); + ok(h2o_memis(token, token_len, H2O_STRLIT("public"))); + NEXT(); + ok(h2o_memis(token, token_len, H2O_STRLIT("max-age=86400"))); + NEXT(); + ok(h2o_memis(token, token_len, H2O_STRLIT("must-revalidate"))); + token = h2o_next_token(&iter, ',', &token_len, NULL); + ok(token == NULL); + + iter = h2o_iovec_init(H2O_STRLIT(" public ,max-age=86400 ,")); + NEXT(); + ok(h2o_memis(token, token_len, H2O_STRLIT("public"))); + NEXT(); + ok(h2o_memis(token, token_len, H2O_STRLIT("max-age=86400"))); + token = h2o_next_token(&iter, ',', &token_len, NULL); + ok(token == NULL); + + iter = h2o_iovec_init(H2O_STRLIT("")); + token = h2o_next_token(&iter, ',', &token_len, NULL); + ok(token == NULL); + + iter = h2o_iovec_init(H2O_STRLIT(", ,a, ")); + NEXT(); + ok(token_len == 0); + NEXT(); + ok(token_len == 0); + NEXT(); + ok(h2o_memis(token, token_len, H2O_STRLIT("a"))); + token = h2o_next_token(&iter, ',', &token_len, NULL); + ok(token == NULL); + +#undef NEXT +} + +static void test_next_token2(void) +{ + h2o_iovec_t iter, value; + const char *name; + size_t name_len; + +#define NEXT() \ + if ((name = h2o_next_token(&iter, ',', &name_len, &value)) == NULL) { \ + ok(0); \ + return; \ + } + + iter = h2o_iovec_init(H2O_STRLIT("public, max-age=86400, must-revalidate")); + NEXT(); + ok(h2o_memis(name, name_len, H2O_STRLIT("public"))); + ok(value.base == NULL); + ok(value.len == 0); + NEXT(); + ok(h2o_memis(name, name_len, H2O_STRLIT("max-age"))); + ok(h2o_memis(value.base, value.len, H2O_STRLIT("86400"))); + NEXT(); + ok(h2o_memis(name, name_len, H2O_STRLIT("must-revalidate"))); + ok(value.base == NULL); + ok(value.len == 0); + name = h2o_next_token(&iter, ',', &name_len, &value); + ok(name == NULL); + + iter = h2o_iovec_init(H2O_STRLIT("public, max-age = 86400 = c , must-revalidate=")); + NEXT(); + ok(h2o_memis(name, name_len, H2O_STRLIT("public"))); + ok(value.base == NULL); + ok(value.len == 0); + NEXT(); + ok(h2o_memis(name, name_len, H2O_STRLIT("max-age"))); + ok(h2o_memis(value.base, value.len, H2O_STRLIT("86400 = c"))); + NEXT(); + ok(h2o_memis(name, name_len, H2O_STRLIT("must-revalidate"))); + name = h2o_next_token(&iter, ',', &name_len, &value); + ok(h2o_memis(value.base, value.len, H2O_STRLIT(""))); + +#undef NEXT +} + +static void test_next_token3(void) +{ + h2o_iovec_t iter, value; + const char *name; + size_t name_len; + +#define NEXT() \ + if ((name = h2o_next_token(&iter, ';', &name_len, &value)) == NULL) { \ + ok(0); \ + return; \ + } + + iter = h2o_iovec_init(H2O_STRLIT("</foo.css>; rel=preload; xxx=,</bar.js>, </zzz.js>")); + NEXT(); + ok(h2o_memis(name, name_len, H2O_STRLIT("</foo.css>"))); + ok(value.base == NULL); + ok(value.len == 0); + NEXT(); + ok(h2o_memis(name, name_len, H2O_STRLIT("rel"))); + ok(h2o_memis(value.base, value.len, H2O_STRLIT("preload"))); + NEXT(); + ok(h2o_memis(name, name_len, H2O_STRLIT("xxx"))); + ok(value.base != NULL); /* xxx _has_ a value! */ + ok(value.len == 0); + NEXT(); + ok(h2o_memis(name, name_len, H2O_STRLIT(","))); + ok(value.base == NULL); + ok(value.len == 0); + NEXT(); + ok(h2o_memis(name, name_len, H2O_STRLIT("</bar.js>"))); + ok(value.base == NULL); + ok(value.len == 0); + NEXT(); + ok(h2o_memis(name, name_len, H2O_STRLIT(","))); + ok(value.base == NULL); + ok(value.len == 0); + NEXT(); + ok(h2o_memis(name, name_len, H2O_STRLIT("</zzz.js>"))); + ok(value.base == NULL); + ok(value.len == 0); + name = h2o_next_token(&iter, ',', &name_len, &value); + ok(name == NULL); + +#undef NEXT +} + +static void test_decode_base64(void) +{ + h2o_mem_pool_t pool; + char buf[256]; + + h2o_mem_init_pool(&pool); + + h2o_iovec_t src = {H2O_STRLIT("The quick brown fox jumps over the lazy dog.")}, decoded; + h2o_base64_encode(buf, (const uint8_t *)src.base, src.len, 1); + ok(strcmp(buf, "VGhlIHF1aWNrIGJyb3duIGZveCBqdW1wcyBvdmVyIHRoZSBsYXp5IGRvZy4") == 0); + decoded = h2o_decode_base64url(&pool, buf, strlen(buf)); + ok(src.len == decoded.len); + ok(strcmp(decoded.base, src.base) == 0); + + h2o_mem_clear_pool(&pool); +} + +static void test_htmlescape(void) +{ + h2o_mem_pool_t pool; + h2o_mem_init_pool(&pool); + +#define TEST(src, expected) \ + do { \ + h2o_iovec_t escaped = h2o_htmlescape(&pool, H2O_STRLIT(src)); \ + ok(h2o_memis(escaped.base, escaped.len, H2O_STRLIT(expected))); \ + } while (0) + + TEST("hello world", "hello world"); + TEST("x < y", "x < y"); + TEST("\0\"&'<>", "\0"&'<>"); + +#undef TEST + + h2o_mem_clear_pool(&pool); +} + +static void test_uri_escape(void) +{ + h2o_mem_pool_t pool; + h2o_mem_init_pool(&pool); + +#define TEST(src, preserve, expected) \ + do { \ + h2o_iovec_t escaped = h2o_uri_escape(&pool, H2O_STRLIT(src), preserve); \ + ok(h2o_memis(escaped.base, escaped.len, H2O_STRLIT(expected))); \ + } while (0) + + TEST("abc", NULL, "abc"); + TEST("a/c", NULL, "a%2Fc"); + TEST("a/c", "/", "a/c"); + TEST("\xe3\x81\x82", NULL, "%E3%81%82"); + TEST("a\0!", NULL, "a%00!"); + TEST("a/\0!", "/", "a/%00!"); + +#undef TEST + + h2o_mem_clear_pool(&pool); +} + +static void test_at_position(void) +{ + char buf[160]; + int ret; + + /* normal cases */ + ret = h2o_str_at_position(buf, H2O_STRLIT("hello\nworld\n"), 1, 1); + ok(ret == 0); + ok(strcmp(buf, "hello\n^\n") == 0); + + ret = h2o_str_at_position(buf, H2O_STRLIT("hello\nworld\n"), 1, 5); + ok(ret == 0); + ok(strcmp(buf, "hello\n ^\n") == 0); + + ret = h2o_str_at_position(buf, H2O_STRLIT("hello\nworld\n"), 1, 6); + ok(ret == 0); + ok(strcmp(buf, "hello\n ^\n") == 0); + + ret = h2o_str_at_position(buf, H2O_STRLIT("hello\nworld\n"), 1, 7); + ok(ret == 0); + ok(strcmp(buf, "hello\n ^\n") == 0); + + ret = h2o_str_at_position(buf, H2O_STRLIT("hello\nworld\n"), 2, 1); + ok(ret == 0); + ok(strcmp(buf, "world\n^\n") == 0); + + ret = h2o_str_at_position(buf, H2O_STRLIT("hello\nworld\n"), 2, 5); + ok(ret == 0); + ok(strcmp(buf, "world\n ^\n") == 0); + + ret = h2o_str_at_position(buf, H2O_STRLIT("hello\nworld\n"), 1, 7); + ok(ret == 0); + ok(strcmp(buf, "hello\n ^\n") == 0); + + ret = h2o_str_at_position( + buf, H2O_STRLIT("_________1_________2_________3_________4_________5_________6_________7_________\nworld\n"), 1, 5); + ok(ret == 0); + ok(strcmp(buf, "_________1_________2_________3_________4_________5_________6_________7______\n ^\n") == 0); + + ret = h2o_str_at_position( + buf, H2O_STRLIT("_________1_________2_________3_________4_________5_________6_________7_________\nworld\n"), 1, 60); + ok(ret == 0); + ok(strcmp(buf, "_________3_________4_________5_________6_________7_________\n ^\n") == 0); + + ret = h2o_str_at_position(buf, H2O_STRLIT("hello"), 1, 20); + ok(ret == 0); + ok(strcmp(buf, "hello\n ^\n") == 0); + + /* error cases */ + ret = h2o_str_at_position(buf, H2O_STRLIT("hello\nworld\n"), 0, 1); + ok(ret != 0); + + ret = h2o_str_at_position(buf, H2O_STRLIT("hello\nworld\n"), 1, 0); + ok(ret != 0); + + ret = h2o_str_at_position(buf, H2O_STRLIT("hello\nworld\n"), 4, 1); + ok(ret != 0); +} + +void test_lib__common__string_c(void) +{ + subtest("strstr", test_strstr); + subtest("stripws", test_stripws); + subtest("get_filext", test_get_filext); + subtest("next_token", test_next_token); + subtest("next_token2", test_next_token2); + subtest("next_token3", test_next_token3); + subtest("decode_base64", test_decode_base64); + subtest("htmlescape", test_htmlescape); + subtest("uri_escape", test_uri_escape); + subtest("at_position", test_at_position); +} diff --git a/web/server/h2o/libh2o/t/00unit/lib/common/time.c b/web/server/h2o/libh2o/t/00unit/lib/common/time.c new file mode 100644 index 000000000..c6fc12ff9 --- /dev/null +++ b/web/server/h2o/libh2o/t/00unit/lib/common/time.c @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2014 DeNA Co., Ltd. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ +#include "../../test.h" +#include "../../../../lib/common/time.c" + +void test_lib__common__time_c(void) +{ + struct tm tm = { + 56, /* sec */ + 34, /* min */ + 12, /* hour */ + 4, /* 4th */ + 1, /* feb */ + 115, /* 2015 */ + 3 /* Wed */ + }; + char buf[H2O_TIMESTR_RFC1123_LEN + 1]; + + h2o_time2str_rfc1123(buf, &tm); + ok(strcmp(buf, "Wed, 04 Feb 2015 12:34:56 GMT") == 0); + tm = (struct tm){0}; + h2o_time_parse_rfc1123(buf, H2O_TIMESTR_RFC1123_LEN, &tm); + ok(tm.tm_year == 115); + ok(tm.tm_mon == 1); + ok(tm.tm_mday == 4); + ok(tm.tm_hour == 12); + ok(tm.tm_min == 34); + ok(tm.tm_sec == 56); +} diff --git a/web/server/h2o/libh2o/t/00unit/lib/common/url.c b/web/server/h2o/libh2o/t/00unit/lib/common/url.c new file mode 100644 index 000000000..ce1676001 --- /dev/null +++ b/web/server/h2o/libh2o/t/00unit/lib/common/url.c @@ -0,0 +1,662 @@ +/* + * Copyright (c) 2014,2015 DeNA Co., Ltd. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ +#include "../../test.h" +#include "../../../../lib/common/url.c" + +static void test_normalize_path(void) +{ + h2o_mem_pool_t pool; + + h2o_mem_init_pool(&pool); + + size_t q; + size_t *norm_indexes = NULL; + h2o_iovec_t input; + h2o_iovec_t b; + + input = h2o_iovec_init(NULL, 0); + b = h2o_url_normalize_path(&pool, input.base, input.len, &q, &norm_indexes); + ok(b.len == 1); + ok(memcmp(b.base, H2O_STRLIT("/")) == 0); + ok(q == SIZE_MAX); + ok(norm_indexes == NULL); + + input = h2o_iovec_init(H2O_STRLIT("a")); + b = h2o_url_normalize_path(&pool, input.base, input.len, &q, &norm_indexes); + ok(b.len == 2); + ok(memcmp(b.base, H2O_STRLIT("/a")) == 0); + ok(q == SIZE_MAX); + ok(norm_indexes != NULL); + ok(norm_indexes[0] == 0); + ok(norm_indexes[1] == 1); + norm_indexes = NULL; + + input = h2o_iovec_init(H2O_STRLIT("aa")); + b = h2o_url_normalize_path(&pool, input.base, input.len, &q, &norm_indexes); + ok(b.len == 3); + ok(memcmp(b.base, H2O_STRLIT("/aa")) == 0); + ok(q == SIZE_MAX); + ok(norm_indexes != NULL); + ok(norm_indexes[0] == 0); + ok(norm_indexes[1] == 1); + ok(norm_indexes[2] == 2); + norm_indexes = NULL; + + input = h2o_iovec_init(H2O_STRLIT("/")); + b = h2o_url_normalize_path(&pool, input.base, input.len, &q, &norm_indexes); + ok(b.len == 1); + ok(memcmp(b.base, H2O_STRLIT("/")) == 0); + ok(q == SIZE_MAX); + ok(norm_indexes == NULL); + + input = h2o_iovec_init(H2O_STRLIT("/.")); + b = h2o_url_normalize_path(&pool, input.base, input.len, &q, &norm_indexes); + ok(b.len == 1); + ok(memcmp(b.base, H2O_STRLIT("/")) == 0); + ok(q == SIZE_MAX); + ok(norm_indexes != NULL); + ok(norm_indexes[0] == 1); + norm_indexes = NULL; + + input = h2o_iovec_init(H2O_STRLIT("/./")); + b = h2o_url_normalize_path(&pool, input.base, input.len, &q, &norm_indexes); + ok(b.len == 1); + ok(memcmp(b.base, H2O_STRLIT("/")) == 0); + ok(q == SIZE_MAX); + ok(norm_indexes != NULL); + ok(norm_indexes[0] == 1); + norm_indexes = NULL; + + input = h2o_iovec_init(H2O_STRLIT("/..")); + b = h2o_url_normalize_path(&pool, input.base, input.len, &q, &norm_indexes); + ok(b.len == 1); + ok(memcmp(b.base, H2O_STRLIT("/")) == 0); + ok(q == SIZE_MAX); + ok(norm_indexes != NULL); + ok(norm_indexes[0] == 1); + norm_indexes = NULL; + + input = h2o_iovec_init(H2O_STRLIT("/../")); + b = h2o_url_normalize_path(&pool, input.base, input.len, &q, &norm_indexes); + ok(b.len == 1); + ok(memcmp(b.base, H2O_STRLIT("/")) == 0); + ok(q == SIZE_MAX); + ok(norm_indexes != NULL); + ok(norm_indexes[0] == 1); + norm_indexes = NULL; + + input = h2o_iovec_init(H2O_STRLIT("/abc")); + b = h2o_url_normalize_path(&pool, input.base, input.len, &q, &norm_indexes); + ok(b.len == 4); + ok(memcmp(b.base, H2O_STRLIT("/abc")) == 0); + ok(q == SIZE_MAX); + ok(norm_indexes == NULL); + + input = h2o_iovec_init(H2O_STRLIT("/abc")); + b = h2o_url_normalize_path(&pool, input.base, input.len, &q, &norm_indexes); + ok(b.len == 4); + ok(memcmp(b.base, H2O_STRLIT("/abc")) == 0); + ok(q == SIZE_MAX); + ok(norm_indexes == NULL); + + input = h2o_iovec_init(H2O_STRLIT("/abc/../def")); + b = h2o_url_normalize_path(&pool, input.base, input.len, &q, &norm_indexes); + ok(b.len == 4); + ok(memcmp(b.base, H2O_STRLIT("/def")) == 0); + ok(q == SIZE_MAX); + ok(norm_indexes != NULL); + ok(norm_indexes[0] == 1); + ok(norm_indexes[1] == 9); + ok(norm_indexes[2] == 10); + ok(norm_indexes[3] == 11); + norm_indexes = NULL; + + input = h2o_iovec_init(H2O_STRLIT("/abc/../../def")); + b = h2o_url_normalize_path(&pool, input.base, input.len, &q, &norm_indexes); + ok(b.len == 4); + ok(memcmp(b.base, H2O_STRLIT("/def")) == 0); + ok(q == SIZE_MAX); + ok(norm_indexes != NULL); + ok(norm_indexes[0] == 1); + ok(norm_indexes[1] == 12); + ok(norm_indexes[2] == 13); + ok(norm_indexes[3] == 14); + norm_indexes = NULL; + + input = h2o_iovec_init(H2O_STRLIT("/abc/./def")); + b = h2o_url_normalize_path(&pool, input.base, input.len, &q, &norm_indexes); + ok(b.len == 8); + ok(memcmp(b.base, H2O_STRLIT("/abc/def")) == 0); + ok(q == SIZE_MAX); + ok(norm_indexes != NULL); + ok(norm_indexes[0] == 1); + ok(norm_indexes[1] == 2); + ok(norm_indexes[2] == 3); + ok(norm_indexes[3] == 4); + ok(norm_indexes[4] == 5); + ok(norm_indexes[5] == 8); + ok(norm_indexes[6] == 9); + ok(norm_indexes[7] == 10); + norm_indexes = NULL; + + input = h2o_iovec_init(H2O_STRLIT("/abc/././def")); + b = h2o_url_normalize_path(&pool, input.base, input.len, &q, &norm_indexes); + ok(b.len == 8); + ok(memcmp(b.base, H2O_STRLIT("/abc/def")) == 0); + ok(q == SIZE_MAX); + ok(norm_indexes != NULL); + ok(norm_indexes[0] == 1); + ok(norm_indexes[1] == 2); + ok(norm_indexes[2] == 3); + ok(norm_indexes[3] == 4); + ok(norm_indexes[4] == 5); + ok(norm_indexes[5] == 10); + ok(norm_indexes[6] == 11); + ok(norm_indexes[7] == 12); + norm_indexes = NULL; + + input = h2o_iovec_init(H2O_STRLIT("/abc/def/ghi/../..")); + b = h2o_url_normalize_path(&pool, input.base, input.len, &q, &norm_indexes); + ok(b.len == 5); + ok(memcmp(b.base, H2O_STRLIT("/abc/")) == 0); + ok(q == SIZE_MAX); + ok(norm_indexes != NULL); + ok(norm_indexes[0] == 1); + ok(norm_indexes[1] == 2); + ok(norm_indexes[2] == 3); + ok(norm_indexes[3] == 4); + ok(norm_indexes[4] == 5); + norm_indexes = NULL; + + input = h2o_iovec_init(H2O_STRLIT("/abc/def/./.")); + b = h2o_url_normalize_path(&pool, input.base, input.len, &q, &norm_indexes); + ok(b.len == 9); + ok(memcmp(b.base, H2O_STRLIT("/abc/def/")) == 0); + ok(q == SIZE_MAX); + ok(norm_indexes != NULL); + ok(norm_indexes[0] == 1); + ok(norm_indexes[1] == 2); + ok(norm_indexes[2] == 3); + ok(norm_indexes[3] == 4); + ok(norm_indexes[4] == 5); + ok(norm_indexes[5] == 6); + ok(norm_indexes[6] == 7); + ok(norm_indexes[7] == 8); + norm_indexes = NULL; + + input = h2o_iovec_init(H2O_STRLIT("/abc/def/ghi/../.")); + b = h2o_url_normalize_path(&pool, input.base, input.len, &q, &norm_indexes); + ok(b.len == 9); + ok(memcmp(b.base, H2O_STRLIT("/abc/def/")) == 0); + ok(q == SIZE_MAX); + ok(norm_indexes != NULL); + ok(norm_indexes[0] == 1); + ok(norm_indexes[1] == 2); + ok(norm_indexes[2] == 3); + ok(norm_indexes[3] == 4); + ok(norm_indexes[4] == 5); + ok(norm_indexes[5] == 6); + ok(norm_indexes[6] == 7); + ok(norm_indexes[7] == 8); + norm_indexes = NULL; + + input = h2o_iovec_init(H2O_STRLIT("/abc/def/./..")); + b = h2o_url_normalize_path(&pool, input.base, input.len, &q, &norm_indexes); + ok(b.len == 5); + ok(memcmp(b.base, H2O_STRLIT("/abc/")) == 0); + ok(q == SIZE_MAX); + ok(norm_indexes != NULL); + ok(norm_indexes[0] == 1); + ok(norm_indexes[1] == 2); + ok(norm_indexes[2] == 3); + ok(norm_indexes[3] == 4); + ok(norm_indexes[4] == 5); + norm_indexes = NULL; + + input = h2o_iovec_init(H2O_STRLIT("/abc/def/..")); + b = h2o_url_normalize_path(&pool, input.base, input.len, &q, &norm_indexes); + ok(b.len == 5); + ok(memcmp(b.base, H2O_STRLIT("/abc/")) == 0); + ok(q == SIZE_MAX); + ok(norm_indexes != NULL); + ok(norm_indexes[0] == 1); + ok(norm_indexes[1] == 2); + ok(norm_indexes[2] == 3); + ok(norm_indexes[3] == 4); + ok(norm_indexes[4] == 5); + norm_indexes = NULL; + + input = h2o_iovec_init(H2O_STRLIT("/abc/def/.")); + b = h2o_url_normalize_path(&pool, input.base, input.len, &q, &norm_indexes); + ok(b.len == 9); + ok(memcmp(b.base, H2O_STRLIT("/abc/def/")) == 0); + ok(q == SIZE_MAX); + ok(norm_indexes != NULL); + ok(norm_indexes[0] == 1); + ok(norm_indexes[1] == 2); + ok(norm_indexes[2] == 3); + ok(norm_indexes[3] == 4); + ok(norm_indexes[4] == 5); + ok(norm_indexes[5] == 6); + ok(norm_indexes[6] == 7); + norm_indexes = NULL; + + input = h2o_iovec_init(H2O_STRLIT("/abc?xx")); + b = h2o_url_normalize_path(&pool, input.base, input.len, &q, &norm_indexes); + ok(b.len == 4); + ok(memcmp(b.base, H2O_STRLIT("/abc")) == 0); + ok(q == 4); + ok(norm_indexes == NULL); + + input = h2o_iovec_init(H2O_STRLIT("/abc/../def?xx")); + b = h2o_url_normalize_path(&pool, input.base, input.len, &q, &norm_indexes); + ok(b.len == 4); + ok(memcmp(b.base, H2O_STRLIT("/def")) == 0); + ok(q == 11); + ok(norm_indexes != NULL); + ok(norm_indexes[0] == 1); + ok(norm_indexes[1] == 9); + ok(norm_indexes[2] == 10); + ok(norm_indexes[3] == 11); + norm_indexes = NULL; + + input = h2o_iovec_init(H2O_STRLIT("/a%62c")); + b = h2o_url_normalize_path(&pool, input.base, input.len, &q, &norm_indexes); + ok(b.len == 4); + ok(memcmp(b.base, H2O_STRLIT("/abc")) == 0); + ok(q == SIZE_MAX); + ok(norm_indexes != NULL); + ok(norm_indexes[0] == 1); + ok(norm_indexes[1] == 2); + ok(norm_indexes[2] == 5); + ok(norm_indexes[3] == 6); + norm_indexes = NULL; + + input = h2o_iovec_init(H2O_STRLIT("/a%6")); + b = h2o_url_normalize_path(&pool, input.base, input.len, &q, &norm_indexes); + ok(b.len == 4); + ok(memcmp(b.base, H2O_STRLIT("/a%6")) == 0); + ok(q == SIZE_MAX); + ok(norm_indexes != NULL); + ok(norm_indexes[0] == 1); + ok(norm_indexes[1] == 2); + ok(norm_indexes[2] == 3); + ok(norm_indexes[3] == 4); + norm_indexes = NULL; + + input = h2o_iovec_init(H2O_STRLIT("/a%6?")); + b = h2o_url_normalize_path(&pool, input.base, input.len, &q, &norm_indexes); + ok(b.len == 4); + ok(memcmp(b.base, H2O_STRLIT("/a%6")) == 0); + ok(q == 4); + ok(norm_indexes != NULL); + ok(norm_indexes[0] == 1); + ok(norm_indexes[1] == 2); + ok(norm_indexes[2] == 3); + ok(norm_indexes[3] == 4); + norm_indexes = NULL; + + input = h2o_iovec_init(H2O_STRLIT("/%25")); + b = h2o_url_normalize_path(&pool, input.base, input.len, &q, &norm_indexes); + ok(b.len == 2); + ok(memcmp(b.base, H2O_STRLIT("/%")) == 0); + ok(q == SIZE_MAX); + ok(norm_indexes != NULL); + ok(norm_indexes[0] == 1); + ok(norm_indexes[1] == 4); + norm_indexes = NULL; + + input = h2o_iovec_init(H2O_STRLIT("/abc//")); + b = h2o_url_normalize_path(&pool, input.base, input.len, &q, &norm_indexes); + ok(b.len == 6); + ok(memcmp(b.base, H2O_STRLIT("/abc//")) == 0); + ok(q == SIZE_MAX); + ok(norm_indexes == NULL); + + input = h2o_iovec_init(H2O_STRLIT("/abc//d")); + b = h2o_url_normalize_path(&pool, input.base, input.len, &q, &norm_indexes); + ok(b.len == 7); + ok(memcmp(b.base, H2O_STRLIT("/abc//d")) == 0); + ok(q == SIZE_MAX); + ok(norm_indexes == NULL); + + input = h2o_iovec_init(H2O_STRLIT("//")); + b = h2o_url_normalize_path(&pool, input.base, input.len, &q, &norm_indexes); + ok(b.len == 2); + ok(memcmp(b.base, H2O_STRLIT("//")) == 0); + ok(q == SIZE_MAX); + ok(norm_indexes == NULL); + + input = h2o_iovec_init(H2O_STRLIT("//abc")); + b = h2o_url_normalize_path(&pool, input.base, input.len, &q, &norm_indexes); + ok(b.len == 5); + ok(memcmp(b.base, H2O_STRLIT("//abc")) == 0); + ok(q == SIZE_MAX); + ok(norm_indexes == NULL); + + h2o_mem_clear_pool(&pool); +} + +static void test_hostport(void) +{ + h2o_iovec_t input, host; + uint16_t port; + const char *ret; + + input = h2o_iovec_init(H2O_STRLIT("127.0.0.1")); + ret = h2o_url_parse_hostport(input.base, input.len, &host, &port); + ok(ret == input.base + input.len); + ok(h2o_memis(host.base, host.len, H2O_STRLIT("127.0.0.1"))); + ok(port == 65535); + + input = h2o_iovec_init(H2O_STRLIT("127.0.0.1/")); + ret = h2o_url_parse_hostport(input.base, input.len, &host, &port); + ok(strcmp(ret, "/") == 0); + ok(h2o_memis(host.base, host.len, H2O_STRLIT("127.0.0.1"))); + ok(port == 65535); + + input = h2o_iovec_init(H2O_STRLIT("127.0.0.1:8081/")); + ret = h2o_url_parse_hostport(input.base, input.len, &host, &port); + ok(strcmp(ret, "/") == 0); + ok(h2o_memis(host.base, host.len, H2O_STRLIT("127.0.0.1"))); + ok(port == 8081); + + input = h2o_iovec_init(H2O_STRLIT("[::ffff:192.0.2.1]:8081/")); + ret = h2o_url_parse_hostport(input.base, input.len, &host, &port); + ok(strcmp(ret, "/") == 0); + ok(h2o_memis(host.base, host.len, H2O_STRLIT("::ffff:192.0.2.1"))); + ok(port == 8081); + + input = h2o_iovec_init(H2O_STRLIT("[::ffff:192.0.2.1:8081/")); + ret = h2o_url_parse_hostport(input.base, input.len, &host, &port); + ok(ret == NULL); + + input = h2o_iovec_init(H2O_STRLIT(":8081/")); + ret = h2o_url_parse_hostport(input.base, input.len, &host, &port); + ok(ret == NULL); + + input = h2o_iovec_init(H2O_STRLIT("[]:8081/")); + ret = h2o_url_parse_hostport(input.base, input.len, &host, &port); + ok(ret == NULL); +} + +static void test_parse(void) +{ + h2o_url_t parsed; + int ret; + + ret = h2o_url_parse("http://example.com/abc", SIZE_MAX, &parsed); + ok(ret == 0); + ok(parsed.scheme == &H2O_URL_SCHEME_HTTP); + ok(h2o_memis(parsed.authority.base, parsed.authority.len, H2O_STRLIT("example.com"))); + ok(h2o_memis(parsed.host.base, parsed.host.len, H2O_STRLIT("example.com"))); + ok(parsed._port == 65535); + ok(h2o_url_get_port(&parsed) == 80); + ok(h2o_memis(parsed.path.base, parsed.path.len, H2O_STRLIT("/abc"))); + + ret = h2o_url_parse("http://example.com", SIZE_MAX, &parsed); + ok(ret == 0); + ok(parsed.scheme == &H2O_URL_SCHEME_HTTP); + ok(h2o_memis(parsed.authority.base, parsed.authority.len, H2O_STRLIT("example.com"))); + ok(h2o_memis(parsed.host.base, parsed.host.len, H2O_STRLIT("example.com"))); + ok(parsed._port == 65535); + ok(h2o_url_get_port(&parsed) == 80); + ok(h2o_memis(parsed.path.base, parsed.path.len, H2O_STRLIT("/"))); + + ret = h2o_url_parse("http://example.com:81/abc", SIZE_MAX, &parsed); + ok(ret == 0); + ok(parsed.scheme == &H2O_URL_SCHEME_HTTP); + ok(h2o_memis(parsed.authority.base, parsed.authority.len, H2O_STRLIT("example.com:81"))); + ok(h2o_memis(parsed.host.base, parsed.host.len, H2O_STRLIT("example.com"))); + ok(parsed._port == 81); + ok(h2o_url_get_port(&parsed) == 81); + ok(h2o_memis(parsed.path.base, parsed.path.len, H2O_STRLIT("/abc"))); + + ret = h2o_url_parse("http://example.com:81", SIZE_MAX, &parsed); + ok(ret == 0); + ok(parsed.scheme == &H2O_URL_SCHEME_HTTP); + ok(h2o_memis(parsed.authority.base, parsed.authority.len, H2O_STRLIT("example.com:81"))); + ok(h2o_memis(parsed.host.base, parsed.host.len, H2O_STRLIT("example.com"))); + ok(parsed._port == 81); + ok(h2o_url_get_port(&parsed) == 81); + ok(h2o_memis(parsed.path.base, parsed.path.len, H2O_STRLIT("/"))); + + ret = h2o_url_parse("https://example.com/abc", SIZE_MAX, &parsed); + ok(ret == 0); + ok(parsed.scheme == &H2O_URL_SCHEME_HTTPS); + ok(h2o_memis(parsed.authority.base, parsed.authority.len, H2O_STRLIT("example.com"))); + ok(h2o_memis(parsed.host.base, parsed.host.len, H2O_STRLIT("example.com"))); + ok(parsed._port == 65535); + ok(h2o_url_get_port(&parsed) == 443); + ok(h2o_memis(parsed.path.base, parsed.path.len, H2O_STRLIT("/abc"))); + + ret = h2o_url_parse("http:/abc", SIZE_MAX, &parsed); + ok(ret != 0); + + ret = h2o_url_parse("ftp://example.com/abc", SIZE_MAX, &parsed); + ok(ret != 0); + + ret = h2o_url_parse("http://abc:111111/def", SIZE_MAX, &parsed); + ok(ret != 0); + + ret = h2o_url_parse("http://[::ffff:192.0.2.128]", SIZE_MAX, &parsed); + ok(ret == 0); + ok(parsed.scheme == &H2O_URL_SCHEME_HTTP); + ok(h2o_memis(parsed.authority.base, parsed.authority.len, H2O_STRLIT("[::ffff:192.0.2.128]"))); + ok(h2o_memis(parsed.host.base, parsed.host.len, H2O_STRLIT("::ffff:192.0.2.128"))); + ok(parsed._port == 65535); + ok(h2o_url_get_port(&parsed) == 80); + ok(h2o_memis(parsed.path.base, parsed.path.len, H2O_STRLIT("/"))); + + ret = h2o_url_parse("https://[::ffff:192.0.2.128]/abc", SIZE_MAX, &parsed); + ok(ret == 0); + ok(parsed.scheme == &H2O_URL_SCHEME_HTTPS); + ok(h2o_memis(parsed.authority.base, parsed.authority.len, H2O_STRLIT("[::ffff:192.0.2.128]"))); + ok(h2o_memis(parsed.host.base, parsed.host.len, H2O_STRLIT("::ffff:192.0.2.128"))); + ok(parsed._port == 65535); + ok(h2o_url_get_port(&parsed) == 443); + ok(h2o_memis(parsed.path.base, parsed.path.len, H2O_STRLIT("/abc"))); + + ret = h2o_url_parse("https://[::ffff:192.0.2.128]:111/abc", SIZE_MAX, &parsed); + ok(ret == 0); + ok(parsed.scheme == &H2O_URL_SCHEME_HTTPS); + ok(h2o_memis(parsed.authority.base, parsed.authority.len, H2O_STRLIT("[::ffff:192.0.2.128]:111"))); + ok(h2o_memis(parsed.host.base, parsed.host.len, H2O_STRLIT("::ffff:192.0.2.128"))); + ok(parsed._port == 111); + ok(h2o_url_get_port(&parsed) == 111); + ok(h2o_memis(parsed.path.base, parsed.path.len, H2O_STRLIT("/abc"))); +} + +static void test_parse_relative(void) +{ + h2o_url_t parsed; + int ret; + + memset(&parsed, 0x55, sizeof(parsed)); + ret = h2o_url_parse_relative("abc", SIZE_MAX, &parsed); + ok(ret == 0); + ok(parsed.scheme == NULL); + ok(parsed.authority.base == NULL); + ok(parsed.host.base == NULL); + ok(parsed._port == 65535); + ok(h2o_memis(parsed.path.base, parsed.path.len, H2O_STRLIT("abc"))); + + memset(&parsed, 0x55, sizeof(parsed)); + ret = h2o_url_parse_relative("/abc", SIZE_MAX, &parsed); + ok(ret == 0); + ok(parsed.scheme == NULL); + ok(parsed.authority.base == NULL); + ok(parsed.host.base == NULL); + ok(parsed._port == 65535); + ok(h2o_memis(parsed.path.base, parsed.path.len, H2O_STRLIT("/abc"))); + + memset(&parsed, 0x55, sizeof(parsed)); + ret = h2o_url_parse_relative("http:abc", SIZE_MAX, &parsed); + ok(ret == 0); + ok(parsed.scheme == &H2O_URL_SCHEME_HTTP); + ok(parsed.authority.base == NULL); + ok(parsed.host.base == NULL); + ok(parsed._port == 65535); + ok(h2o_memis(parsed.path.base, parsed.path.len, H2O_STRLIT("abc"))); + + memset(&parsed, 0x55, sizeof(parsed)); + ret = h2o_url_parse_relative("//host", SIZE_MAX, &parsed); + ok(ret == 0); + ok(parsed.scheme == NULL); + ok(h2o_memis(parsed.authority.base, parsed.authority.len, H2O_STRLIT("host"))); + ok(h2o_memis(parsed.host.base, parsed.host.len, H2O_STRLIT("host"))); + ok(parsed._port == 65535); + ok(h2o_memis(parsed.path.base, parsed.path.len, H2O_STRLIT("/"))); + + memset(&parsed, 0x55, sizeof(parsed)); + ret = h2o_url_parse_relative("//host:12345/path", SIZE_MAX, &parsed); + ok(ret == 0); + ok(parsed.scheme == NULL); + ok(h2o_memis(parsed.authority.base, parsed.authority.len, H2O_STRLIT("host:12345"))); + ok(h2o_memis(parsed.host.base, parsed.host.len, H2O_STRLIT("host"))); + ok(parsed._port == 12345); + ok(h2o_memis(parsed.path.base, parsed.path.len, H2O_STRLIT("/path"))); + + memset(&parsed, 0x55, sizeof(parsed)); + ret = h2o_url_parse_relative("https://host:12345/path", SIZE_MAX, &parsed); + ok(ret == 0); + ok(parsed.scheme == &H2O_URL_SCHEME_HTTPS); + ok(h2o_memis(parsed.authority.base, parsed.authority.len, H2O_STRLIT("host:12345"))); + ok(h2o_memis(parsed.host.base, parsed.host.len, H2O_STRLIT("host"))); + ok(parsed._port == 12345); + ok(h2o_memis(parsed.path.base, parsed.path.len, H2O_STRLIT("/path"))); +} + +static void test_resolve(void) +{ + h2o_mem_pool_t pool; + h2o_url_t base, relative, resolved; + h2o_iovec_t final; + int ret; + + h2o_mem_init_pool(&pool); + + ret = h2o_url_parse("http://example.com/dir/index.html", SIZE_MAX, &base); + ok(ret == 0); + + ret = h2o_url_parse_relative("../assets/jquery.js", SIZE_MAX, &relative); + ok(ret == 0); + final = h2o_url_resolve(&pool, &base, &relative, &resolved); + ok(h2o_memis(final.base, final.len, H2O_STRLIT("http://example.com/assets/jquery.js"))); + ok(resolved.scheme == &H2O_URL_SCHEME_HTTP); + ok(h2o_memis(resolved.authority.base, resolved.authority.len, H2O_STRLIT("example.com"))); + ok(h2o_memis(resolved.host.base, resolved.host.len, H2O_STRLIT("example.com"))); + ok(resolved._port == 65535); + ok(h2o_url_get_port(&resolved) == 80); + ok(h2o_memis(resolved.path.base, resolved.path.len, H2O_STRLIT("/assets/jquery.js"))); + + ret = h2o_url_parse_relative("foo.html", SIZE_MAX, &relative); + ok(ret == 0); + final = h2o_url_resolve(&pool, &base, &relative, &resolved); + ok(h2o_memis(final.base, final.len, H2O_STRLIT("http://example.com/dir/foo.html"))); + ok(resolved.scheme == &H2O_URL_SCHEME_HTTP); + ok(h2o_memis(resolved.authority.base, resolved.authority.len, H2O_STRLIT("example.com"))); + ok(h2o_memis(resolved.host.base, resolved.host.len, H2O_STRLIT("example.com"))); + ok(resolved._port == 65535); + ok(h2o_url_get_port(&resolved) == 80); + ok(h2o_memis(resolved.path.base, resolved.path.len, H2O_STRLIT("/dir/foo.html"))); + + ret = h2o_url_parse_relative("./bar.txt", SIZE_MAX, &relative); + ok(ret == 0); + final = h2o_url_resolve(&pool, &base, &relative, &resolved); + ok(h2o_memis(final.base, final.len, H2O_STRLIT("http://example.com/dir/bar.txt"))); + ok(resolved.scheme == &H2O_URL_SCHEME_HTTP); + ok(h2o_memis(resolved.authority.base, resolved.authority.len, H2O_STRLIT("example.com"))); + ok(h2o_memis(resolved.host.base, resolved.host.len, H2O_STRLIT("example.com"))); + ok(resolved._port == 65535); + ok(h2o_url_get_port(&resolved) == 80); + ok(h2o_memis(resolved.path.base, resolved.path.len, H2O_STRLIT("/dir/bar.txt"))); + + ret = h2o_url_parse_relative("../../../traverse", SIZE_MAX, &relative); + ok(ret == 0); + final = h2o_url_resolve(&pool, &base, &relative, &resolved); + ok(h2o_memis(final.base, final.len, H2O_STRLIT("http://example.com/traverse"))); + ok(resolved.scheme == &H2O_URL_SCHEME_HTTP); + ok(h2o_memis(resolved.authority.base, resolved.authority.len, H2O_STRLIT("example.com"))); + ok(h2o_memis(resolved.host.base, resolved.host.len, H2O_STRLIT("example.com"))); + ok(resolved._port == 65535); + ok(h2o_url_get_port(&resolved) == 80); + ok(h2o_memis(resolved.path.base, resolved.path.len, H2O_STRLIT("/traverse"))); + + ret = h2o_url_parse_relative("http:foo.html", SIZE_MAX, &relative); + ok(ret == 0); + final = h2o_url_resolve(&pool, &base, &relative, &resolved); + ok(h2o_memis(final.base, final.len, H2O_STRLIT("http://example.com/dir/foo.html"))); + ok(resolved.scheme == &H2O_URL_SCHEME_HTTP); + ok(h2o_memis(resolved.authority.base, resolved.authority.len, H2O_STRLIT("example.com"))); + ok(h2o_memis(resolved.host.base, resolved.host.len, H2O_STRLIT("example.com"))); + ok(resolved._port == 65535); + ok(h2o_url_get_port(&resolved) == 80); + ok(h2o_memis(resolved.path.base, resolved.path.len, H2O_STRLIT("/dir/foo.html"))); + + ret = h2o_url_parse_relative("http:/icon.ico", SIZE_MAX, &relative); + ok(ret == 0); + final = h2o_url_resolve(&pool, &base, &relative, &resolved); + ok(h2o_memis(final.base, final.len, H2O_STRLIT("http://example.com/icon.ico"))); + ok(resolved.scheme == &H2O_URL_SCHEME_HTTP); + ok(h2o_memis(resolved.authority.base, resolved.authority.len, H2O_STRLIT("example.com"))); + ok(h2o_memis(resolved.host.base, resolved.host.len, H2O_STRLIT("example.com"))); + ok(resolved._port == 65535); + ok(h2o_url_get_port(&resolved) == 80); + ok(h2o_memis(resolved.path.base, resolved.path.len, H2O_STRLIT("/icon.ico"))); + + ret = h2o_url_parse_relative("https:/icon.ico", SIZE_MAX, &relative); + ok(ret == 0); + final = h2o_url_resolve(&pool, &base, &relative, &resolved); + ok(h2o_memis(final.base, final.len, H2O_STRLIT("https://example.com/icon.ico"))); + ok(resolved.scheme == &H2O_URL_SCHEME_HTTPS); + ok(h2o_memis(resolved.authority.base, resolved.authority.len, H2O_STRLIT("example.com"))); + ok(h2o_memis(resolved.host.base, resolved.host.len, H2O_STRLIT("example.com"))); + ok(resolved._port == 65535); + ok(h2o_url_get_port(&resolved) == 443); + ok(h2o_memis(resolved.path.base, resolved.path.len, H2O_STRLIT("/icon.ico"))); + + ret = h2o_url_parse_relative("//example.jp:81/icon.ico", SIZE_MAX, &relative); + ok(ret == 0); + final = h2o_url_resolve(&pool, &base, &relative, &resolved); + ok(h2o_memis(final.base, final.len, H2O_STRLIT("http://example.jp:81/icon.ico"))); + ok(resolved.scheme == &H2O_URL_SCHEME_HTTP); + ok(h2o_memis(resolved.authority.base, resolved.authority.len, H2O_STRLIT("example.jp:81"))); + ok(h2o_memis(resolved.host.base, resolved.host.len, H2O_STRLIT("example.jp"))); + ok(resolved._port == 81); + ok(h2o_url_get_port(&resolved) == 81); + ok(h2o_memis(resolved.path.base, resolved.path.len, H2O_STRLIT("/icon.ico"))); + + final = h2o_url_stringify(&pool, &base); + ok(h2o_memis(final.base, final.len, H2O_STRLIT("http://example.com/dir/index.html"))); + + h2o_mem_clear_pool(&pool); +} + +void test_lib__common__url_c(void) +{ + subtest("normalize_path", test_normalize_path); + subtest("hostport", test_hostport); + subtest("parse", test_parse); + subtest("parse_relative", test_parse_relative); + subtest("resolve", test_resolve); +} |