From 6a7eecec57783a042d12f895d5ae148c44f4d074 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sat, 13 Apr 2024 10:52:22 +0200 Subject: Merging upstream version 1.60.0. Signed-off-by: Daniel Baumann --- src/CMakeLists.txt | 84 +-- src/HttpServer.cc | 60 ++- src/HttpServer.h | 7 +- src/Makefile.am | 13 +- src/allocator.h | 2 +- src/app_helper.cc | 40 -- src/app_helper.h | 3 - src/base64_test.cc | 67 ++- src/base64_test.h | 10 +- src/buffer_test.cc | 51 +- src/buffer_test.h | 8 +- src/deflatehd.cc | 6 +- src/h2load.cc | 37 +- src/h2load.h | 6 +- src/h2load_http2_session.cc | 23 +- src/h2load_http3_session.cc | 2 +- src/h2load_quic.cc | 3 +- src/http2_test.cc | 777 +++++++++++++++------------- src/http2_test.h | 40 +- src/inflatehd.cc | 9 +- src/libevent_util.cc | 162 ------ src/libevent_util.h | 75 --- src/memchunk_test.cc | 218 ++++---- src/memchunk_test.h | 26 +- src/nghttp.cc | 66 ++- src/nghttp.h | 9 +- src/nghttp2_gzip_test.c | 52 +- src/nghttp2_gzip_test.h | 8 +- src/shrpx-unittest.cc | 210 +------- src/shrpx.h | 2 + src/shrpx_config.cc | 34 ++ src/shrpx_config.h | 5 + src/shrpx_config_test.cc | 238 +++++---- src/shrpx_config_test.h | 15 +- src/shrpx_connection.cc | 14 +- src/shrpx_connection.h | 16 +- src/shrpx_connection_handler.cc | 23 +- src/shrpx_downstream_test.cc | 66 ++- src/shrpx_downstream_test.h | 20 +- src/shrpx_http.cc | 6 +- src/shrpx_http.h | 6 +- src/shrpx_http2_downstream_connection.cc | 13 +- src/shrpx_http2_session.cc | 20 +- src/shrpx_http2_session.h | 2 +- src/shrpx_http2_upstream.cc | 51 +- src/shrpx_http3_upstream.cc | 9 +- src/shrpx_http_test.cc | 130 +++-- src/shrpx_http_test.h | 16 +- src/shrpx_live_check.cc | 12 +- src/shrpx_mruby.cc | 4 +- src/shrpx_quic.cc | 34 +- src/shrpx_quic.h | 11 +- src/shrpx_quic_connection_handler.cc | 6 +- src/shrpx_router_test.cc | 88 ++-- src/shrpx_router_test.h | 12 +- src/shrpx_tls.cc | 159 +++++- src/shrpx_tls_test.cc | 125 +++-- src/shrpx_tls_test.h | 16 +- src/shrpx_worker.cc | 138 ++++- src/shrpx_worker_process.cc | 10 + src/shrpx_worker_test.cc | 305 ++++++----- src/shrpx_worker_test.h | 8 +- src/template_test.cc | 132 ++--- src/template_test.h | 10 +- src/tls.cc | 56 ++ src/tls.h | 9 + src/util_test.cc | 841 +++++++++++++++++-------------- src/util_test.h | 82 +-- 68 files changed, 2611 insertions(+), 2207 deletions(-) delete mode 100644 src/libevent_util.cc delete mode 100644 src/libevent_util.h (limited to 'src') diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 201c5a2..6583324 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -21,6 +21,8 @@ include_directories( ${JANSSON_INCLUDE_DIRS} ${ZLIB_INCLUDE_DIRS} ${LIBBPF_INCLUDE_DIRS} + ${LIBBROTLIENC_INCLUDE_DIRS} + ${LIBBROTLIDEC_INCLUDE_DIRS} ) # XXX per-target? @@ -38,6 +40,8 @@ link_libraries( ${ZLIB_LIBRARIES} ${APP_LIBRARIES} ${LIBBPF_LIBRARIES} + ${LIBBROTLIENC_LIBRARIES} + ${LIBBROTLIDEC_LIBRARIES} ) if(ENABLE_APP) @@ -163,45 +167,45 @@ if(ENABLE_APP) target_link_libraries(nghttpx_static neverbleed) endif() - - if(HAVE_CUNIT) - set(NGHTTPX_UNITTEST_SOURCES - shrpx-unittest.cc - shrpx_tls_test.cc - shrpx_downstream_test.cc - shrpx_config_test.cc - shrpx_worker_test.cc - shrpx_http_test.cc - shrpx_router_test.cc - http2_test.cc - util_test.cc - nghttp2_gzip_test.c - nghttp2_gzip.c - buffer_test.cc - memchunk_test.cc - template_test.cc - base64_test.cc - ) - add_executable(nghttpx-unittest EXCLUDE_FROM_ALL - ${NGHTTPX_UNITTEST_SOURCES} - $ - $ - ) - target_include_directories(nghttpx-unittest PRIVATE ${CUNIT_INCLUDE_DIRS}) - target_compile_definitions(nghttpx-unittest - PRIVATE "-DNGHTTP2_SRC_DIR=\"${CMAKE_SOURCE_DIR}/src\"" + set(NGHTTPX_UNITTEST_SOURCES + shrpx-unittest.cc + shrpx_tls_test.cc + shrpx_downstream_test.cc + shrpx_config_test.cc + shrpx_worker_test.cc + shrpx_http_test.cc + shrpx_router_test.cc + http2_test.cc + util_test.cc + nghttp2_gzip_test.c + nghttp2_gzip.c + buffer_test.cc + memchunk_test.cc + template_test.cc + base64_test.cc + ${CMAKE_SOURCE_DIR}/tests/munit/munit.c + ) + add_executable(nghttpx-unittest EXCLUDE_FROM_ALL + ${NGHTTPX_UNITTEST_SOURCES} + $ + $ ) - target_link_libraries(nghttpx-unittest nghttpx_static ${CUNIT_LIBRARIES}) - if(HAVE_MRUBY) - target_link_libraries(nghttpx-unittest mruby-lib) - endif() - if(HAVE_NEVERBLEED) - target_link_libraries(nghttpx-unittest neverbleed) - endif() - - add_test(nghttpx-unittest nghttpx-unittest) - add_dependencies(check nghttpx-unittest) + target_include_directories(nghttpx-unittest PRIVATE + ${CMAKE_SOURCE_DIR}/tests/munit + ) + target_compile_definitions(nghttpx-unittest + PRIVATE "-DNGHTTP2_SRC_DIR=\"${CMAKE_SOURCE_DIR}/src\"" + ) + target_link_libraries(nghttpx-unittest nghttpx_static) + if(HAVE_MRUBY) + target_link_libraries(nghttpx-unittest mruby-lib) endif() + if(HAVE_NEVERBLEED) + target_link_libraries(nghttpx-unittest neverbleed) + endif() + + add_test(nghttpx-unittest nghttpx-unittest) + add_dependencies(check nghttpx-unittest) add_executable(nghttp ${NGHTTP_SOURCES} $ $ @@ -221,8 +225,7 @@ if(ENABLE_APP) $ ) - install(TARGETS nghttp nghttpd nghttpx h2load - RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}") + install(TARGETS nghttp nghttpd nghttpx h2load) endif() if(ENABLE_HPACK_TOOLS) @@ -238,6 +241,5 @@ if(ENABLE_HPACK_TOOLS) ) add_executable(inflatehd ${inflatehd_SOURCES}) add_executable(deflatehd ${deflatehd_SOURCES}) - install(TARGETS inflatehd deflatehd - RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}") + install(TARGETS inflatehd deflatehd) endif() diff --git a/src/HttpServer.cc b/src/HttpServer.cc index 0385cd0..b59cecd 100644 --- a/src/HttpServer.cc +++ b/src/HttpServer.cc @@ -607,10 +607,10 @@ int Http2Handler::fill_wb() { for (;;) { const uint8_t *data; - auto datalen = nghttp2_session_mem_send(session_, &data); + auto datalen = nghttp2_session_mem_send2(session_, &data); if (datalen < 0) { - std::cerr << "nghttp2_session_mem_send() returned error: " + std::cerr << "nghttp2_session_mem_send2() returned error: " << nghttp2_strerror(datalen) << std::endl; return -1; } @@ -648,10 +648,10 @@ int Http2Handler::read_clear() { util::hexdump(stdout, buf.data(), nread); } - rv = nghttp2_session_mem_recv(session_, buf.data(), nread); + rv = nghttp2_session_mem_recv2(session_, buf.data(), nread); if (rv < 0) { if (rv != NGHTTP2_ERR_BAD_CLIENT_MAGIC) { - std::cerr << "nghttp2_session_mem_recv() returned error: " + std::cerr << "nghttp2_session_mem_recv2() returned error: " << nghttp2_strerror(rv) << std::endl; } return -1; @@ -771,10 +771,10 @@ int Http2Handler::read_tls() { util::hexdump(stdout, buf.data(), nread); } - rv = nghttp2_session_mem_recv(session_, buf.data(), nread); + rv = nghttp2_session_mem_recv2(session_, buf.data(), nread); if (rv < 0) { if (rv != NGHTTP2_ERR_BAD_CLIENT_MAGIC) { - std::cerr << "nghttp2_session_mem_recv() returned error: " + std::cerr << "nghttp2_session_mem_recv2() returned error: " << nghttp2_strerror(rv) << std::endl; } return -1; @@ -917,7 +917,7 @@ int Http2Handler::verify_alpn_result() { int Http2Handler::submit_file_response(const StringRef &status, Stream *stream, time_t last_modified, off_t file_length, const std::string *content_type, - nghttp2_data_provider *data_prd) { + nghttp2_data_provider2 *data_prd) { std::string last_modified_str; auto nva = make_array(http2::make_nv_ls_nocopy(":status", status), http2::make_nv_ls_nocopy("server", NGHTTPD_SERVER), @@ -942,13 +942,13 @@ int Http2Handler::submit_file_response(const StringRef &status, Stream *stream, if (!trailer_names.empty()) { nva[nvlen++] = http2::make_nv_ls_nocopy("trailer", trailer_names); } - return nghttp2_submit_response(session_, stream->stream_id, nva.data(), nvlen, - data_prd); + return nghttp2_submit_response2(session_, stream->stream_id, nva.data(), + nvlen, data_prd); } int Http2Handler::submit_response(const StringRef &status, int32_t stream_id, const HeaderRefs &headers, - nghttp2_data_provider *data_prd) { + nghttp2_data_provider2 *data_prd) { auto nva = std::vector(); nva.reserve(4 + headers.size()); nva.push_back(http2::make_nv_ls_nocopy(":status", status)); @@ -965,13 +965,13 @@ int Http2Handler::submit_response(const StringRef &status, int32_t stream_id, for (auto &nv : headers) { nva.push_back(http2::make_nv_nocopy(nv.name, nv.value, nv.no_index)); } - int r = nghttp2_submit_response(session_, stream_id, nva.data(), nva.size(), - data_prd); + int r = nghttp2_submit_response2(session_, stream_id, nva.data(), nva.size(), + data_prd); return r; } int Http2Handler::submit_response(const StringRef &status, int32_t stream_id, - nghttp2_data_provider *data_prd) { + nghttp2_data_provider2 *data_prd) { auto nva = make_array(http2::make_nv_ls_nocopy(":status", status), http2::make_nv_ls_nocopy("server", NGHTTPD_SERVER), http2::make_nv_ls("date", sessions_->get_cached_date()), @@ -985,8 +985,8 @@ int Http2Handler::submit_response(const StringRef &status, int32_t stream_id, } } - return nghttp2_submit_response(session_, stream_id, nva.data(), nvlen, - data_prd); + return nghttp2_submit_response2(session_, stream_id, nva.data(), nvlen, + data_prd); } int Http2Handler::submit_non_final_response(const std::string &status, @@ -1076,9 +1076,10 @@ void Http2Handler::terminate_session(uint32_t error_code) { nghttp2_session_terminate_session(session_, error_code); } -ssize_t file_read_callback(nghttp2_session *session, int32_t stream_id, - uint8_t *buf, size_t length, uint32_t *data_flags, - nghttp2_data_source *source, void *user_data) { +nghttp2_ssize file_read_callback(nghttp2_session *session, int32_t stream_id, + uint8_t *buf, size_t length, + uint32_t *data_flags, + nghttp2_data_source *source, void *user_data) { int rv; auto hd = static_cast(user_data); auto stream = hd->get_stream(stream_id); @@ -1127,7 +1128,7 @@ void prepare_status_response(Stream *stream, Http2Handler *hd, int status) { // we don't set stream->file_ent since we don't want to expire it. stream->body_length = file_ent->length; - nghttp2_data_provider data_prd; + nghttp2_data_provider2 data_prd; data_prd.source.fd = file_ent->fd; data_prd.read_callback = file_read_callback; @@ -1155,7 +1156,7 @@ void prepare_echo_response(Stream *stream, Http2Handler *hd) { hd->submit_rst_stream(stream, NGHTTP2_INTERNAL_ERROR); return; } - nghttp2_data_provider data_prd; + nghttp2_data_provider2 data_prd; data_prd.source.fd = stream->file_ent->fd; data_prd.read_callback = file_read_callback; @@ -1378,7 +1379,7 @@ void prepare_response(Stream *stream, Http2Handler *hd, stream->body_length = file_ent->length; - nghttp2_data_provider data_prd; + nghttp2_data_provider2 data_prd; data_prd.source.fd = file_ent->fd; data_prd.read_callback = file_read_callback; @@ -1676,9 +1677,9 @@ int send_data_callback(nghttp2_session *session, nghttp2_frame *frame, } // namespace namespace { -ssize_t select_padding_callback(nghttp2_session *session, - const nghttp2_frame *frame, size_t max_payload, - void *user_data) { +nghttp2_ssize select_padding_callback(nghttp2_session *session, + const nghttp2_frame *frame, + size_t max_payload, void *user_data) { auto hd = static_cast(user_data); return std::min(max_payload, frame->hd.length + hd->get_config()->padding); } @@ -1765,7 +1766,7 @@ void fill_callback(nghttp2_session_callbacks *callbacks, const Config *config) { send_data_callback); if (config->padding) { - nghttp2_session_callbacks_set_select_padding_callback( + nghttp2_session_callbacks_set_select_padding_callback2( callbacks, select_padding_callback); } } @@ -2205,6 +2206,15 @@ int HttpServer::run() { // ALPN selection callback SSL_CTX_set_alpn_select_cb(ssl_ctx, alpn_select_proto_cb, this); + +#if defined(NGHTTP2_OPENSSL_IS_BORINGSSL) && defined(HAVE_LIBBROTLI) + if (!SSL_CTX_add_cert_compression_alg( + ssl_ctx, nghttp2::tls::CERTIFICATE_COMPRESSION_ALGO_BROTLI, + nghttp2::tls::cert_compress, nghttp2::tls::cert_decompress)) { + std::cerr << "SSL_CTX_add_cert_compression_alg failed." << std::endl; + return -1; + } +#endif // NGHTTP2_OPENSSL_IS_BORINGSSL && HAVE_LIBBROTLI } auto loop = EV_DEFAULT; diff --git a/src/HttpServer.h b/src/HttpServer.h index 949bd1f..00fd6bf 100644 --- a/src/HttpServer.h +++ b/src/HttpServer.h @@ -41,6 +41,7 @@ #include +#define NGHTTP2_NO_SSIZE_T #include #include "http2.h" @@ -172,14 +173,14 @@ public: int submit_file_response(const StringRef &status, Stream *stream, time_t last_modified, off_t file_length, const std::string *content_type, - nghttp2_data_provider *data_prd); + nghttp2_data_provider2 *data_prd); int submit_response(const StringRef &status, int32_t stream_id, - nghttp2_data_provider *data_prd); + nghttp2_data_provider2 *data_prd); int submit_response(const StringRef &status, int32_t stream_id, const HeaderRefs &headers, - nghttp2_data_provider *data_prd); + nghttp2_data_provider2 *data_prd); int submit_non_final_response(const std::string &status, int32_t stream_id); diff --git a/src/Makefile.am b/src/Makefile.am index f112ac2..5e90018 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -53,6 +53,8 @@ AM_CPPFLAGS = \ @JANSSON_CFLAGS@ \ @LIBBPF_CFLAGS@ \ @ZLIB_CFLAGS@ \ + @LIBBROTLIENC_CFLAGS@ \ + @LIBBROTLIDEC_CFLAGS@ \ @EXTRA_DEFS@ \ @DEFS@ AM_LDFLAGS = @LIBTOOL_LDFLAGS@ @@ -73,6 +75,8 @@ LDADD = $(top_builddir)/lib/libnghttp2.la \ @JANSSON_LIBS@ \ @LIBBPF_LIBS@ \ @ZLIB_LIBS@ \ + @LIBBROTLIENC_LIBS@ \ + @LIBBROTLIDEC_LIBS@ \ @APPLDFLAGS@ if ENABLE_APP @@ -203,7 +207,6 @@ libnghttpx_a_CPPFLAGS += -I${top_srcdir}/third-party/neverbleed nghttpx_LDADD += ${top_builddir}/third-party/libneverbleed.la endif # HAVE_NEVERBLEED -if HAVE_CUNIT check_PROGRAMS += nghttpx-unittest nghttpx_unittest_SOURCES = shrpx-unittest.cc \ shrpx_tls_test.cc shrpx_tls_test.h \ @@ -219,10 +222,13 @@ nghttpx_unittest_SOURCES = shrpx-unittest.cc \ buffer_test.cc buffer_test.h \ memchunk_test.cc memchunk_test.h \ template_test.cc template_test.h \ - base64_test.cc base64_test.h + base64_test.cc base64_test.h \ + $(top_srcdir)/tests/munit/munit.c $(top_srcdir)/tests/munit/munit.h \ + $(top_srcdir)/tests/munit/munitxx.h nghttpx_unittest_CPPFLAGS = ${AM_CPPFLAGS} \ + -I$(top_srcdir)/tests/munit \ -DNGHTTP2_SRC_DIR=\"$(top_srcdir)/src\" -nghttpx_unittest_LDADD = libnghttpx.a ${LDADD} @CUNIT_LIBS@ @TESTLDADD@ +nghttpx_unittest_LDADD = libnghttpx.a ${LDADD} @TESTLDADD@ if HAVE_MRUBY nghttpx_unittest_CPPFLAGS += \ @@ -237,7 +243,6 @@ nghttpx_unittest_LDADD += ${top_builddir}/third-party/libneverbleed.la endif # HAVE_NEVERBLEED TESTS += nghttpx-unittest -endif # HAVE_CUNIT endif # ENABLE_APP diff --git a/src/allocator.h b/src/allocator.h index 97b9a41..363ee91 100644 --- a/src/allocator.h +++ b/src/allocator.h @@ -119,7 +119,7 @@ struct BlockAllocator { } if (!head || - head->end - head->last < static_cast(size + sizeof(size_t))) { + static_cast(head->end - head->last) < size + sizeof(size_t)) { head = alloc_mem_block(block_size); } diff --git a/src/app_helper.cc b/src/app_helper.cc index ef92762..666d16c 100644 --- a/src/app_helper.cc +++ b/src/app_helper.cc @@ -53,8 +53,6 @@ #include #include -#include - #include "app_helper.h" #include "util.h" #include "http2.h" @@ -477,42 +475,4 @@ std::chrono::steady_clock::time_point get_time() { return std::chrono::steady_clock::now(); } -ssize_t deflate_data(uint8_t *out, size_t outlen, const uint8_t *in, - size_t inlen) { - int rv; - z_stream zst{}; - uint8_t temp_out[8_k]; - auto temp_outlen = sizeof(temp_out); - - rv = deflateInit2(&zst, Z_DEFAULT_COMPRESSION, Z_DEFLATED, 31, 9, - Z_DEFAULT_STRATEGY); - - if (rv != Z_OK) { - return -1; - } - - zst.avail_in = inlen; - zst.next_in = (uint8_t *)in; - zst.avail_out = temp_outlen; - zst.next_out = temp_out; - - rv = deflate(&zst, Z_FINISH); - - deflateEnd(&zst); - - if (rv != Z_STREAM_END) { - return -1; - } - - temp_outlen -= zst.avail_out; - - if (temp_outlen > outlen) { - return -1; - } - - memcpy(out, temp_out, temp_outlen); - - return temp_outlen; -} - } // namespace nghttp2 diff --git a/src/app_helper.h b/src/app_helper.h index 5424054..a7ef7cc 100644 --- a/src/app_helper.h +++ b/src/app_helper.h @@ -90,9 +90,6 @@ void set_color_output(bool f); // used. void set_output(FILE *file); -ssize_t deflate_data(uint8_t *out, size_t outlen, const uint8_t *in, - size_t inlen); - } // namespace nghttp2 #endif // APP_HELPER_H diff --git a/src/base64_test.cc b/src/base64_test.cc index 4324bd7..9ab770f 100644 --- a/src/base64_test.cc +++ b/src/base64_test.cc @@ -27,7 +27,7 @@ #include #include -#include +#include "munitxx.h" #include @@ -35,26 +35,38 @@ namespace nghttp2 { +namespace { +const MunitTest tests[]{ + munit_void_test(test_base64_encode), + munit_void_test(test_base64_decode), + munit_test_end(), +}; +} // namespace + +const MunitSuite base64_suite{ + "/base64", tests, NULL, 1, MUNIT_SUITE_OPTION_NONE, +}; + void test_base64_encode(void) { { std::string in = "\xff"; auto out = base64::encode(std::begin(in), std::end(in)); - CU_ASSERT("/w==" == out); + assert_stdstring_equal("/w==", out); } { std::string in = "\xff\xfe"; auto out = base64::encode(std::begin(in), std::end(in)); - CU_ASSERT("//4=" == out); + assert_stdstring_equal("//4=", out); } { std::string in = "\xff\xfe\xfd"; auto out = base64::encode(std::begin(in), std::end(in)); - CU_ASSERT("//79" == out); + assert_stdstring_equal("//79", out); } { std::string in = "\xff\xfe\xfd\xfc"; auto out = base64::encode(std::begin(in), std::end(in)); - CU_ASSERT("//79/A==" == out); + assert_stdstring_equal("//79/A==", out); } } @@ -63,58 +75,65 @@ void test_base64_decode(void) { { std::string in = "/w=="; auto out = base64::decode(std::begin(in), std::end(in)); - CU_ASSERT("\xff" == out); - CU_ASSERT("\xff" == base64::decode(balloc, std::begin(in), std::end(in))); + assert_stdstring_equal("\xff", out); + assert_stdstring_equal( + "\xff", base64::decode(balloc, std::begin(in), std::end(in)).str()); } { std::string in = "//4="; auto out = base64::decode(std::begin(in), std::end(in)); - CU_ASSERT("\xff\xfe" == out); - CU_ASSERT("\xff\xfe" == - base64::decode(balloc, std::begin(in), std::end(in))); + assert_stdstring_equal("\xff\xfe", out); + assert_stdstring_equal( + "\xff\xfe", base64::decode(balloc, std::begin(in), std::end(in)).str()); } { std::string in = "//79"; auto out = base64::decode(std::begin(in), std::end(in)); - CU_ASSERT("\xff\xfe\xfd" == out); - CU_ASSERT("\xff\xfe\xfd" == - base64::decode(balloc, std::begin(in), std::end(in))); + assert_stdstring_equal("\xff\xfe\xfd", out); + assert_stdstring_equal( + "\xff\xfe\xfd", + base64::decode(balloc, std::begin(in), std::end(in)).str()); } { std::string in = "//79/A=="; auto out = base64::decode(std::begin(in), std::end(in)); - CU_ASSERT("\xff\xfe\xfd\xfc" == out); - CU_ASSERT("\xff\xfe\xfd\xfc" == - base64::decode(balloc, std::begin(in), std::end(in))); + assert_stdstring_equal("\xff\xfe\xfd\xfc", out); + assert_stdstring_equal( + "\xff\xfe\xfd\xfc", + base64::decode(balloc, std::begin(in), std::end(in)).str()); } { // we check the number of valid input must be multiples of 4 std::string in = "//79="; auto out = base64::decode(std::begin(in), std::end(in)); - CU_ASSERT("" == out); - CU_ASSERT("" == base64::decode(balloc, std::begin(in), std::end(in))); + assert_stdstring_equal("", out); + assert_stdstring_equal( + "", base64::decode(balloc, std::begin(in), std::end(in)).str()); } { // ending invalid character at the boundary of multiples of 4 is // bad std::string in = "bmdodHRw\n"; auto out = base64::decode(std::begin(in), std::end(in)); - CU_ASSERT("" == out); - CU_ASSERT("" == base64::decode(balloc, std::begin(in), std::end(in))); + assert_stdstring_equal("", out); + assert_stdstring_equal( + "", base64::decode(balloc, std::begin(in), std::end(in)).str()); } { // after seeing '=', subsequent input must be also '='. std::string in = "//79/A=A"; auto out = base64::decode(std::begin(in), std::end(in)); - CU_ASSERT("" == out); - CU_ASSERT("" == base64::decode(balloc, std::begin(in), std::end(in))); + assert_stdstring_equal("", out); + assert_stdstring_equal( + "", base64::decode(balloc, std::begin(in), std::end(in)).str()); } { // additional '=' at the end is bad std::string in = "//79/A======"; auto out = base64::decode(std::begin(in), std::end(in)); - CU_ASSERT("" == out); - CU_ASSERT("" == base64::decode(balloc, std::begin(in), std::end(in))); + assert_stdstring_equal("", out); + assert_stdstring_equal( + "", base64::decode(balloc, std::begin(in), std::end(in)).str()); } } diff --git a/src/base64_test.h b/src/base64_test.h index 8bdb84f..fd74f27 100644 --- a/src/base64_test.h +++ b/src/base64_test.h @@ -29,10 +29,16 @@ # include #endif // HAVE_CONFIG_H +#define MUNIT_ENABLE_ASSERT_ALIASES + +#include "munit.h" + namespace nghttp2 { -void test_base64_encode(void); -void test_base64_decode(void); +extern const MunitSuite base64_suite; + +munit_void_test_decl(test_base64_encode); +munit_void_test_decl(test_base64_decode); } // namespace nghttp2 diff --git a/src/buffer_test.cc b/src/buffer_test.cc index 38688ed..2079086 100644 --- a/src/buffer_test.cc +++ b/src/buffer_test.cc @@ -28,7 +28,7 @@ #include #include -#include +#include "munitxx.h" #include @@ -36,43 +36,54 @@ namespace nghttp2 { +namespace { +const MunitTest tests[]{ + munit_void_test(test_buffer_write), + munit_test_end(), +}; +} // namespace + +const MunitSuite buffer_suite{ + "/buffer", tests, NULL, 1, MUNIT_SUITE_OPTION_NONE, +}; + void test_buffer_write(void) { Buffer<16> b; - CU_ASSERT(0 == b.rleft()); - CU_ASSERT(16 == b.wleft()); + assert_size(0, ==, b.rleft()); + assert_size(16, ==, b.wleft()); b.write("012", 3); - CU_ASSERT(3 == b.rleft()); - CU_ASSERT(13 == b.wleft()); - CU_ASSERT(b.pos == std::begin(b.buf)); + assert_size(3, ==, b.rleft()); + assert_size(13, ==, b.wleft()); + assert_ptr_equal(b.pos, std::begin(b.buf)); b.drain(3); - CU_ASSERT(0 == b.rleft()); - CU_ASSERT(13 == b.wleft()); - CU_ASSERT(3 == b.pos - std::begin(b.buf)); + assert_size(0, ==, b.rleft()); + assert_size(13, ==, b.wleft()); + assert_ptrdiff(3, ==, b.pos - std::begin(b.buf)); auto n = b.write("0123456789ABCDEF", 16); - CU_ASSERT(n == 13); + assert_ssize(13, ==, n); - CU_ASSERT(13 == b.rleft()); - CU_ASSERT(0 == b.wleft()); - CU_ASSERT(3 == b.pos - std::begin(b.buf)); - CU_ASSERT(0 == memcmp(b.pos, "0123456789ABC", 13)); + assert_size(13, ==, b.rleft()); + assert_size(0, ==, b.wleft()); + assert_ptrdiff(3, ==, b.pos - std::begin(b.buf)); + assert_memory_equal(13, b.pos, "0123456789ABC"); b.reset(); - CU_ASSERT(0 == b.rleft()); - CU_ASSERT(16 == b.wleft()); - CU_ASSERT(b.pos == std::begin(b.buf)); + assert_size(0, ==, b.rleft()); + assert_size(16, ==, b.wleft()); + assert_ptr_equal(b.pos, std::begin(b.buf)); b.write(5); - CU_ASSERT(5 == b.rleft()); - CU_ASSERT(11 == b.wleft()); - CU_ASSERT(b.pos == std::begin(b.buf)); + assert_size(5, ==, b.rleft()); + assert_size(11, ==, b.wleft()); + assert_ptr_equal(b.pos, std::begin(b.buf)); } } // namespace nghttp2 diff --git a/src/buffer_test.h b/src/buffer_test.h index 6789aa3..4fb004f 100644 --- a/src/buffer_test.h +++ b/src/buffer_test.h @@ -29,9 +29,15 @@ # include #endif // HAVE_CONFIG_H +#define MUNIT_ENABLE_ASSERT_ALIASES + +#include "munit.h" + namespace nghttp2 { -void test_buffer_write(void); +extern const MunitSuite buffer_suite; + +munit_void_test_decl(test_buffer_write); } // namespace nghttp2 diff --git a/src/deflatehd.cc b/src/deflatehd.cc index 7dcfccf..ad472de 100644 --- a/src/deflatehd.cc +++ b/src/deflatehd.cc @@ -41,6 +41,7 @@ #include +#define NGHTTP2_NO_SSIZE_T #include #include "template.h" @@ -113,11 +114,10 @@ static void output_to_json(nghttp2_hd_deflater *deflater, const uint8_t *buf, static void deflate_hd(nghttp2_hd_deflater *deflater, const std::vector &nva, size_t inputlen, int seq) { - ssize_t rv; std::array buf; - rv = nghttp2_hd_deflate_hd(deflater, buf.data(), buf.size(), - (nghttp2_nv *)nva.data(), nva.size()); + auto rv = nghttp2_hd_deflate_hd2(deflater, buf.data(), buf.size(), + (nghttp2_nv *)nva.data(), nva.size()); if (rv < 0) { fprintf(stderr, "deflate failed with error code %zd at %d\n", rv, seq); exit(EXIT_FAILURE); diff --git a/src/h2load.cc b/src/h2load.cc index 0f07610..8136a9f 100644 --- a/src/h2load.cc +++ b/src/h2load.cc @@ -410,7 +410,7 @@ namespace { void client_request_timeout_cb(struct ev_loop *loop, ev_timer *w, int revents) { auto client = static_cast(w->data); - if (client->streams.size() >= (size_t)config.max_concurrent_streams) { + if (client->streams.size() >= config.max_concurrent_streams) { ev_timer_stop(client->worker->loop, w); return; } @@ -582,8 +582,12 @@ int Client::make_socket(addrinfo *addr) { } } - if (ssl && !util::numeric_host(config.host.c_str())) { - SSL_set_tlsext_host_name(ssl, config.host.c_str()); + if (ssl) { + if (!config.sni.empty()) { + SSL_set_tlsext_host_name(ssl, config.sni.c_str()); + } else if (!util::numeric_host(config.host.c_str())) { + SSL_set_tlsext_host_name(ssl, config.host.c_str()); + } } if (config.is_quic()) { @@ -2301,6 +2305,9 @@ Options: --max-udp-payload-size= Specify the maximum outgoing UDP datagram payload size. --ktls Enable ktls. + --sni= + Send in TLS SNI, overriding the host name + specified in URI. -v, --verbose Output debug information. --version Display version information and exit. @@ -2363,6 +2370,7 @@ int main(int argc, char **argv) { {"max-udp-payload-size", required_argument, &flag, 17}, {"ktls", no_argument, &flag, 18}, {"alpn-list", required_argument, &flag, 19}, + {"sni", required_argument, &flag, 20}, {nullptr, 0, nullptr, 0}}; int option_index = 0; auto c = getopt_long(argc, argv, @@ -2699,6 +2707,10 @@ int main(int argc, char **argv) { // alpn-list option config.alpn_list = util::parse_config_str_list(StringRef{optarg}); break; + case 20: + // --sni + config.sni = optarg; + break; } break; default: @@ -2973,6 +2985,15 @@ int main(int argc, char **argv) { } } +#if defined(NGHTTP2_OPENSSL_IS_BORINGSSL) && defined(HAVE_LIBBROTLI) + if (!SSL_CTX_add_cert_compression_alg( + ssl_ctx, nghttp2::tls::CERTIFICATE_COMPRESSION_ALGO_BROTLI, + nghttp2::tls::cert_compress, nghttp2::tls::cert_decompress)) { + std::cerr << "SSL_CTX_add_cert_compression_alg failed" << std::endl; + exit(EXIT_FAILURE); + } +#endif // NGHTTP2_OPENSSL_IS_BORINGSSL && HAVE_LIBBROTLI + std::string user_agent = "h2load nghttp2/" NGHTTP2_VERSION; Headers shared_nva; shared_nva.emplace_back(":scheme", config.scheme); @@ -3079,18 +3100,18 @@ int main(int argc, char **argv) { #ifndef NOTHREADS size_t nreqs_per_thread = 0; - ssize_t nreqs_rem = 0; + size_t nreqs_rem = 0; if (!config.timing_script) { nreqs_per_thread = config.nreqs / config.nthreads; nreqs_rem = config.nreqs % config.nthreads; } - size_t nclients_per_thread = config.nclients / config.nthreads; - ssize_t nclients_rem = config.nclients % config.nthreads; + auto nclients_per_thread = config.nclients / config.nthreads; + auto nclients_rem = config.nclients % config.nthreads; - size_t rate_per_thread = config.rate / config.nthreads; - ssize_t rate_per_thread_rem = config.rate % config.nthreads; + auto rate_per_thread = config.rate / config.nthreads; + auto rate_per_thread_rem = config.rate % config.nthreads; size_t max_samples_per_thread = std::max(static_cast(256), MAX_SAMPLES / config.nthreads); diff --git a/src/h2load.h b/src/h2load.h index 11bb54c..860bf77 100644 --- a/src/h2load.h +++ b/src/h2load.h @@ -43,6 +43,7 @@ #include #include +#define NGHTTP2_NO_SSIZE_T #include #ifdef ENABLE_HTTP3 @@ -92,7 +93,7 @@ struct Config { size_t nclients; size_t nthreads; // The maximum number of concurrent streams per session. - ssize_t max_concurrent_streams; + size_t max_concurrent_streams; size_t window_bits; size_t connection_window_bits; size_t max_frame_size; @@ -138,6 +139,9 @@ struct Config { size_t max_udp_payload_size; // Enable ktls. bool ktls; + // sni is the value sent in TLS SNI, overriding DNS name of the + // remote host. + std::string sni; Config(); ~Config(); diff --git a/src/h2load_http2_session.cc b/src/h2load_http2_session.cc index b058a33..6e810ab 100644 --- a/src/h2load_http2_session.cc +++ b/src/h2load_http2_session.cc @@ -124,9 +124,10 @@ int before_frame_send_callback(nghttp2_session *session, } // namespace namespace { -ssize_t file_read_callback(nghttp2_session *session, int32_t stream_id, - uint8_t *buf, size_t length, uint32_t *data_flags, - nghttp2_data_source *source, void *user_data) { +nghttp2_ssize file_read_callback(nghttp2_session *session, int32_t stream_id, + uint8_t *buf, size_t length, + uint32_t *data_flags, + nghttp2_data_source *source, void *user_data) { auto client = static_cast(user_data); auto config = client->worker->config; auto req_stat = client->get_req_stat(stream_id); @@ -158,8 +159,8 @@ ssize_t file_read_callback(nghttp2_session *session, int32_t stream_id, } // namespace namespace { -ssize_t send_callback(nghttp2_session *session, const uint8_t *data, - size_t length, int flags, void *user_data) { +nghttp2_ssize send_callback(nghttp2_session *session, const uint8_t *data, + size_t length, int flags, void *user_data) { auto client = static_cast(user_data); auto &wb = client->wb; @@ -198,7 +199,7 @@ void Http2Session::on_connect() { nghttp2_session_callbacks_set_before_frame_send_callback( callbacks, before_frame_send_callback); - nghttp2_session_callbacks_set_send_callback(callbacks, send_callback); + nghttp2_session_callbacks_set_send_callback2(callbacks, send_callback); nghttp2_option *opt; @@ -257,11 +258,11 @@ int Http2Session::submit_request() { client_->reqidx = 0; } - nghttp2_data_provider prd{{0}, file_read_callback}; + nghttp2_data_provider2 prd{{0}, file_read_callback}; auto stream_id = - nghttp2_submit_request(session_, nullptr, nva.data(), nva.size(), - config->data_fd == -1 ? nullptr : &prd, nullptr); + nghttp2_submit_request2(session_, nullptr, nva.data(), nva.size(), + config->data_fd == -1 ? nullptr : &prd, nullptr); if (stream_id < 0) { return -1; } @@ -272,7 +273,7 @@ int Http2Session::submit_request() { } int Http2Session::on_read(const uint8_t *data, size_t len) { - auto rv = nghttp2_session_mem_recv(session_, data, len); + auto rv = nghttp2_session_mem_recv2(session_, data, len); if (rv < 0) { return -1; } @@ -308,7 +309,7 @@ void Http2Session::terminate() { } size_t Http2Session::max_concurrent_streams() { - return (size_t)client_->worker->config->max_concurrent_streams; + return client_->worker->config->max_concurrent_streams; } } // namespace h2load diff --git a/src/h2load_http3_session.cc b/src/h2load_http3_session.cc index d491cba..03a2233 100644 --- a/src/h2load_http3_session.cc +++ b/src/h2load_http3_session.cc @@ -124,7 +124,7 @@ int Http3Session::on_write() { return -1; } void Http3Session::terminate() {} size_t Http3Session::max_concurrent_streams() { - return (size_t)client_->worker->config->max_concurrent_streams; + return client_->worker->config->max_concurrent_streams; } namespace { diff --git a/src/h2load_quic.cc b/src/h2load_quic.cc index e492a3e..8b3c552 100644 --- a/src/h2load_quic.cc +++ b/src/h2load_quic.cc @@ -654,7 +654,8 @@ int Client::write_quic() { ngtcp2_conn_get_path_max_tx_udp_payload_size(quic.conn); #endif // UDP_SEGMENT auto max_pktcnt = - ngtcp2_conn_get_send_quantum(quic.conn) / max_udp_payload_size; + std::max(ngtcp2_conn_get_send_quantum(quic.conn) / max_udp_payload_size, + static_cast(1)); uint8_t *bufpos = quic.tx.data.get(); ngtcp2_path_storage ps; size_t gso_size = 0; diff --git a/src/http2_test.cc b/src/http2_test.cc index f8be9f4..3cb0b71 100644 --- a/src/http2_test.cc +++ b/src/http2_test.cc @@ -28,7 +28,7 @@ #include #include -#include +#include "munitxx.h" #include "url-parser/url_parser.h" @@ -45,12 +45,39 @@ using namespace nghttp2; namespace shrpx { +namespace { +const MunitTest tests[]{ + munit_void_test(test_http2_add_header), + munit_void_test(test_http2_get_header), + munit_void_test(test_http2_copy_headers_to_nva), + munit_void_test(test_http2_build_http1_headers_from_headers), + munit_void_test(test_http2_lws), + munit_void_test(test_http2_rewrite_location_uri), + munit_void_test(test_http2_parse_http_status_code), + munit_void_test(test_http2_index_header), + munit_void_test(test_http2_lookup_token), + munit_void_test(test_http2_parse_link_header), + munit_void_test(test_http2_path_join), + munit_void_test(test_http2_normalize_path), + munit_void_test(test_http2_rewrite_clean_path), + munit_void_test(test_http2_get_pure_path_component), + munit_void_test(test_http2_construct_push_component), + munit_void_test(test_http2_contains_trailers), + munit_void_test(test_http2_check_transfer_encoding), + munit_test_end(), +}; +} // namespace + +const MunitSuite http2_suite{ + "/http2", tests, NULL, 1, MUNIT_SUITE_OPTION_NONE, +}; + namespace { void check_nv(const HeaderRef &a, const nghttp2_nv *b) { - CU_ASSERT(a.name.size() == b->namelen); - CU_ASSERT(a.value.size() == b->valuelen); - CU_ASSERT(memcmp(a.name.c_str(), b->name, b->namelen) == 0); - CU_ASSERT(memcmp(a.value.c_str(), b->value, b->valuelen) == 0); + assert_size(a.name.size(), ==, b->namelen); + assert_size(a.value.size(), ==, b->valuelen); + assert_memory_equal(b->namelen, a.name.c_str(), b->name); + assert_memory_equal(b->valuelen, a.value.c_str(), b->value); } } // namespace @@ -59,51 +86,51 @@ void test_http2_add_header(void) { http2::add_header(nva, (const uint8_t *)"alpha", 5, (const uint8_t *)"123", 3, false, -1); - CU_ASSERT(Headers::value_type("alpha", "123") == nva[0]); - CU_ASSERT(!nva[0].no_index); + assert_true(Headers::value_type("alpha", "123") == nva[0]); + assert_false(nva[0].no_index); nva.clear(); http2::add_header(nva, (const uint8_t *)"alpha", 5, (const uint8_t *)"", 0, true, -1); - CU_ASSERT(Headers::value_type("alpha", "") == nva[0]); - CU_ASSERT(nva[0].no_index); + assert_true(Headers::value_type("alpha", "") == nva[0]); + assert_true(nva[0].no_index); nva.clear(); http2::add_header(nva, (const uint8_t *)"a", 1, (const uint8_t *)" b", 2, false, -1); - CU_ASSERT(Headers::value_type("a", "b") == nva[0]); + assert_true(Headers::value_type("a", "b") == nva[0]); nva.clear(); http2::add_header(nva, (const uint8_t *)"a", 1, (const uint8_t *)"b ", 2, false, -1); - CU_ASSERT(Headers::value_type("a", "b") == nva[0]); + assert_true(Headers::value_type("a", "b") == nva[0]); nva.clear(); http2::add_header(nva, (const uint8_t *)"a", 1, (const uint8_t *)" b ", 5, false, -1); - CU_ASSERT(Headers::value_type("a", "b") == nva[0]); + assert_true(Headers::value_type("a", "b") == nva[0]); nva.clear(); http2::add_header(nva, (const uint8_t *)"a", 1, (const uint8_t *)" bravo ", 9, false, -1); - CU_ASSERT(Headers::value_type("a", "bravo") == nva[0]); + assert_true(Headers::value_type("a", "bravo") == nva[0]); nva.clear(); http2::add_header(nva, (const uint8_t *)"a", 1, (const uint8_t *)" ", 4, false, -1); - CU_ASSERT(Headers::value_type("a", "") == nva[0]); + assert_true(Headers::value_type("a", "") == nva[0]); nva.clear(); http2::add_header(nva, (const uint8_t *)"te", 2, (const uint8_t *)"trailers", 8, false, http2::HD_TE); - CU_ASSERT(http2::HD_TE == nva[0].token); + assert_int32(http2::HD_TE, ==, nva[0].token); } void test_http2_get_header(void) { @@ -112,21 +139,21 @@ void test_http2_get_header(void) { {"content-length", "7"}}; const Headers::value_type *rv; rv = http2::get_header(nva, "delta"); - CU_ASSERT(rv != nullptr); - CU_ASSERT("delta" == rv->name); + assert_not_null(rv); + assert_stdstring_equal("delta", rv->name); rv = http2::get_header(nva, "bravo"); - CU_ASSERT(rv != nullptr); - CU_ASSERT("bravo" == rv->name); + assert_not_null(rv); + assert_stdstring_equal("bravo", rv->name); rv = http2::get_header(nva, "foxtrot"); - CU_ASSERT(rv == nullptr); + assert_null(rv); http2::HeaderIndex hdidx; http2::init_hdidx(hdidx); hdidx[http2::HD_CONTENT_LENGTH] = 6; rv = http2::get_header(hdidx, http2::HD_CONTENT_LENGTH, nva); - CU_ASSERT("content-length" == rv->name); + assert_stdstring_equal("content-length", rv->name); } namespace { @@ -177,29 +204,31 @@ void test_http2_copy_headers_to_nva(void) { http2::copy_headers_to_nva_nocopy(nva, headers, http2::HDOP_STRIP_X_FORWARDED_FOR); - CU_ASSERT(7 == nva.size()); + assert_size(7, ==, nva.size()); for (size_t i = 0; i < ans.size(); ++i) { check_nv(headers[ans[i]], &nva[i]); if (ans[i] == 0) { - CU_ASSERT((NGHTTP2_NV_FLAG_NO_COPY_NAME | NGHTTP2_NV_FLAG_NO_COPY_VALUE | - NGHTTP2_NV_FLAG_NO_INDEX) == nva[i].flags); + assert_uint8((NGHTTP2_NV_FLAG_NO_COPY_NAME | + NGHTTP2_NV_FLAG_NO_COPY_VALUE | NGHTTP2_NV_FLAG_NO_INDEX), + ==, nva[i].flags); } else { - CU_ASSERT((NGHTTP2_NV_FLAG_NO_COPY_NAME | - NGHTTP2_NV_FLAG_NO_COPY_VALUE) == nva[i].flags); + assert_uint8( + (NGHTTP2_NV_FLAG_NO_COPY_NAME | NGHTTP2_NV_FLAG_NO_COPY_VALUE), ==, + nva[i].flags); } } nva.clear(); http2::copy_headers_to_nva(nva, headers, http2::HDOP_STRIP_X_FORWARDED_FOR); - CU_ASSERT(7 == nva.size()); + assert_size(7, ==, nva.size()); for (size_t i = 0; i < ans.size(); ++i) { check_nv(headers[ans[i]], &nva[i]); if (ans[i] == 0) { - CU_ASSERT(nva[i].flags & NGHTTP2_NV_FLAG_NO_INDEX); + assert_true(nva[i].flags & NGHTTP2_NV_FLAG_NO_INDEX); } else { - CU_ASSERT(NGHTTP2_NV_FLAG_NONE == nva[i].flags); + assert_false(nva[i].flags); } } @@ -207,7 +236,7 @@ void test_http2_copy_headers_to_nva(void) { auto ans2 = std::vector{0, 2, 4, 6}; http2::copy_headers_to_nva(nva, headers2, http2::HDOP_NONE); - CU_ASSERT(ans2.size() == nva.size()); + assert_size(ans2.size(), ==, nva.size()); for (size_t i = 0; i < ans2.size(); ++i) { check_nv(headers2[ans2[i]], &nva[i]); } @@ -215,7 +244,7 @@ void test_http2_copy_headers_to_nva(void) { nva.clear(); http2::copy_headers_to_nva(nva, headers2, http2::HDOP_STRIP_ALL); - CU_ASSERT(nva.empty()); + assert_true(nva.empty()); } void test_http2_build_http1_headers_from_headers(void) { @@ -224,36 +253,38 @@ void test_http2_build_http1_headers_from_headers(void) { http2::build_http1_headers_from_headers(&buf, headers, http2::HDOP_STRIP_X_FORWARDED_FOR); auto hdrs = std::string(buf.head->pos, buf.head->last); - CU_ASSERT("Alpha: 0\r\n" - "Bravo: 1\r\n" - "Delta: 4\r\n" - "Expect: 5\r\n" - "Foxtrot: 6\r\n" - "Tango: 7\r\n" - "Te: 8\r\n" - "Te: 9\r\n" - "Zulu: 12\r\n" == hdrs); + assert_stdstring_equal("Alpha: 0\r\n" + "Bravo: 1\r\n" + "Delta: 4\r\n" + "Expect: 5\r\n" + "Foxtrot: 6\r\n" + "Tango: 7\r\n" + "Te: 8\r\n" + "Te: 9\r\n" + "Zulu: 12\r\n", + hdrs); buf.reset(); http2::build_http1_headers_from_headers(&buf, headers2, http2::HDOP_NONE); hdrs = std::string(buf.head->pos, buf.head->last); - CU_ASSERT("X-Forwarded-For: xff1\r\n" - "X-Forwarded-Proto: xfp1\r\n" - "Forwarded: fwd1\r\n" - "Via: via1\r\n" == hdrs); + assert_stdstring_equal("X-Forwarded-For: xff1\r\n" + "X-Forwarded-Proto: xfp1\r\n" + "Forwarded: fwd1\r\n" + "Via: via1\r\n", + hdrs); buf.reset(); http2::build_http1_headers_from_headers(&buf, headers2, http2::HDOP_STRIP_ALL); - CU_ASSERT(0 == buf.rleft()); + assert_size(0, ==, buf.rleft()); } void test_http2_lws(void) { - CU_ASSERT(!http2::lws("alpha")); - CU_ASSERT(http2::lws(" ")); - CU_ASSERT(http2::lws("")); + assert_false(http2::lws("alpha")); + assert_true(http2::lws(" ")); + assert_true(http2::lws("")); } namespace { @@ -263,11 +294,11 @@ void check_rewrite_location_uri(const std::string &want, const std::string &uri, const std::string &upstream_scheme) { BlockAllocator balloc(4096, 4096); http_parser_url u{}; - CU_ASSERT(0 == http_parser_parse_url(uri.c_str(), uri.size(), 0, &u)); + assert_int(0, ==, http_parser_parse_url(uri.c_str(), uri.size(), 0, &u)); auto got = http2::rewrite_location_uri( balloc, StringRef{uri}, u, StringRef{match_host}, StringRef{req_authority}, StringRef{upstream_scheme}); - CU_ASSERT(want == got); + assert_stdstring_equal(want, got.str()); } } // namespace @@ -299,13 +330,15 @@ void test_http2_rewrite_location_uri(void) { } void test_http2_parse_http_status_code(void) { - CU_ASSERT(200 == http2::parse_http_status_code(StringRef::from_lit("200"))); - CU_ASSERT(102 == http2::parse_http_status_code(StringRef::from_lit("102"))); - CU_ASSERT(-1 == http2::parse_http_status_code(StringRef::from_lit("099"))); - CU_ASSERT(-1 == http2::parse_http_status_code(StringRef::from_lit("99"))); - CU_ASSERT(-1 == http2::parse_http_status_code(StringRef::from_lit("-1"))); - CU_ASSERT(-1 == http2::parse_http_status_code(StringRef::from_lit("20a"))); - CU_ASSERT(-1 == http2::parse_http_status_code(StringRef{})); + assert_int(200, ==, + http2::parse_http_status_code(StringRef::from_lit("200"))); + assert_int(102, ==, + http2::parse_http_status_code(StringRef::from_lit("102"))); + assert_int(-1, ==, http2::parse_http_status_code(StringRef::from_lit("099"))); + assert_int(-1, ==, http2::parse_http_status_code(StringRef::from_lit("99"))); + assert_int(-1, ==, http2::parse_http_status_code(StringRef::from_lit("-1"))); + assert_int(-1, ==, http2::parse_http_status_code(StringRef::from_lit("20a"))); + assert_int(-1, ==, http2::parse_http_status_code(StringRef{})); } void test_http2_index_header(void) { @@ -315,402 +348,402 @@ void test_http2_index_header(void) { http2::index_header(hdidx, http2::HD__AUTHORITY, 0); http2::index_header(hdidx, -1, 1); - CU_ASSERT(0 == hdidx[http2::HD__AUTHORITY]); + assert_uint16(0, ==, hdidx[http2::HD__AUTHORITY]); } void test_http2_lookup_token(void) { - CU_ASSERT(http2::HD__AUTHORITY == - http2::lookup_token(StringRef::from_lit(":authority"))); - CU_ASSERT(-1 == http2::lookup_token(StringRef::from_lit(":authorit"))); - CU_ASSERT(-1 == http2::lookup_token(StringRef::from_lit(":Authority"))); - CU_ASSERT(http2::HD_EXPECT == - http2::lookup_token(StringRef::from_lit("expect"))); + assert_int(http2::HD__AUTHORITY, ==, + http2::lookup_token(StringRef::from_lit(":authority"))); + assert_int(-1, ==, http2::lookup_token(StringRef::from_lit(":authorit"))); + assert_int(-1, ==, http2::lookup_token(StringRef::from_lit(":Authority"))); + assert_int(http2::HD_EXPECT, ==, + http2::lookup_token(StringRef::from_lit("expect"))); } void test_http2_parse_link_header(void) { { // only URI appears; we don't extract URI unless it bears rel=preload auto res = http2::parse_link_header(StringRef::from_lit("")); - CU_ASSERT(0 == res.size()); + assert_size(0, ==, res.size()); } { // URI url should be extracted auto res = http2::parse_link_header(StringRef::from_lit("; rel=preload")); - CU_ASSERT(1 == res.size()); - CU_ASSERT("url" == res[0].uri); + assert_size(1, ==, res.size()); + assert_stdstring_equal("url", res[0].uri.str()); } { // With extra link-param. URI url should be extracted auto res = http2::parse_link_header( StringRef::from_lit("; rel=preload; as=file")); - CU_ASSERT(1 == res.size()); - CU_ASSERT("url" == res[0].uri); + assert_size(1, ==, res.size()); + assert_stdstring_equal("url", res[0].uri.str()); } { // With extra link-param. URI url should be extracted auto res = http2::parse_link_header( StringRef::from_lit("; as=file; rel=preload")); - CU_ASSERT(1 == res.size()); - CU_ASSERT("url" == res[0].uri); + assert_size(1, ==, res.size()); + assert_stdstring_equal("url", res[0].uri.str()); } { // With extra link-param and quote-string. URI url should be // extracted auto res = http2::parse_link_header( StringRef::from_lit(R"(; rel=preload; title="foo,bar")")); - CU_ASSERT(1 == res.size()); - CU_ASSERT("url" == res[0].uri); + assert_size(1, ==, res.size()); + assert_stdstring_equal("url", res[0].uri.str()); } { // With extra link-param and quote-string. URI url should be // extracted auto res = http2::parse_link_header( StringRef::from_lit(R"(; title="foo,bar"; rel=preload)")); - CU_ASSERT(1 == res.size()); - CU_ASSERT("url" == res[0].uri); + assert_size(1, ==, res.size()); + assert_stdstring_equal("url", res[0].uri.str()); } { // ',' after quote-string auto res = http2::parse_link_header( StringRef::from_lit(R"(; title="foo,bar", ; rel=preload)")); - CU_ASSERT(1 == res.size()); - CU_ASSERT("url2" == res[0].uri); + assert_size(1, ==, res.size()); + assert_stdstring_equal("url2", res[0].uri.str()); } { // Only first URI should be extracted. auto res = http2::parse_link_header( StringRef::from_lit("; rel=preload, ")); - CU_ASSERT(1 == res.size()); - CU_ASSERT("url" == res[0].uri); + assert_size(1, ==, res.size()); + assert_stdstring_equal("url", res[0].uri.str()); } { // Both have rel=preload, so both urls should be extracted auto res = http2::parse_link_header( StringRef::from_lit("; rel=preload, ; rel=preload")); - CU_ASSERT(2 == res.size()); - CU_ASSERT("url" == res[0].uri); - CU_ASSERT("url2" == res[1].uri); + assert_size(2, ==, res.size()); + assert_stdstring_equal("url", res[0].uri.str()); + assert_stdstring_equal("url2", res[1].uri.str()); } { // Second URI uri should be extracted. auto res = http2::parse_link_header( StringRef::from_lit(", ;rel=preload")); - CU_ASSERT(1 == res.size()); - CU_ASSERT("url2" == res[0].uri); + assert_size(1, ==, res.size()); + assert_stdstring_equal("url2", res[0].uri.str()); } { // Error if input ends with ';' auto res = http2::parse_link_header(StringRef::from_lit(";rel=preload;")); - CU_ASSERT(0 == res.size()); + assert_size(0, ==, res.size()); } { // Error if link header ends with ';' auto res = http2::parse_link_header( StringRef::from_lit(";rel=preload;, ")); - CU_ASSERT(0 == res.size()); + assert_size(0, ==, res.size()); } { // OK if input ends with ',' auto res = http2::parse_link_header(StringRef::from_lit(";rel=preload,")); - CU_ASSERT(1 == res.size()); - CU_ASSERT("url" == res[0].uri); + assert_size(1, ==, res.size()); + assert_stdstring_equal("url", res[0].uri.str()); } { // Multiple repeated ','s between fields is OK auto res = http2::parse_link_header( StringRef::from_lit(",,,;rel=preload")); - CU_ASSERT(1 == res.size()); - CU_ASSERT("url2" == res[0].uri); + assert_size(1, ==, res.size()); + assert_stdstring_equal("url2", res[0].uri.str()); } { // Error if url is not enclosed by <> auto res = http2::parse_link_header(StringRef::from_lit("url>;rel=preload")); - CU_ASSERT(0 == res.size()); + assert_size(0, ==, res.size()); } { // Error if url is not enclosed by <> auto res = http2::parse_link_header(StringRef::from_lit(";rel=preload; as=")); - CU_ASSERT(0 == res.size()); + assert_size(0, ==, res.size()); } { // Empty parameter value is not allowed auto res = http2::parse_link_header(StringRef::from_lit(";as=;rel=preload")); - CU_ASSERT(0 == res.size()); + assert_size(0, ==, res.size()); } { // Empty parameter value is not allowed auto res = http2::parse_link_header( StringRef::from_lit(";as=, ;rel=preload")); - CU_ASSERT(0 == res.size()); + assert_size(0, ==, res.size()); } { // Empty parameter name is not allowed auto res = http2::parse_link_header( StringRef::from_lit("; =file; rel=preload")); - CU_ASSERT(0 == res.size()); + assert_size(0, ==, res.size()); } { // Without whitespaces auto res = http2::parse_link_header( StringRef::from_lit(";as=file;rel=preload,;rel=preload")); - CU_ASSERT(2 == res.size()); - CU_ASSERT("url" == res[0].uri); - CU_ASSERT("url2" == res[1].uri); + assert_size(2, ==, res.size()); + assert_stdstring_equal("url", res[0].uri.str()); + assert_stdstring_equal("url2", res[1].uri.str()); } { // link-extension may have no value auto res = http2::parse_link_header(StringRef::from_lit("; as; rel=preload")); - CU_ASSERT(1 == res.size()); - CU_ASSERT("url" == res[0].uri); + assert_size(1, ==, res.size()); + assert_stdstring_equal("url", res[0].uri.str()); } { // ext-name-star auto res = http2::parse_link_header( StringRef::from_lit("; foo*=bar; rel=preload")); - CU_ASSERT(1 == res.size()); - CU_ASSERT("url" == res[0].uri); + assert_size(1, ==, res.size()); + assert_stdstring_equal("url", res[0].uri.str()); } { // '*' is not allowed expect for trailing one auto res = http2::parse_link_header( StringRef::from_lit("; *=bar; rel=preload")); - CU_ASSERT(0 == res.size()); + assert_size(0, ==, res.size()); } { // '*' is not allowed expect for trailing one auto res = http2::parse_link_header( StringRef::from_lit("; foo*bar=buzz; rel=preload")); - CU_ASSERT(0 == res.size()); + assert_size(0, ==, res.size()); } { // ext-name-star must be followed by '=' auto res = http2::parse_link_header( StringRef::from_lit("; foo*; rel=preload")); - CU_ASSERT(0 == res.size()); + assert_size(0, ==, res.size()); } { // '>' is not followed by ';' auto res = http2::parse_link_header(StringRef::from_lit(" rel=preload")); - CU_ASSERT(0 == res.size()); + assert_size(0, ==, res.size()); } { // Starting with whitespace is no problem. auto res = http2::parse_link_header(StringRef::from_lit(" ; rel=preload")); - CU_ASSERT(1 == res.size()); - CU_ASSERT("url" == res[0].uri); + assert_size(1, ==, res.size()); + assert_stdstring_equal("url", res[0].uri.str()); } { // preload is a prefix of bogus rel parameter value auto res = http2::parse_link_header(StringRef::from_lit("; rel=preloadx")); - CU_ASSERT(0 == res.size()); + assert_size(0, ==, res.size()); } { // preload in relation-types list auto res = http2::parse_link_header( StringRef::from_lit(R"(; rel="preload")")); - CU_ASSERT(1 == res.size()); - CU_ASSERT("url" == res[0].uri); + assert_size(1, ==, res.size()); + assert_stdstring_equal("url", res[0].uri.str()); } { // preload in relation-types list followed by another parameter auto res = http2::parse_link_header( StringRef::from_lit(R"(; rel="preload foo")")); - CU_ASSERT(1 == res.size()); - CU_ASSERT("url" == res[0].uri); + assert_size(1, ==, res.size()); + assert_stdstring_equal("url", res[0].uri.str()); } { // preload in relation-types list following another parameter auto res = http2::parse_link_header( StringRef::from_lit(R"(; rel="foo preload")")); - CU_ASSERT(1 == res.size()); - CU_ASSERT("url" == res[0].uri); + assert_size(1, ==, res.size()); + assert_stdstring_equal("url", res[0].uri.str()); } { // preload in relation-types list between other parameters auto res = http2::parse_link_header( StringRef::from_lit(R"(; rel="foo preload bar")")); - CU_ASSERT(1 == res.size()); - CU_ASSERT("url" == res[0].uri); + assert_size(1, ==, res.size()); + assert_stdstring_equal("url", res[0].uri.str()); } { // preload in relation-types list between other parameters auto res = http2::parse_link_header( StringRef::from_lit(R"(; rel="foo preload bar")")); - CU_ASSERT(1 == res.size()); - CU_ASSERT("url" == res[0].uri); + assert_size(1, ==, res.size()); + assert_stdstring_equal("url", res[0].uri.str()); } { // no preload in relation-types list auto res = http2::parse_link_header(StringRef::from_lit(R"(; rel="foo")")); - CU_ASSERT(0 == res.size()); + assert_size(0, ==, res.size()); } { // no preload in relation-types list, multiple unrelated elements. auto res = http2::parse_link_header( StringRef::from_lit(R"(; rel="foo bar")")); - CU_ASSERT(0 == res.size()); + assert_size(0, ==, res.size()); } { // preload in relation-types list, followed by another link-value. auto res = http2::parse_link_header( StringRef::from_lit(R"(; rel="preload", )")); - CU_ASSERT(1 == res.size()); - CU_ASSERT("url" == res[0].uri); + assert_size(1, ==, res.size()); + assert_stdstring_equal("url", res[0].uri.str()); } { // preload in relation-types list, following another link-value. auto res = http2::parse_link_header( StringRef::from_lit(R"(, ; rel="preload")")); - CU_ASSERT(1 == res.size()); - CU_ASSERT("url2" == res[0].uri); + assert_size(1, ==, res.size()); + assert_stdstring_equal("url2", res[0].uri.str()); } { // preload in relation-types list, followed by another link-param. auto res = http2::parse_link_header( StringRef::from_lit(R"(; rel="preload"; as="font")")); - CU_ASSERT(1 == res.size()); - CU_ASSERT("url" == res[0].uri); + assert_size(1, ==, res.size()); + assert_stdstring_equal("url", res[0].uri.str()); } { // preload in relation-types list, followed by character other // than ';' or ',' auto res = http2::parse_link_header( StringRef::from_lit(R"(; rel="preload".)")); - CU_ASSERT(0 == res.size()); + assert_size(0, ==, res.size()); } { // preload in relation-types list, followed by ';' but it // terminates input auto res = http2::parse_link_header( StringRef::from_lit(R"(; rel="preload";)")); - CU_ASSERT(0 == res.size()); + assert_size(0, ==, res.size()); } { // preload in relation-types list, followed by ',' but it // terminates input auto res = http2::parse_link_header( StringRef::from_lit(R"(; rel="preload",)")); - CU_ASSERT(1 == res.size()); - CU_ASSERT("url" == res[0].uri); + assert_size(1, ==, res.size()); + assert_stdstring_equal("url", res[0].uri.str()); } { // preload in relation-types list but there is preceding white // space. auto res = http2::parse_link_header( StringRef::from_lit(R"(; rel=" preload")")); - CU_ASSERT(0 == res.size()); + assert_size(0, ==, res.size()); } { // preload in relation-types list but there is trailing white // space. auto res = http2::parse_link_header( StringRef::from_lit(R"(; rel="preload ")")); - CU_ASSERT(0 == res.size()); + assert_size(0, ==, res.size()); } { // backslash escaped characters in quoted-string auto res = http2::parse_link_header( StringRef::from_lit(R"(; rel=preload; title="foo\"baz\"bar")")); - CU_ASSERT(1 == res.size()); - CU_ASSERT("url" == res[0].uri); + assert_size(1, ==, res.size()); + assert_stdstring_equal("url", res[0].uri.str()); } { // anchor="" is acceptable auto res = http2::parse_link_header( StringRef::from_lit(R"(; rel=preload; anchor="")")); - CU_ASSERT(1 == res.size()); - CU_ASSERT("url" == res[0].uri); + assert_size(1, ==, res.size()); + assert_stdstring_equal("url", res[0].uri.str()); } { // With anchor="#foo", url should be ignored auto res = http2::parse_link_header( StringRef::from_lit(R"(; rel=preload; anchor="#foo")")); - CU_ASSERT(0 == res.size()); + assert_size(0, ==, res.size()); } { // With anchor=f, url should be ignored auto res = http2::parse_link_header( StringRef::from_lit("; rel=preload; anchor=f")); - CU_ASSERT(0 == res.size()); + assert_size(0, ==, res.size()); } { // First url is ignored With anchor="#foo", but url should be // accepted. auto res = http2::parse_link_header(StringRef::from_lit( R"(; rel=preload; anchor="#foo", ; rel=preload)")); - CU_ASSERT(1 == res.size()); - CU_ASSERT("url2" == res[0].uri); + assert_size(1, ==, res.size()); + assert_stdstring_equal("url2", res[0].uri.str()); } { // With loadpolicy="next", url should be ignored auto res = http2::parse_link_header( StringRef::from_lit(R"(; rel=preload; loadpolicy="next")")); - CU_ASSERT(0 == res.size()); + assert_size(0, ==, res.size()); } { // url should be picked up if empty loadpolicy is specified auto res = http2::parse_link_header( StringRef::from_lit(R"(; rel=preload; loadpolicy="")")); - CU_ASSERT(1 == res.size()); - CU_ASSERT("url" == res[0].uri); + assert_size(1, ==, res.size()); + assert_stdstring_equal("url", res[0].uri.str()); } { // case-insensitive match auto res = http2::parse_link_header( StringRef::from_lit(R"(; rel=preload; ANCHOR="#foo", ; )" R"(REL=PRELOAD, ; REL="foo PRELOAD bar")")); - CU_ASSERT(2 == res.size()); - CU_ASSERT("url2" == res[0].uri); - CU_ASSERT("url3" == res[1].uri); + assert_size(2, ==, res.size()); + assert_stdstring_equal("url2", res[0].uri.str()); + assert_stdstring_equal("url3", res[1].uri.str()); } { // nopush at the end of input auto res = http2::parse_link_header( StringRef::from_lit("; rel=preload; nopush")); - CU_ASSERT(0 == res.size()); + assert_size(0, ==, res.size()); } { // nopush followed by ';' auto res = http2::parse_link_header( StringRef::from_lit("; rel=preload; nopush; foo")); - CU_ASSERT(0 == res.size()); + assert_size(0, ==, res.size()); } { // nopush followed by ',' auto res = http2::parse_link_header( StringRef::from_lit("; nopush; rel=preload")); - CU_ASSERT(0 == res.size()); + assert_size(0, ==, res.size()); } { // string whose prefix is nopush auto res = http2::parse_link_header( StringRef::from_lit("; nopushyes; rel=preload")); - CU_ASSERT(1 == res.size()); - CU_ASSERT("url" == res[0].uri); + assert_size(1, ==, res.size()); + assert_stdstring_equal("url", res[0].uri.str()); } { // rel=preload twice auto res = http2::parse_link_header( StringRef::from_lit("; rel=preload; rel=preload")); - CU_ASSERT(1 == res.size()); - CU_ASSERT("url" == res[0].uri); + assert_size(1, ==, res.size()); + assert_stdstring_equal("url", res[0].uri.str()); } } @@ -718,124 +751,132 @@ void test_http2_path_join(void) { { auto base = StringRef::from_lit("/"); auto rel = StringRef::from_lit("/"); - CU_ASSERT("/" == http2::path_join(base, StringRef{}, rel, StringRef{})); + assert_stdstring_equal( + "/", http2::path_join(base, StringRef{}, rel, StringRef{})); } { auto base = StringRef::from_lit("/"); auto rel = StringRef::from_lit("/alpha"); - CU_ASSERT("/alpha" == - http2::path_join(base, StringRef{}, rel, StringRef{})); + assert_stdstring_equal( + "/alpha", http2::path_join(base, StringRef{}, rel, StringRef{})); } { // rel ends with trailing '/' auto base = StringRef::from_lit("/"); auto rel = StringRef::from_lit("/alpha/"); - CU_ASSERT("/alpha/" == - http2::path_join(base, StringRef{}, rel, StringRef{})); + assert_stdstring_equal( + "/alpha/", http2::path_join(base, StringRef{}, rel, StringRef{})); } { // rel contains multiple components auto base = StringRef::from_lit("/"); auto rel = StringRef::from_lit("/alpha/bravo"); - CU_ASSERT("/alpha/bravo" == - http2::path_join(base, StringRef{}, rel, StringRef{})); + assert_stdstring_equal( + "/alpha/bravo", http2::path_join(base, StringRef{}, rel, StringRef{})); } { // rel is relative auto base = StringRef::from_lit("/"); auto rel = StringRef::from_lit("alpha/bravo"); - CU_ASSERT("/alpha/bravo" == - http2::path_join(base, StringRef{}, rel, StringRef{})); + assert_stdstring_equal( + "/alpha/bravo", http2::path_join(base, StringRef{}, rel, StringRef{})); } { // rel is relative and base ends without /, which means it refers // to file. auto base = StringRef::from_lit("/alpha"); auto rel = StringRef::from_lit("bravo/charlie"); - CU_ASSERT("/bravo/charlie" == - http2::path_join(base, StringRef{}, rel, StringRef{})); + assert_stdstring_equal( + "/bravo/charlie", + http2::path_join(base, StringRef{}, rel, StringRef{})); } { // rel contains repeated '/'s auto base = StringRef::from_lit("/"); auto rel = StringRef::from_lit("/alpha/////bravo/////"); - CU_ASSERT("/alpha/bravo/" == - http2::path_join(base, StringRef{}, rel, StringRef{})); + assert_stdstring_equal( + "/alpha/bravo/", http2::path_join(base, StringRef{}, rel, StringRef{})); } { // base ends with '/', so '..' eats 'bravo' auto base = StringRef::from_lit("/alpha/bravo/"); auto rel = StringRef::from_lit("../charlie/delta"); - CU_ASSERT("/alpha/charlie/delta" == - http2::path_join(base, StringRef{}, rel, StringRef{})); + assert_stdstring_equal( + "/alpha/charlie/delta", + http2::path_join(base, StringRef{}, rel, StringRef{})); } { // base does not end with '/', so '..' eats 'alpha/bravo' auto base = StringRef::from_lit("/alpha/bravo"); auto rel = StringRef::from_lit("../charlie"); - CU_ASSERT("/charlie" == - http2::path_join(base, StringRef{}, rel, StringRef{})); + assert_stdstring_equal( + "/charlie", http2::path_join(base, StringRef{}, rel, StringRef{})); } { // 'charlie' is eaten by following '..' auto base = StringRef::from_lit("/alpha/bravo/"); auto rel = StringRef::from_lit("../charlie/../delta"); - CU_ASSERT("/alpha/delta" == - http2::path_join(base, StringRef{}, rel, StringRef{})); + assert_stdstring_equal( + "/alpha/delta", http2::path_join(base, StringRef{}, rel, StringRef{})); } { // excessive '..' results in '/' auto base = StringRef::from_lit("/alpha/bravo/"); auto rel = StringRef::from_lit("../../../"); - CU_ASSERT("/" == http2::path_join(base, StringRef{}, rel, StringRef{})); + assert_stdstring_equal( + "/", http2::path_join(base, StringRef{}, rel, StringRef{})); } { // excessive '..' and path component auto base = StringRef::from_lit("/alpha/bravo/"); auto rel = StringRef::from_lit("../../../charlie"); - CU_ASSERT("/charlie" == - http2::path_join(base, StringRef{}, rel, StringRef{})); + assert_stdstring_equal( + "/charlie", http2::path_join(base, StringRef{}, rel, StringRef{})); } { // rel ends with '..' auto base = StringRef::from_lit("/alpha/bravo/"); auto rel = StringRef::from_lit("charlie/.."); - CU_ASSERT("/alpha/bravo/" == - http2::path_join(base, StringRef{}, rel, StringRef{})); + assert_stdstring_equal( + "/alpha/bravo/", http2::path_join(base, StringRef{}, rel, StringRef{})); } { // base empty and rel contains '..' auto base = StringRef{}; auto rel = StringRef::from_lit("charlie/.."); - CU_ASSERT("/" == http2::path_join(base, StringRef{}, rel, StringRef{})); + assert_stdstring_equal( + "/", http2::path_join(base, StringRef{}, rel, StringRef{})); } { // '.' is ignored auto base = StringRef::from_lit("/"); auto rel = StringRef::from_lit("charlie/././././delta"); - CU_ASSERT("/charlie/delta" == - http2::path_join(base, StringRef{}, rel, StringRef{})); + assert_stdstring_equal( + "/charlie/delta", + http2::path_join(base, StringRef{}, rel, StringRef{})); } { // trailing '.' is ignored auto base = StringRef::from_lit("/"); auto rel = StringRef::from_lit("charlie/."); - CU_ASSERT("/charlie/" == - http2::path_join(base, StringRef{}, rel, StringRef{})); + assert_stdstring_equal( + "/charlie/", http2::path_join(base, StringRef{}, rel, StringRef{})); } { // query auto base = StringRef::from_lit("/"); auto rel = StringRef::from_lit("/"); auto relq = StringRef::from_lit("q"); - CU_ASSERT("/?q" == http2::path_join(base, StringRef{}, rel, relq)); + assert_stdstring_equal("/?q", + http2::path_join(base, StringRef{}, rel, relq)); } { // empty rel and query auto base = StringRef::from_lit("/alpha"); auto rel = StringRef{}; auto relq = StringRef::from_lit("q"); - CU_ASSERT("/alpha?q" == http2::path_join(base, StringRef{}, rel, relq)); + assert_stdstring_equal("/alpha?q", + http2::path_join(base, StringRef{}, rel, relq)); } { // both rel and query are empty @@ -843,26 +884,28 @@ void test_http2_path_join(void) { auto baseq = StringRef::from_lit("r"); auto rel = StringRef{}; auto relq = StringRef{}; - CU_ASSERT("/alpha?r" == http2::path_join(base, baseq, rel, relq)); + assert_stdstring_equal("/alpha?r", + http2::path_join(base, baseq, rel, relq)); } { // empty base auto base = StringRef{}; auto rel = StringRef::from_lit("/alpha"); - CU_ASSERT("/alpha" == - http2::path_join(base, StringRef{}, rel, StringRef{})); + assert_stdstring_equal( + "/alpha", http2::path_join(base, StringRef{}, rel, StringRef{})); } { // everything is empty - CU_ASSERT("/" == http2::path_join(StringRef{}, StringRef{}, StringRef{}, - StringRef{})); + assert_stdstring_equal("/", http2::path_join(StringRef{}, StringRef{}, + StringRef{}, StringRef{})); } { // only baseq is not empty auto base = StringRef{}; auto baseq = StringRef::from_lit("r"); auto rel = StringRef{}; - CU_ASSERT("/?r" == http2::path_join(base, baseq, rel, StringRef{})); + assert_stdstring_equal("/?r", + http2::path_join(base, baseq, rel, StringRef{})); } { // path starts with multiple '/'s. @@ -870,8 +913,8 @@ void test_http2_path_join(void) { auto baseq = StringRef{}; auto rel = StringRef::from_lit("//alpha//bravo"); auto relq = StringRef::from_lit("charlie"); - CU_ASSERT("/alpha/bravo?charlie" == - http2::path_join(base, baseq, rel, relq)); + assert_stdstring_equal("/alpha/bravo?charlie", + http2::path_join(base, baseq, rel, relq)); } // Test cases from RFC 3986, section 5.4. constexpr auto base = StringRef::from_lit("/b/c/d;p"); @@ -879,239 +922,266 @@ void test_http2_path_join(void) { { auto rel = StringRef::from_lit("g"); auto relq = StringRef{}; - CU_ASSERT("/b/c/g" == http2::path_join(base, baseq, rel, relq)); + assert_stdstring_equal("/b/c/g", http2::path_join(base, baseq, rel, relq)); } { auto rel = StringRef::from_lit("./g"); auto relq = StringRef{}; - CU_ASSERT("/b/c/g" == http2::path_join(base, baseq, rel, relq)); + assert_stdstring_equal("/b/c/g", http2::path_join(base, baseq, rel, relq)); } { auto rel = StringRef::from_lit("g/"); auto relq = StringRef{}; - CU_ASSERT("/b/c/g/" == http2::path_join(base, baseq, rel, relq)); + assert_stdstring_equal("/b/c/g/", http2::path_join(base, baseq, rel, relq)); } { auto rel = StringRef::from_lit("/g"); auto relq = StringRef{}; - CU_ASSERT("/g" == http2::path_join(base, baseq, rel, relq)); + assert_stdstring_equal("/g", http2::path_join(base, baseq, rel, relq)); } { auto rel = StringRef{}; auto relq = StringRef::from_lit("y"); - CU_ASSERT("/b/c/d;p?y" == http2::path_join(base, baseq, rel, relq)); + assert_stdstring_equal("/b/c/d;p?y", + http2::path_join(base, baseq, rel, relq)); } { auto rel = StringRef::from_lit("g"); auto relq = StringRef::from_lit("y"); - CU_ASSERT("/b/c/g?y" == http2::path_join(base, baseq, rel, relq)); + assert_stdstring_equal("/b/c/g?y", + http2::path_join(base, baseq, rel, relq)); } { auto rel = StringRef::from_lit(";x"); auto relq = StringRef{}; - CU_ASSERT("/b/c/;x" == http2::path_join(base, baseq, rel, relq)); + assert_stdstring_equal("/b/c/;x", http2::path_join(base, baseq, rel, relq)); } { auto rel = StringRef::from_lit("g;x"); auto relq = StringRef{}; - CU_ASSERT("/b/c/g;x" == http2::path_join(base, baseq, rel, relq)); + assert_stdstring_equal("/b/c/g;x", + http2::path_join(base, baseq, rel, relq)); } { auto rel = StringRef::from_lit("g;x"); auto relq = StringRef::from_lit("y"); - CU_ASSERT("/b/c/g;x?y" == http2::path_join(base, baseq, rel, relq)); + assert_stdstring_equal("/b/c/g;x?y", + http2::path_join(base, baseq, rel, relq)); } { auto rel = StringRef{}; auto relq = StringRef{}; - CU_ASSERT("/b/c/d;p?q" == http2::path_join(base, baseq, rel, relq)); + assert_stdstring_equal("/b/c/d;p?q", + http2::path_join(base, baseq, rel, relq)); } { auto rel = StringRef::from_lit("."); auto relq = StringRef{}; - CU_ASSERT("/b/c/" == http2::path_join(base, baseq, rel, relq)); + assert_stdstring_equal("/b/c/", http2::path_join(base, baseq, rel, relq)); } { auto rel = StringRef::from_lit("./"); auto relq = StringRef{}; - CU_ASSERT("/b/c/" == http2::path_join(base, baseq, rel, relq)); + assert_stdstring_equal("/b/c/", http2::path_join(base, baseq, rel, relq)); } { auto rel = StringRef::from_lit(".."); auto relq = StringRef{}; - CU_ASSERT("/b/" == http2::path_join(base, baseq, rel, relq)); + assert_stdstring_equal("/b/", http2::path_join(base, baseq, rel, relq)); } { auto rel = StringRef::from_lit("../"); auto relq = StringRef{}; - CU_ASSERT("/b/" == http2::path_join(base, baseq, rel, relq)); + assert_stdstring_equal("/b/", http2::path_join(base, baseq, rel, relq)); } { auto rel = StringRef::from_lit("../g"); auto relq = StringRef{}; - CU_ASSERT("/b/g" == http2::path_join(base, baseq, rel, relq)); + assert_stdstring_equal("/b/g", http2::path_join(base, baseq, rel, relq)); } { auto rel = StringRef::from_lit("../.."); auto relq = StringRef{}; - CU_ASSERT("/" == http2::path_join(base, baseq, rel, relq)); + assert_stdstring_equal("/", http2::path_join(base, baseq, rel, relq)); } { auto rel = StringRef::from_lit("../../"); auto relq = StringRef{}; - CU_ASSERT("/" == http2::path_join(base, baseq, rel, relq)); + assert_stdstring_equal("/", http2::path_join(base, baseq, rel, relq)); } { auto rel = StringRef::from_lit("../../g"); auto relq = StringRef{}; - CU_ASSERT("/g" == http2::path_join(base, baseq, rel, relq)); + assert_stdstring_equal("/g", http2::path_join(base, baseq, rel, relq)); } { auto rel = StringRef::from_lit("../../../g"); auto relq = StringRef{}; - CU_ASSERT("/g" == http2::path_join(base, baseq, rel, relq)); + assert_stdstring_equal("/g", http2::path_join(base, baseq, rel, relq)); } { auto rel = StringRef::from_lit("../../../../g"); auto relq = StringRef{}; - CU_ASSERT("/g" == http2::path_join(base, baseq, rel, relq)); + assert_stdstring_equal("/g", http2::path_join(base, baseq, rel, relq)); } { auto rel = StringRef::from_lit("/./g"); auto relq = StringRef{}; - CU_ASSERT("/g" == http2::path_join(base, baseq, rel, relq)); + assert_stdstring_equal("/g", http2::path_join(base, baseq, rel, relq)); } { auto rel = StringRef::from_lit("/../g"); auto relq = StringRef{}; - CU_ASSERT("/g" == http2::path_join(base, baseq, rel, relq)); + assert_stdstring_equal("/g", http2::path_join(base, baseq, rel, relq)); } { auto rel = StringRef::from_lit("g."); auto relq = StringRef{}; - CU_ASSERT("/b/c/g." == http2::path_join(base, baseq, rel, relq)); + assert_stdstring_equal("/b/c/g.", http2::path_join(base, baseq, rel, relq)); } { auto rel = StringRef::from_lit(".g"); auto relq = StringRef{}; - CU_ASSERT("/b/c/.g" == http2::path_join(base, baseq, rel, relq)); + assert_stdstring_equal("/b/c/.g", http2::path_join(base, baseq, rel, relq)); } { auto rel = StringRef::from_lit("g.."); auto relq = StringRef{}; - CU_ASSERT("/b/c/g.." == http2::path_join(base, baseq, rel, relq)); + assert_stdstring_equal("/b/c/g..", + http2::path_join(base, baseq, rel, relq)); } { auto rel = StringRef::from_lit("..g"); auto relq = StringRef{}; - CU_ASSERT("/b/c/..g" == http2::path_join(base, baseq, rel, relq)); + assert_stdstring_equal("/b/c/..g", + http2::path_join(base, baseq, rel, relq)); } { auto rel = StringRef::from_lit("./../g"); auto relq = StringRef{}; - CU_ASSERT("/b/g" == http2::path_join(base, baseq, rel, relq)); + assert_stdstring_equal("/b/g", http2::path_join(base, baseq, rel, relq)); } { auto rel = StringRef::from_lit("./g/."); auto relq = StringRef{}; - CU_ASSERT("/b/c/g/" == http2::path_join(base, baseq, rel, relq)); + assert_stdstring_equal("/b/c/g/", http2::path_join(base, baseq, rel, relq)); } { auto rel = StringRef::from_lit("g/./h"); auto relq = StringRef{}; - CU_ASSERT("/b/c/g/h" == http2::path_join(base, baseq, rel, relq)); + assert_stdstring_equal("/b/c/g/h", + http2::path_join(base, baseq, rel, relq)); } { auto rel = StringRef::from_lit("g/../h"); auto relq = StringRef{}; - CU_ASSERT("/b/c/h" == http2::path_join(base, baseq, rel, relq)); + assert_stdstring_equal("/b/c/h", http2::path_join(base, baseq, rel, relq)); } { auto rel = StringRef::from_lit("g;x=1/./y"); auto relq = StringRef{}; - CU_ASSERT("/b/c/g;x=1/y" == http2::path_join(base, baseq, rel, relq)); + assert_stdstring_equal("/b/c/g;x=1/y", + http2::path_join(base, baseq, rel, relq)); } { auto rel = StringRef::from_lit("g;x=1/../y"); auto relq = StringRef{}; - CU_ASSERT("/b/c/y" == http2::path_join(base, baseq, rel, relq)); + assert_stdstring_equal("/b/c/y", http2::path_join(base, baseq, rel, relq)); } } void test_http2_normalize_path(void) { - CU_ASSERT("/alpha/charlie" == - http2::normalize_path( - StringRef::from_lit("/alpha/bravo/../charlie"), StringRef{})); + assert_stdstring_equal( + "/alpha/charlie", + http2::normalize_path(StringRef::from_lit("/alpha/bravo/../charlie"), + StringRef{})); - CU_ASSERT("/alpha" == - http2::normalize_path(StringRef::from_lit("/a%6c%70%68%61"), - StringRef{})); + assert_stdstring_equal( + "/alpha", http2::normalize_path(StringRef::from_lit("/a%6c%70%68%61"), + StringRef{})); - CU_ASSERT( - "/alpha%2F%3A" == + assert_stdstring_equal( + "/alpha%2F%3A", http2::normalize_path(StringRef::from_lit("/alpha%2f%3a"), StringRef{})); - CU_ASSERT("/%2F" == - http2::normalize_path(StringRef::from_lit("%2f"), StringRef{})); + assert_stdstring_equal( + "/%2F", http2::normalize_path(StringRef::from_lit("%2f"), StringRef{})); - CU_ASSERT("/%f" == - http2::normalize_path(StringRef::from_lit("%f"), StringRef{})); + assert_stdstring_equal( + "/%f", http2::normalize_path(StringRef::from_lit("%f"), StringRef{})); - CU_ASSERT("/%" == - http2::normalize_path(StringRef::from_lit("%"), StringRef{})); + assert_stdstring_equal( + "/%", http2::normalize_path(StringRef::from_lit("%"), StringRef{})); - CU_ASSERT("/" == http2::normalize_path(StringRef{}, StringRef{})); + assert_stdstring_equal("/", http2::normalize_path(StringRef{}, StringRef{})); - CU_ASSERT("/alpha?bravo" == - http2::normalize_path(StringRef::from_lit("/alpha"), - StringRef::from_lit("bravo"))); + assert_stdstring_equal("/alpha?bravo", + http2::normalize_path(StringRef::from_lit("/alpha"), + StringRef::from_lit("bravo"))); } void test_http2_rewrite_clean_path(void) { BlockAllocator balloc(4096, 4096); // unreserved characters - CU_ASSERT("/alpha/bravo/" == - http2::rewrite_clean_path(balloc, - StringRef::from_lit("/alpha/%62ravo/"))); + assert_stdstring_equal( + "/alpha/bravo/", + http2::rewrite_clean_path(balloc, StringRef::from_lit("/alpha/%62ravo/")) + .str()); // percent-encoding is converted to upper case. - CU_ASSERT("/delta%3A" == http2::rewrite_clean_path( - balloc, StringRef::from_lit("/delta%3a"))); + assert_stdstring_equal( + "/delta%3A", + http2::rewrite_clean_path(balloc, StringRef::from_lit("/delta%3a")) + .str()); // path component is normalized before matching - CU_ASSERT( - "/alpha/bravo/" == + assert_stdstring_equal( + "/alpha/bravo/", http2::rewrite_clean_path( - balloc, StringRef::from_lit("/alpha/charlie/%2e././bravo/delta/.."))); + balloc, StringRef::from_lit("/alpha/charlie/%2e././bravo/delta/..")) + .str()); - CU_ASSERT("alpha%3a" == - http2::rewrite_clean_path(balloc, StringRef::from_lit("alpha%3a"))); + assert_stdstring_equal( + "alpha%3a", + http2::rewrite_clean_path(balloc, StringRef::from_lit("alpha%3a")).str()); - CU_ASSERT("" == http2::rewrite_clean_path(balloc, StringRef{})); + assert_stdstring_equal("", + http2::rewrite_clean_path(balloc, StringRef{}).str()); - CU_ASSERT( - "/alpha?bravo" == - http2::rewrite_clean_path(balloc, StringRef::from_lit("//alpha?bravo"))); + assert_stdstring_equal( + "/alpha?bravo", + http2::rewrite_clean_path(balloc, StringRef::from_lit("//alpha?bravo")) + .str()); } void test_http2_get_pure_path_component(void) { - CU_ASSERT("/" == http2::get_pure_path_component(StringRef::from_lit("/"))); - - CU_ASSERT("/foo" == - http2::get_pure_path_component(StringRef::from_lit("/foo"))); - - CU_ASSERT("/bar" == http2::get_pure_path_component( - StringRef::from_lit("https://example.org/bar"))); - - CU_ASSERT("/alpha" == http2::get_pure_path_component(StringRef::from_lit( - "https://example.org/alpha?q=a"))); - - CU_ASSERT("/bravo" == http2::get_pure_path_component(StringRef::from_lit( - "https://example.org/bravo?q=a#fragment"))); - - CU_ASSERT("" == - http2::get_pure_path_component(StringRef::from_lit("\x01\x02"))); + assert_stdstring_equal( + "/", http2::get_pure_path_component(StringRef::from_lit("/")).str()); + + assert_stdstring_equal( + "/foo", + http2::get_pure_path_component(StringRef::from_lit("/foo")).str()); + + assert_stdstring_equal("/bar", + http2::get_pure_path_component( + StringRef::from_lit("https://example.org/bar")) + .str()); + + assert_stdstring_equal( + "/alpha", http2::get_pure_path_component( + StringRef::from_lit("https://example.org/alpha?q=a")) + .str()); + + assert_stdstring_equal( + "/bravo", + http2::get_pure_path_component( + StringRef::from_lit("https://example.org/bravo?q=a#fragment")) + .str()); + + assert_stdstring_equal( + "", + http2::get_pure_path_component(StringRef::from_lit("\x01\x02")).str()); } void test_http2_construct_push_component(void) { @@ -1122,11 +1192,12 @@ void test_http2_construct_push_component(void) { base = StringRef::from_lit("/b/"); uri = StringRef::from_lit("https://example.org/foo"); - CU_ASSERT(0 == http2::construct_push_component(balloc, scheme, authority, - path, base, uri)); - CU_ASSERT("https" == scheme); - CU_ASSERT("example.org" == authority); - CU_ASSERT("/foo" == path); + assert_int(0, ==, + http2::construct_push_component(balloc, scheme, authority, path, + base, uri)); + assert_stdstring_equal("https", scheme.str()); + assert_stdstring_equal("example.org", authority.str()); + assert_stdstring_equal("/foo", path.str()); scheme = StringRef{}; authority = StringRef{}; @@ -1134,11 +1205,12 @@ void test_http2_construct_push_component(void) { uri = StringRef::from_lit("/foo/bar?q=a"); - CU_ASSERT(0 == http2::construct_push_component(balloc, scheme, authority, - path, base, uri)); - CU_ASSERT("" == scheme); - CU_ASSERT("" == authority); - CU_ASSERT("/foo/bar?q=a" == path); + assert_int(0, ==, + http2::construct_push_component(balloc, scheme, authority, path, + base, uri)); + assert_stdstring_equal("", scheme.str()); + assert_stdstring_equal("", authority.str()); + assert_stdstring_equal("/foo/bar?q=a", path.str()); scheme = StringRef{}; authority = StringRef{}; @@ -1146,11 +1218,12 @@ void test_http2_construct_push_component(void) { uri = StringRef::from_lit("foo/../bar?q=a"); - CU_ASSERT(0 == http2::construct_push_component(balloc, scheme, authority, - path, base, uri)); - CU_ASSERT("" == scheme); - CU_ASSERT("" == authority); - CU_ASSERT("/b/bar?q=a" == path); + assert_int(0, ==, + http2::construct_push_component(balloc, scheme, authority, path, + base, uri)); + assert_stdstring_equal("", scheme.str()); + assert_stdstring_equal("", authority.str()); + assert_stdstring_equal("/b/bar?q=a", path.str()); scheme = StringRef{}; authority = StringRef{}; @@ -1158,91 +1231,97 @@ void test_http2_construct_push_component(void) { uri = StringRef{}; - CU_ASSERT(-1 == http2::construct_push_component(balloc, scheme, authority, - path, base, uri)); + assert_int(-1, ==, + http2::construct_push_component(balloc, scheme, authority, path, + base, uri)); scheme = StringRef{}; authority = StringRef{}; path = StringRef{}; uri = StringRef::from_lit("?q=a"); - CU_ASSERT(0 == http2::construct_push_component(balloc, scheme, authority, - path, base, uri)); - CU_ASSERT("" == scheme); - CU_ASSERT("" == authority); - CU_ASSERT("/b/?q=a" == path); + assert_int(0, ==, + http2::construct_push_component(balloc, scheme, authority, path, + base, uri)); + assert_stdstring_equal("", scheme.str()); + assert_stdstring_equal("", authority.str()); + assert_stdstring_equal("/b/?q=a", path.str()); } void test_http2_contains_trailers(void) { - CU_ASSERT(!http2::contains_trailers(StringRef::from_lit(""))); - CU_ASSERT(http2::contains_trailers(StringRef::from_lit("trailers"))); + assert_false(http2::contains_trailers(StringRef::from_lit(""))); + assert_true(http2::contains_trailers(StringRef::from_lit("trailers"))); // Match must be case-insensitive. - CU_ASSERT(http2::contains_trailers(StringRef::from_lit("TRAILERS"))); - CU_ASSERT(!http2::contains_trailers(StringRef::from_lit("trailer"))); - CU_ASSERT(!http2::contains_trailers(StringRef::from_lit("trailers 3"))); - CU_ASSERT(http2::contains_trailers(StringRef::from_lit("trailers,"))); - CU_ASSERT(http2::contains_trailers(StringRef::from_lit("trailers,foo"))); - CU_ASSERT(http2::contains_trailers(StringRef::from_lit("foo,trailers"))); - CU_ASSERT(http2::contains_trailers(StringRef::from_lit("foo,trailers,bar"))); - CU_ASSERT( + assert_true(http2::contains_trailers(StringRef::from_lit("TRAILERS"))); + assert_false(http2::contains_trailers(StringRef::from_lit("trailer"))); + assert_false(http2::contains_trailers(StringRef::from_lit("trailers 3"))); + assert_true(http2::contains_trailers(StringRef::from_lit("trailers,"))); + assert_true(http2::contains_trailers(StringRef::from_lit("trailers,foo"))); + assert_true(http2::contains_trailers(StringRef::from_lit("foo,trailers"))); + assert_true( + http2::contains_trailers(StringRef::from_lit("foo,trailers,bar"))); + assert_true( http2::contains_trailers(StringRef::from_lit("foo, trailers ,bar"))); - CU_ASSERT(http2::contains_trailers(StringRef::from_lit(",trailers"))); + assert_true(http2::contains_trailers(StringRef::from_lit(",trailers"))); } void test_http2_check_transfer_encoding(void) { - CU_ASSERT(http2::check_transfer_encoding(StringRef::from_lit("chunked"))); - CU_ASSERT(http2::check_transfer_encoding(StringRef::from_lit("foo,chunked"))); - CU_ASSERT( + assert_true(http2::check_transfer_encoding(StringRef::from_lit("chunked"))); + assert_true( + http2::check_transfer_encoding(StringRef::from_lit("foo,chunked"))); + assert_true( http2::check_transfer_encoding(StringRef::from_lit("foo, chunked"))); - CU_ASSERT( + assert_true( http2::check_transfer_encoding(StringRef::from_lit("foo , chunked"))); - CU_ASSERT( + assert_true( http2::check_transfer_encoding(StringRef::from_lit("chunked;foo=bar"))); - CU_ASSERT( + assert_true( http2::check_transfer_encoding(StringRef::from_lit("chunked ; foo=bar"))); - CU_ASSERT(http2::check_transfer_encoding( + assert_true(http2::check_transfer_encoding( StringRef::from_lit(R"(chunked;foo="bar")"))); - CU_ASSERT(http2::check_transfer_encoding( + assert_true(http2::check_transfer_encoding( StringRef::from_lit(R"(chunked;foo="\bar\"";FOO=BAR)"))); - CU_ASSERT( + assert_true( http2::check_transfer_encoding(StringRef::from_lit(R"(chunked;foo="")"))); - CU_ASSERT(http2::check_transfer_encoding( + assert_true(http2::check_transfer_encoding( StringRef::from_lit(R"(chunked;foo="bar" , gzip)"))); - CU_ASSERT(!http2::check_transfer_encoding(StringRef{})); - CU_ASSERT(!http2::check_transfer_encoding(StringRef::from_lit(",chunked"))); - CU_ASSERT(!http2::check_transfer_encoding(StringRef::from_lit("chunked,"))); - CU_ASSERT(!http2::check_transfer_encoding(StringRef::from_lit("chunked, "))); - CU_ASSERT( - !http2::check_transfer_encoding(StringRef::from_lit("foo,,chunked"))); - CU_ASSERT( - !http2::check_transfer_encoding(StringRef::from_lit("chunked;foo"))); - CU_ASSERT(!http2::check_transfer_encoding(StringRef::from_lit("chunked;"))); - CU_ASSERT( - !http2::check_transfer_encoding(StringRef::from_lit("chunked;foo=bar;"))); - CU_ASSERT( - !http2::check_transfer_encoding(StringRef::from_lit("chunked;?=bar"))); - CU_ASSERT( - !http2::check_transfer_encoding(StringRef::from_lit("chunked;=bar"))); - CU_ASSERT(!http2::check_transfer_encoding(StringRef::from_lit("chunked;;"))); - CU_ASSERT(!http2::check_transfer_encoding(StringRef::from_lit("chunked?"))); - CU_ASSERT(!http2::check_transfer_encoding(StringRef::from_lit(","))); - CU_ASSERT(!http2::check_transfer_encoding(StringRef::from_lit(" "))); - CU_ASSERT(!http2::check_transfer_encoding(StringRef::from_lit(";"))); - CU_ASSERT(!http2::check_transfer_encoding(StringRef::from_lit("\""))); - CU_ASSERT(!http2::check_transfer_encoding( + assert_false(http2::check_transfer_encoding(StringRef{})); + assert_false(http2::check_transfer_encoding(StringRef::from_lit(",chunked"))); + assert_false(http2::check_transfer_encoding(StringRef::from_lit("chunked,"))); + assert_false( + http2::check_transfer_encoding(StringRef::from_lit("chunked, "))); + assert_false( + http2::check_transfer_encoding(StringRef::from_lit("foo,,chunked"))); + assert_false( + http2::check_transfer_encoding(StringRef::from_lit("chunked;foo"))); + assert_false(http2::check_transfer_encoding(StringRef::from_lit("chunked;"))); + assert_false( + http2::check_transfer_encoding(StringRef::from_lit("chunked;foo=bar;"))); + assert_false( + http2::check_transfer_encoding(StringRef::from_lit("chunked;?=bar"))); + assert_false( + http2::check_transfer_encoding(StringRef::from_lit("chunked;=bar"))); + assert_false( + http2::check_transfer_encoding(StringRef::from_lit("chunked;;"))); + assert_false(http2::check_transfer_encoding(StringRef::from_lit("chunked?"))); + assert_false(http2::check_transfer_encoding(StringRef::from_lit(","))); + assert_false(http2::check_transfer_encoding(StringRef::from_lit(" "))); + assert_false(http2::check_transfer_encoding(StringRef::from_lit(";"))); + assert_false(http2::check_transfer_encoding(StringRef::from_lit("\""))); + assert_false(http2::check_transfer_encoding( StringRef::from_lit(R"(chunked;foo="bar)"))); - CU_ASSERT(!http2::check_transfer_encoding( + assert_false(http2::check_transfer_encoding( StringRef::from_lit(R"(chunked;foo="bar\)"))); - CU_ASSERT( - !http2::check_transfer_encoding(StringRef::from_lit(R"(chunked;foo="bar\)" - "\x0a" - R"(")"))); - CU_ASSERT( - !http2::check_transfer_encoding(StringRef::from_lit(R"(chunked;foo=")" - "\x0a" - R"(")"))); - CU_ASSERT(!http2::check_transfer_encoding( + assert_false( + http2::check_transfer_encoding(StringRef::from_lit(R"(chunked;foo="bar\)" + "\x0a" + R"(")"))); + assert_false( + http2::check_transfer_encoding(StringRef::from_lit(R"(chunked;foo=")" + "\x0a" + R"(")"))); + assert_false(http2::check_transfer_encoding( StringRef::from_lit(R"(chunked;foo="bar",,gzip)"))); } diff --git a/src/http2_test.h b/src/http2_test.h index 382470d..75fd707 100644 --- a/src/http2_test.h +++ b/src/http2_test.h @@ -29,25 +29,31 @@ # include #endif // HAVE_CONFIG_H +#define MUNIT_ENABLE_ASSERT_ALIASES + +#include "munit.h" + namespace shrpx { -void test_http2_add_header(void); -void test_http2_get_header(void); -void test_http2_copy_headers_to_nva(void); -void test_http2_build_http1_headers_from_headers(void); -void test_http2_lws(void); -void test_http2_rewrite_location_uri(void); -void test_http2_parse_http_status_code(void); -void test_http2_index_header(void); -void test_http2_lookup_token(void); -void test_http2_parse_link_header(void); -void test_http2_path_join(void); -void test_http2_normalize_path(void); -void test_http2_rewrite_clean_path(void); -void test_http2_get_pure_path_component(void); -void test_http2_construct_push_component(void); -void test_http2_contains_trailers(void); -void test_http2_check_transfer_encoding(void); +extern const MunitSuite http2_suite; + +munit_void_test_decl(test_http2_add_header); +munit_void_test_decl(test_http2_get_header); +munit_void_test_decl(test_http2_copy_headers_to_nva); +munit_void_test_decl(test_http2_build_http1_headers_from_headers); +munit_void_test_decl(test_http2_lws); +munit_void_test_decl(test_http2_rewrite_location_uri); +munit_void_test_decl(test_http2_parse_http_status_code); +munit_void_test_decl(test_http2_index_header); +munit_void_test_decl(test_http2_lookup_token); +munit_void_test_decl(test_http2_parse_link_header); +munit_void_test_decl(test_http2_path_join); +munit_void_test_decl(test_http2_normalize_path); +munit_void_test_decl(test_http2_rewrite_clean_path); +munit_void_test_decl(test_http2_get_pure_path_component); +munit_void_test_decl(test_http2_construct_push_component); +munit_void_test_decl(test_http2_contains_trailers); +munit_void_test_decl(test_http2_check_transfer_encoding); } // namespace shrpx diff --git a/src/inflatehd.cc b/src/inflatehd.cc index f484042..537b4fa 100644 --- a/src/inflatehd.cc +++ b/src/inflatehd.cc @@ -41,6 +41,7 @@ #include +#define NGHTTP2_NO_SSIZE_T #include #include "template.h" @@ -93,7 +94,6 @@ static void to_json(nghttp2_hd_inflater *inflater, json_t *headers, } static int inflate_hd(json_t *obj, nghttp2_hd_inflater *inflater, int seq) { - ssize_t rv; nghttp2_nv nv; int inflate_flags; size_t old_settings_table_size = @@ -120,8 +120,8 @@ static int inflate_hd(json_t *obj, nghttp2_hd_inflater *inflater, int seq) { seq); return -1; } - rv = nghttp2_hd_inflate_change_table_size(inflater, - json_integer_value(table_size)); + auto rv = nghttp2_hd_inflate_change_table_size( + inflater, json_integer_value(table_size)); if (rv != 0) { fprintf(stderr, "nghttp2_hd_change_table_size() failed with error %s at %d\n", @@ -147,7 +147,8 @@ static int inflate_hd(json_t *obj, nghttp2_hd_inflater *inflater, int seq) { auto p = buf.data(); for (;;) { inflate_flags = 0; - rv = nghttp2_hd_inflate_hd(inflater, &nv, &inflate_flags, p, buflen, 1); + auto rv = + nghttp2_hd_inflate_hd3(inflater, &nv, &inflate_flags, p, buflen, 1); if (rv < 0) { fprintf(stderr, "inflate failed with error code %zd at %d\n", rv, seq); exit(EXIT_FAILURE); diff --git a/src/libevent_util.cc b/src/libevent_util.cc deleted file mode 100644 index 3b60b6d..0000000 --- a/src/libevent_util.cc +++ /dev/null @@ -1,162 +0,0 @@ -/* - * nghttp2 - HTTP/2 C Library - * - * Copyright (c) 2014 Tatsuhiro Tsujikawa - * - * 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 "libevent_util.h" - -#include -#include - -namespace nghttp2 { - -namespace util { - -EvbufferBuffer::EvbufferBuffer() - : evbuffer_(nullptr), - bucket_(nullptr), - buf_(nullptr), - bufmax_(0), - buflen_(0), - limit_(0), - writelen_(0) {} - -EvbufferBuffer::EvbufferBuffer(evbuffer *evbuffer, uint8_t *buf, size_t bufmax, - ssize_t limit) - : evbuffer_(evbuffer), - bucket_(limit == -1 ? nullptr : evbuffer_new()), - buf_(buf), - bufmax_(bufmax), - buflen_(0), - limit_(limit), - writelen_(0) {} - -void EvbufferBuffer::reset(evbuffer *evbuffer, uint8_t *buf, size_t bufmax, - ssize_t limit) { - evbuffer_ = evbuffer; - buf_ = buf; - if (limit != -1 && !bucket_) { - bucket_ = evbuffer_new(); - } - bufmax_ = bufmax; - buflen_ = 0; - limit_ = limit; - writelen_ = 0; -} - -EvbufferBuffer::~EvbufferBuffer() { - if (bucket_) { - evbuffer_free(bucket_); - } -} - -int EvbufferBuffer::write_buffer() { - for (auto pos = buf_, end = buf_ + buflen_; pos < end;) { - // To avoid merging chunks in evbuffer, we first add to temporal - // buffer bucket_ and then move its chain to evbuffer_. - auto nwrite = std::min(end - pos, limit_); - auto rv = evbuffer_add(bucket_, pos, nwrite); - if (rv == -1) { - return -1; - } - rv = evbuffer_add_buffer(evbuffer_, bucket_); - if (rv == -1) { - return -1; - } - pos += nwrite; - } - return 0; -} - -int EvbufferBuffer::flush() { - int rv; - if (buflen_ > 0) { - if (limit_ == -1) { - rv = evbuffer_add(evbuffer_, buf_, buflen_); - } else { - rv = write_buffer(); - } - if (rv == -1) { - return -1; - } - writelen_ += buflen_; - buflen_ = 0; - } - return 0; -} - -int EvbufferBuffer::add(const uint8_t *data, size_t datalen) { - int rv; - if (buflen_ + datalen > bufmax_) { - if (buflen_ > 0) { - if (limit_ == -1) { - rv = evbuffer_add(evbuffer_, buf_, buflen_); - } else { - rv = write_buffer(); - } - if (rv == -1) { - return -1; - } - writelen_ += buflen_; - buflen_ = 0; - } - if (datalen > bufmax_) { - if (limit_ == -1) { - rv = evbuffer_add(evbuffer_, data, datalen); - } else { - rv = write_buffer(); - } - if (rv == -1) { - return -1; - } - writelen_ += buflen_; - return 0; - } - } - memcpy(buf_ + buflen_, data, datalen); - buflen_ += datalen; - return 0; -} - -size_t EvbufferBuffer::get_buflen() const { return buflen_; } - -size_t EvbufferBuffer::get_writelen() const { return writelen_; } - -void bev_enable_unless(bufferevent *bev, int events) { - if ((bufferevent_get_enabled(bev) & events) == events) { - return; - } - - bufferevent_enable(bev, events); -} - -void bev_disable_unless(bufferevent *bev, int events) { - if ((bufferevent_get_enabled(bev) & events) == 0) { - return; - } - - bufferevent_disable(bev, events); -} - -} // namespace util - -} // namespace nghttp2 diff --git a/src/libevent_util.h b/src/libevent_util.h deleted file mode 100644 index 1d1ee91..0000000 --- a/src/libevent_util.h +++ /dev/null @@ -1,75 +0,0 @@ -/* - * nghttp2 - HTTP/2 C Library - * - * Copyright (c) 2014 Tatsuhiro Tsujikawa - * - * 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. - */ -#ifndef LIBEVENT_UTIL_H -#define LIBEVENT_UTIL_H - -#include "nghttp2_config.h" - -#include -#include - -namespace nghttp2 { - -namespace util { - -class EvbufferBuffer { -public: - EvbufferBuffer(); - // If |limit| is not -1, at most min(limit, bufmax) size bytes are - // added to evbuffer_. - EvbufferBuffer(evbuffer *evbuffer, uint8_t *buf, size_t bufmax, - ssize_t limit = -1); - ~EvbufferBuffer(); - void reset(evbuffer *evbuffer, uint8_t *buf, size_t bufmax, - ssize_t limit = -1); - int flush(); - int add(const uint8_t *data, size_t datalen); - size_t get_buflen() const; - int write_buffer(); - // Returns the number of written bytes to evbuffer_ so far. reset() - // resets this value to 0. - size_t get_writelen() const; - -private: - evbuffer *evbuffer_; - evbuffer *bucket_; - uint8_t *buf_; - size_t bufmax_; - size_t buflen_; - ssize_t limit_; - size_t writelen_; -}; - -// These functions are provided to reduce epoll_ctl syscall. Avoid -// calling bufferevent_enable/disable() unless it is required by -// sniffing current enabled events. -void bev_enable_unless(bufferevent *bev, int events); -void bev_disable_unless(bufferevent *bev, int events); - -} // namespace util - -} // namespace nghttp2 - -#endif // LIBEVENT_UTIL_H diff --git a/src/memchunk_test.cc b/src/memchunk_test.cc index 236d9ea..1c57c02 100644 --- a/src/memchunk_test.cc +++ b/src/memchunk_test.cc @@ -24,7 +24,7 @@ */ #include "memchunk_test.h" -#include +#include "munitxx.h" #include @@ -33,52 +33,72 @@ namespace nghttp2 { +namespace { +const MunitTest tests[]{ + munit_void_test(test_pool_recycle), + munit_void_test(test_memchunks_append), + munit_void_test(test_memchunks_drain), + munit_void_test(test_memchunks_riovec), + munit_void_test(test_memchunks_recycle), + munit_void_test(test_memchunks_reset), + munit_void_test(test_peek_memchunks_append), + munit_void_test(test_peek_memchunks_disable_peek_drain), + munit_void_test(test_peek_memchunks_disable_peek_no_drain), + munit_void_test(test_peek_memchunks_reset), + munit_test_end(), +}; +} // namespace + +const MunitSuite memchunk_suite{ + "/memchunk", tests, NULL, 1, MUNIT_SUITE_OPTION_NONE, +}; + void test_pool_recycle(void) { MemchunkPool pool; - CU_ASSERT(!pool.pool); - CU_ASSERT(0 == pool.poolsize); - CU_ASSERT(nullptr == pool.freelist); + assert_null(pool.pool); + assert_size(0, ==, pool.poolsize); + assert_null(pool.freelist); auto m1 = pool.get(); - CU_ASSERT(m1 == pool.pool); - CU_ASSERT(MemchunkPool::value_type::size == pool.poolsize); - CU_ASSERT(nullptr == pool.freelist); + assert_ptr_equal(m1, pool.pool); + assert_size(MemchunkPool::value_type::size, ==, pool.poolsize); + assert_null(pool.freelist); auto m2 = pool.get(); - CU_ASSERT(m2 == pool.pool); - CU_ASSERT(2 * MemchunkPool::value_type::size == pool.poolsize); - CU_ASSERT(nullptr == pool.freelist); - CU_ASSERT(m1 == m2->knext); - CU_ASSERT(nullptr == m1->knext); + assert_ptr_equal(m2, pool.pool); + assert_size(2 * MemchunkPool::value_type::size, ==, pool.poolsize); + assert_null(pool.freelist); + assert_ptr_equal(m1, m2->knext); + assert_null(m1->knext); auto m3 = pool.get(); - CU_ASSERT(m3 == pool.pool); - CU_ASSERT(3 * MemchunkPool::value_type::size == pool.poolsize); - CU_ASSERT(nullptr == pool.freelist); + assert_ptr_equal(m3, pool.pool); + assert_size(3 * MemchunkPool::value_type::size, ==, pool.poolsize); + assert_null(pool.freelist); pool.recycle(m3); - CU_ASSERT(m3 == pool.pool); - CU_ASSERT(3 * MemchunkPool::value_type::size == pool.poolsize); - CU_ASSERT(m3 == pool.freelist); + assert_ptr_equal(m3, pool.pool); + assert_size(3 * MemchunkPool::value_type::size, ==, pool.poolsize); + assert_ptr_equal(m3, pool.freelist); auto m4 = pool.get(); - CU_ASSERT(m3 == m4); - CU_ASSERT(m4 == pool.pool); - CU_ASSERT(3 * MemchunkPool::value_type::size == pool.poolsize); - CU_ASSERT(nullptr == pool.freelist); + assert_ptr_equal(m3, m4); + assert_ptr_equal(m4, pool.pool); + assert_size(3 * MemchunkPool::value_type::size, ==, pool.poolsize); + assert_null(pool.freelist); pool.recycle(m2); pool.recycle(m1); - CU_ASSERT(m1 == pool.freelist); - CU_ASSERT(m2 == m1->next); - CU_ASSERT(nullptr == m2->next); + assert_ptr_equal(m1, pool.freelist); + assert_ptr_equal(m2, m1->next); + assert_null(m2->next); } using Memchunk16 = Memchunk<16>; @@ -94,37 +114,37 @@ void test_memchunks_append(void) { auto m = chunks.tail; - CU_ASSERT(3 == m->len()); - CU_ASSERT(13 == m->left()); + assert_size(3, ==, m->len()); + assert_size(13, ==, m->left()); chunks.append("3456789abcdef@"); - CU_ASSERT(16 == m->len()); - CU_ASSERT(0 == m->left()); + assert_size(16, ==, m->len()); + assert_size(0, ==, m->left()); m = chunks.tail; - CU_ASSERT(1 == m->len()); - CU_ASSERT(15 == m->left()); - CU_ASSERT(17 == chunks.rleft()); + assert_size(1, ==, m->len()); + assert_size(15, ==, m->left()); + assert_size(17, ==, chunks.rleft()); char buf[16]; size_t nread; nread = chunks.remove(buf, 8); - CU_ASSERT(8 == nread); - CU_ASSERT(0 == memcmp("01234567", buf, nread)); - CU_ASSERT(9 == chunks.rleft()); + assert_size(8, ==, nread); + assert_memory_equal(nread, "01234567", buf); + assert_size(9, ==, chunks.rleft()); nread = chunks.remove(buf, sizeof(buf)); - CU_ASSERT(9 == nread); - CU_ASSERT(0 == memcmp("89abcdef@", buf, nread)); - CU_ASSERT(0 == chunks.rleft()); - CU_ASSERT(nullptr == chunks.head); - CU_ASSERT(nullptr == chunks.tail); - CU_ASSERT(32 == pool.poolsize); + assert_size(9, ==, nread); + assert_memory_equal(nread, "89abcdef@", buf); + assert_size(0, ==, chunks.rleft()); + assert_null(chunks.head); + assert_null(chunks.tail); + assert_size(32, ==, pool.poolsize); } void test_memchunks_drain(void) { @@ -137,14 +157,14 @@ void test_memchunks_drain(void) { nread = chunks.drain(3); - CU_ASSERT(3 == nread); + assert_size(3, ==, nread); char buf[16]; nread = chunks.remove(buf, sizeof(buf)); - CU_ASSERT(7 == nread); - CU_ASSERT(0 == memcmp("3456789", buf, nread)); + assert_size(7, ==, nread); + assert_memory_equal(nread, "3456789", buf); } void test_memchunks_riovec(void) { @@ -160,24 +180,24 @@ void test_memchunks_riovec(void) { auto m = chunks.head; - CU_ASSERT(2 == iovcnt); - CU_ASSERT(m->buf.data() == iov[0].iov_base); - CU_ASSERT(m->len() == iov[0].iov_len); + assert_int(2, ==, iovcnt); + assert_ptr_equal(m->buf.data(), iov[0].iov_base); + assert_size(m->len(), ==, iov[0].iov_len); m = m->next; - CU_ASSERT(m->buf.data() == iov[1].iov_base); - CU_ASSERT(m->len() == iov[1].iov_len); + assert_ptr_equal(m->buf.data(), iov[1].iov_base); + assert_size(m->len(), ==, iov[1].iov_len); chunks.drain(2 * 16); iovcnt = chunks.riovec(iov.data(), iov.size()); - CU_ASSERT(1 == iovcnt); + assert_int(1, ==, iovcnt); m = chunks.head; - CU_ASSERT(m->buf.data() == iov[0].iov_base); - CU_ASSERT(m->len() == iov[0].iov_len); + assert_ptr_equal(m->buf.data(), iov[0].iov_base); + assert_size(m->len(), ==, iov[0].iov_len); } void test_memchunks_recycle(void) { @@ -187,14 +207,14 @@ void test_memchunks_recycle(void) { std::array buf{}; chunks.append(buf.data(), buf.size()); } - CU_ASSERT(32 == pool.poolsize); - CU_ASSERT(nullptr != pool.freelist); + assert_size(32, ==, pool.poolsize); + assert_not_null(pool.freelist); auto m = pool.freelist; m = m->next; - CU_ASSERT(nullptr != m); - CU_ASSERT(nullptr == m->next); + assert_not_null(m); + assert_null(m->next); } void test_memchunks_reset(void) { @@ -205,19 +225,19 @@ void test_memchunks_reset(void) { chunks.append(b.data(), b.size()); - CU_ASSERT(32 == chunks.rleft()); + assert_size(32, ==, chunks.rleft()); chunks.reset(); - CU_ASSERT(0 == chunks.rleft()); - CU_ASSERT(nullptr == chunks.head); - CU_ASSERT(nullptr == chunks.tail); + assert_size(0, ==, chunks.rleft()); + assert_null(chunks.head); + assert_null(chunks.tail); auto m = pool.freelist; - CU_ASSERT(nullptr != m); - CU_ASSERT(nullptr != m->next); - CU_ASSERT(nullptr == m->next->next); + assert_not_null(m); + assert_not_null(m->next); + assert_null(m->next->next); } void test_peek_memchunks_append(void) { @@ -232,27 +252,27 @@ void test_peek_memchunks_append(void) { pchunks.append(b.data(), b.size()); - CU_ASSERT(32 == pchunks.rleft()); - CU_ASSERT(32 == pchunks.rleft_buffered()); + assert_size(32, ==, pchunks.rleft()); + assert_size(32, ==, pchunks.rleft_buffered()); - CU_ASSERT(0 == pchunks.remove(nullptr, 0)); + assert_size(0, ==, pchunks.remove(nullptr, 0)); - CU_ASSERT(32 == pchunks.rleft()); - CU_ASSERT(32 == pchunks.rleft_buffered()); + assert_size(32, ==, pchunks.rleft()); + assert_size(32, ==, pchunks.rleft_buffered()); - CU_ASSERT(12 == pchunks.remove(d.data(), 12)); + assert_size(12, ==, pchunks.remove(d.data(), 12)); - CU_ASSERT(std::equal(std::begin(b), std::begin(b) + 12, std::begin(d))); + assert_true(std::equal(std::begin(b), std::begin(b) + 12, std::begin(d))); - CU_ASSERT(20 == pchunks.rleft()); - CU_ASSERT(32 == pchunks.rleft_buffered()); + assert_size(20, ==, pchunks.rleft()); + assert_size(32, ==, pchunks.rleft_buffered()); - CU_ASSERT(20 == pchunks.remove(d.data(), d.size())); + assert_size(20, ==, pchunks.remove(d.data(), d.size())); - CU_ASSERT(std::equal(std::begin(b) + 12, std::end(b), std::begin(d))); + assert_true(std::equal(std::begin(b) + 12, std::end(b), std::begin(d))); - CU_ASSERT(0 == pchunks.rleft()); - CU_ASSERT(32 == pchunks.rleft_buffered()); + assert_size(0, ==, pchunks.rleft()); + assert_size(32, ==, pchunks.rleft_buffered()); } void test_peek_memchunks_disable_peek_drain(void) { @@ -267,20 +287,20 @@ void test_peek_memchunks_disable_peek_drain(void) { pchunks.append(b.data(), b.size()); - CU_ASSERT(12 == pchunks.remove(d.data(), 12)); + assert_size(12, ==, pchunks.remove(d.data(), 12)); pchunks.disable_peek(true); - CU_ASSERT(!pchunks.peeking); - CU_ASSERT(20 == pchunks.rleft()); - CU_ASSERT(20 == pchunks.rleft_buffered()); + assert_false(pchunks.peeking); + assert_size(20, ==, pchunks.rleft()); + assert_size(20, ==, pchunks.rleft_buffered()); - CU_ASSERT(20 == pchunks.remove(d.data(), d.size())); + assert_size(20, ==, pchunks.remove(d.data(), d.size())); - CU_ASSERT(std::equal(std::begin(b) + 12, std::end(b), std::begin(d))); + assert_true(std::equal(std::begin(b) + 12, std::end(b), std::begin(d))); - CU_ASSERT(0 == pchunks.rleft()); - CU_ASSERT(0 == pchunks.rleft_buffered()); + assert_size(0, ==, pchunks.rleft()); + assert_size(0, ==, pchunks.rleft_buffered()); } void test_peek_memchunks_disable_peek_no_drain(void) { @@ -295,20 +315,20 @@ void test_peek_memchunks_disable_peek_no_drain(void) { pchunks.append(b.data(), b.size()); - CU_ASSERT(12 == pchunks.remove(d.data(), 12)); + assert_size(12, ==, pchunks.remove(d.data(), 12)); pchunks.disable_peek(false); - CU_ASSERT(!pchunks.peeking); - CU_ASSERT(32 == pchunks.rleft()); - CU_ASSERT(32 == pchunks.rleft_buffered()); + assert_false(pchunks.peeking); + assert_size(32, ==, pchunks.rleft()); + assert_size(32, ==, pchunks.rleft_buffered()); - CU_ASSERT(32 == pchunks.remove(d.data(), d.size())); + assert_size(32, ==, pchunks.remove(d.data(), d.size())); - CU_ASSERT(std::equal(std::begin(b), std::end(b), std::begin(d))); + assert_true(std::equal(std::begin(b), std::end(b), std::begin(d))); - CU_ASSERT(0 == pchunks.rleft()); - CU_ASSERT(0 == pchunks.rleft_buffered()); + assert_size(0, ==, pchunks.rleft()); + assert_size(0, ==, pchunks.rleft_buffered()); } void test_peek_memchunks_reset(void) { @@ -323,18 +343,18 @@ void test_peek_memchunks_reset(void) { pchunks.append(b.data(), b.size()); - CU_ASSERT(12 == pchunks.remove(d.data(), 12)); + assert_size(12, ==, pchunks.remove(d.data(), 12)); pchunks.disable_peek(true); pchunks.reset(); - CU_ASSERT(0 == pchunks.rleft()); - CU_ASSERT(0 == pchunks.rleft_buffered()); + assert_size(0, ==, pchunks.rleft()); + assert_size(0, ==, pchunks.rleft_buffered()); - CU_ASSERT(nullptr == pchunks.cur); - CU_ASSERT(nullptr == pchunks.cur_pos); - CU_ASSERT(nullptr == pchunks.cur_last); - CU_ASSERT(pchunks.peeking); + assert_null(pchunks.cur); + assert_null(pchunks.cur_pos); + assert_null(pchunks.cur_last); + assert_true(pchunks.peeking); } } // namespace nghttp2 diff --git a/src/memchunk_test.h b/src/memchunk_test.h index 7d677e7..a3fe028 100644 --- a/src/memchunk_test.h +++ b/src/memchunk_test.h @@ -29,18 +29,24 @@ # include #endif // HAVE_CONFIG_H +#define MUNIT_ENABLE_ASSERT_ALIASES + +#include "munit.h" + namespace nghttp2 { -void test_pool_recycle(void); -void test_memchunks_append(void); -void test_memchunks_drain(void); -void test_memchunks_riovec(void); -void test_memchunks_recycle(void); -void test_memchunks_reset(void); -void test_peek_memchunks_append(void); -void test_peek_memchunks_disable_peek_drain(void); -void test_peek_memchunks_disable_peek_no_drain(void); -void test_peek_memchunks_reset(void); +extern const MunitSuite memchunk_suite; + +munit_void_test_decl(test_pool_recycle); +munit_void_test_decl(test_memchunks_append); +munit_void_test_decl(test_memchunks_drain); +munit_void_test_decl(test_memchunks_riovec); +munit_void_test_decl(test_memchunks_recycle); +munit_void_test_decl(test_memchunks_reset); +munit_void_test_decl(test_peek_memchunks_append); +munit_void_test_decl(test_peek_memchunks_disable_peek_drain); +munit_void_test_decl(test_peek_memchunks_disable_peek_no_drain); +munit_void_test_decl(test_peek_memchunks_reset); } // namespace nghttp2 diff --git a/src/nghttp.cc b/src/nghttp.cc index 41a88c6..f670320 100644 --- a/src/nghttp.cc +++ b/src/nghttp.cc @@ -157,7 +157,7 @@ std::string strip_fragment(const char *raw_uri) { } // namespace Request::Request(const std::string &uri, const http_parser_url &u, - const nghttp2_data_provider *data_prd, int64_t data_length, + const nghttp2_data_provider2 *data_prd, int64_t data_length, const nghttp2_priority_spec &pri_spec, int level) : uri(uri), u(u), @@ -370,11 +370,11 @@ void continue_timeout_cb(struct ev_loop *loop, ev_timer *w, int revents) { auto req = static_cast(w->data); int error; - error = nghttp2_submit_data(client->session, NGHTTP2_FLAG_END_STREAM, - req->stream_id, req->data_prd); + error = nghttp2_submit_data2(client->session, NGHTTP2_FLAG_END_STREAM, + req->stream_id, req->data_prd); if (error) { - std::cerr << "[ERROR] nghttp2_submit_data() returned error: " + std::cerr << "[ERROR] nghttp2_submit_data2() returned error: " << nghttp2_strerror(error) << std::endl; nghttp2_submit_rst_stream(client->session, NGHTTP2_FLAG_NONE, req->stream_id, NGHTTP2_INTERNAL_ERROR); @@ -525,13 +525,13 @@ int submit_request(HttpClient *client, const Headers &headers, Request *req) { nva.data(), nva.size(), req); } else { stream_id = - nghttp2_submit_request(client->session, &req->pri_spec, nva.data(), - nva.size(), req->data_prd, req); + nghttp2_submit_request2(client->session, &req->pri_spec, nva.data(), + nva.size(), req->data_prd, req); } if (stream_id < 0) { std::cerr << "[ERROR] nghttp2_submit_" - << (expect_continue ? "headers" : "request") + << (expect_continue ? "headers" : "request2") << "() returned error: " << nghttp2_strerror(stream_id) << std::endl; return -1; @@ -953,14 +953,14 @@ size_t populate_settings(nghttp2_settings_entry *iv) { } // namespace int HttpClient::on_upgrade_connect() { - ssize_t rv; + nghttp2_ssize rv; record_connect_end_time(); assert(!reqvec.empty()); std::array iv; size_t niv = populate_settings(iv.data()); assert(settings_payload.size() >= 8 * niv); - rv = nghttp2_pack_settings_payload(settings_payload.data(), - settings_payload.size(), iv.data(), niv); + rv = nghttp2_pack_settings_payload2(settings_payload.data(), + settings_payload.size(), iv.data(), niv); if (rv < 0) { return -1; } @@ -1250,9 +1250,9 @@ int HttpClient::on_read(const uint8_t *data, size_t len) { util::hexdump(stdout, data, len); } - auto rv = nghttp2_session_mem_recv(session, data, len); + auto rv = nghttp2_session_mem_recv2(session, data, len); if (rv < 0) { - std::cerr << "[ERROR] nghttp2_session_mem_recv() returned error: " + std::cerr << "[ERROR] nghttp2_session_mem_recv2() returned error: " << nghttp2_strerror(rv) << std::endl; return -1; } @@ -1276,9 +1276,9 @@ int HttpClient::on_write() { } const uint8_t *data; - auto len = nghttp2_session_mem_send(session, &data); + auto len = nghttp2_session_mem_send2(session, &data); if (len < 0) { - std::cerr << "[ERROR] nghttp2_session_send() returned error: " + std::cerr << "[ERROR] nghttp2_session_send2() returned error: " << nghttp2_strerror(len) << std::endl; return -1; } @@ -1449,7 +1449,7 @@ void HttpClient::update_hostport() { } bool HttpClient::add_request(const std::string &uri, - const nghttp2_data_provider *data_prd, + const nghttp2_data_provider2 *data_prd, int64_t data_length, const nghttp2_priority_spec &pri_spec, int level) { http_parser_url u{}; @@ -1768,9 +1768,9 @@ int on_data_chunk_recv_callback(nghttp2_session *session, uint8_t flags, } // namespace namespace { -ssize_t select_padding_callback(nghttp2_session *session, - const nghttp2_frame *frame, size_t max_payload, - void *user_data) { +nghttp2_ssize select_padding_callback(nghttp2_session *session, + const nghttp2_frame *frame, + size_t max_payload, void *user_data) { return std::min(max_payload, frame->hd.length + config.padding); } } // namespace @@ -2241,7 +2241,7 @@ namespace { int communicate( const std::string &scheme, const std::string &host, uint16_t port, std::vector< - std::tuple> + std::tuple> requests, const nghttp2_session_callbacks *callbacks) { int result = 0; @@ -2311,6 +2311,17 @@ int communicate( auto proto_list = util::get_default_alpn(); SSL_CTX_set_alpn_protos(ssl_ctx, proto_list.data(), proto_list.size()); + +#if defined(NGHTTP2_OPENSSL_IS_BORINGSSL) && defined(HAVE_LIBBROTLI) + if (!SSL_CTX_add_cert_compression_alg( + ssl_ctx, nghttp2::tls::CERTIFICATE_COMPRESSION_ALGO_BROTLI, + nghttp2::tls::cert_compress, nghttp2::tls::cert_decompress)) { + std::cerr << "[ERROR] SSL_CTX_add_cert_compression_alg failed." + << std::endl; + result = -1; + goto fin; + } +#endif // NGHTTP2_OPENSSL_IS_BORINGSSL && HAVE_LIBBROTLI } { HttpClient client{callbacks, loop, ssl_ctx}; @@ -2391,9 +2402,10 @@ fin: } // namespace namespace { -ssize_t file_read_callback(nghttp2_session *session, int32_t stream_id, - uint8_t *buf, size_t length, uint32_t *data_flags, - nghttp2_data_source *source, void *user_data) { +nghttp2_ssize file_read_callback(nghttp2_session *session, int32_t stream_id, + uint8_t *buf, size_t length, + uint32_t *data_flags, + nghttp2_data_source *source, void *user_data) { int rv; auto req = static_cast( nghttp2_session_get_stream_user_data(session, stream_id)); @@ -2429,14 +2441,14 @@ ssize_t file_read_callback(nghttp2_session *session, int32_t stream_id, } } - return nread; + return static_cast(nread); } if (req->data_offset > req->data_length || nread == 0) { return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE; } - return nread; + return static_cast(nread); } } // namespace @@ -2480,7 +2492,7 @@ int run(char **uris, int n) { callbacks, on_frame_not_send_callback); if (config.padding) { - nghttp2_session_callbacks_set_select_padding_callback( + nghttp2_session_callbacks_set_select_padding_callback2( callbacks, select_padding_callback); } @@ -2489,7 +2501,7 @@ int run(char **uris, int n) { uint16_t prev_port = 0; int failures = 0; int data_fd = -1; - nghttp2_data_provider data_prd; + nghttp2_data_provider2 data_prd; struct stat data_stat; if (!config.datafile.empty()) { @@ -2557,7 +2569,7 @@ int run(char **uris, int n) { data_prd.read_callback = file_read_callback; } std::vector< - std::tuple> + std::tuple> requests; size_t next_weight_idx = 0; diff --git a/src/nghttp.h b/src/nghttp.h index a880414..5b339e8 100644 --- a/src/nghttp.h +++ b/src/nghttp.h @@ -45,6 +45,7 @@ #include +#define NGHTTP2_NO_SSIZE_T #include #include "llhttp.h" @@ -77,7 +78,7 @@ struct Config { int64_t encoder_header_table_size; size_t padding; size_t max_concurrent_streams; - ssize_t peer_max_concurrent_streams; + size_t peer_max_concurrent_streams; int multiply; // milliseconds ev_tstamp timeout; @@ -137,7 +138,7 @@ struct ContinueTimer { struct Request { // For pushed request, |uri| is empty and |u| is zero-cleared. Request(const std::string &uri, const http_parser_url &u, - const nghttp2_data_provider *data_prd, int64_t data_length, + const nghttp2_data_provider2 *data_prd, int64_t data_length, const nghttp2_priority_spec &pri_spec, int level = 0); ~Request(); @@ -180,7 +181,7 @@ struct Request { int64_t response_len; nghttp2_gzip *inflater; std::unique_ptr html_parser; - const nghttp2_data_provider *data_prd; + const nghttp2_data_provider2 *data_prd; size_t header_buffer_size; int32_t stream_id; int status; @@ -246,7 +247,7 @@ struct HttpClient { bool all_requests_processed() const; void update_hostport(); bool add_request(const std::string &uri, - const nghttp2_data_provider *data_prd, int64_t data_length, + const nghttp2_data_provider2 *data_prd, int64_t data_length, const nghttp2_priority_spec &pri_spec, int level = 0); void record_start_time(); diff --git a/src/nghttp2_gzip_test.c b/src/nghttp2_gzip_test.c index de19d5d..9a36db0 100644 --- a/src/nghttp2_gzip_test.c +++ b/src/nghttp2_gzip_test.c @@ -27,26 +27,35 @@ #include #include -#include +#include "munit.h" #include #include "nghttp2_gzip.h" +static const MunitTest tests[] = { + munit_void_test(test_nghttp2_gzip_inflate), + munit_test_end(), +}; + +const MunitSuite gzip_suite = { + "/gzip", tests, NULL, 1, MUNIT_SUITE_OPTION_NONE, +}; + static size_t deflate_data(uint8_t *out, size_t outlen, const uint8_t *in, size_t inlen) { int rv; z_stream zst = {0}; rv = deflateInit(&zst, Z_DEFAULT_COMPRESSION); - CU_ASSERT(rv == Z_OK); + assert_int(Z_OK, ==, rv); zst.avail_in = (unsigned int)inlen; zst.next_in = (uint8_t *)in; zst.avail_out = (unsigned int)outlen; zst.next_out = out; rv = deflate(&zst, Z_SYNC_FLUSH); - CU_ASSERT(rv == Z_OK); + assert_int(Z_OK, ==, rv); deflateEnd(&zst); @@ -71,41 +80,44 @@ void test_nghttp2_gzip_inflate(void) { inlen = deflate_data(in, inlen, (const uint8_t *)input, sizeof(input) - 1); - CU_ASSERT(0 == nghttp2_gzip_inflate_new(&inflater)); + assert_int(0, ==, nghttp2_gzip_inflate_new(&inflater)); /* First 16 bytes */ inptr = in; inproclen = inlen; outproclen = 16; - CU_ASSERT( - 0 == nghttp2_gzip_inflate(inflater, out, &outproclen, inptr, &inproclen)); - CU_ASSERT(16 == outproclen); - CU_ASSERT(inproclen > 0); - CU_ASSERT(0 == memcmp(inputptr, out, outproclen)); + assert_int( + 0, ==, + nghttp2_gzip_inflate(inflater, out, &outproclen, inptr, &inproclen)); + assert_size(16, ==, outproclen); + assert_size(0, <, inproclen); + assert_memory_equal(outproclen, inputptr, out); /* Next 32 bytes */ inptr += inproclen; inlen -= inproclen; inproclen = inlen; inputptr += outproclen; outproclen = 32; - CU_ASSERT( - 0 == nghttp2_gzip_inflate(inflater, out, &outproclen, inptr, &inproclen)); - CU_ASSERT(32 == outproclen); - CU_ASSERT(inproclen > 0); - CU_ASSERT(0 == memcmp(inputptr, out, outproclen)); + assert_int( + 0, ==, + nghttp2_gzip_inflate(inflater, out, &outproclen, inptr, &inproclen)); + assert_size(32, ==, outproclen); + assert_size(0, <, inproclen); + assert_memory_equal(outproclen, inputptr, out); /* Rest */ inptr += inproclen; inlen -= inproclen; inproclen = inlen; inputptr += outproclen; outproclen = sizeof(out); - CU_ASSERT( - 0 == nghttp2_gzip_inflate(inflater, out, &outproclen, inptr, &inproclen)); - CU_ASSERT(sizeof(input) - 49 == outproclen); - CU_ASSERT(inproclen > 0); - CU_ASSERT(0 == memcmp(inputptr, out, outproclen)); + assert_int( + 0, ==, + nghttp2_gzip_inflate(inflater, out, &outproclen, inptr, &inproclen)); + assert_size(sizeof(input) - 49, ==, outproclen); + assert_size(0, <, inproclen); + assert_memory_equal(outproclen, inputptr, out); inlen -= inproclen; - CU_ASSERT(0 == inlen); + assert_size(0, ==, inlen); nghttp2_gzip_inflate_del(inflater); } diff --git a/src/nghttp2_gzip_test.h b/src/nghttp2_gzip_test.h index 8d554f7..fa6938b 100644 --- a/src/nghttp2_gzip_test.h +++ b/src/nghttp2_gzip_test.h @@ -33,7 +33,13 @@ extern "C" { #endif -void test_nghttp2_gzip_inflate(void); +#define MUNIT_ENABLE_ASSERT_ALIASES + +#include "munit.h" + +extern const MunitSuite gzip_suite; + +munit_void_test_decl(test_nghttp2_gzip_inflate); #ifdef __cplusplus } diff --git a/src/shrpx-unittest.cc b/src/shrpx-unittest.cc index f089adf..ec707e5 100644 --- a/src/shrpx-unittest.cc +++ b/src/shrpx-unittest.cc @@ -26,9 +26,8 @@ # include #endif // HAVE_CONFIG_H -#include -#include -#include +#include "munit.h" + // include test cases' include files here #include "shrpx_tls_test.h" #include "shrpx_downstream_test.h" @@ -47,200 +46,21 @@ #include "shrpx_router_test.h" #include "shrpx_log.h" -static int init_suite1(void) { return 0; } - -static int clean_suite1(void) { return 0; } - int main(int argc, char *argv[]) { - CU_pSuite pSuite = nullptr; - unsigned int num_tests_failed; - shrpx::create_config(); - // initialize the CUnit test registry - if (CUE_SUCCESS != CU_initialize_registry()) - return CU_get_error(); - - // add a suite to the registry - pSuite = CU_add_suite("shrpx_TestSuite", init_suite1, clean_suite1); - if (nullptr == pSuite) { - CU_cleanup_registry(); - return CU_get_error(); - } - - // add the tests to the suite - if (!CU_add_test(pSuite, "tls_create_lookup_tree", - shrpx::test_shrpx_tls_create_lookup_tree) || - !CU_add_test(pSuite, "tls_cert_lookup_tree_add_ssl_ctx", - shrpx::test_shrpx_tls_cert_lookup_tree_add_ssl_ctx) || - !CU_add_test(pSuite, "tls_tls_hostname_match", - shrpx::test_shrpx_tls_tls_hostname_match) || - !CU_add_test(pSuite, "tls_tls_verify_numeric_hostname", - shrpx::test_shrpx_tls_verify_numeric_hostname) || - !CU_add_test(pSuite, "tls_tls_verify_dns_hostname", - shrpx::test_shrpx_tls_verify_dns_hostname) || - !CU_add_test(pSuite, "http2_add_header", shrpx::test_http2_add_header) || - !CU_add_test(pSuite, "http2_get_header", shrpx::test_http2_get_header) || - !CU_add_test(pSuite, "http2_copy_headers_to_nva", - shrpx::test_http2_copy_headers_to_nva) || - !CU_add_test(pSuite, "http2_build_http1_headers_from_headers", - shrpx::test_http2_build_http1_headers_from_headers) || - !CU_add_test(pSuite, "http2_lws", shrpx::test_http2_lws) || - !CU_add_test(pSuite, "http2_rewrite_location_uri", - shrpx::test_http2_rewrite_location_uri) || - !CU_add_test(pSuite, "http2_parse_http_status_code", - shrpx::test_http2_parse_http_status_code) || - !CU_add_test(pSuite, "http2_index_header", - shrpx::test_http2_index_header) || - !CU_add_test(pSuite, "http2_lookup_token", - shrpx::test_http2_lookup_token) || - !CU_add_test(pSuite, "http2_parse_link_header", - shrpx::test_http2_parse_link_header) || - !CU_add_test(pSuite, "http2_path_join", shrpx::test_http2_path_join) || - !CU_add_test(pSuite, "http2_normalize_path", - shrpx::test_http2_normalize_path) || - !CU_add_test(pSuite, "http2_rewrite_clean_path", - shrpx::test_http2_rewrite_clean_path) || - !CU_add_test(pSuite, "http2_get_pure_path_component", - shrpx::test_http2_get_pure_path_component) || - !CU_add_test(pSuite, "http2_construct_push_component", - shrpx::test_http2_construct_push_component) || - !CU_add_test(pSuite, "http2_contains_trailers", - shrpx::test_http2_contains_trailers) || - !CU_add_test(pSuite, "http2_check_transfer_encoding", - shrpx::test_http2_check_transfer_encoding) || - !CU_add_test(pSuite, "downstream_field_store_append_last_header", - shrpx::test_downstream_field_store_append_last_header) || - !CU_add_test(pSuite, "downstream_field_store_header", - shrpx::test_downstream_field_store_header) || - !CU_add_test(pSuite, "downstream_crumble_request_cookie", - shrpx::test_downstream_crumble_request_cookie) || - !CU_add_test(pSuite, "downstream_assemble_request_cookie", - shrpx::test_downstream_assemble_request_cookie) || - !CU_add_test(pSuite, "downstream_rewrite_location_response_header", - shrpx::test_downstream_rewrite_location_response_header) || - !CU_add_test(pSuite, "downstream_supports_non_final_response", - shrpx::test_downstream_supports_non_final_response) || - !CU_add_test(pSuite, "downstream_find_affinity_cookie", - shrpx::test_downstream_find_affinity_cookie) || - !CU_add_test(pSuite, "config_parse_header", - shrpx::test_shrpx_config_parse_header) || - !CU_add_test(pSuite, "config_parse_log_format", - shrpx::test_shrpx_config_parse_log_format) || - !CU_add_test(pSuite, "config_read_tls_ticket_key_file", - shrpx::test_shrpx_config_read_tls_ticket_key_file) || - !CU_add_test(pSuite, "config_read_tls_ticket_key_file_aes_256", - shrpx::test_shrpx_config_read_tls_ticket_key_file_aes_256) || - !CU_add_test(pSuite, "worker_match_downstream_addr_group", - shrpx::test_shrpx_worker_match_downstream_addr_group) || - !CU_add_test(pSuite, "http_create_forwarded", - shrpx::test_shrpx_http_create_forwarded) || - !CU_add_test(pSuite, "http_create_via_header_value", - shrpx::test_shrpx_http_create_via_header_value) || - !CU_add_test(pSuite, "http_create_affinity_cookie", - shrpx::test_shrpx_http_create_affinity_cookie) || - !CU_add_test(pSuite, "http_create_atlsvc_header_field_value", - shrpx::test_shrpx_http_create_altsvc_header_value) || - !CU_add_test(pSuite, "http_check_http_scheme", - shrpx::test_shrpx_http_check_http_scheme) || - !CU_add_test(pSuite, "router_match", shrpx::test_shrpx_router_match) || - !CU_add_test(pSuite, "router_match_wildcard", - shrpx::test_shrpx_router_match_wildcard) || - !CU_add_test(pSuite, "router_match_prefix", - shrpx::test_shrpx_router_match_prefix) || - !CU_add_test(pSuite, "util_streq", shrpx::test_util_streq) || - !CU_add_test(pSuite, "util_strieq", shrpx::test_util_strieq) || - !CU_add_test(pSuite, "util_inp_strlower", - shrpx::test_util_inp_strlower) || - !CU_add_test(pSuite, "util_to_base64", shrpx::test_util_to_base64) || - !CU_add_test(pSuite, "util_to_token68", shrpx::test_util_to_token68) || - !CU_add_test(pSuite, "util_percent_encode_token", - shrpx::test_util_percent_encode_token) || - !CU_add_test(pSuite, "util_percent_decode", - shrpx::test_util_percent_decode) || - !CU_add_test(pSuite, "util_quote_string", - shrpx::test_util_quote_string) || - !CU_add_test(pSuite, "util_utox", shrpx::test_util_utox) || - !CU_add_test(pSuite, "util_http_date", shrpx::test_util_http_date) || - !CU_add_test(pSuite, "util_select_h2", shrpx::test_util_select_h2) || - !CU_add_test(pSuite, "util_ipv6_numeric_addr", - shrpx::test_util_ipv6_numeric_addr) || - !CU_add_test(pSuite, "util_utos", shrpx::test_util_utos) || - !CU_add_test(pSuite, "util_make_string_ref_uint", - shrpx::test_util_make_string_ref_uint) || - !CU_add_test(pSuite, "util_utos_unit", shrpx::test_util_utos_unit) || - !CU_add_test(pSuite, "util_utos_funit", shrpx::test_util_utos_funit) || - !CU_add_test(pSuite, "util_parse_uint_with_unit", - shrpx::test_util_parse_uint_with_unit) || - !CU_add_test(pSuite, "util_parse_uint", shrpx::test_util_parse_uint) || - !CU_add_test(pSuite, "util_parse_duration_with_unit", - shrpx::test_util_parse_duration_with_unit) || - !CU_add_test(pSuite, "util_duration_str", - shrpx::test_util_duration_str) || - !CU_add_test(pSuite, "util_format_duration", - shrpx::test_util_format_duration) || - !CU_add_test(pSuite, "util_starts_with", shrpx::test_util_starts_with) || - !CU_add_test(pSuite, "util_ends_with", shrpx::test_util_ends_with) || - !CU_add_test(pSuite, "util_parse_http_date", - shrpx::test_util_parse_http_date) || - !CU_add_test(pSuite, "util_localtime_date", - shrpx::test_util_localtime_date) || - !CU_add_test(pSuite, "util_get_uint64", shrpx::test_util_get_uint64) || - !CU_add_test(pSuite, "util_parse_config_str_list", - shrpx::test_util_parse_config_str_list) || - !CU_add_test(pSuite, "util_make_http_hostport", - shrpx::test_util_make_http_hostport) || - !CU_add_test(pSuite, "util_make_hostport", - shrpx::test_util_make_hostport) || - !CU_add_test(pSuite, "util_strifind", shrpx::test_util_strifind) || - !CU_add_test(pSuite, "util_random_alpha_digit", - shrpx::test_util_random_alpha_digit) || - !CU_add_test(pSuite, "util_format_hex", shrpx::test_util_format_hex) || - !CU_add_test(pSuite, "util_is_hex_string", - shrpx::test_util_is_hex_string) || - !CU_add_test(pSuite, "util_decode_hex", shrpx::test_util_decode_hex) || - !CU_add_test(pSuite, "util_extract_host", - shrpx::test_util_extract_host) || - !CU_add_test(pSuite, "util_split_hostport", - shrpx::test_util_split_hostport) || - !CU_add_test(pSuite, "util_split_str", shrpx::test_util_split_str) || - !CU_add_test(pSuite, "util_rstrip", shrpx::test_util_rstrip) || - !CU_add_test(pSuite, "gzip_inflate", test_nghttp2_gzip_inflate) || - !CU_add_test(pSuite, "buffer_write", nghttp2::test_buffer_write) || - !CU_add_test(pSuite, "pool_recycle", nghttp2::test_pool_recycle) || - !CU_add_test(pSuite, "memchunk_append", nghttp2::test_memchunks_append) || - !CU_add_test(pSuite, "memchunk_drain", nghttp2::test_memchunks_drain) || - !CU_add_test(pSuite, "memchunk_riovec", nghttp2::test_memchunks_riovec) || - !CU_add_test(pSuite, "memchunk_recycle", - nghttp2::test_memchunks_recycle) || - !CU_add_test(pSuite, "memchunk_reset", nghttp2::test_memchunks_reset) || - !CU_add_test(pSuite, "peek_memchunk_append", - nghttp2::test_peek_memchunks_append) || - !CU_add_test(pSuite, "peek_memchunk_disable_peek_drain", - nghttp2::test_peek_memchunks_disable_peek_drain) || - !CU_add_test(pSuite, "peek_memchunk_disable_peek_no_drain", - nghttp2::test_peek_memchunks_disable_peek_no_drain) || - !CU_add_test(pSuite, "peek_memchunk_reset", - nghttp2::test_peek_memchunks_reset) || - !CU_add_test(pSuite, "template_immutable_string", - nghttp2::test_template_immutable_string) || - !CU_add_test(pSuite, "template_string_ref", - nghttp2::test_template_string_ref) || - !CU_add_test(pSuite, "base64_encode", nghttp2::test_base64_encode) || - !CU_add_test(pSuite, "base64_decode", nghttp2::test_base64_decode)) { - CU_cleanup_registry(); - return CU_get_error(); - } + const MunitSuite suites[] = { + shrpx::tls_suite, shrpx::downstream_suite, + shrpx::config_suite, shrpx::worker_suite, + shrpx::http_suite, shrpx::router_suite, + shrpx::http2_suite, shrpx::util_suite, + gzip_suite, buffer_suite, + memchunk_suite, template_suite, + base64_suite, {NULL, NULL, NULL, 0, MUNIT_SUITE_OPTION_NONE}, + }; + const MunitSuite suite = { + "", NULL, suites, 1, MUNIT_SUITE_OPTION_NONE, + }; - // Run all tests using the CUnit Basic interface - CU_basic_set_mode(CU_BRM_VERBOSE); - CU_basic_run_tests(); - num_tests_failed = CU_get_number_of_tests_failed(); - CU_cleanup_registry(); - if (CU_get_error() == CUE_SUCCESS) { - return num_tests_failed; - } else { - printf("CUnit Error: %s\n", CU_get_error_msg()); - return CU_get_error(); - } + return munit_suite_main(&suite, NULL, argc, argv); } diff --git a/src/shrpx.h b/src/shrpx.h index d881ef5..e6379bd 100644 --- a/src/shrpx.h +++ b/src/shrpx.h @@ -36,6 +36,8 @@ #include +#define NGHTTP2_NO_SSIZE_T + #ifndef HAVE__EXIT # define nghttp2_Exit(status) _exit(status) #else // HAVE__EXIT diff --git a/src/shrpx_config.cc b/src/shrpx_config.cc index d6d0d07..89b3672 100644 --- a/src/shrpx_config.cc +++ b/src/shrpx_config.cc @@ -49,6 +49,8 @@ #include #include +#include + #include #include "url-parser/url_parser.h" @@ -64,6 +66,10 @@ #include "ssl_compat.h" #include "xsi_strerror.h" +#ifndef AI_NUMERICSERV +# define AI_NUMERICSERV 0 +#endif + namespace shrpx { namespace { @@ -4691,4 +4697,32 @@ int resolve_hostname(Address *addr, const char *hostname, uint16_t port, return 0; } +#ifdef ENABLE_HTTP3 +QUICKeyingMaterial::QUICKeyingMaterial(QUICKeyingMaterial &&other) noexcept + : cid_encryption_ctx{std::exchange(other.cid_encryption_ctx, nullptr)}, + reserved{other.reserved}, + secret{other.secret}, + salt{other.salt}, + cid_encryption_key{other.cid_encryption_key}, + id{other.id} {} + +QUICKeyingMaterial::~QUICKeyingMaterial() noexcept { + if (cid_encryption_ctx) { + EVP_CIPHER_CTX_free(cid_encryption_ctx); + } +} + +QUICKeyingMaterial & +QUICKeyingMaterial::operator=(QUICKeyingMaterial &&other) noexcept { + cid_encryption_ctx = std::exchange(other.cid_encryption_ctx, nullptr); + reserved = other.reserved; + secret = other.secret; + salt = other.salt; + cid_encryption_key = other.cid_encryption_key; + id = other.id; + + return *this; +} +#endif // ENABLE_HTTP3 + } // namespace shrpx diff --git a/src/shrpx_config.h b/src/shrpx_config.h index 7f316eb..335b0f9 100644 --- a/src/shrpx_config.h +++ b/src/shrpx_config.h @@ -636,6 +636,11 @@ struct TLSCertificate { #ifdef ENABLE_HTTP3 struct QUICKeyingMaterial { + QUICKeyingMaterial() noexcept = default; + QUICKeyingMaterial(QUICKeyingMaterial &&other) noexcept; + ~QUICKeyingMaterial() noexcept; + QUICKeyingMaterial &operator=(QUICKeyingMaterial &&other) noexcept; + EVP_CIPHER_CTX *cid_encryption_ctx; std::array reserved; std::array secret; std::array salt; diff --git a/src/shrpx_config_test.cc b/src/shrpx_config_test.cc index a8f0962..068f185 100644 --- a/src/shrpx_config_test.cc +++ b/src/shrpx_config_test.cc @@ -30,43 +30,57 @@ #include -#include +#include "munitxx.h" #include "shrpx_config.h" #include "shrpx_log.h" namespace shrpx { +namespace { +const MunitTest tests[]{ + munit_void_test(test_shrpx_config_parse_header), + munit_void_test(test_shrpx_config_parse_log_format), + munit_void_test(test_shrpx_config_read_tls_ticket_key_file), + munit_void_test(test_shrpx_config_read_tls_ticket_key_file_aes_256), + munit_test_end(), +}; +} // namespace + +const MunitSuite config_suite{ + "/config_suite", tests, NULL, 1, MUNIT_SUITE_OPTION_NONE, +}; + void test_shrpx_config_parse_header(void) { BlockAllocator balloc(4096, 4096); auto p = parse_header(balloc, StringRef::from_lit("a: b")); - CU_ASSERT("a" == p.name); - CU_ASSERT("b" == p.value); + assert_stdstring_equal("a", p.name.str()); + assert_stdstring_equal("b", p.value.str()); p = parse_header(balloc, StringRef::from_lit("a: b")); - CU_ASSERT("a" == p.name); - CU_ASSERT("b" == p.value); + assert_stdstring_equal("a", p.name.str()); + assert_stdstring_equal("b", p.value.str()); p = parse_header(balloc, StringRef::from_lit(":a: b")); - CU_ASSERT(p.name.empty()); + assert_true(p.name.empty()); p = parse_header(balloc, StringRef::from_lit("a: :b")); - CU_ASSERT("a" == p.name); - CU_ASSERT(":b" == p.value); + assert_stdstring_equal("a", p.name.str()); + assert_stdstring_equal(":b", p.value.str()); p = parse_header(balloc, StringRef::from_lit(": b")); - CU_ASSERT(p.name.empty()); + assert_true(p.name.empty()); p = parse_header(balloc, StringRef::from_lit("alpha: bravo charlie")); - CU_ASSERT("alpha" == p.name); - CU_ASSERT("bravo charlie" == p.value); + assert_stdstring_equal("alpha", p.name.str()); + assert_stdstring_equal("bravo charlie", p.value.str()); p = parse_header(balloc, StringRef::from_lit("a,: b")); - CU_ASSERT(p.name.empty()); + assert_true(p.name.empty()); p = parse_header(balloc, StringRef::from_lit("a: b\x0a")); - CU_ASSERT(p.name.empty()); + assert_true(p.name.empty()); } void test_shrpx_config_parse_log_format(void) { @@ -77,100 +91,102 @@ void test_shrpx_config_parse_log_format(void) { R"($remote_addr - $remote_user [$time_local] )" R"("$request" $status $body_bytes_sent )" R"("${http_referer}" $http_host "$http_user_agent")")); - CU_ASSERT(16 == res.size()); + assert_size(16, ==, res.size()); - CU_ASSERT(LogFragmentType::REMOTE_ADDR == res[0].type); + assert_enum_class(LogFragmentType::REMOTE_ADDR, ==, res[0].type); - CU_ASSERT(LogFragmentType::LITERAL == res[1].type); - CU_ASSERT(" - $remote_user [" == res[1].value); + assert_enum_class(LogFragmentType::LITERAL, ==, res[1].type); + assert_stdstring_equal(" - $remote_user [", res[1].value.str()); - CU_ASSERT(LogFragmentType::TIME_LOCAL == res[2].type); + assert_enum_class(LogFragmentType::TIME_LOCAL, ==, res[2].type); - CU_ASSERT(LogFragmentType::LITERAL == res[3].type); - CU_ASSERT("] \"" == res[3].value); + assert_enum_class(LogFragmentType::LITERAL, ==, res[3].type); + assert_stdstring_equal("] \"", res[3].value.str()); - CU_ASSERT(LogFragmentType::REQUEST == res[4].type); + assert_enum_class(LogFragmentType::REQUEST, ==, res[4].type); - CU_ASSERT(LogFragmentType::LITERAL == res[5].type); - CU_ASSERT("\" " == res[5].value); + assert_enum_class(LogFragmentType::LITERAL, ==, res[5].type); + assert_stdstring_equal("\" ", res[5].value.str()); - CU_ASSERT(LogFragmentType::STATUS == res[6].type); + assert_enum_class(LogFragmentType::STATUS, ==, res[6].type); - CU_ASSERT(LogFragmentType::LITERAL == res[7].type); - CU_ASSERT(" " == res[7].value); + assert_enum_class(LogFragmentType::LITERAL, ==, res[7].type); + assert_stdstring_equal(" ", res[7].value.str()); - CU_ASSERT(LogFragmentType::BODY_BYTES_SENT == res[8].type); + assert_enum_class(LogFragmentType::BODY_BYTES_SENT, ==, res[8].type); - CU_ASSERT(LogFragmentType::LITERAL == res[9].type); - CU_ASSERT(" \"" == res[9].value); + assert_enum_class(LogFragmentType::LITERAL, ==, res[9].type); + assert_stdstring_equal(" \"", res[9].value.str()); - CU_ASSERT(LogFragmentType::HTTP == res[10].type); - CU_ASSERT("referer" == res[10].value); + assert_enum_class(LogFragmentType::HTTP, ==, res[10].type); + assert_stdstring_equal("referer", res[10].value.str()); - CU_ASSERT(LogFragmentType::LITERAL == res[11].type); - CU_ASSERT("\" " == res[11].value); + assert_enum_class(LogFragmentType::LITERAL, ==, res[11].type); + assert_stdstring_equal("\" ", res[11].value.str()); - CU_ASSERT(LogFragmentType::AUTHORITY == res[12].type); + assert_enum_class(LogFragmentType::AUTHORITY, ==, res[12].type); - CU_ASSERT(LogFragmentType::LITERAL == res[13].type); - CU_ASSERT(" \"" == res[13].value); + assert_enum_class(LogFragmentType::LITERAL, ==, res[13].type); + assert_stdstring_equal(" \"", res[13].value.str()); - CU_ASSERT(LogFragmentType::HTTP == res[14].type); - CU_ASSERT("user-agent" == res[14].value); + assert_enum_class(LogFragmentType::HTTP, ==, res[14].type); + assert_stdstring_equal("user-agent", res[14].value.str()); - CU_ASSERT(LogFragmentType::LITERAL == res[15].type); - CU_ASSERT("\"" == res[15].value); + assert_enum_class(LogFragmentType::LITERAL, ==, res[15].type); + assert_stdstring_equal("\"", res[15].value.str()); res = parse_log_format(balloc, StringRef::from_lit("$")); - CU_ASSERT(1 == res.size()); + assert_size(1, ==, res.size()); - CU_ASSERT(LogFragmentType::LITERAL == res[0].type); - CU_ASSERT("$" == res[0].value); + assert_enum_class(LogFragmentType::LITERAL, ==, res[0].type); + assert_stdstring_equal("$", res[0].value.str()); res = parse_log_format(balloc, StringRef::from_lit("${")); - CU_ASSERT(1 == res.size()); + assert_size(1, ==, res.size()); - CU_ASSERT(LogFragmentType::LITERAL == res[0].type); - CU_ASSERT("${" == res[0].value); + assert_enum_class(LogFragmentType::LITERAL, ==, res[0].type); + assert_stdstring_equal("${", res[0].value.str()); res = parse_log_format(balloc, StringRef::from_lit("${a")); - CU_ASSERT(1 == res.size()); + assert_size(1, ==, res.size()); - CU_ASSERT(LogFragmentType::LITERAL == res[0].type); - CU_ASSERT("${a" == res[0].value); + assert_enum_class(LogFragmentType::LITERAL, ==, res[0].type); + assert_stdstring_equal("${a", res[0].value.str()); res = parse_log_format(balloc, StringRef::from_lit("${a ")); - CU_ASSERT(1 == res.size()); + assert_size(1, ==, res.size()); - CU_ASSERT(LogFragmentType::LITERAL == res[0].type); - CU_ASSERT("${a " == res[0].value); + assert_enum_class(LogFragmentType::LITERAL, ==, res[0].type); + assert_stdstring_equal("${a ", res[0].value.str()); res = parse_log_format(balloc, StringRef::from_lit("$$remote_addr")); - CU_ASSERT(2 == res.size()); + assert_size(2, ==, res.size()); - CU_ASSERT(LogFragmentType::LITERAL == res[0].type); - CU_ASSERT("$" == res[0].value); + assert_enum_class(LogFragmentType::LITERAL, ==, res[0].type); + assert_stdstring_equal("$", res[0].value.str()); - CU_ASSERT(LogFragmentType::REMOTE_ADDR == res[1].type); - CU_ASSERT("" == res[1].value); + assert_enum_class(LogFragmentType::REMOTE_ADDR, ==, res[1].type); + assert_stdstring_equal("", res[1].value.str()); } void test_shrpx_config_read_tls_ticket_key_file(void) { char file1[] = "/tmp/nghttpx-unittest.XXXXXX"; auto fd1 = mkstemp(file1); - CU_ASSERT(fd1 != -1); - CU_ASSERT(48 == - write(fd1, "0..............12..............34..............5", 48)); + assert_int(-1, !=, fd1); + assert_ssize( + 48, ==, + write(fd1, "0..............12..............34..............5", 48)); char file2[] = "/tmp/nghttpx-unittest.XXXXXX"; auto fd2 = mkstemp(file2); - CU_ASSERT(fd2 != -1); - CU_ASSERT(48 == - write(fd2, "6..............78..............9a..............b", 48)); + assert_int(-1, !=, fd2); + assert_ssize( + 48, ==, + write(fd2, "6..............78..............9a..............b", 48)); close(fd1); close(fd2); @@ -178,44 +194,48 @@ void test_shrpx_config_read_tls_ticket_key_file(void) { {StringRef{file1}, StringRef{file2}}, EVP_aes_128_cbc(), EVP_sha256()); unlink(file1); unlink(file2); - CU_ASSERT(ticket_keys.get() != nullptr); - CU_ASSERT(2 == ticket_keys->keys.size()); + assert_not_null(ticket_keys.get()); + assert_size(2, ==, ticket_keys->keys.size()); auto key = &ticket_keys->keys[0]; - CU_ASSERT(std::equal(std::begin(key->data.name), std::end(key->data.name), - "0..............1")); - CU_ASSERT(std::equal(std::begin(key->data.enc_key), - std::begin(key->data.enc_key) + 16, "2..............3")); - CU_ASSERT(std::equal(std::begin(key->data.hmac_key), - std::begin(key->data.hmac_key) + 16, - "4..............5")); - CU_ASSERT(16 == key->hmac_keylen); + assert_true(std::equal(std::begin(key->data.name), std::end(key->data.name), + "0..............1")); + assert_true(std::equal(std::begin(key->data.enc_key), + std::begin(key->data.enc_key) + 16, + "2..............3")); + assert_true(std::equal(std::begin(key->data.hmac_key), + std::begin(key->data.hmac_key) + 16, + "4..............5")); + assert_size(16, ==, key->hmac_keylen); key = &ticket_keys->keys[1]; - CU_ASSERT(std::equal(std::begin(key->data.name), std::end(key->data.name), - "6..............7")); - CU_ASSERT(std::equal(std::begin(key->data.enc_key), - std::begin(key->data.enc_key) + 16, "8..............9")); - CU_ASSERT(std::equal(std::begin(key->data.hmac_key), - std::begin(key->data.hmac_key) + 16, - "a..............b")); - CU_ASSERT(16 == key->hmac_keylen); + assert_true(std::equal(std::begin(key->data.name), std::end(key->data.name), + "6..............7")); + assert_true(std::equal(std::begin(key->data.enc_key), + std::begin(key->data.enc_key) + 16, + "8..............9")); + assert_true(std::equal(std::begin(key->data.hmac_key), + std::begin(key->data.hmac_key) + 16, + "a..............b")); + assert_size(16, ==, key->hmac_keylen); } void test_shrpx_config_read_tls_ticket_key_file_aes_256(void) { char file1[] = "/tmp/nghttpx-unittest.XXXXXX"; auto fd1 = mkstemp(file1); - CU_ASSERT(fd1 != -1); - CU_ASSERT(80 == write(fd1, - "0..............12..............................34..." - "...........................5", - 80)); + assert_int(-1, !=, fd1); + assert_ssize(80, ==, + write(fd1, + "0..............12..............................34..." + "...........................5", + 80)); char file2[] = "/tmp/nghttpx-unittest.XXXXXX"; auto fd2 = mkstemp(file2); - CU_ASSERT(fd2 != -1); - CU_ASSERT(80 == write(fd2, - "6..............78..............................9a..." - "...........................b", - 80)); + assert_int(-1, !=, fd2); + assert_ssize(80, ==, + write(fd2, + "6..............78..............................9a..." + "...........................b", + 80)); close(fd1); close(fd2); @@ -223,27 +243,27 @@ void test_shrpx_config_read_tls_ticket_key_file_aes_256(void) { {StringRef{file1}, StringRef{file2}}, EVP_aes_256_cbc(), EVP_sha256()); unlink(file1); unlink(file2); - CU_ASSERT(ticket_keys.get() != nullptr); - CU_ASSERT(2 == ticket_keys->keys.size()); + assert_not_null(ticket_keys.get()); + assert_size(2, ==, ticket_keys->keys.size()); auto key = &ticket_keys->keys[0]; - CU_ASSERT(std::equal(std::begin(key->data.name), std::end(key->data.name), - "0..............1")); - CU_ASSERT(std::equal(std::begin(key->data.enc_key), - std::end(key->data.enc_key), - "2..............................3")); - CU_ASSERT(std::equal(std::begin(key->data.hmac_key), - std::end(key->data.hmac_key), - "4..............................5")); + assert_true(std::equal(std::begin(key->data.name), std::end(key->data.name), + "0..............1")); + assert_true(std::equal(std::begin(key->data.enc_key), + std::end(key->data.enc_key), + "2..............................3")); + assert_true(std::equal(std::begin(key->data.hmac_key), + std::end(key->data.hmac_key), + "4..............................5")); key = &ticket_keys->keys[1]; - CU_ASSERT(std::equal(std::begin(key->data.name), std::end(key->data.name), - "6..............7")); - CU_ASSERT(std::equal(std::begin(key->data.enc_key), - std::end(key->data.enc_key), - "8..............................9")); - CU_ASSERT(std::equal(std::begin(key->data.hmac_key), - std::end(key->data.hmac_key), - "a..............................b")); + assert_true(std::equal(std::begin(key->data.name), std::end(key->data.name), + "6..............7")); + assert_true(std::equal(std::begin(key->data.enc_key), + std::end(key->data.enc_key), + "8..............................9")); + assert_true(std::equal(std::begin(key->data.hmac_key), + std::end(key->data.hmac_key), + "a..............................b")); } } // namespace shrpx diff --git a/src/shrpx_config_test.h b/src/shrpx_config_test.h index a30de41..9863101 100644 --- a/src/shrpx_config_test.h +++ b/src/shrpx_config_test.h @@ -29,13 +29,18 @@ # include #endif // HAVE_CONFIG_H +#define MUNIT_ENABLE_ASSERT_ALIASES + +#include "munit.h" + namespace shrpx { -void test_shrpx_config_parse_header(void); -void test_shrpx_config_parse_log_format(void); -void test_shrpx_config_read_tls_ticket_key_file(void); -void test_shrpx_config_read_tls_ticket_key_file_aes_256(void); -void test_shrpx_config_match_downstream_addr_group(void); +extern const MunitSuite config_suite; + +munit_void_test_decl(test_shrpx_config_parse_header); +munit_void_test_decl(test_shrpx_config_parse_log_format); +munit_void_test_decl(test_shrpx_config_read_tls_ticket_key_file); +munit_void_test_decl(test_shrpx_config_read_tls_ticket_key_file_aes_256); } // namespace shrpx diff --git a/src/shrpx_connection.cc b/src/shrpx_connection.cc index a5ab390..d863284 100644 --- a/src/shrpx_connection.cc +++ b/src/shrpx_connection.cc @@ -863,7 +863,7 @@ void Connection::start_tls_write_idle() { } } -ssize_t Connection::write_tls(const void *data, size_t len) { +nghttp2_ssize Connection::write_tls(const void *data, size_t len) { // SSL_write requires the same arguments (buf pointer and its // length) on SSL_ERROR_WANT_READ or SSL_ERROR_WANT_WRITE. // get_write_limit() may return smaller length than previously @@ -950,7 +950,7 @@ ssize_t Connection::write_tls(const void *data, size_t len) { return rv; } -ssize_t Connection::read_tls(void *data, size_t len) { +nghttp2_ssize Connection::read_tls(void *data, size_t len) { ERR_clear_error(); #if defined(NGHTTP2_GENUINE_OPENSSL) || defined(NGHTTP2_OPENSSL_IS_BORINGSSL) @@ -1061,7 +1061,7 @@ ssize_t Connection::read_tls(void *data, size_t len) { return rv; } -ssize_t Connection::write_clear(const void *data, size_t len) { +nghttp2_ssize Connection::write_clear(const void *data, size_t len) { len = std::min(len, wlimit.avail()); if (len == 0) { return 0; @@ -1088,7 +1088,7 @@ ssize_t Connection::write_clear(const void *data, size_t len) { return nwrite; } -ssize_t Connection::writev_clear(struct iovec *iov, int iovcnt) { +nghttp2_ssize Connection::writev_clear(struct iovec *iov, int iovcnt) { iovcnt = limit_iovec(iov, iovcnt, wlimit.avail()); if (iovcnt == 0) { return 0; @@ -1115,7 +1115,7 @@ ssize_t Connection::writev_clear(struct iovec *iov, int iovcnt) { return nwrite; } -ssize_t Connection::read_clear(void *data, size_t len) { +nghttp2_ssize Connection::read_clear(void *data, size_t len) { len = std::min(len, rlimit.avail()); if (len == 0) { return 0; @@ -1140,7 +1140,7 @@ ssize_t Connection::read_clear(void *data, size_t len) { return nread; } -ssize_t Connection::read_nolim_clear(void *data, size_t len) { +nghttp2_ssize Connection::read_nolim_clear(void *data, size_t len) { ssize_t nread; while ((nread = read(fd, data, len)) == -1 && errno == EINTR) ; @@ -1158,7 +1158,7 @@ ssize_t Connection::read_nolim_clear(void *data, size_t len) { return nread; } -ssize_t Connection::peek_clear(void *data, size_t len) { +nghttp2_ssize Connection::peek_clear(void *data, size_t len) { ssize_t nread; while ((nread = recv(fd, data, len, MSG_PEEK)) == -1 && errno == EINTR) ; diff --git a/src/shrpx_connection.h b/src/shrpx_connection.h index 10526f7..2db2588 100644 --- a/src/shrpx_connection.h +++ b/src/shrpx_connection.h @@ -33,6 +33,8 @@ #include +#include + #ifdef ENABLE_HTTP3 # include #endif // ENABLE_HTTP3 @@ -128,8 +130,8 @@ struct Connection { // underlying connection blocks), return 0. SHRPX_ERR_EOF is // returned in case of EOF and no data was read. Otherwise // SHRPX_ERR_NETWORK is return in case of error. - ssize_t write_tls(const void *data, size_t len); - ssize_t read_tls(void *data, size_t len); + nghttp2_ssize write_tls(const void *data, size_t len); + nghttp2_ssize read_tls(void *data, size_t len); size_t get_tls_write_limit(); // Updates the number of bytes written in warm up period. @@ -138,13 +140,13 @@ struct Connection { // determine fallback to short record size mode. void start_tls_write_idle(); - ssize_t write_clear(const void *data, size_t len); - ssize_t writev_clear(struct iovec *iov, int iovcnt); - ssize_t read_clear(void *data, size_t len); + nghttp2_ssize write_clear(const void *data, size_t len); + nghttp2_ssize writev_clear(struct iovec *iov, int iovcnt); + nghttp2_ssize read_clear(void *data, size_t len); // Read at most |len| bytes of data from socket without rate limit. - ssize_t read_nolim_clear(void *data, size_t len); + nghttp2_ssize read_nolim_clear(void *data, size_t len); // Peek at most |len| bytes of data from socket without rate limit. - ssize_t peek_clear(void *data, size_t len); + nghttp2_ssize peek_clear(void *data, size_t len); void handle_tls_pending_read(); diff --git a/src/shrpx_connection_handler.cc b/src/shrpx_connection_handler.cc index 330e832..af4b8fc 100644 --- a/src/shrpx_connection_handler.cc +++ b/src/shrpx_connection_handler.cc @@ -739,40 +739,31 @@ void ConnectionHandler::handle_ocsp_complete() { // that case we get nullptr. auto quic_ssl_ctx = quic_all_ssl_ctx_[ocsp_.next]; if (quic_ssl_ctx) { -# ifndef NGHTTP2_OPENSSL_IS_BORINGSSL auto quic_tls_ctx_data = static_cast( SSL_CTX_get_app_data(quic_ssl_ctx)); -# ifdef HAVE_ATOMIC_STD_SHARED_PTR +# ifdef HAVE_ATOMIC_STD_SHARED_PTR std::atomic_store_explicit( &quic_tls_ctx_data->ocsp_data, std::make_shared>(ocsp_.resp), std::memory_order_release); -# else // !HAVE_ATOMIC_STD_SHARED_PTR +# else // !HAVE_ATOMIC_STD_SHARED_PTR std::lock_guard g(quic_tls_ctx_data->mu); quic_tls_ctx_data->ocsp_data = std::make_shared>(ocsp_.resp); -# endif // !HAVE_ATOMIC_STD_SHARED_PTR -# else // NGHTTP2_OPENSSL_IS_BORINGSSL - SSL_CTX_set_ocsp_response(quic_ssl_ctx, ocsp_.resp.data(), - ocsp_.resp.size()); -# endif // NGHTTP2_OPENSSL_IS_BORINGSSL +# endif // !HAVE_ATOMIC_STD_SHARED_PTR } #endif // ENABLE_HTTP3 -#ifndef NGHTTP2_OPENSSL_IS_BORINGSSL -# ifdef HAVE_ATOMIC_STD_SHARED_PTR +#ifdef HAVE_ATOMIC_STD_SHARED_PTR std::atomic_store_explicit( &tls_ctx_data->ocsp_data, std::make_shared>(std::move(ocsp_.resp)), std::memory_order_release); -# else // !HAVE_ATOMIC_STD_SHARED_PTR +#else // !HAVE_ATOMIC_STD_SHARED_PTR std::lock_guard g(tls_ctx_data->mu); tls_ctx_data->ocsp_data = std::make_shared>(std::move(ocsp_.resp)); -# endif // !HAVE_ATOMIC_STD_SHARED_PTR -#else // NGHTTP2_OPENSSL_IS_BORINGSSL - SSL_CTX_set_ocsp_response(ssl_ctx, ocsp_.resp.data(), ocsp_.resp.size()); -#endif // NGHTTP2_OPENSSL_IS_BORINGSSL +#endif // !HAVE_ATOMIC_STD_SHARED_PTR } ++ocsp_.next; @@ -1288,7 +1279,7 @@ int ConnectionHandler::quic_ipc_read() { if (decrypt_quic_connection_id(decrypted_dcid.data(), vc.dcid + SHRPX_QUIC_CID_PREFIX_OFFSET, - qkm.cid_encryption_key.data()) != 0) { + qkm.cid_encryption_ctx) != 0) { return -1; } diff --git a/src/shrpx_downstream_test.cc b/src/shrpx_downstream_test.cc index 6100b18..46db9b7 100644 --- a/src/shrpx_downstream_test.cc +++ b/src/shrpx_downstream_test.cc @@ -26,12 +26,29 @@ #include -#include +#include "munitxx.h" #include "shrpx_downstream.h" namespace shrpx { +namespace { +const MunitTest tests[]{ + munit_void_test(test_downstream_field_store_append_last_header), + munit_void_test(test_downstream_field_store_header), + munit_void_test(test_downstream_crumble_request_cookie), + munit_void_test(test_downstream_assemble_request_cookie), + munit_void_test(test_downstream_rewrite_location_response_header), + munit_void_test(test_downstream_supports_non_final_response), + munit_void_test(test_downstream_find_affinity_cookie), + munit_test_end(), +}; +} // namespace + +const MunitSuite downstream_suite{ + "/downstream", tests, NULL, 1, MUNIT_SUITE_OPTION_NONE, +}; + void test_downstream_field_store_append_last_header(void) { BlockAllocator balloc(16, 16); FieldStore fs(balloc, 0); @@ -57,7 +74,7 @@ void test_downstream_field_store_append_last_header(void) { HeaderRefs{{StringRef::from_lit("alphabravogolf0123456789"), StringRef::from_lit("CharliedeltAecho0123456789")}, {StringRef::from_lit("echo"), StringRef::from_lit("foxtrot")}}; - CU_ASSERT(ans == fs.headers()); + assert_true(ans == fs.headers()); } void test_downstream_field_store_header(void) { @@ -72,14 +89,14 @@ void test_downstream_field_store_header(void) { http2::HD_CONTENT_LENGTH); // By token - CU_ASSERT(HeaderRef(StringRef{":authority"}, StringRef{"1"}) == - *fs.header(http2::HD__AUTHORITY)); - CU_ASSERT(nullptr == fs.header(http2::HD__METHOD)); + assert_true(HeaderRef(StringRef{":authority"}, StringRef{"1"}) == + *fs.header(http2::HD__AUTHORITY)); + assert_null(fs.header(http2::HD__METHOD)); // By name - CU_ASSERT(HeaderRef(StringRef{"alpha"}, StringRef{"0"}) == - *fs.header(StringRef::from_lit("alpha"))); - CU_ASSERT(nullptr == fs.header(StringRef::from_lit("bravo"))); + assert_true(HeaderRef(StringRef{"alpha"}, StringRef{"0"}) == + *fs.header(StringRef::from_lit("alpha"))); + assert_null(fs.header(StringRef::from_lit("bravo"))); } void test_downstream_crumble_request_cookie(void) { @@ -103,8 +120,8 @@ void test_downstream_crumble_request_cookie(void) { auto num_cookies = d.count_crumble_request_cookie(); - CU_ASSERT(5 == nva.size()); - CU_ASSERT(5 == num_cookies); + assert_size(5, ==, nva.size()); + assert_size(5, ==, num_cookies); HeaderRefs cookies; std::transform(std::begin(nva), std::end(nva), std::back_inserter(cookies), @@ -121,10 +138,10 @@ void test_downstream_crumble_request_cookie(void) { {StringRef::from_lit("cookie"), StringRef::from_lit("delta")}, {StringRef::from_lit("cookie"), StringRef::from_lit("echo")}}; - CU_ASSERT(ans == cookies); - CU_ASSERT(cookies[0].no_index); - CU_ASSERT(cookies[1].no_index); - CU_ASSERT(cookies[2].no_index); + assert_true(ans == cookies); + assert_true(cookies[0].no_index); + assert_true(cookies[1].no_index); + assert_true(cookies[2].no_index); } void test_downstream_assemble_request_cookie(void) { @@ -147,7 +164,8 @@ void test_downstream_assemble_request_cookie(void) { req.fs.add_header_token(StringRef::from_lit("cookie"), StringRef::from_lit("delta;;"), false, http2::HD_COOKIE); - CU_ASSERT("alpha; bravo; charlie; delta" == d.assemble_request_cookie()); + assert_stdstring_equal("alpha; bravo; charlie; delta", + d.assemble_request_cookie().str()); } void test_downstream_rewrite_location_response_header(void) { @@ -161,7 +179,7 @@ void test_downstream_rewrite_location_response_header(void) { false, http2::HD_LOCATION); d.rewrite_location_response_header(StringRef::from_lit("https")); auto location = resp.fs.header(http2::HD_LOCATION); - CU_ASSERT("https://localhost:8443/" == (*location).value); + assert_stdstring_equal("https://localhost:8443/", (*location).value.str()); } void test_downstream_supports_non_final_response(void) { @@ -171,27 +189,27 @@ void test_downstream_supports_non_final_response(void) { req.http_major = 3; req.http_minor = 0; - CU_ASSERT(d.supports_non_final_response()); + assert_true(d.supports_non_final_response()); req.http_major = 2; req.http_minor = 0; - CU_ASSERT(d.supports_non_final_response()); + assert_true(d.supports_non_final_response()); req.http_major = 1; req.http_minor = 1; - CU_ASSERT(d.supports_non_final_response()); + assert_true(d.supports_non_final_response()); req.http_major = 1; req.http_minor = 0; - CU_ASSERT(!d.supports_non_final_response()); + assert_false(d.supports_non_final_response()); req.http_major = 0; req.http_minor = 9; - CU_ASSERT(!d.supports_non_final_response()); + assert_false(d.supports_non_final_response()); } void test_downstream_find_affinity_cookie(void) { @@ -217,15 +235,15 @@ void test_downstream_find_affinity_cookie(void) { aff = d.find_affinity_cookie(StringRef::from_lit("lb")); - CU_ASSERT(0xdeadbeef == aff); + assert_uint32(0xdeadbeef, ==, aff); aff = d.find_affinity_cookie(StringRef::from_lit("LB")); - CU_ASSERT(0xf1f2f3f4 == aff); + assert_uint32(0xf1f2f3f4, ==, aff); aff = d.find_affinity_cookie(StringRef::from_lit("short")); - CU_ASSERT(0 == aff); + assert_uint32(0, ==, aff); } } // namespace shrpx diff --git a/src/shrpx_downstream_test.h b/src/shrpx_downstream_test.h index ef06ea3..07adbca 100644 --- a/src/shrpx_downstream_test.h +++ b/src/shrpx_downstream_test.h @@ -29,15 +29,21 @@ # include #endif // HAVE_CONFIG_H +#define MUNIT_ENABLE_ASSERT_ALIASES + +#include "munit.h" + namespace shrpx { -void test_downstream_field_store_append_last_header(void); -void test_downstream_field_store_header(void); -void test_downstream_crumble_request_cookie(void); -void test_downstream_assemble_request_cookie(void); -void test_downstream_rewrite_location_response_header(void); -void test_downstream_supports_non_final_response(void); -void test_downstream_find_affinity_cookie(void); +extern const MunitSuite downstream_suite; + +munit_void_test_decl(test_downstream_field_store_append_last_header); +munit_void_test_decl(test_downstream_field_store_header); +munit_void_test_decl(test_downstream_crumble_request_cookie); +munit_void_test_decl(test_downstream_assemble_request_cookie); +munit_void_test_decl(test_downstream_rewrite_location_response_header); +munit_void_test_decl(test_downstream_supports_non_final_response); +munit_void_test_decl(test_downstream_find_affinity_cookie); } // namespace shrpx diff --git a/src/shrpx_http.cc b/src/shrpx_http.cc index ad32dc9..4750500 100644 --- a/src/shrpx_http.cc +++ b/src/shrpx_http.cc @@ -167,9 +167,9 @@ std::string colorizeHeaders(const char *hdrs) { return nhdrs; } -ssize_t select_padding_callback(nghttp2_session *session, - const nghttp2_frame *frame, size_t max_payload, - void *user_data) { +nghttp2_ssize select_padding_callback(nghttp2_session *session, + const nghttp2_frame *frame, + size_t max_payload, void *user_data) { return std::min(max_payload, frame->hd.length + get_config()->padding); } diff --git a/src/shrpx_http.h b/src/shrpx_http.h index 18935d8..774686c 100644 --- a/src/shrpx_http.h +++ b/src/shrpx_http.h @@ -63,9 +63,9 @@ StringRef create_forwarded(BlockAllocator &balloc, int params, // Adds ANSI color codes to HTTP headers |hdrs|. std::string colorizeHeaders(const char *hdrs); -ssize_t select_padding_callback(nghttp2_session *session, - const nghttp2_frame *frame, size_t max_payload, - void *user_data); +nghttp2_ssize select_padding_callback(nghttp2_session *session, + const nghttp2_frame *frame, + size_t max_payload, void *user_data); // Creates set-cookie-string for cookie based affinity. If |path| is // not empty, "; " is added. If |secure| is true, "; Secure" is diff --git a/src/shrpx_http2_downstream_connection.cc b/src/shrpx_http2_downstream_connection.cc index ee48799..a6c9d53 100644 --- a/src/shrpx_http2_downstream_connection.cc +++ b/src/shrpx_http2_downstream_connection.cc @@ -162,10 +162,11 @@ int Http2DownstreamConnection::submit_rst_stream(Downstream *downstream, } namespace { -ssize_t http2_data_read_callback(nghttp2_session *session, int32_t stream_id, - uint8_t *buf, size_t length, - uint32_t *data_flags, - nghttp2_data_source *source, void *user_data) { +nghttp2_ssize http2_data_read_callback(nghttp2_session *session, + int32_t stream_id, uint8_t *buf, + size_t length, uint32_t *data_flags, + nghttp2_data_source *source, + void *user_data) { int rv; auto sd = static_cast( nghttp2_session_get_stream_user_data(session, stream_id)); @@ -476,8 +477,8 @@ int Http2DownstreamConnection::push_request_headers() { auto transfer_encoding = req.fs.header(http2::HD_TRANSFER_ENCODING); - nghttp2_data_provider *data_prdptr = nullptr; - nghttp2_data_provider data_prd; + nghttp2_data_provider2 *data_prdptr = nullptr; + nghttp2_data_provider2 data_prd; // Add body as long as transfer-encoding is given even if // req.fs.content_length == 0 to forward trailer fields. diff --git a/src/shrpx_http2_session.cc b/src/shrpx_http2_session.cc index f58ed2f..dccdae4 100644 --- a/src/shrpx_http2_session.cc +++ b/src/shrpx_http2_session.cc @@ -755,15 +755,15 @@ void Http2Session::remove_stream_data(StreamData *sd) { int Http2Session::submit_request(Http2DownstreamConnection *dconn, const nghttp2_nv *nva, size_t nvlen, - const nghttp2_data_provider *data_prd) { + const nghttp2_data_provider2 *data_prd) { assert(state_ == Http2SessionState::CONNECTED); auto sd = std::make_unique(); sd->dlnext = sd->dlprev = nullptr; // TODO Specify nullptr to pri_spec for now - auto stream_id = - nghttp2_submit_request(session_, nullptr, nva, nvlen, data_prd, sd.get()); + auto stream_id = nghttp2_submit_request2(session_, nullptr, nva, nvlen, + data_prd, sd.get()); if (stream_id < 0) { - SSLOG(FATAL, this) << "nghttp2_submit_request() failed: " + SSLOG(FATAL, this) << "nghttp2_submit_request2() failed: " << nghttp2_strerror(stream_id); return -1; } @@ -1653,7 +1653,7 @@ nghttp2_session_callbacks *create_http2_downstream_callbacks() { send_data_callback); if (get_config()->padding) { - nghttp2_session_callbacks_set_select_padding_callback( + nghttp2_session_callbacks_set_select_padding_callback2( callbacks, http::select_padding_callback); } @@ -1754,11 +1754,9 @@ int Http2Session::on_read(const uint8_t *data, size_t datalen) { int Http2Session::on_write() { return on_write_(*this); } int Http2Session::downstream_read(const uint8_t *data, size_t datalen) { - ssize_t rv; - - rv = nghttp2_session_mem_recv(session_, data, datalen); + auto rv = nghttp2_session_mem_recv2(session_, data, datalen); if (rv < 0) { - SSLOG(ERROR, this) << "nghttp2_session_mem_recv() returned error: " + SSLOG(ERROR, this) << "nghttp2_session_mem_recv2() returned error: " << nghttp2_strerror(rv); return -1; } @@ -1778,9 +1776,9 @@ int Http2Session::downstream_read(const uint8_t *data, size_t datalen) { int Http2Session::downstream_write() { for (;;) { const uint8_t *data; - auto datalen = nghttp2_session_mem_send(session_, &data); + auto datalen = nghttp2_session_mem_send2(session_, &data); if (datalen < 0) { - SSLOG(ERROR, this) << "nghttp2_session_mem_send() returned error: " + SSLOG(ERROR, this) << "nghttp2_session_mem_send2() returned error: " << nghttp2_strerror(datalen); return -1; } diff --git a/src/shrpx_http2_session.h b/src/shrpx_http2_session.h index 31b2545..1a67a5f 100644 --- a/src/shrpx_http2_session.h +++ b/src/shrpx_http2_session.h @@ -116,7 +116,7 @@ public: void remove_stream_data(StreamData *sd); int submit_request(Http2DownstreamConnection *dconn, const nghttp2_nv *nva, - size_t nvlen, const nghttp2_data_provider *data_prd); + size_t nvlen, const nghttp2_data_provider2 *data_prd); int submit_rst_stream(int32_t stream_id, uint32_t error_code); diff --git a/src/shrpx_http2_upstream.cc b/src/shrpx_http2_upstream.cc index c9f8a8c..2cb5436 100644 --- a/src/shrpx_http2_upstream.cc +++ b/src/shrpx_http2_upstream.cc @@ -717,7 +717,7 @@ int on_frame_send_callback(nghttp2_session *session, const nghttp2_frame *frame, upstream, handler->get_mcpool(), promised_stream_id); auto &req = promised_downstream->request(); - // As long as we use nghttp2_session_mem_send(), setting stream + // As long as we use nghttp2_session_mem_send2(), setting stream // user data here should not fail. This is because this callback // is called just after frame was serialized. So no worries about // hanging Downstream. @@ -995,7 +995,7 @@ nghttp2_session_callbacks *create_http2_upstream_callbacks() { auto config = get_config(); if (config->padding) { - nghttp2_session_callbacks_set_select_padding_callback( + nghttp2_session_callbacks_set_select_padding_callback2( callbacks, http::select_padding_callback); } @@ -1145,21 +1145,20 @@ Http2Upstream::~Http2Upstream() { } int Http2Upstream::on_read() { - ssize_t rv = 0; auto rb = handler_->get_rb(); auto rlimit = handler_->get_rlimit(); if (rb->rleft()) { - rv = nghttp2_session_mem_recv(session_, rb->pos(), rb->rleft()); + auto rv = nghttp2_session_mem_recv2(session_, rb->pos(), rb->rleft()); if (rv < 0) { if (rv != NGHTTP2_ERR_BAD_CLIENT_MAGIC) { - ULOG(ERROR, this) << "nghttp2_session_mem_recv() returned error: " + ULOG(ERROR, this) << "nghttp2_session_mem_recv2() returned error: " << nghttp2_strerror(rv); } return -1; } - // nghttp2_session_mem_recv should consume all input bytes on + // nghttp2_session_mem_recv2 should consume all input bytes on // success. assert(static_cast(rv) == rb->rleft()); rb->reset(); @@ -1221,10 +1220,10 @@ int Http2Upstream::on_write() { } const uint8_t *data; - auto datalen = nghttp2_session_mem_send(session_, &data); + auto datalen = nghttp2_session_mem_send2(session_, &data); if (datalen < 0) { - ULOG(ERROR, this) << "nghttp2_session_mem_send() returned error: " + ULOG(ERROR, this) << "nghttp2_session_mem_send2() returned error: " << nghttp2_strerror(datalen); return -1; } @@ -1436,11 +1435,11 @@ int Http2Upstream::terminate_session(uint32_t error_code) { } namespace { -ssize_t downstream_data_read_callback(nghttp2_session *session, - int32_t stream_id, uint8_t *buf, - size_t length, uint32_t *data_flags, - nghttp2_data_source *source, - void *user_data) { +nghttp2_ssize downstream_data_read_callback(nghttp2_session *session, + int32_t stream_id, uint8_t *buf, + size_t length, uint32_t *data_flags, + nghttp2_data_source *source, + void *user_data) { int rv; auto downstream = static_cast(source->ptr); auto body = downstream->get_response_buf(); @@ -1508,7 +1507,7 @@ int Http2Upstream::send_reply(Downstream *downstream, const uint8_t *body, size_t bodylen) { int rv; - nghttp2_data_provider data_prd, *data_prd_ptr = nullptr; + nghttp2_data_provider2 data_prd, *data_prd_ptr = nullptr; if (bodylen) { data_prd.source.ptr = downstream; @@ -1555,10 +1554,10 @@ int Http2Upstream::send_reply(Downstream *downstream, const uint8_t *body, nva.push_back(http2::make_nv_nocopy(p.name, p.value)); } - rv = nghttp2_submit_response(session_, downstream->get_stream_id(), - nva.data(), nva.size(), data_prd_ptr); + rv = nghttp2_submit_response2(session_, downstream->get_stream_id(), + nva.data(), nva.size(), data_prd_ptr); if (nghttp2_is_fatal(rv)) { - ULOG(FATAL, this) << "nghttp2_submit_response() failed: " + ULOG(FATAL, this) << "nghttp2_submit_response2() failed: " << nghttp2_strerror(rv); return -1; } @@ -1589,7 +1588,7 @@ int Http2Upstream::error_reply(Downstream *downstream, body->append(html); downstream->set_response_state(DownstreamState::MSG_COMPLETE); - nghttp2_data_provider data_prd; + nghttp2_data_provider2 data_prd; data_prd.source.ptr = downstream; data_prd.read_callback = downstream_data_read_callback; @@ -1607,10 +1606,10 @@ int Http2Upstream::error_reply(Downstream *downstream, http2::make_nv_ls_nocopy("content-length", content_length), http2::make_nv_ls_nocopy("date", date)}}; - rv = nghttp2_submit_response(session_, downstream->get_stream_id(), - nva.data(), nva.size(), &data_prd); + rv = nghttp2_submit_response2(session_, downstream->get_stream_id(), + nva.data(), nva.size(), &data_prd); if (rv < NGHTTP2_ERR_FATAL) { - ULOG(FATAL, this) << "nghttp2_submit_response() failed: " + ULOG(FATAL, this) << "nghttp2_submit_response2() failed: " << nghttp2_strerror(rv); return -1; } @@ -1876,11 +1875,11 @@ int Http2Upstream::on_downstream_header_complete(Downstream *downstream) { } } - nghttp2_data_provider data_prd; + nghttp2_data_provider2 data_prd; data_prd.source.ptr = downstream; data_prd.read_callback = downstream_data_read_callback; - nghttp2_data_provider *data_prdptr; + nghttp2_data_provider2 *data_prdptr; if (downstream->expect_response_body() || downstream->expect_response_trailer()) { @@ -1889,10 +1888,10 @@ int Http2Upstream::on_downstream_header_complete(Downstream *downstream) { data_prdptr = nullptr; } - rv = nghttp2_submit_response(session_, downstream->get_stream_id(), - nva.data(), nva.size(), data_prdptr); + rv = nghttp2_submit_response2(session_, downstream->get_stream_id(), + nva.data(), nva.size(), data_prdptr); if (rv != 0) { - ULOG(FATAL, this) << "nghttp2_submit_response() failed"; + ULOG(FATAL, this) << "nghttp2_submit_response2() failed"; return -1; } diff --git a/src/shrpx_http3_upstream.cc b/src/shrpx_http3_upstream.cc index f8ae1ce..b8667a3 100644 --- a/src/shrpx_http3_upstream.cc +++ b/src/shrpx_http3_upstream.cc @@ -213,7 +213,7 @@ int get_new_connection_id(ngtcp2_conn *conn, ngtcp2_cid *cid, uint8_t *token, auto &qkm = qkms->keying_materials.front(); if (generate_quic_connection_id(*cid, cidlen, worker->get_cid_prefix(), - qkm.id, qkm.cid_encryption_key.data()) != 0) { + qkm.id, qkm.cid_encryption_ctx) != 0) { return NGTCP2_ERR_CALLBACK_FAILURE; } @@ -611,7 +611,7 @@ int Http3Upstream::init(const UpstreamAddr *faddr, const Address &remote_addr, if (generate_quic_connection_id(scid, SHRPX_QUIC_SCIDLEN, worker->get_cid_prefix(), qkm.id, - qkm.cid_encryption_key.data()) != 0) { + qkm.cid_encryption_ctx) != 0) { return -1; } @@ -635,7 +635,6 @@ int Http3Upstream::init(const UpstreamAddr *faddr, const Address &remote_addr, settings.cc_algo = quicconf.upstream.congestion_controller; settings.max_window = http3conf.upstream.max_connection_window_size; settings.max_stream_window = http3conf.upstream.max_window_size; - settings.max_tx_udp_payload_size = SHRPX_QUIC_MAX_UDP_PAYLOAD_SIZE; settings.rand_ctx.native_handle = &worker->get_randgen(); settings.token = token; settings.tokenlen = tokenlen; @@ -783,7 +782,9 @@ int Http3Upstream::write_streams() { auto path_max_udp_payload_size = ngtcp2_conn_get_path_max_tx_udp_payload_size(conn_); #endif // UDP_SEGMENT - auto max_pktcnt = ngtcp2_conn_get_send_quantum(conn_) / max_udp_payload_size; + auto max_pktcnt = + std::max(ngtcp2_conn_get_send_quantum(conn_) / max_udp_payload_size, + static_cast(1)); ngtcp2_pkt_info pi, prev_pi; uint8_t *bufpos = tx_.data.get(); ngtcp2_path_storage ps, prev_ps; diff --git a/src/shrpx_http_test.cc b/src/shrpx_http_test.cc index 3ace870..f753ec8 100644 --- a/src/shrpx_http_test.cc +++ b/src/shrpx_http_test.cc @@ -30,7 +30,7 @@ #include -#include +#include "munitxx.h" #include "shrpx_http.h" #include "shrpx_config.h" @@ -38,43 +38,65 @@ namespace shrpx { +namespace { +const MunitTest tests[]{ + munit_void_test(test_shrpx_http_create_forwarded), + munit_void_test(test_shrpx_http_create_via_header_value), + munit_void_test(test_shrpx_http_create_affinity_cookie), + munit_void_test(test_shrpx_http_create_altsvc_header_value), + munit_void_test(test_shrpx_http_check_http_scheme), + munit_test_end(), +}; +} // namespace + +const MunitSuite http_suite{ + "/http", tests, NULL, 1, MUNIT_SUITE_OPTION_NONE, +}; + void test_shrpx_http_create_forwarded(void) { BlockAllocator balloc(1024, 1024); - CU_ASSERT("by=\"example.com:3000\";for=\"[::1]\";host=\"www.example.com\";" - "proto=https" == - http::create_forwarded(balloc, - FORWARDED_BY | FORWARDED_FOR | - FORWARDED_HOST | FORWARDED_PROTO, - StringRef::from_lit("example.com:3000"), - StringRef::from_lit("[::1]"), - StringRef::from_lit("www.example.com"), - StringRef::from_lit("https"))); - - CU_ASSERT("for=192.168.0.1" == - http::create_forwarded( - balloc, FORWARDED_FOR, StringRef::from_lit("alpha"), - StringRef::from_lit("192.168.0.1"), - StringRef::from_lit("bravo"), StringRef::from_lit("charlie"))); - - CU_ASSERT("by=_hidden;for=\"[::1]\"" == - http::create_forwarded( - balloc, FORWARDED_BY | FORWARDED_FOR, - StringRef::from_lit("_hidden"), StringRef::from_lit("[::1]"), - StringRef::from_lit(""), StringRef::from_lit(""))); - - CU_ASSERT("by=\"[::1]\";for=_hidden" == - http::create_forwarded( - balloc, FORWARDED_BY | FORWARDED_FOR, - StringRef::from_lit("[::1]"), StringRef::from_lit("_hidden"), - StringRef::from_lit(""), StringRef::from_lit(""))); - - CU_ASSERT("" == - http::create_forwarded( - balloc, - FORWARDED_BY | FORWARDED_FOR | FORWARDED_HOST | FORWARDED_PROTO, - StringRef::from_lit(""), StringRef::from_lit(""), - StringRef::from_lit(""), StringRef::from_lit(""))); + assert_stdstring_equal( + "by=\"example.com:3000\";for=\"[::1]\";host=\"www.example.com\";" + "proto=https", + http::create_forwarded( + balloc, + FORWARDED_BY | FORWARDED_FOR | FORWARDED_HOST | FORWARDED_PROTO, + StringRef::from_lit("example.com:3000"), StringRef::from_lit("[::1]"), + StringRef::from_lit("www.example.com"), StringRef::from_lit("https")) + .str()); + + assert_stdstring_equal( + "for=192.168.0.1", + http::create_forwarded( + balloc, FORWARDED_FOR, StringRef::from_lit("alpha"), + StringRef::from_lit("192.168.0.1"), StringRef::from_lit("bravo"), + StringRef::from_lit("charlie")) + .str()); + + assert_stdstring_equal( + "by=_hidden;for=\"[::1]\"", + http::create_forwarded(balloc, FORWARDED_BY | FORWARDED_FOR, + StringRef::from_lit("_hidden"), + StringRef::from_lit("[::1]"), + StringRef::from_lit(""), StringRef::from_lit("")) + .str()); + + assert_stdstring_equal( + "by=\"[::1]\";for=_hidden", + http::create_forwarded(balloc, FORWARDED_BY | FORWARDED_FOR, + StringRef::from_lit("[::1]"), + StringRef::from_lit("_hidden"), + StringRef::from_lit(""), StringRef::from_lit("")) + .str()); + + assert_stdstring_equal( + "", http::create_forwarded( + balloc, + FORWARDED_BY | FORWARDED_FOR | FORWARDED_HOST | FORWARDED_PROTO, + StringRef::from_lit(""), StringRef::from_lit(""), + StringRef::from_lit(""), StringRef::from_lit("")) + .str()); } void test_shrpx_http_create_via_header_value(void) { @@ -82,13 +104,13 @@ void test_shrpx_http_create_via_header_value(void) { auto end = http::create_via_header_value(std::begin(buf), 1, 1); - CU_ASSERT(("1.1 nghttpx" == StringRef{std::begin(buf), end})); + assert_stdstring_equal("1.1 nghttpx", (std::string{std::begin(buf), end})); std::fill(std::begin(buf), std::end(buf), '\0'); end = http::create_via_header_value(std::begin(buf), 2, 0); - CU_ASSERT(("2 nghttpx" == StringRef{std::begin(buf), end})); + assert_stdstring_equal("2 nghttpx", (std::string{std::begin(buf), end})); } void test_shrpx_http_create_affinity_cookie(void) { @@ -98,24 +120,24 @@ void test_shrpx_http_create_affinity_cookie(void) { c = http::create_affinity_cookie(balloc, StringRef::from_lit("cookie-val"), 0xf1e2d3c4u, StringRef{}, false); - CU_ASSERT("cookie-val=f1e2d3c4" == c); + assert_stdstring_equal("cookie-val=f1e2d3c4", c.str()); c = http::create_affinity_cookie(balloc, StringRef::from_lit("alpha"), 0x00000000u, StringRef{}, true); - CU_ASSERT("alpha=00000000; Secure" == c); + assert_stdstring_equal("alpha=00000000; Secure", c.str()); c = http::create_affinity_cookie(balloc, StringRef::from_lit("bravo"), 0x01111111u, StringRef::from_lit("bar"), false); - CU_ASSERT("bravo=01111111; Path=bar" == c); + assert_stdstring_equal("bravo=01111111; Path=bar", c.str()); c = http::create_affinity_cookie(balloc, StringRef::from_lit("charlie"), 0x01111111u, StringRef::from_lit("bar"), true); - CU_ASSERT("charlie=01111111; Path=bar; Secure" == c); + assert_stdstring_equal("charlie=01111111; Path=bar; Secure", c.str()); } void test_shrpx_http_create_altsvc_header_value(void) { @@ -130,8 +152,9 @@ void test_shrpx_http_create_altsvc_header_value(void) { }, }; - CU_ASSERT(R"(h3="127.0.0.1:443"; ma=3600)" == - http::create_altsvc_header_value(balloc, altsvcs)); + assert_stdstring_equal( + R"(h3="127.0.0.1:443"; ma=3600)", + http::create_altsvc_header_value(balloc, altsvcs).str()); } { @@ -149,20 +172,21 @@ void test_shrpx_http_create_altsvc_header_value(void) { }, }; - CU_ASSERT(R"(h3=":443"; ma=3600, h3%25="\"foo\":4433")" == - http::create_altsvc_header_value(balloc, altsvcs)); + assert_stdstring_equal( + R"(h3=":443"; ma=3600, h3%25="\"foo\":4433")", + http::create_altsvc_header_value(balloc, altsvcs).str()); } } void test_shrpx_http_check_http_scheme(void) { - CU_ASSERT(http::check_http_scheme(StringRef::from_lit("https"), true)); - CU_ASSERT(!http::check_http_scheme(StringRef::from_lit("https"), false)); - CU_ASSERT(!http::check_http_scheme(StringRef::from_lit("http"), true)); - CU_ASSERT(http::check_http_scheme(StringRef::from_lit("http"), false)); - CU_ASSERT(!http::check_http_scheme(StringRef::from_lit("foo"), true)); - CU_ASSERT(!http::check_http_scheme(StringRef::from_lit("foo"), false)); - CU_ASSERT(!http::check_http_scheme(StringRef{}, true)); - CU_ASSERT(!http::check_http_scheme(StringRef{}, false)); + assert_true(http::check_http_scheme(StringRef::from_lit("https"), true)); + assert_false(http::check_http_scheme(StringRef::from_lit("https"), false)); + assert_false(http::check_http_scheme(StringRef::from_lit("http"), true)); + assert_true(http::check_http_scheme(StringRef::from_lit("http"), false)); + assert_false(http::check_http_scheme(StringRef::from_lit("foo"), true)); + assert_false(http::check_http_scheme(StringRef::from_lit("foo"), false)); + assert_false(http::check_http_scheme(StringRef{}, true)); + assert_false(http::check_http_scheme(StringRef{}, false)); } } // namespace shrpx diff --git a/src/shrpx_http_test.h b/src/shrpx_http_test.h index d50ab53..2abdc20 100644 --- a/src/shrpx_http_test.h +++ b/src/shrpx_http_test.h @@ -29,13 +29,19 @@ # include #endif // HAVE_CONFIG_H +#define MUNIT_ENABLE_ASSERT_ALIASES + +#include "munit.h" + namespace shrpx { -void test_shrpx_http_create_forwarded(void); -void test_shrpx_http_create_via_header_value(void); -void test_shrpx_http_create_affinity_cookie(void); -void test_shrpx_http_create_altsvc_header_value(void); -void test_shrpx_http_check_http_scheme(void); +extern const MunitSuite http_suite; + +munit_void_test_decl(test_shrpx_http_create_forwarded); +munit_void_test_decl(test_shrpx_http_create_via_header_value); +munit_void_test_decl(test_shrpx_http_create_affinity_cookie); +munit_void_test_decl(test_shrpx_http_create_altsvc_header_value); +munit_void_test_decl(test_shrpx_http_check_http_scheme); } // namespace shrpx diff --git a/src/shrpx_live_check.cc b/src/shrpx_live_check.cc index 9b932cd..8e8d316 100644 --- a/src/shrpx_live_check.cc +++ b/src/shrpx_live_check.cc @@ -580,18 +580,16 @@ int LiveCheck::write_clear() { } int LiveCheck::on_read(const uint8_t *data, size_t len) { - ssize_t rv; - - rv = nghttp2_session_mem_recv(session_, data, len); + auto rv = nghttp2_session_mem_recv2(session_, data, len); if (rv < 0) { - LOG(ERROR) << "nghttp2_session_mem_recv() returned error: " + LOG(ERROR) << "nghttp2_session_mem_recv2() returned error: " << nghttp2_strerror(rv); return -1; } if (settings_ack_received_ && !session_closing_) { session_closing_ = true; - rv = nghttp2_session_terminate_session(session_, NGHTTP2_NO_ERROR); + auto rv = nghttp2_session_terminate_session(session_, NGHTTP2_NO_ERROR); if (rv != 0) { return -1; } @@ -619,10 +617,10 @@ int LiveCheck::on_read(const uint8_t *data, size_t len) { int LiveCheck::on_write() { for (;;) { const uint8_t *data; - auto datalen = nghttp2_session_mem_send(session_, &data); + auto datalen = nghttp2_session_mem_send2(session_, &data); if (datalen < 0) { - LOG(ERROR) << "nghttp2_session_mem_send() returned error: " + LOG(ERROR) << "nghttp2_session_mem_send2() returned error: " << nghttp2_strerror(datalen); return -1; } diff --git a/src/shrpx_mruby.cc b/src/shrpx_mruby.cc index b5c6ed3..4d412ef 100644 --- a/src/shrpx_mruby.cc +++ b/src/shrpx_mruby.cc @@ -151,12 +151,12 @@ RProc *compile(mrb_state *mrb, const StringRef &filename) { } auto infile_d = defer(fclose, infile); - auto mrbc = mrbc_context_new(mrb); + auto mrbc = mrb_ccontext_new(mrb); if (mrbc == nullptr) { LOG(ERROR) << "mrb_context_new failed"; return nullptr; } - auto mrbc_d = defer(mrbc_context_free, mrb, mrbc); + auto mrbc_d = defer(mrb_ccontext_free, mrb, mrbc); auto parser = mrb_parse_file(mrb, infile, nullptr); if (parser == nullptr) { diff --git a/src/shrpx_quic.cc b/src/shrpx_quic.cc index 2d4de59..a6d4dfa 100644 --- a/src/shrpx_quic.cc +++ b/src/shrpx_quic.cc @@ -175,7 +175,7 @@ int quic_send_packet(const UpstreamAddr *faddr, const sockaddr *remote_sa, int generate_quic_retry_connection_id(ngtcp2_cid &cid, size_t cidlen, const uint8_t *server_id, uint8_t km_id, - const uint8_t *key) { + EVP_CIPHER_CTX *ctx) { assert(cidlen == SHRPX_QUIC_SCIDLEN); if (RAND_bytes(cid.data, cidlen) != 1) { @@ -190,12 +190,12 @@ int generate_quic_retry_connection_id(ngtcp2_cid &cid, size_t cidlen, std::copy_n(server_id, SHRPX_QUIC_SERVER_IDLEN, p); - return encrypt_quic_connection_id(p, p, key); + return encrypt_quic_connection_id(p, p, ctx); } int generate_quic_connection_id(ngtcp2_cid &cid, size_t cidlen, const uint8_t *cid_prefix, uint8_t km_id, - const uint8_t *key) { + EVP_CIPHER_CTX *ctx) { assert(cidlen == SHRPX_QUIC_SCIDLEN); if (RAND_bytes(cid.data, cidlen) != 1) { @@ -210,20 +210,11 @@ int generate_quic_connection_id(ngtcp2_cid &cid, size_t cidlen, std::copy_n(cid_prefix, SHRPX_QUIC_CID_PREFIXLEN, p); - return encrypt_quic_connection_id(p, p, key); + return encrypt_quic_connection_id(p, p, ctx); } int encrypt_quic_connection_id(uint8_t *dest, const uint8_t *src, - const uint8_t *key) { - auto ctx = EVP_CIPHER_CTX_new(); - auto d = defer(EVP_CIPHER_CTX_free, ctx); - - if (!EVP_EncryptInit_ex(ctx, EVP_aes_128_ecb(), nullptr, key, nullptr)) { - return -1; - } - - EVP_CIPHER_CTX_set_padding(ctx, 0); - + EVP_CIPHER_CTX *ctx) { int len; if (!EVP_EncryptUpdate(ctx, dest, &len, src, SHRPX_QUIC_DECRYPTED_DCIDLEN) || @@ -235,20 +226,11 @@ int encrypt_quic_connection_id(uint8_t *dest, const uint8_t *src, } int decrypt_quic_connection_id(uint8_t *dest, const uint8_t *src, - const uint8_t *key) { - auto ctx = EVP_CIPHER_CTX_new(); - auto d = defer(EVP_CIPHER_CTX_free, ctx); - - if (!EVP_DecryptInit_ex(ctx, EVP_aes_128_ecb(), nullptr, key, nullptr)) { - return -1; - } - - EVP_CIPHER_CTX_set_padding(ctx, 0); - + EVP_CIPHER_CTX *ctx) { int len; - if (!EVP_DecryptUpdate(ctx, dest, &len, src, SHRPX_QUIC_DECRYPTED_DCIDLEN) || - !EVP_DecryptFinal_ex(ctx, dest + len, &len)) { + if (!EVP_EncryptUpdate(ctx, dest, &len, src, SHRPX_QUIC_DECRYPTED_DCIDLEN) || + !EVP_EncryptFinal_ex(ctx, dest + len, &len)) { return -1; } diff --git a/src/shrpx_quic.h b/src/shrpx_quic.h index b2f6087..88388e9 100644 --- a/src/shrpx_quic.h +++ b/src/shrpx_quic.h @@ -31,6 +31,8 @@ #include +#include + #include #include "network.h" @@ -70,7 +72,6 @@ constexpr size_t SHRPX_QUIC_CID_PREFIXLEN = 8; constexpr size_t SHRPX_QUIC_CID_PREFIX_OFFSET = 1; constexpr size_t SHRPX_QUIC_DECRYPTED_DCIDLEN = 16; constexpr size_t SHRPX_QUIC_CID_ENCRYPTION_KEYLEN = 16; -constexpr size_t SHRPX_QUIC_MAX_UDP_PAYLOAD_SIZE = 1472; constexpr size_t SHRPX_QUIC_CONN_CLOSE_PKTLEN = 256; constexpr size_t SHRPX_QUIC_STATELESS_RESET_BURST = 100; constexpr size_t SHRPX_QUIC_SECRET_RESERVEDLEN = 4; @@ -87,17 +88,17 @@ int quic_send_packet(const UpstreamAddr *faddr, const sockaddr *remote_sa, int generate_quic_retry_connection_id(ngtcp2_cid &cid, size_t cidlen, const uint8_t *server_id, uint8_t km_id, - const uint8_t *key); + EVP_CIPHER_CTX *ctx); int generate_quic_connection_id(ngtcp2_cid &cid, size_t cidlen, const uint8_t *cid_prefix, uint8_t km_id, - const uint8_t *key); + EVP_CIPHER_CTX *ctx); int encrypt_quic_connection_id(uint8_t *dest, const uint8_t *src, - const uint8_t *key); + EVP_CIPHER_CTX *ctx); int decrypt_quic_connection_id(uint8_t *dest, const uint8_t *src, - const uint8_t *key); + EVP_CIPHER_CTX *ctx); int generate_quic_hashed_connection_id(ngtcp2_cid &dest, const Address &remote_addr, diff --git a/src/shrpx_quic_connection_handler.cc b/src/shrpx_quic_connection_handler.cc index 6287971..13f710b 100644 --- a/src/shrpx_quic_connection_handler.cc +++ b/src/shrpx_quic_connection_handler.cc @@ -134,7 +134,7 @@ int QUICConnectionHandler::handle_packet(const UpstreamAddr *faddr, if (decrypt_quic_connection_id(decrypted_dcid.data(), vc.dcid + SHRPX_QUIC_CID_PREFIX_OFFSET, - qkm->cid_encryption_key.data()) != 0) { + qkm->cid_encryption_ctx) != 0) { return 0; } @@ -186,7 +186,7 @@ int QUICConnectionHandler::handle_packet(const UpstreamAddr *faddr, if (decrypt_quic_connection_id(decrypted_dcid.data(), vc.dcid + SHRPX_QUIC_CID_PREFIX_OFFSET, - qkm->cid_encryption_key.data()) != 0) { + qkm->cid_encryption_ctx) != 0) { return 0; } } @@ -480,7 +480,7 @@ int QUICConnectionHandler::send_retry( if (generate_quic_retry_connection_id(retry_scid, SHRPX_QUIC_SCIDLEN, quicconf.server_id.data(), qkm.id, - qkm.cid_encryption_key.data()) != 0) { + qkm.cid_encryption_ctx) != 0) { return -1; } diff --git a/src/shrpx_router_test.cc b/src/shrpx_router_test.cc index 21c2f51..a9625a0 100644 --- a/src/shrpx_router_test.cc +++ b/src/shrpx_router_test.cc @@ -24,12 +24,25 @@ */ #include "shrpx_router_test.h" -#include +#include "munitxx.h" #include "shrpx_router.h" namespace shrpx { +namespace { +const MunitTest tests[]{ + munit_void_test(test_shrpx_router_match), + munit_void_test(test_shrpx_router_match_wildcard), + munit_void_test(test_shrpx_router_match_prefix), + munit_test_end(), +}; +} // namespace + +const MunitSuite router_suite{ + "/router", tests, NULL, 1, MUNIT_SUITE_OPTION_NONE, +}; + struct Pattern { StringRef pattern; size_t idx; @@ -61,42 +74,42 @@ void test_shrpx_router_match(void) { idx = router.match(StringRef::from_lit("nghttp2.org"), StringRef::from_lit("/")); - CU_ASSERT(0 == idx); + assert_ssize(0, ==, idx); idx = router.match(StringRef::from_lit("nghttp2.org"), StringRef::from_lit("/alpha")); - CU_ASSERT(1 == idx); + assert_ssize(1, ==, idx); idx = router.match(StringRef::from_lit("nghttp2.org"), StringRef::from_lit("/alpha/")); - CU_ASSERT(2 == idx); + assert_ssize(2, ==, idx); idx = router.match(StringRef::from_lit("nghttp2.org"), StringRef::from_lit("/alpha/charlie")); - CU_ASSERT(2 == idx); + assert_ssize(2, ==, idx); idx = router.match(StringRef::from_lit("nghttp2.org"), StringRef::from_lit("/alpha/bravo/")); - CU_ASSERT(3 == idx); + assert_ssize(3, ==, idx); // matches pattern when last '/' is missing in path idx = router.match(StringRef::from_lit("nghttp2.org"), StringRef::from_lit("/alpha/bravo")); - CU_ASSERT(3 == idx); + assert_ssize(3, ==, idx); idx = router.match(StringRef::from_lit("www2.nghttp2.org"), StringRef::from_lit("/alpha")); - CU_ASSERT(8 == idx); + assert_ssize(8, ==, idx); idx = router.match(StringRef{}, StringRef::from_lit("/alpha")); - CU_ASSERT(5 == idx); + assert_ssize(5, ==, idx); } void test_shrpx_router_match_wildcard(void) { @@ -115,32 +128,41 @@ void test_shrpx_router_match_wildcard(void) { router.add_route(p.pattern, p.idx, p.wildcard); } - CU_ASSERT(0 == router.match(StringRef::from_lit("nghttp2.org"), - StringRef::from_lit("/"))); + assert_ssize(0, ==, + router.match(StringRef::from_lit("nghttp2.org"), + StringRef::from_lit("/"))); - CU_ASSERT(1 == router.match(StringRef::from_lit("nghttp2.org"), - StringRef::from_lit("/a"))); + assert_ssize(1, ==, + router.match(StringRef::from_lit("nghttp2.org"), + StringRef::from_lit("/a"))); - CU_ASSERT(1 == router.match(StringRef::from_lit("nghttp2.org"), - StringRef::from_lit("/charlie"))); + assert_ssize(1, ==, + router.match(StringRef::from_lit("nghttp2.org"), + StringRef::from_lit("/charlie"))); - CU_ASSERT(2 == router.match(StringRef::from_lit("nghttp2.org"), - StringRef::from_lit("/alpha"))); + assert_ssize(2, ==, + router.match(StringRef::from_lit("nghttp2.org"), + StringRef::from_lit("/alpha"))); - CU_ASSERT(2 == router.match(StringRef::from_lit("nghttp2.org"), - StringRef::from_lit("/alpha/"))); + assert_ssize(2, ==, + router.match(StringRef::from_lit("nghttp2.org"), + StringRef::from_lit("/alpha/"))); - CU_ASSERT(3 == router.match(StringRef::from_lit("nghttp2.org"), - StringRef::from_lit("/alpha/b"))); + assert_ssize(3, ==, + router.match(StringRef::from_lit("nghttp2.org"), + StringRef::from_lit("/alpha/b"))); - CU_ASSERT(4 == router.match(StringRef::from_lit("nghttp2.org"), - StringRef::from_lit("/bravo"))); + assert_ssize(4, ==, + router.match(StringRef::from_lit("nghttp2.org"), + StringRef::from_lit("/bravo"))); - CU_ASSERT(5 == router.match(StringRef::from_lit("nghttp2.org"), - StringRef::from_lit("/bravocharlie"))); + assert_ssize(5, ==, + router.match(StringRef::from_lit("nghttp2.org"), + StringRef::from_lit("/bravocharlie"))); - CU_ASSERT(5 == router.match(StringRef::from_lit("nghttp2.org"), - StringRef::from_lit("/bravo/"))); + assert_ssize(5, ==, + router.match(StringRef::from_lit("nghttp2.org"), + StringRef::from_lit("/bravo/"))); } void test_shrpx_router_match_prefix(void) { @@ -166,19 +188,19 @@ void test_shrpx_router_match_prefix(void) { idx = router.match_prefix(&nread, &node, StringRef::from_lit("gro.2ptthgn.gmi.ahpla.ovarb")); - CU_ASSERT(0 == idx); - CU_ASSERT(12 == nread); + assert_ssize(0, ==, idx); + assert_size(12, ==, nread); idx = router.match_prefix(&nread, &node, StringRef::from_lit("gmi.ahpla.ovarb")); - CU_ASSERT(2 == idx); - CU_ASSERT(4 == nread); + assert_ssize(2, ==, idx); + assert_size(4, ==, nread); idx = router.match_prefix(&nread, &node, StringRef::from_lit("ahpla.ovarb")); - CU_ASSERT(3 == idx); - CU_ASSERT(6 == nread); + assert_ssize(3, ==, idx); + assert_ssize(6, ==, nread); } } // namespace shrpx diff --git a/src/shrpx_router_test.h b/src/shrpx_router_test.h index d39cb87..04d4c45 100644 --- a/src/shrpx_router_test.h +++ b/src/shrpx_router_test.h @@ -29,11 +29,17 @@ # include #endif // HAVE_CONFIG_H +#define MUNIT_ENABLE_ASSERT_ALIASES + +#include "munit.h" + namespace shrpx { -void test_shrpx_router_match(void); -void test_shrpx_router_match_wildcard(void); -void test_shrpx_router_match_prefix(void); +extern const MunitSuite router_suite; + +munit_void_test_decl(test_shrpx_router_match); +munit_void_test_decl(test_shrpx_router_match_wildcard); +munit_void_test_decl(test_shrpx_router_match_prefix); } // namespace shrpx diff --git a/src/shrpx_tls.cc b/src/shrpx_tls.cc index aa0c9f2..10bbbf2 100644 --- a/src/shrpx_tls.cc +++ b/src/shrpx_tls.cc @@ -72,6 +72,11 @@ # endif // HAVE_LIBNGTCP2_CRYPTO_BORINGSSL #endif // ENABLE_HTTP3 +#ifdef HAVE_LIBBROTLI +# include +# include +#endif // HAVE_LIBBROTLI + #include "shrpx_log.h" #include "shrpx_client_handler.h" #include "shrpx_config.h" @@ -157,6 +162,35 @@ int ssl_pem_passwd_cb(char *buf, int size, int rwflag, void *user_data) { } } // namespace +namespace { +std::shared_ptr> +get_ocsp_data(TLSContextData *tls_ctx_data) { +#ifdef HAVE_ATOMIC_STD_SHARED_PTR + return std::atomic_load_explicit(&tls_ctx_data->ocsp_data, + std::memory_order_acquire); +#else // !HAVE_ATOMIC_STD_SHARED_PTR + std::lock_guard g(tls_ctx_data->mu); + return tls_ctx_data->ocsp_data; +#endif // !HAVE_ATOMIC_STD_SHARED_PTR +} +} // namespace + +namespace { +void set_ocsp_response(SSL *ssl) { +#ifdef NGHTTP2_OPENSSL_IS_BORINGSSL + auto tls_ctx_data = + static_cast(SSL_CTX_get_app_data(SSL_get_SSL_CTX(ssl))); + auto data = get_ocsp_data(tls_ctx_data); + + if (!data) { + return; + } + + SSL_set_ocsp_response(ssl, data->data(), data->size()); +#endif // NGHTTP2_OPENSSL_IS_BORINGSSL +} +} // namespace + namespace { // *al is set to SSL_AD_UNRECOGNIZED_NAME by openssl, so we don't have // to set it explicitly. @@ -167,12 +201,16 @@ int servername_callback(SSL *ssl, int *al, void *arg) { auto rawhost = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name); if (rawhost == nullptr) { + set_ocsp_response(ssl); + return SSL_TLSEXT_ERR_NOACK; } auto len = strlen(rawhost); // NI_MAXHOST includes terminal NULL. if (len == 0 || len + 1 > NI_MAXHOST) { + set_ocsp_response(ssl); + return SSL_TLSEXT_ERR_NOACK; } @@ -194,6 +232,8 @@ int servername_callback(SSL *ssl, int *al, void *arg) { auto idx = cert_tree->lookup(hostname); if (idx == -1) { + set_ocsp_response(ssl); + return SSL_TLSEXT_ERR_NOACK; } @@ -290,24 +330,13 @@ int servername_callback(SSL *ssl, int *al, void *arg) { SSL_set_SSL_CTX(ssl, ssl_ctx_list[0]); + set_ocsp_response(ssl); + return SSL_TLSEXT_ERR_OK; } } // namespace #ifndef NGHTTP2_OPENSSL_IS_BORINGSSL -namespace { -std::shared_ptr> -get_ocsp_data(TLSContextData *tls_ctx_data) { -# ifdef HAVE_ATOMIC_STD_SHARED_PTR - return std::atomic_load_explicit(&tls_ctx_data->ocsp_data, - std::memory_order_acquire); -# else // !HAVE_ATOMIC_STD_SHARED_PTR - std::lock_guard g(tls_ctx_data->mu); - return tls_ctx_data->ocsp_data; -# endif // !HAVE_ATOMIC_STD_SHARED_PTR -} -} // namespace - namespace { int ocsp_resp_cb(SSL *ssl, void *arg) { auto ssl_ctx = SSL_get_SSL_CTX(ssl); @@ -817,6 +846,83 @@ unsigned int psk_client_cb(SSL *ssl, const char *hint, char *identity_out, } // namespace #endif // !OPENSSL_NO_PSK +#if defined(NGHTTP2_OPENSSL_IS_BORINGSSL) && defined(HAVE_LIBBROTLI) +namespace { +int cert_compress(SSL *ssl, CBB *out, const uint8_t *in, size_t in_len) { + uint8_t *dest; + + size_t compressed_size = BrotliEncoderMaxCompressedSize(in_len); + if (compressed_size == 0) { + LOG(ERROR) << "BrotliEncoderMaxCompressedSize failed"; + + return 0; + } + + if (LOG_ENABLED(INFO)) { + LOG(INFO) << "Maximum compressed size is " << compressed_size + << " bytes against input " << in_len << " bytes"; + } + + if (!CBB_reserve(out, &dest, compressed_size)) { + LOG(ERROR) << "CBB_reserve failed"; + + return 0; + } + + if (BrotliEncoderCompress(BROTLI_MAX_QUALITY, BROTLI_DEFAULT_WINDOW, + BROTLI_MODE_GENERIC, in_len, in, &compressed_size, + dest) != BROTLI_TRUE) { + LOG(ERROR) << "BrotliEncoderCompress failed"; + + return 0; + } + + if (LOG_ENABLED(INFO)) { + LOG(INFO) << "BrotliEncoderCompress succeeded, produced " << compressed_size + << " bytes, " << (in_len - compressed_size) * 100 / in_len + << "% reduction"; + } + + if (!CBB_did_write(out, compressed_size)) { + LOG(ERROR) << "CBB_did_write failed"; + + return 0; + } + + return 1; +} + +int cert_decompress(SSL *ssl, CRYPTO_BUFFER **out, size_t uncompressed_len, + const uint8_t *in, size_t in_len) { + uint8_t *dest; + auto buf = CRYPTO_BUFFER_alloc(&dest, uncompressed_len); + auto len = uncompressed_len; + + if (BrotliDecoderDecompress(in_len, in, &len, dest) != + BROTLI_DECODER_RESULT_SUCCESS) { + LOG(ERROR) << "BrotliDecoderDecompress failed"; + + CRYPTO_BUFFER_free(buf); + + return 0; + } + + if (uncompressed_len != len) { + LOG(ERROR) << "Unexpected uncompressed length: expected " + << uncompressed_len << " bytes, actual " << len << " bytes"; + + CRYPTO_BUFFER_free(buf); + + return 0; + } + + *out = buf; + + return 1; +} +} // namespace +#endif // NGHTTP2_OPENSSL_IS_BORINGSSL && HAVE_LIBBROTLI + struct TLSProtocol { StringRef name; long int mask; @@ -1110,6 +1216,15 @@ SSL_CTX *create_ssl_context(const char *private_key_file, const char *cert_file, SSL_CTX_set_psk_server_callback(ssl_ctx, psk_server_cb); #endif // !LIBRESSL_NO_PSK +#if defined(NGHTTP2_OPENSSL_IS_BORINGSSL) && defined(HAVE_LIBBROTLI) + if (!SSL_CTX_add_cert_compression_alg( + ssl_ctx, nghttp2::tls::CERTIFICATE_COMPRESSION_ALGO_BROTLI, + cert_compress, cert_decompress)) { + LOG(FATAL) << "SSL_CTX_add_cert_compression_alg failed"; + DIE(); + } +#endif // NGHTTP2_OPENSSL_IS_BORINGSSL && HAVE_LIBBROTLI + return ssl_ctx; } @@ -1369,6 +1484,15 @@ SSL_CTX *create_quic_ssl_context(const char *private_key_file, SSL_CTX_set_psk_server_callback(ssl_ctx, psk_server_cb); # endif // !LIBRESSL_NO_PSK +# if defined(NGHTTP2_OPENSSL_IS_BORINGSSL) && defined(HAVE_LIBBROTLI) + if (!SSL_CTX_add_cert_compression_alg( + ssl_ctx, nghttp2::tls::CERTIFICATE_COMPRESSION_ALGO_BROTLI, + cert_compress, cert_decompress)) { + LOG(FATAL) << "SSL_CTX_add_cert_compression_alg failed"; + DIE(); + } +# endif // NGHTTP2_OPENSSL_IS_BORINGSSL && HAVE_LIBBROTLI + return ssl_ctx; } #endif // ENABLE_HTTP3 @@ -1478,6 +1602,15 @@ SSL_CTX *create_ssl_client_context( SSL_CTX_set_psk_client_callback(ssl_ctx, psk_client_cb); #endif // !OPENSSL_NO_PSK +#if defined(NGHTTP2_OPENSSL_IS_BORINGSSL) && defined(HAVE_LIBBROTLI) + if (!SSL_CTX_add_cert_compression_alg( + ssl_ctx, nghttp2::tls::CERTIFICATE_COMPRESSION_ALGO_BROTLI, + cert_compress, cert_decompress)) { + LOG(FATAL) << "SSL_CTX_add_cert_compression_alg failed"; + DIE(); + } +#endif // NGHTTP2_OPENSSL_IS_BORINGSSL && HAVE_LIBBROTLI + return ssl_ctx; } diff --git a/src/shrpx_tls_test.cc b/src/shrpx_tls_test.cc index 02fb168..04d16da 100644 --- a/src/shrpx_tls_test.cc +++ b/src/shrpx_tls_test.cc @@ -24,7 +24,7 @@ */ #include "shrpx_tls_test.h" -#include +#include "munitxx.h" #include "shrpx_tls.h" #include "shrpx_log.h" @@ -35,6 +35,21 @@ using namespace nghttp2; namespace shrpx { +namespace { +const MunitTest tests[]{ + munit_void_test(test_shrpx_tls_create_lookup_tree), + munit_void_test(test_shrpx_tls_cert_lookup_tree_add_ssl_ctx), + munit_void_test(test_shrpx_tls_tls_hostname_match), + munit_void_test(test_shrpx_tls_verify_numeric_hostname), + munit_void_test(test_shrpx_tls_verify_dns_hostname), + munit_test_end(), +}; +} // namespace + +const MunitSuite tls_suite{ + "/tls", tests, NULL, 1, MUNIT_SUITE_OPTION_NONE, +}; + void test_shrpx_tls_create_lookup_tree(void) { auto tree = std::make_unique(); @@ -58,24 +73,24 @@ void test_shrpx_tls_create_lookup_tree(void) { tree->dump(); - CU_ASSERT(0 == tree->lookup(hostnames[0])); - CU_ASSERT(1 == tree->lookup(hostnames[1])); - CU_ASSERT(2 == tree->lookup(StringRef::from_lit("2www.example.org"))); - CU_ASSERT(-1 == tree->lookup(StringRef::from_lit("www2.example.org"))); - CU_ASSERT(3 == tree->lookup(StringRef::from_lit("xy1.host.domain"))); + assert_ssize(0, ==, tree->lookup(hostnames[0])); + assert_ssize(1, ==, tree->lookup(hostnames[1])); + assert_ssize(2, ==, tree->lookup(StringRef::from_lit("2www.example.org"))); + assert_ssize(-1, ==, tree->lookup(StringRef::from_lit("www2.example.org"))); + assert_ssize(3, ==, tree->lookup(StringRef::from_lit("xy1.host.domain"))); // Does not match *yy.host.domain, because * must match at least 1 // character. - CU_ASSERT(-1 == tree->lookup(StringRef::from_lit("yy.host.domain"))); - CU_ASSERT(4 == tree->lookup(StringRef::from_lit("xyy.host.domain"))); - CU_ASSERT(-1 == tree->lookup(StringRef{})); - CU_ASSERT(5 == tree->lookup(hostnames[5])); - CU_ASSERT(6 == tree->lookup(hostnames[6])); + assert_ssize(-1, ==, tree->lookup(StringRef::from_lit("yy.host.domain"))); + assert_ssize(4, ==, tree->lookup(StringRef::from_lit("xyy.host.domain"))); + assert_ssize(-1, ==, tree->lookup(StringRef{})); + assert_ssize(5, ==, tree->lookup(hostnames[5])); + assert_ssize(6, ==, tree->lookup(hostnames[6])); static constexpr char h6[] = "pdylay.sourceforge.net"; for (int i = 0; i < 7; ++i) { - CU_ASSERT(-1 == tree->lookup(StringRef{h6 + i, str_size(h6) - i})); + assert_ssize(-1, ==, tree->lookup(StringRef{h6 + i, str_size(h6) - i})); } - CU_ASSERT(8 == tree->lookup(StringRef::from_lit("x.foo.bar"))); - CU_ASSERT(9 == tree->lookup(hostnames[9])); + assert_ssize(8, ==, tree->lookup(StringRef::from_lit("x.foo.bar"))); + assert_ssize(9, ==, tree->lookup(hostnames[9])); constexpr StringRef names[] = { StringRef::from_lit("rab"), // 1 @@ -90,7 +105,7 @@ void test_shrpx_tls_create_lookup_tree(void) { tree->add_cert(names[idx], idx); } for (size_t i = 0; i < num; ++i) { - CU_ASSERT((ssize_t)i == tree->lookup(names[i])); + assert_ssize((ssize_t)i, ==, tree->lookup(names[i])); } } @@ -128,7 +143,7 @@ void test_shrpx_tls_cert_lookup_tree_add_ssl_ctx(void) { SSL_CTX_set_app_data(nghttp2_ssl_ctx, nghttp2_tls_ctx_data.get()); rv = SSL_CTX_use_certificate_chain_file(nghttp2_ssl_ctx, nghttp2_certfile); - CU_ASSERT(1 == rv); + assert_int(1, ==, rv); static constexpr char examples_certfile[] = NGHTTP2_SRC_DIR "/test.example.com.pem"; @@ -139,7 +154,7 @@ void test_shrpx_tls_cert_lookup_tree_add_ssl_ctx(void) { SSL_CTX_set_app_data(examples_ssl_ctx, examples_tls_ctx_data.get()); rv = SSL_CTX_use_certificate_chain_file(examples_ssl_ctx, examples_certfile); - CU_ASSERT(1 == rv); + assert_int(1, ==, rv); tls::CertLookupTree tree; std::vector> indexed_ssl_ctx; @@ -147,18 +162,19 @@ void test_shrpx_tls_cert_lookup_tree_add_ssl_ctx(void) { rv = tls::cert_lookup_tree_add_ssl_ctx(&tree, indexed_ssl_ctx, nghttp2_ssl_ctx); - CU_ASSERT(0 == rv); + assert_int(0, ==, rv); rv = tls::cert_lookup_tree_add_ssl_ctx(&tree, indexed_ssl_ctx, examples_ssl_ctx); - CU_ASSERT(0 == rv); + assert_int(0, ==, rv); - CU_ASSERT(-1 == tree.lookup(StringRef::from_lit("not-used.nghttp2.org"))); - CU_ASSERT(0 == tree.lookup(StringRef::from_lit("test.nghttp2.org"))); - CU_ASSERT(1 == tree.lookup(StringRef::from_lit("w.test.nghttp2.org"))); - CU_ASSERT(2 == tree.lookup(StringRef::from_lit("www.test.nghttp2.org"))); - CU_ASSERT(3 == tree.lookup(StringRef::from_lit("test.example.com"))); + assert_ssize(-1, ==, + tree.lookup(StringRef::from_lit("not-used.nghttp2.org"))); + assert_ssize(0, ==, tree.lookup(StringRef::from_lit("test.nghttp2.org"))); + assert_ssize(1, ==, tree.lookup(StringRef::from_lit("w.test.nghttp2.org"))); + assert_ssize(2, ==, tree.lookup(StringRef::from_lit("www.test.nghttp2.org"))); + assert_ssize(3, ==, tree.lookup(StringRef::from_lit("test.example.com"))); } template @@ -168,30 +184,32 @@ bool tls_hostname_match_wrapper(const char (&pattern)[N], } void test_shrpx_tls_tls_hostname_match(void) { - CU_ASSERT(tls_hostname_match_wrapper("example.com", "example.com")); - CU_ASSERT(tls_hostname_match_wrapper("example.com", "EXAMPLE.com")); + assert_true(tls_hostname_match_wrapper("example.com", "example.com")); + assert_true(tls_hostname_match_wrapper("example.com", "EXAMPLE.com")); // check wildcard - CU_ASSERT(tls_hostname_match_wrapper("*.example.com", "www.example.com")); - CU_ASSERT(tls_hostname_match_wrapper("*w.example.com", "www.example.com")); - CU_ASSERT(tls_hostname_match_wrapper("www*.example.com", "www1.example.com")); - CU_ASSERT( + assert_true(tls_hostname_match_wrapper("*.example.com", "www.example.com")); + assert_true(tls_hostname_match_wrapper("*w.example.com", "www.example.com")); + assert_true( + tls_hostname_match_wrapper("www*.example.com", "www1.example.com")); + assert_true( tls_hostname_match_wrapper("www*.example.com", "WWW12.EXAMPLE.com")); // at least 2 dots are required after '*' - CU_ASSERT(!tls_hostname_match_wrapper("*.com", "example.com")); - CU_ASSERT(!tls_hostname_match_wrapper("*", "example.com")); + assert_false(tls_hostname_match_wrapper("*.com", "example.com")); + assert_false(tls_hostname_match_wrapper("*", "example.com")); // '*' must be in left most label - CU_ASSERT( - !tls_hostname_match_wrapper("blog.*.example.com", "blog.my.example.com")); + assert_false( + tls_hostname_match_wrapper("blog.*.example.com", "blog.my.example.com")); // prefix is wrong - CU_ASSERT( - !tls_hostname_match_wrapper("client*.example.com", "server.example.com")); + assert_false( + tls_hostname_match_wrapper("client*.example.com", "server.example.com")); // '*' must match at least one character - CU_ASSERT(!tls_hostname_match_wrapper("www*.example.com", "www.example.com")); + assert_false( + tls_hostname_match_wrapper("www*.example.com", "www.example.com")); - CU_ASSERT(!tls_hostname_match_wrapper("example.com", "nghttp2.org")); - CU_ASSERT(!tls_hostname_match_wrapper("www.example.com", "example.com")); - CU_ASSERT(!tls_hostname_match_wrapper("example.com", "www.example.com")); + assert_false(tls_hostname_match_wrapper("example.com", "nghttp2.org")); + assert_false(tls_hostname_match_wrapper("www.example.com", "example.com")); + assert_false(tls_hostname_match_wrapper("example.com", "www.example.com")); } static X509 *load_cert(const char *path) { @@ -207,14 +225,17 @@ static Address parse_addr(const char *ipaddr) { addrinfo hints{}; hints.ai_family = AF_UNSPEC; - hints.ai_flags = AI_NUMERICHOST | AI_NUMERICSERV; + hints.ai_flags = AI_NUMERICHOST; +#ifdef AI_NUMERICSERV + hints.ai_flags |= AI_NUMERICSERV; +#endif addrinfo *res = nullptr; auto rv = getaddrinfo(ipaddr, "443", &hints, &res); - CU_ASSERT(0 == rv); - CU_ASSERT(nullptr != res); + assert_int(0, ==, rv); + assert_not_null(res); Address addr; addr.len = res->ai_addrlen; @@ -234,7 +255,7 @@ void test_shrpx_tls_verify_numeric_hostname(void) { auto rv = tls::verify_numeric_hostname(cert, StringRef::from_lit(ipaddr), &addr); - CU_ASSERT(0 == rv); + assert_int(0, ==, rv); X509_free(cert); } @@ -247,7 +268,7 @@ void test_shrpx_tls_verify_numeric_hostname(void) { auto rv = tls::verify_numeric_hostname(cert, StringRef::from_lit(ipaddr), &addr); - CU_ASSERT(0 == rv); + assert_int(0, ==, rv); X509_free(cert); } @@ -260,7 +281,7 @@ void test_shrpx_tls_verify_numeric_hostname(void) { auto rv = tls::verify_numeric_hostname(cert, StringRef::from_lit(ipaddr), &addr); - CU_ASSERT(-1 == rv); + assert_int(-1, ==, rv); X509_free(cert); } @@ -273,7 +294,7 @@ void test_shrpx_tls_verify_numeric_hostname(void) { auto rv = tls::verify_numeric_hostname(cert, StringRef::from_lit(ipaddr), &addr); - CU_ASSERT(-1 == rv); + assert_int(-1, ==, rv); X509_free(cert); } @@ -286,7 +307,7 @@ void test_shrpx_tls_verify_numeric_hostname(void) { auto rv = tls::verify_numeric_hostname(cert, StringRef::from_lit(ipaddr), &addr); - CU_ASSERT(0 == rv); + assert_int(0, ==, rv); X509_free(cert); } @@ -299,7 +320,7 @@ void test_shrpx_tls_verify_dns_hostname(void) { auto rv = tls::verify_dns_hostname( cert, StringRef::from_lit("nghttp2.example.com")); - CU_ASSERT(0 == rv); + assert_int(0, ==, rv); X509_free(cert); } @@ -310,7 +331,7 @@ void test_shrpx_tls_verify_dns_hostname(void) { auto rv = tls::verify_dns_hostname( cert, StringRef::from_lit("www.nghttp2.example.com")); - CU_ASSERT(0 == rv); + assert_int(0, ==, rv); X509_free(cert); } @@ -320,7 +341,7 @@ void test_shrpx_tls_verify_dns_hostname(void) { auto cert = load_cert(NGHTTP2_SRC_DIR "/testdata/verify_hostname.crt"); auto rv = tls::verify_dns_hostname(cert, StringRef::from_lit("localhost")); - CU_ASSERT(-1 == rv); + assert_int(-1, ==, rv); X509_free(cert); } @@ -330,7 +351,7 @@ void test_shrpx_tls_verify_dns_hostname(void) { auto cert = load_cert(NGHTTP2_SRC_DIR "/testdata/nosan.crt"); auto rv = tls::verify_dns_hostname(cert, StringRef::from_lit("localhost")); - CU_ASSERT(0 == rv); + assert_int(0, ==, rv); X509_free(cert); } diff --git a/src/shrpx_tls_test.h b/src/shrpx_tls_test.h index 7edc742..3334b23 100644 --- a/src/shrpx_tls_test.h +++ b/src/shrpx_tls_test.h @@ -29,13 +29,19 @@ # include #endif // HAVE_CONFIG_H +#define MUNIT_ENABLE_ASSERT_ALIASES + +#include "munit.h" + namespace shrpx { -void test_shrpx_tls_create_lookup_tree(void); -void test_shrpx_tls_cert_lookup_tree_add_ssl_ctx(void); -void test_shrpx_tls_tls_hostname_match(void); -void test_shrpx_tls_verify_numeric_hostname(void); -void test_shrpx_tls_verify_dns_hostname(void); +extern const MunitSuite tls_suite; + +munit_void_test_decl(test_shrpx_tls_create_lookup_tree); +munit_void_test_decl(test_shrpx_tls_cert_lookup_tree_add_ssl_ctx); +munit_void_test_decl(test_shrpx_tls_tls_hostname_match); +munit_void_test_decl(test_shrpx_tls_verify_numeric_hostname); +munit_void_test_decl(test_shrpx_tls_verify_dns_hostname); } // namespace shrpx diff --git a/src/shrpx_worker.cc b/src/shrpx_worker.cc index 4c069db..e7d6740 100644 --- a/src/shrpx_worker.cc +++ b/src/shrpx_worker.cc @@ -731,6 +731,119 @@ int Worker::setup_quic_server_socket() { return 0; } +# ifdef HAVE_LIBBPF +namespace { +// https://github.com/kokke/tiny-AES-c +// +// License is Public Domain. +// Commit hash: 12e7744b4919e9d55de75b7ab566326a1c8e7a67 + +// The number of columns comprising a state in AES. This is a constant +// in AES. Value=4 +# define Nb 4 + +# define Nk 4 // The number of 32 bit words in a key. +# define Nr 10 // The number of rounds in AES Cipher. + +// The lookup-tables are marked const so they can be placed in +// read-only storage instead of RAM The numbers below can be computed +// dynamically trading ROM for RAM - This can be useful in (embedded) +// bootloader applications, where ROM is often limited. +const uint8_t sbox[256] = { + // 0 1 2 3 4 5 6 7 8 9 A B C D E F + 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, + 0xfe, 0xd7, 0xab, 0x76, 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, + 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, 0xb7, 0xfd, 0x93, 0x26, + 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, + 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, + 0xeb, 0x27, 0xb2, 0x75, 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, + 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, 0x53, 0xd1, 0x00, 0xed, + 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, + 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, + 0x50, 0x3c, 0x9f, 0xa8, 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, + 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, 0xcd, 0x0c, 0x13, 0xec, + 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73, + 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, + 0xde, 0x5e, 0x0b, 0xdb, 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, + 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, 0xe7, 0xc8, 0x37, 0x6d, + 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, + 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, + 0x4b, 0xbd, 0x8b, 0x8a, 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, + 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, 0xe1, 0xf8, 0x98, 0x11, + 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, + 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, + 0xb0, 0x54, 0xbb, 0x16}; + +# define getSBoxValue(num) (sbox[(num)]) + +// The round constant word array, Rcon[i], contains the values given +// by x to the power (i-1) being powers of x (x is denoted as {02}) in +// the field GF(2^8) +const uint8_t Rcon[11] = {0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, + 0x20, 0x40, 0x80, 0x1b, 0x36}; + +// This function produces Nb(Nr+1) round keys. The round keys are used +// in each round to decrypt the states. +void KeyExpansion(uint8_t *RoundKey, const uint8_t *Key) { + unsigned i, j, k; + uint8_t tempa[4]; // Used for the column/row operations + + // The first round key is the key itself. + for (i = 0; i < Nk; ++i) { + RoundKey[(i * 4) + 0] = Key[(i * 4) + 0]; + RoundKey[(i * 4) + 1] = Key[(i * 4) + 1]; + RoundKey[(i * 4) + 2] = Key[(i * 4) + 2]; + RoundKey[(i * 4) + 3] = Key[(i * 4) + 3]; + } + + // All other round keys are found from the previous round keys. + for (i = Nk; i < Nb * (Nr + 1); ++i) { + { + k = (i - 1) * 4; + tempa[0] = RoundKey[k + 0]; + tempa[1] = RoundKey[k + 1]; + tempa[2] = RoundKey[k + 2]; + tempa[3] = RoundKey[k + 3]; + } + + if (i % Nk == 0) { + // This function shifts the 4 bytes in a word to the left once. + // [a0,a1,a2,a3] becomes [a1,a2,a3,a0] + + // Function RotWord() + { + const uint8_t u8tmp = tempa[0]; + tempa[0] = tempa[1]; + tempa[1] = tempa[2]; + tempa[2] = tempa[3]; + tempa[3] = u8tmp; + } + + // SubWord() is a function that takes a four-byte input word and + // applies the S-box to each of the four bytes to produce an + // output word. + + // Function Subword() + { + tempa[0] = getSBoxValue(tempa[0]); + tempa[1] = getSBoxValue(tempa[1]); + tempa[2] = getSBoxValue(tempa[2]); + tempa[3] = getSBoxValue(tempa[3]); + } + + tempa[0] = tempa[0] ^ Rcon[i / Nk]; + } + j = i * 4; + k = (i - Nk) * 4; + RoundKey[j + 0] = RoundKey[k + 0] ^ tempa[0]; + RoundKey[j + 1] = RoundKey[k + 1] ^ tempa[1]; + RoundKey[j + 2] = RoundKey[k + 2] ^ tempa[2]; + RoundKey[j + 3] = RoundKey[k + 3] ^ tempa[3]; + } +} +} // namespace +# endif // HAVE_LIBBPF + int Worker::create_quic_server_socket(UpstreamAddr &faddr) { std::array errbuf; int fd = -1; @@ -989,30 +1102,29 @@ int Worker::create_quic_server_socket(UpstreamAddr &faddr) { return -1; } - constexpr uint32_t key_high_idx = 1; - constexpr uint32_t key_low_idx = 2; - auto &qkms = conn_handler_->get_quic_keying_materials(); auto &qkm = qkms->keying_materials.front(); - rv = bpf_map__update_elem(sk_info, &key_high_idx, sizeof(key_high_idx), - qkm.cid_encryption_key.data(), - qkm.cid_encryption_key.size() / 2, BPF_ANY); - if (rv != 0) { + auto aes_key = bpf_object__find_map_by_name(obj, "aes_key"); + if (!aes_key) { auto error = errno; - LOG(FATAL) << "Failed to update key_high_idx sk_info: " + LOG(FATAL) << "Failed to get aes_key: " << xsi_strerror(error, errbuf.data(), errbuf.size()); close(fd); return -1; } - rv = bpf_map__update_elem(sk_info, &key_low_idx, sizeof(key_low_idx), - qkm.cid_encryption_key.data() + - qkm.cid_encryption_key.size() / 2, - qkm.cid_encryption_key.size() / 2, BPF_ANY); + constexpr size_t expanded_aes_keylen = 176; + std::array aes_exp_key; + + KeyExpansion(aes_exp_key.data(), qkm.cid_encryption_key.data()); + + rv = + bpf_map__update_elem(aes_key, &zero, sizeof(zero), aes_exp_key.data(), + aes_exp_key.size(), BPF_ANY); if (rv != 0) { auto error = errno; - LOG(FATAL) << "Failed to update key_low_idx sk_info: " + LOG(FATAL) << "Failed to update aes_key: " << xsi_strerror(error, errbuf.data(), errbuf.size()); close(fd); return -1; diff --git a/src/shrpx_worker_process.cc b/src/shrpx_worker_process.cc index 05eac02..e3f7dae 100644 --- a/src/shrpx_worker_process.cc +++ b/src/shrpx_worker_process.cc @@ -583,6 +583,16 @@ int worker_process_event_loop(WorkerProcessConfig *wpconf) { LOG(ERROR) << "Failed to generate QUIC Connection ID encryption key"; return -1; } + + qkm.cid_encryption_ctx = EVP_CIPHER_CTX_new(); + if (!EVP_EncryptInit_ex(qkm.cid_encryption_ctx, EVP_aes_128_ecb(), nullptr, + qkm.cid_encryption_key.data(), nullptr)) { + LOG(ERROR) + << "Failed to initialize QUIC Connection ID encryption context"; + return -1; + } + + EVP_CIPHER_CTX_set_padding(qkm.cid_encryption_ctx, 0); } conn_handler->set_quic_keying_materials(std::move(qkms)); diff --git a/src/shrpx_worker_test.cc b/src/shrpx_worker_test.cc index 7c5c329..4b4b7a6 100644 --- a/src/shrpx_worker_test.cc +++ b/src/shrpx_worker_test.cc @@ -30,7 +30,7 @@ #include -#include +#include "munitxx.h" #include "shrpx_worker.h" #include "shrpx_connect_blocker.h" @@ -38,6 +38,17 @@ namespace shrpx { +namespace { +const MunitTest tests[]{ + munit_void_test(test_shrpx_worker_match_downstream_addr_group), + munit_test_end(), +}; +} // namespace + +const MunitSuite worker_suite{ + "/worker", tests, NULL, 1, MUNIT_SUITE_OPTION_NONE, +}; + void test_shrpx_worker_match_downstream_addr_group(void) { auto groups = std::vector>(); for (auto &s : {"nghttp2.org/", "nghttp2.org/alpha/bravo/", @@ -62,131 +73,155 @@ void test_shrpx_worker_match_downstream_addr_group(void) { router.add_route(StringRef{g->pattern}, i); } - CU_ASSERT(0 == match_downstream_addr_group( - routerconf, StringRef::from_lit("nghttp2.org"), - StringRef::from_lit("/"), groups, 255, balloc)); + assert_size(0, ==, + match_downstream_addr_group( + routerconf, StringRef::from_lit("nghttp2.org"), + StringRef::from_lit("/"), groups, 255, balloc)); // port is removed - CU_ASSERT(0 == match_downstream_addr_group( - routerconf, StringRef::from_lit("nghttp2.org:8080"), - StringRef::from_lit("/"), groups, 255, balloc)); + assert_size(0, ==, + match_downstream_addr_group( + routerconf, StringRef::from_lit("nghttp2.org:8080"), + StringRef::from_lit("/"), groups, 255, balloc)); // host is case-insensitive - CU_ASSERT(4 == match_downstream_addr_group( - routerconf, StringRef::from_lit("WWW.nghttp2.org"), - StringRef::from_lit("/alpha"), groups, 255, balloc)); + assert_size(4, ==, + match_downstream_addr_group( + routerconf, StringRef::from_lit("WWW.nghttp2.org"), + StringRef::from_lit("/alpha"), groups, 255, balloc)); - CU_ASSERT(1 == match_downstream_addr_group( - routerconf, StringRef::from_lit("nghttp2.org"), - StringRef::from_lit("/alpha/bravo/"), groups, 255, - balloc)); + assert_size(1, ==, + match_downstream_addr_group( + routerconf, StringRef::from_lit("nghttp2.org"), + StringRef::from_lit("/alpha/bravo/"), groups, 255, balloc)); // /alpha/bravo also matches /alpha/bravo/ - CU_ASSERT(1 == match_downstream_addr_group( - routerconf, StringRef::from_lit("nghttp2.org"), - StringRef::from_lit("/alpha/bravo"), groups, 255, balloc)); + assert_size(1, ==, + match_downstream_addr_group( + routerconf, StringRef::from_lit("nghttp2.org"), + StringRef::from_lit("/alpha/bravo"), groups, 255, balloc)); // path part is case-sensitive - CU_ASSERT(0 == match_downstream_addr_group( - routerconf, StringRef::from_lit("nghttp2.org"), - StringRef::from_lit("/Alpha/bravo"), groups, 255, balloc)); - - CU_ASSERT(1 == match_downstream_addr_group( - routerconf, StringRef::from_lit("nghttp2.org"), - StringRef::from_lit("/alpha/bravo/charlie"), groups, 255, - balloc)); - - CU_ASSERT(2 == match_downstream_addr_group( - routerconf, StringRef::from_lit("nghttp2.org"), - StringRef::from_lit("/alpha/charlie"), groups, 255, - balloc)); + assert_size(0, ==, + match_downstream_addr_group( + routerconf, StringRef::from_lit("nghttp2.org"), + StringRef::from_lit("/Alpha/bravo"), groups, 255, balloc)); + + assert_size(1, ==, + match_downstream_addr_group( + routerconf, StringRef::from_lit("nghttp2.org"), + StringRef::from_lit("/alpha/bravo/charlie"), groups, 255, + balloc)); + + assert_size(2, ==, + match_downstream_addr_group( + routerconf, StringRef::from_lit("nghttp2.org"), + StringRef::from_lit("/alpha/charlie"), groups, 255, balloc)); // pattern which does not end with '/' must match its entirely. So // this matches to group 0, not group 2. - CU_ASSERT(0 == match_downstream_addr_group( - routerconf, StringRef::from_lit("nghttp2.org"), - StringRef::from_lit("/alpha/charlie/"), groups, 255, - balloc)); - - CU_ASSERT(255 == match_downstream_addr_group( - routerconf, StringRef::from_lit("example.org"), - StringRef::from_lit("/"), groups, 255, balloc)); - - CU_ASSERT(255 == match_downstream_addr_group( - routerconf, StringRef::from_lit(""), - StringRef::from_lit("/"), groups, 255, balloc)); - - CU_ASSERT(255 == match_downstream_addr_group( - routerconf, StringRef::from_lit(""), - StringRef::from_lit("alpha"), groups, 255, balloc)); - - CU_ASSERT(255 == match_downstream_addr_group( - routerconf, StringRef::from_lit("foo/bar"), - StringRef::from_lit("/"), groups, 255, balloc)); + assert_size(0, ==, + match_downstream_addr_group( + routerconf, StringRef::from_lit("nghttp2.org"), + StringRef::from_lit("/alpha/charlie/"), groups, 255, balloc)); + + assert_size(255, ==, + match_downstream_addr_group( + routerconf, StringRef::from_lit("example.org"), + StringRef::from_lit("/"), groups, 255, balloc)); + + assert_size(255, ==, + match_downstream_addr_group(routerconf, StringRef::from_lit(""), + StringRef::from_lit("/"), groups, 255, + balloc)); + + assert_size(255, ==, + match_downstream_addr_group(routerconf, StringRef::from_lit(""), + StringRef::from_lit("alpha"), groups, + 255, balloc)); + + assert_size(255, ==, + match_downstream_addr_group( + routerconf, StringRef::from_lit("foo/bar"), + StringRef::from_lit("/"), groups, 255, balloc)); // If path is StringRef::from_lit("*", only match with host + "/"). - CU_ASSERT(0 == match_downstream_addr_group( - routerconf, StringRef::from_lit("nghttp2.org"), - StringRef::from_lit("*"), groups, 255, balloc)); - - CU_ASSERT(5 == match_downstream_addr_group( - routerconf, StringRef::from_lit("[::1]"), - StringRef::from_lit("/"), groups, 255, balloc)); - CU_ASSERT(5 == match_downstream_addr_group( - routerconf, StringRef::from_lit("[::1]:8080"), - StringRef::from_lit("/"), groups, 255, balloc)); - CU_ASSERT(255 == match_downstream_addr_group( - routerconf, StringRef::from_lit("[::1"), - StringRef::from_lit("/"), groups, 255, balloc)); - CU_ASSERT(255 == match_downstream_addr_group( - routerconf, StringRef::from_lit("[::1]8000"), - StringRef::from_lit("/"), groups, 255, balloc)); + assert_size(0, ==, + match_downstream_addr_group( + routerconf, StringRef::from_lit("nghttp2.org"), + StringRef::from_lit("*"), groups, 255, balloc)); + + assert_size(5, ==, + match_downstream_addr_group( + routerconf, StringRef::from_lit("[::1]"), + StringRef::from_lit("/"), groups, 255, balloc)); + assert_size(5, ==, + match_downstream_addr_group( + routerconf, StringRef::from_lit("[::1]:8080"), + StringRef::from_lit("/"), groups, 255, balloc)); + assert_size(255, ==, + match_downstream_addr_group( + routerconf, StringRef::from_lit("[::1"), + StringRef::from_lit("/"), groups, 255, balloc)); + assert_size(255, ==, + match_downstream_addr_group( + routerconf, StringRef::from_lit("[::1]8000"), + StringRef::from_lit("/"), groups, 255, balloc)); // Check the case where adding route extends tree - CU_ASSERT(6 == match_downstream_addr_group( - routerconf, StringRef::from_lit("nghttp2.org"), - StringRef::from_lit("/alpha/bravo/delta"), groups, 255, - balloc)); - - CU_ASSERT(1 == match_downstream_addr_group( - routerconf, StringRef::from_lit("nghttp2.org"), - StringRef::from_lit("/alpha/bravo/delta/"), groups, 255, - balloc)); + assert_size(6, ==, + match_downstream_addr_group( + routerconf, StringRef::from_lit("nghttp2.org"), + StringRef::from_lit("/alpha/bravo/delta"), groups, 255, + balloc)); + + assert_size(1, ==, + match_downstream_addr_group( + routerconf, StringRef::from_lit("nghttp2.org"), + StringRef::from_lit("/alpha/bravo/delta/"), groups, 255, + balloc)); // Check the case where query is done in a single node - CU_ASSERT(7 == match_downstream_addr_group( - routerconf, StringRef::from_lit("example.com"), - StringRef::from_lit("/alpha/bravo"), groups, 255, balloc)); + assert_size(7, ==, + match_downstream_addr_group( + routerconf, StringRef::from_lit("example.com"), + StringRef::from_lit("/alpha/bravo"), groups, 255, balloc)); - CU_ASSERT(255 == match_downstream_addr_group( - routerconf, StringRef::from_lit("example.com"), - StringRef::from_lit("/alpha/bravo/"), groups, 255, - balloc)); + assert_size(255, ==, + match_downstream_addr_group( + routerconf, StringRef::from_lit("example.com"), + StringRef::from_lit("/alpha/bravo/"), groups, 255, balloc)); - CU_ASSERT(255 == match_downstream_addr_group( - routerconf, StringRef::from_lit("example.com"), - StringRef::from_lit("/alpha"), groups, 255, balloc)); + assert_size(255, ==, + match_downstream_addr_group( + routerconf, StringRef::from_lit("example.com"), + StringRef::from_lit("/alpha"), groups, 255, balloc)); // Check the case where quey is done in a single node - CU_ASSERT(8 == match_downstream_addr_group( - routerconf, StringRef::from_lit("192.168.0.1"), - StringRef::from_lit("/alpha"), groups, 255, balloc)); - - CU_ASSERT(8 == match_downstream_addr_group( - routerconf, StringRef::from_lit("192.168.0.1"), - StringRef::from_lit("/alpha/"), groups, 255, balloc)); - - CU_ASSERT(8 == match_downstream_addr_group( - routerconf, StringRef::from_lit("192.168.0.1"), - StringRef::from_lit("/alpha/bravo"), groups, 255, balloc)); - - CU_ASSERT(255 == match_downstream_addr_group( - routerconf, StringRef::from_lit("192.168.0.1"), - StringRef::from_lit("/alph"), groups, 255, balloc)); - - CU_ASSERT(255 == match_downstream_addr_group( - routerconf, StringRef::from_lit("192.168.0.1"), - StringRef::from_lit("/"), groups, 255, balloc)); + assert_size(8, ==, + match_downstream_addr_group( + routerconf, StringRef::from_lit("192.168.0.1"), + StringRef::from_lit("/alpha"), groups, 255, balloc)); + + assert_size(8, ==, + match_downstream_addr_group( + routerconf, StringRef::from_lit("192.168.0.1"), + StringRef::from_lit("/alpha/"), groups, 255, balloc)); + + assert_size(8, ==, + match_downstream_addr_group( + routerconf, StringRef::from_lit("192.168.0.1"), + StringRef::from_lit("/alpha/bravo"), groups, 255, balloc)); + + assert_size(255, ==, + match_downstream_addr_group( + routerconf, StringRef::from_lit("192.168.0.1"), + StringRef::from_lit("/alph"), groups, 255, balloc)); + + assert_size(255, ==, + match_downstream_addr_group( + routerconf, StringRef::from_lit("192.168.0.1"), + StringRef::from_lit("/"), groups, 255, balloc)); // Test for wildcard hosts auto g1 = std::make_shared(); @@ -214,34 +249,40 @@ void test_shrpx_worker_match_downstream_addr_group(void) { wcrouter.add_route(StringRef::from_lit("lacol."), 2); wp.back().router.add_route(StringRef::from_lit("/"), 13); - CU_ASSERT(11 == match_downstream_addr_group( - routerconf, StringRef::from_lit("git.nghttp2.org"), - StringRef::from_lit("/echo"), groups, 255, balloc)); - - CU_ASSERT(10 == match_downstream_addr_group( - routerconf, StringRef::from_lit("0git.nghttp2.org"), - StringRef::from_lit("/echo"), groups, 255, balloc)); - - CU_ASSERT(11 == match_downstream_addr_group( - routerconf, StringRef::from_lit("it.nghttp2.org"), - StringRef::from_lit("/echo"), groups, 255, balloc)); - - CU_ASSERT(255 == match_downstream_addr_group( - routerconf, StringRef::from_lit(".nghttp2.org"), - StringRef::from_lit("/echo/foxtrot"), groups, 255, - balloc)); - - CU_ASSERT(9 == match_downstream_addr_group( - routerconf, StringRef::from_lit("alpha.nghttp2.org"), - StringRef::from_lit("/golf"), groups, 255, balloc)); - - CU_ASSERT(0 == match_downstream_addr_group( - routerconf, StringRef::from_lit("nghttp2.org"), - StringRef::from_lit("/echo"), groups, 255, balloc)); - - CU_ASSERT(13 == match_downstream_addr_group( - routerconf, StringRef::from_lit("test.local"), - StringRef{}, groups, 255, balloc)); + assert_size(11, ==, + match_downstream_addr_group( + routerconf, StringRef::from_lit("git.nghttp2.org"), + StringRef::from_lit("/echo"), groups, 255, balloc)); + + assert_size(10, ==, + match_downstream_addr_group( + routerconf, StringRef::from_lit("0git.nghttp2.org"), + StringRef::from_lit("/echo"), groups, 255, balloc)); + + assert_size(11, ==, + match_downstream_addr_group( + routerconf, StringRef::from_lit("it.nghttp2.org"), + StringRef::from_lit("/echo"), groups, 255, balloc)); + + assert_size(255, ==, + match_downstream_addr_group( + routerconf, StringRef::from_lit(".nghttp2.org"), + StringRef::from_lit("/echo/foxtrot"), groups, 255, balloc)); + + assert_size(9, ==, + match_downstream_addr_group( + routerconf, StringRef::from_lit("alpha.nghttp2.org"), + StringRef::from_lit("/golf"), groups, 255, balloc)); + + assert_size(0, ==, + match_downstream_addr_group( + routerconf, StringRef::from_lit("nghttp2.org"), + StringRef::from_lit("/echo"), groups, 255, balloc)); + + assert_size(13, ==, + match_downstream_addr_group(routerconf, + StringRef::from_lit("test.local"), + StringRef{}, groups, 255, balloc)); } } // namespace shrpx diff --git a/src/shrpx_worker_test.h b/src/shrpx_worker_test.h index 8ffa2f1..4dfaa2b 100644 --- a/src/shrpx_worker_test.h +++ b/src/shrpx_worker_test.h @@ -29,9 +29,15 @@ # include #endif // HAVE_CONFIG_H +#define MUNIT_ENABLE_ASSERT_ALIASES + +#include "munit.h" + namespace shrpx { -void test_shrpx_worker_match_downstream_addr_group(void); +extern const MunitSuite worker_suite; + +munit_void_test_decl(test_shrpx_worker_match_downstream_addr_group); } // namespace shrpx diff --git a/src/template_test.cc b/src/template_test.cc index 4a77315..db212d1 100644 --- a/src/template_test.cc +++ b/src/template_test.cc @@ -28,80 +28,92 @@ #include #include -#include +#include "munitxx.h" #include "template.h" namespace nghttp2 { +namespace { +const MunitTest tests[]{ + munit_void_test(test_template_immutable_string), + munit_void_test(test_template_string_ref), + munit_test_end(), +}; +} // namespace + +const MunitSuite template_suite{ + "/template", tests, NULL, 1, MUNIT_SUITE_OPTION_NONE, +}; + void test_template_immutable_string(void) { ImmutableString null; - CU_ASSERT("" == null); - CU_ASSERT(0 == null.size()); - CU_ASSERT(null.empty()); + assert_string_equal("", null.c_str()); + assert_size(0, ==, null.size()); + assert_true(null.empty()); ImmutableString from_cstr("alpha"); - CU_ASSERT(0 == strcmp("alpha", from_cstr.c_str())); - CU_ASSERT(5 == from_cstr.size()); - CU_ASSERT(!from_cstr.empty()); - CU_ASSERT("alpha" == from_cstr); - CU_ASSERT(from_cstr == "alpha"); - CU_ASSERT(std::string("alpha") == from_cstr); - CU_ASSERT(from_cstr == std::string("alpha")); + assert_string_equal("alpha", from_cstr.c_str()); + assert_size(5, ==, from_cstr.size()); + assert_false(from_cstr.empty()); + assert_true("alpha" == from_cstr); + assert_true(from_cstr == "alpha"); + assert_true(std::string("alpha") == from_cstr); + assert_true(from_cstr == std::string("alpha")); // copy constructor ImmutableString src("charlie"); ImmutableString copy = src; - CU_ASSERT("charlie" == copy); - CU_ASSERT(7 == copy.size()); + assert_string_equal("charlie", copy.c_str()); + assert_size(7, ==, copy.size()); // copy assignment ImmutableString copy2; copy2 = src; - CU_ASSERT("charlie" == copy2); - CU_ASSERT(7 == copy2.size()); + assert_string_equal("charlie", copy2.c_str()); + assert_size(7, ==, copy2.size()); // move constructor ImmutableString move = std::move(copy); - CU_ASSERT("charlie" == move); - CU_ASSERT(7 == move.size()); - CU_ASSERT("" == copy); - CU_ASSERT(0 == copy.size()); + assert_string_equal("charlie", move.c_str()); + assert_size(7, ==, move.size()); + assert_string_equal("", copy.c_str()); + assert_size(0, ==, copy.size()); // move assignment move = std::move(from_cstr); - CU_ASSERT("alpha" == move); - CU_ASSERT(5 == move.size()); - CU_ASSERT("" == from_cstr); - CU_ASSERT(0 == from_cstr.size()); + assert_string_equal("alpha", move.c_str()); + assert_size(5, ==, move.size()); + assert_string_equal("", from_cstr.c_str()); + assert_size(0, ==, from_cstr.size()); // from string literal - auto from_lit = StringRef::from_lit("bravo"); + auto from_lit = ImmutableString::from_lit("bravo"); - CU_ASSERT("bravo" == from_lit); - CU_ASSERT(5 == from_lit.size()); + assert_string_equal("bravo", from_lit.c_str()); + assert_size(5, ==, from_lit.size()); // equality ImmutableString eq("delta"); - CU_ASSERT("delta1" != eq); - CU_ASSERT("delt" != eq); - CU_ASSERT(eq != "delta1"); - CU_ASSERT(eq != "delt"); + assert_true("delta1" != eq); + assert_true("delt" != eq); + assert_true(eq != "delta1"); + assert_true(eq != "delt"); // operator[] ImmutableString br_op("foxtrot"); - CU_ASSERT('f' == br_op[0]); - CU_ASSERT('o' == br_op[1]); - CU_ASSERT('t' == br_op[6]); - CU_ASSERT('\0' == br_op[7]); + assert_char('f', ==, br_op[0]); + assert_char('o', ==, br_op[1]); + assert_char('t', ==, br_op[6]); + assert_char('\0', ==, br_op[7]); // operator==(const ImmutableString &, const ImmutableString &) { @@ -109,9 +121,9 @@ void test_template_immutable_string(void) { ImmutableString b("foo"); ImmutableString c("fo"); - CU_ASSERT(a == b); - CU_ASSERT(a != c); - CU_ASSERT(c != b); + assert_true(a == b); + assert_true(a != c); + assert_true(c != b); } // operator<< @@ -120,7 +132,7 @@ void test_template_immutable_string(void) { std::stringstream ss; ss << a; - CU_ASSERT("foo" == ss.str()); + assert_stdstring_equal("foo", ss.str()); } // operator +=(std::string &, const ImmutableString &) @@ -128,60 +140,60 @@ void test_template_immutable_string(void) { std::string a = "alpha"; a += ImmutableString("bravo"); - CU_ASSERT("alphabravo" == a); + assert_stdstring_equal("alphabravo", a); } } void test_template_string_ref(void) { StringRef empty; - CU_ASSERT("" == empty); - CU_ASSERT(0 == empty.size()); + assert_stdstring_equal("", empty.str()); + assert_size(0, ==, empty.size()); // from std::string std::string alpha = "alpha"; StringRef ref(alpha); - CU_ASSERT("alpha" == ref); - CU_ASSERT(ref == "alpha"); - CU_ASSERT(alpha == ref); - CU_ASSERT(ref == alpha); - CU_ASSERT(5 == ref.size()); + assert_true("alpha" == ref); + assert_true(ref == "alpha"); + assert_true(alpha == ref); + assert_true(ref == alpha); + assert_size(5, ==, ref.size()); // from string literal auto from_lit = StringRef::from_lit("alpha"); - CU_ASSERT("alpha" == from_lit); - CU_ASSERT(5 == from_lit.size()); + assert_stdstring_equal("alpha", from_lit.str()); + assert_size(5, ==, from_lit.size()); // from ImmutableString auto im = ImmutableString::from_lit("bravo"); StringRef imref(im); - CU_ASSERT("bravo" == imref); - CU_ASSERT(5 == imref.size()); + assert_stdstring_equal("bravo", imref.str()); + assert_size(5, ==, imref.size()); // from C-string StringRef cstrref("charlie"); - CU_ASSERT("charlie" == cstrref); - CU_ASSERT(7 == cstrref.size()); + assert_stdstring_equal("charlie", cstrref.str()); + assert_size(7, ==, cstrref.size()); // from C-string and its length StringRef cstrnref("delta", 5); - CU_ASSERT("delta" == cstrnref); - CU_ASSERT(5 == cstrnref.size()); + assert_stdstring_equal("delta", cstrnref.str()); + assert_size(5, ==, cstrnref.size()); // operator[] StringRef br_op("foxtrot"); - CU_ASSERT('f' == br_op[0]); - CU_ASSERT('o' == br_op[1]); - CU_ASSERT('t' == br_op[6]); - CU_ASSERT('\0' == br_op[7]); + assert_char('f', ==, br_op[0]); + assert_char('o', ==, br_op[1]); + assert_char('t', ==, br_op[6]); + assert_char('\0', ==, br_op[7]); // operator<< { @@ -189,7 +201,7 @@ void test_template_string_ref(void) { std::stringstream ss; ss << a; - CU_ASSERT("foo" == ss.str()); + assert_stdstring_equal("foo", ss.str()); } // operator +=(std::string &, const StringRef &) @@ -197,7 +209,7 @@ void test_template_string_ref(void) { std::string a = "alpha"; a += StringRef("bravo"); - CU_ASSERT("alphabravo" == a); + assert_stdstring_equal("alphabravo", a); } } diff --git a/src/template_test.h b/src/template_test.h index 2c1448f..df39de9 100644 --- a/src/template_test.h +++ b/src/template_test.h @@ -29,10 +29,16 @@ # include #endif // HAVE_CONFIG_H +#define MUNIT_ENABLE_ASSERT_ALIASES + +#include "munit.h" + namespace nghttp2 { -void test_template_immutable_string(void); -void test_template_string_ref(void); +extern const MunitSuite template_suite; + +munit_void_test_decl(test_template_immutable_string); +munit_void_test_decl(test_template_string_ref); } // namespace nghttp2 diff --git a/src/tls.cc b/src/tls.cc index e88dc56..9babf2a 100644 --- a/src/tls.cc +++ b/src/tls.cc @@ -32,6 +32,11 @@ #include #include +#ifdef HAVE_LIBBROTLI +# include +# include +#endif // HAVE_LIBBROTLI + #include "ssl_compat.h" namespace nghttp2 { @@ -120,6 +125,57 @@ int ssl_ctx_set_proto_versions(SSL_CTX *ssl_ctx, int min, int max) { return 0; } +#if defined(NGHTTP2_OPENSSL_IS_BORINGSSL) && defined(HAVE_LIBBROTLI) +int cert_compress(SSL *ssl, CBB *out, const uint8_t *in, size_t in_len) { + uint8_t *dest; + + auto compressed_size = BrotliEncoderMaxCompressedSize(in_len); + if (compressed_size == 0) { + return 0; + } + + if (!CBB_reserve(out, &dest, compressed_size)) { + return 0; + } + + if (BrotliEncoderCompress(BROTLI_MAX_QUALITY, BROTLI_DEFAULT_WINDOW, + BROTLI_MODE_GENERIC, in_len, in, &compressed_size, + dest) != BROTLI_TRUE) { + return 0; + } + + if (!CBB_did_write(out, compressed_size)) { + return 0; + } + + return 1; +} + +int cert_decompress(SSL *ssl, CRYPTO_BUFFER **out, size_t uncompressed_len, + const uint8_t *in, size_t in_len) { + uint8_t *dest; + auto buf = CRYPTO_BUFFER_alloc(&dest, uncompressed_len); + auto len = uncompressed_len; + + if (BrotliDecoderDecompress(in_len, in, &len, dest) != + BROTLI_DECODER_RESULT_SUCCESS) { + CRYPTO_BUFFER_free(buf); + + return 0; + } + + if (uncompressed_len != len) { + CRYPTO_BUFFER_free(buf); + + return 0; + } + + *out = buf; + + return 1; +} +#endif // NGHTTP2_OPENSSL_IS_BORINGSSL && HAVE_LIBBROTLI + } // namespace tls } // namespace nghttp2 diff --git a/src/tls.h b/src/tls.h index 59e2ccd..03612c8 100644 --- a/src/tls.h +++ b/src/tls.h @@ -97,6 +97,15 @@ bool check_http2_requirement(SSL *ssl); // 0 if it succeeds, or -1. int ssl_ctx_set_proto_versions(SSL_CTX *ssl_ctx, int min, int max); +constexpr uint16_t CERTIFICATE_COMPRESSION_ALGO_BROTLI = 2; + +#if defined(NGHTTP2_OPENSSL_IS_BORINGSSL) && defined(HAVE_LIBBROTLI) +int cert_compress(SSL *ssl, CBB *out, const uint8_t *in, size_t in_len); + +int cert_decompress(SSL *ssl, CRYPTO_BUFFER **out, size_t uncompressed_len, + const uint8_t *in, size_t in_len); +#endif // NGHTTP2_OPENSSL_IS_BORINGSSL && HAVE_LIBBROTLI + } // namespace tls } // namespace nghttp2 diff --git a/src/util_test.cc b/src/util_test.cc index 0ac0f1d..2e01e9d 100644 --- a/src/util_test.cc +++ b/src/util_test.cc @@ -28,7 +28,7 @@ #include #include -#include +#include "munitxx.h" #include @@ -39,166 +39,233 @@ using namespace nghttp2; namespace shrpx { +namespace { +const MunitTest tests[]{ + munit_void_test(test_util_streq), + munit_void_test(test_util_strieq), + munit_void_test(test_util_inp_strlower), + munit_void_test(test_util_to_base64), + munit_void_test(test_util_to_token68), + munit_void_test(test_util_percent_encode_token), + munit_void_test(test_util_percent_decode), + munit_void_test(test_util_quote_string), + munit_void_test(test_util_utox), + munit_void_test(test_util_http_date), + munit_void_test(test_util_select_h2), + munit_void_test(test_util_ipv6_numeric_addr), + munit_void_test(test_util_utos), + munit_void_test(test_util_make_string_ref_uint), + munit_void_test(test_util_utos_unit), + munit_void_test(test_util_utos_funit), + munit_void_test(test_util_parse_uint_with_unit), + munit_void_test(test_util_parse_uint), + munit_void_test(test_util_parse_duration_with_unit), + munit_void_test(test_util_duration_str), + munit_void_test(test_util_format_duration), + munit_void_test(test_util_starts_with), + munit_void_test(test_util_ends_with), + munit_void_test(test_util_parse_http_date), + munit_void_test(test_util_localtime_date), + munit_void_test(test_util_get_uint64), + munit_void_test(test_util_parse_config_str_list), + munit_void_test(test_util_make_http_hostport), + munit_void_test(test_util_make_hostport), + munit_void_test(test_util_strifind), + munit_void_test(test_util_random_alpha_digit), + munit_void_test(test_util_format_hex), + munit_void_test(test_util_is_hex_string), + munit_void_test(test_util_decode_hex), + munit_void_test(test_util_extract_host), + munit_void_test(test_util_split_hostport), + munit_void_test(test_util_split_str), + munit_void_test(test_util_rstrip), + munit_test_end(), +}; +} // namespace + +const MunitSuite util_suite{ + "/util", tests, NULL, 1, MUNIT_SUITE_OPTION_NONE, +}; + void test_util_streq(void) { - CU_ASSERT( + assert_true( util::streq(StringRef::from_lit("alpha"), StringRef::from_lit("alpha"))); - CU_ASSERT(!util::streq(StringRef::from_lit("alpha"), - StringRef::from_lit("alphabravo"))); - CU_ASSERT(!util::streq(StringRef::from_lit("alphabravo"), - StringRef::from_lit("alpha"))); - CU_ASSERT( - !util::streq(StringRef::from_lit("alpha"), StringRef::from_lit("alphA"))); - CU_ASSERT(!util::streq(StringRef{}, StringRef::from_lit("a"))); - CU_ASSERT(util::streq(StringRef{}, StringRef{})); - CU_ASSERT(!util::streq(StringRef::from_lit("alpha"), StringRef{})); - - CU_ASSERT( - !util::streq(StringRef::from_lit("alph"), StringRef::from_lit("alpha"))); - CU_ASSERT( - !util::streq(StringRef::from_lit("alpha"), StringRef::from_lit("alph"))); - CU_ASSERT( - !util::streq(StringRef::from_lit("alpha"), StringRef::from_lit("alphA"))); - - CU_ASSERT(util::streq_l("alpha", "alpha", 5)); - CU_ASSERT(util::streq_l("alpha", "alphabravo", 5)); - CU_ASSERT(!util::streq_l("alpha", "alphabravo", 6)); - CU_ASSERT(!util::streq_l("alphabravo", "alpha", 5)); - CU_ASSERT(!util::streq_l("alpha", "alphA", 5)); - CU_ASSERT(!util::streq_l("", "a", 1)); - CU_ASSERT(util::streq_l("", "", 0)); - CU_ASSERT(!util::streq_l("alpha", "", 0)); + assert_false(util::streq(StringRef::from_lit("alpha"), + StringRef::from_lit("alphabravo"))); + assert_false(util::streq(StringRef::from_lit("alphabravo"), + StringRef::from_lit("alpha"))); + assert_false( + util::streq(StringRef::from_lit("alpha"), StringRef::from_lit("alphA"))); + assert_false(util::streq(StringRef{}, StringRef::from_lit("a"))); + assert_true(util::streq(StringRef{}, StringRef{})); + assert_false(util::streq(StringRef::from_lit("alpha"), StringRef{})); + + assert_false( + util::streq(StringRef::from_lit("alph"), StringRef::from_lit("alpha"))); + assert_false( + util::streq(StringRef::from_lit("alpha"), StringRef::from_lit("alph"))); + assert_false( + util::streq(StringRef::from_lit("alpha"), StringRef::from_lit("alphA"))); + + assert_true(util::streq_l("alpha", "alpha", 5)); + assert_true(util::streq_l("alpha", "alphabravo", 5)); + assert_false(util::streq_l("alpha", "alphabravo", 6)); + assert_false(util::streq_l("alphabravo", "alpha", 5)); + assert_false(util::streq_l("alpha", "alphA", 5)); + assert_false(util::streq_l("", "a", 1)); + assert_true(util::streq_l("", "", 0)); + assert_false(util::streq_l("alpha", "", 0)); } void test_util_strieq(void) { - CU_ASSERT(util::strieq(std::string("alpha"), std::string("alpha"))); - CU_ASSERT(util::strieq(std::string("alpha"), std::string("AlPhA"))); - CU_ASSERT(util::strieq(std::string(), std::string())); - CU_ASSERT(!util::strieq(std::string("alpha"), std::string("AlPhA "))); - CU_ASSERT(!util::strieq(std::string(), std::string("AlPhA "))); + assert_true(util::strieq(std::string("alpha"), std::string("alpha"))); + assert_true(util::strieq(std::string("alpha"), std::string("AlPhA"))); + assert_true(util::strieq(std::string(), std::string())); + assert_false(util::strieq(std::string("alpha"), std::string("AlPhA "))); + assert_false(util::strieq(std::string(), std::string("AlPhA "))); - CU_ASSERT( + assert_true( util::strieq(StringRef::from_lit("alpha"), StringRef::from_lit("alpha"))); - CU_ASSERT( + assert_true( util::strieq(StringRef::from_lit("alpha"), StringRef::from_lit("AlPhA"))); - CU_ASSERT(util::strieq(StringRef{}, StringRef{})); - CU_ASSERT(!util::strieq(StringRef::from_lit("alpha"), - StringRef::from_lit("AlPhA "))); - CU_ASSERT( - !util::strieq(StringRef::from_lit(""), StringRef::from_lit("AlPhA "))); + assert_true(util::strieq(StringRef{}, StringRef{})); + assert_false(util::strieq(StringRef::from_lit("alpha"), + StringRef::from_lit("AlPhA "))); + assert_false( + util::strieq(StringRef::from_lit(""), StringRef::from_lit("AlPhA "))); - CU_ASSERT(util::strieq_l("alpha", "alpha", 5)); - CU_ASSERT(util::strieq_l("alpha", "AlPhA", 5)); - CU_ASSERT(util::strieq_l("", static_cast(nullptr), 0)); - CU_ASSERT(!util::strieq_l("alpha", "AlPhA ", 6)); - CU_ASSERT(!util::strieq_l("", "AlPhA ", 6)); + assert_true(util::strieq_l("alpha", "alpha", 5)); + assert_true(util::strieq_l("alpha", "AlPhA", 5)); + assert_true(util::strieq_l("", static_cast(nullptr), 0)); + assert_false(util::strieq_l("alpha", "AlPhA ", 6)); + assert_false(util::strieq_l("", "AlPhA ", 6)); - CU_ASSERT(util::strieq_l("alpha", StringRef::from_lit("alpha"))); - CU_ASSERT(util::strieq_l("alpha", StringRef::from_lit("AlPhA"))); - CU_ASSERT(util::strieq_l("", StringRef{})); - CU_ASSERT(!util::strieq_l("alpha", StringRef::from_lit("AlPhA "))); - CU_ASSERT(!util::strieq_l("", StringRef::from_lit("AlPhA "))); + assert_true(util::strieq_l("alpha", StringRef::from_lit("alpha"))); + assert_true(util::strieq_l("alpha", StringRef::from_lit("AlPhA"))); + assert_true(util::strieq_l("", StringRef{})); + assert_false(util::strieq_l("alpha", StringRef::from_lit("AlPhA "))); + assert_false(util::strieq_l("", StringRef::from_lit("AlPhA "))); } void test_util_inp_strlower(void) { std::string a("alPha"); util::inp_strlower(a); - CU_ASSERT("alpha" == a); + assert_stdstring_equal("alpha", a); a = "ALPHA123BRAVO"; util::inp_strlower(a); - CU_ASSERT("alpha123bravo" == a); + assert_stdstring_equal("alpha123bravo", a); a = ""; util::inp_strlower(a); - CU_ASSERT("" == a); + assert_stdstring_equal("", a); } void test_util_to_base64(void) { BlockAllocator balloc(4096, 4096); - CU_ASSERT("AAA++B/=" == - util::to_base64(balloc, StringRef::from_lit("AAA--B_"))); - CU_ASSERT("AAA++B/B" == - util::to_base64(balloc, StringRef::from_lit("AAA--B_B"))); + assert_stdstring_equal( + "AAA++B/=", + util::to_base64(balloc, StringRef::from_lit("AAA--B_")).str()); + assert_stdstring_equal( + "AAA++B/B", + util::to_base64(balloc, StringRef::from_lit("AAA--B_B")).str()); } void test_util_to_token68(void) { std::string x = "AAA++B/="; util::to_token68(x); - CU_ASSERT("AAA--B_" == x); + assert_stdstring_equal("AAA--B_", x); x = "AAA++B/B"; util::to_token68(x); - CU_ASSERT("AAA--B_B" == x); + assert_stdstring_equal("AAA--B_B", x); } void test_util_percent_encode_token(void) { BlockAllocator balloc(4096, 4096); - CU_ASSERT("h2" == - util::percent_encode_token(balloc, StringRef::from_lit("h2"))); - CU_ASSERT("h3~" == - util::percent_encode_token(balloc, StringRef::from_lit("h3~"))); - CU_ASSERT("100%25" == - util::percent_encode_token(balloc, StringRef::from_lit("100%"))); - CU_ASSERT("http%202" == - util::percent_encode_token(balloc, StringRef::from_lit("http 2"))); + assert_stdstring_equal( + "h2", + util::percent_encode_token(balloc, StringRef::from_lit("h2")).str()); + assert_stdstring_equal( + "h3~", + util::percent_encode_token(balloc, StringRef::from_lit("h3~")).str()); + assert_stdstring_equal( + "100%25", + util::percent_encode_token(balloc, StringRef::from_lit("100%")).str()); + assert_stdstring_equal( + "http%202", + util::percent_encode_token(balloc, StringRef::from_lit("http 2")).str()); } void test_util_percent_decode(void) { { std::string s = "%66%6F%6f%62%61%72"; - CU_ASSERT("foobar" == util::percent_decode(std::begin(s), std::end(s))); + assert_stdstring_equal("foobar", + util::percent_decode(std::begin(s), std::end(s))); } { std::string s = "%66%6"; - CU_ASSERT("f%6" == util::percent_decode(std::begin(s), std::end(s))); + assert_stdstring_equal("f%6", + util::percent_decode(std::begin(s), std::end(s))); } { std::string s = "%66%"; - CU_ASSERT("f%" == util::percent_decode(std::begin(s), std::end(s))); + assert_stdstring_equal("f%", + util::percent_decode(std::begin(s), std::end(s))); } BlockAllocator balloc(1024, 1024); - CU_ASSERT("foobar" == util::percent_decode( - balloc, StringRef::from_lit("%66%6F%6f%62%61%72"))); + assert_stdstring_equal( + "foobar", + util::percent_decode(balloc, StringRef::from_lit("%66%6F%6f%62%61%72")) + .str()); - CU_ASSERT("f%6" == - util::percent_decode(balloc, StringRef::from_lit("%66%6"))); + assert_stdstring_equal( + "f%6", util::percent_decode(balloc, StringRef::from_lit("%66%6")).str()); - CU_ASSERT("f%" == util::percent_decode(balloc, StringRef::from_lit("%66%"))); + assert_stdstring_equal( + "f%", util::percent_decode(balloc, StringRef::from_lit("%66%")).str()); } void test_util_quote_string(void) { BlockAllocator balloc(4096, 4096); - CU_ASSERT("alpha" == - util::quote_string(balloc, StringRef::from_lit("alpha"))); - CU_ASSERT("" == util::quote_string(balloc, StringRef::from_lit(""))); - CU_ASSERT("\\\"alpha\\\"" == - util::quote_string(balloc, StringRef::from_lit("\"alpha\""))); + assert_stdstring_equal( + "alpha", util::quote_string(balloc, StringRef::from_lit("alpha")).str()); + assert_stdstring_equal( + "", util::quote_string(balloc, StringRef::from_lit("")).str()); + assert_stdstring_equal( + "\\\"alpha\\\"", + util::quote_string(balloc, StringRef::from_lit("\"alpha\"")).str()); } void test_util_utox(void) { - CU_ASSERT("0" == util::utox(0)); - CU_ASSERT("1" == util::utox(1)); - CU_ASSERT("F" == util::utox(15)); - CU_ASSERT("10" == util::utox(16)); - CU_ASSERT("3B9ACA07" == util::utox(1000000007)); - CU_ASSERT("100000000" == util::utox(1LL << 32)); + assert_stdstring_equal("0", util::utox(0)); + assert_stdstring_equal("1", util::utox(1)); + assert_stdstring_equal("F", util::utox(15)); + assert_stdstring_equal("10", util::utox(16)); + assert_stdstring_equal("3B9ACA07", util::utox(1000000007)); + assert_stdstring_equal("100000000", util::utox(1LL << 32)); } void test_util_http_date(void) { - CU_ASSERT("Thu, 01 Jan 1970 00:00:00 GMT" == util::http_date(0)); - CU_ASSERT("Wed, 29 Feb 2012 09:15:16 GMT" == util::http_date(1330506916)); + assert_stdstring_equal("Thu, 01 Jan 1970 00:00:00 GMT", util::http_date(0)); + assert_stdstring_equal("Wed, 29 Feb 2012 09:15:16 GMT", + util::http_date(1330506916)); std::array http_buf; - CU_ASSERT("Thu, 01 Jan 1970 00:00:00 GMT" == - util::format_http_date(http_buf.data(), - std::chrono::system_clock::time_point())); - CU_ASSERT("Wed, 29 Feb 2012 09:15:16 GMT" == - util::format_http_date(http_buf.data(), - std::chrono::system_clock::time_point( - std::chrono::seconds(1330506916)))); + assert_stdstring_equal( + "Thu, 01 Jan 1970 00:00:00 GMT", + util::format_http_date(http_buf.data(), + std::chrono::system_clock::time_point()) + .str()); + assert_stdstring_equal( + "Wed, 29 Feb 2012 09:15:16 GMT", + util::format_http_date(http_buf.data(), + std::chrono::system_clock::time_point( + std::chrono::seconds(1330506916))) + .str()); } void test_util_select_h2(void) { @@ -207,10 +274,10 @@ void test_util_select_h2(void) { // Check single entry and select it. const unsigned char t1[] = "\x2h2"; - CU_ASSERT(util::select_h2(&out, &outlen, t1, sizeof(t1) - 1)); - CU_ASSERT( - memcmp(NGHTTP2_PROTO_VERSION_ID, out, NGHTTP2_PROTO_VERSION_ID_LEN) == 0); - CU_ASSERT(NGHTTP2_PROTO_VERSION_ID_LEN == outlen); + assert_true(util::select_h2(&out, &outlen, t1, sizeof(t1) - 1)); + assert_memory_equal(NGHTTP2_PROTO_VERSION_ID_LEN, NGHTTP2_PROTO_VERSION_ID, + out); + assert_uchar(NGHTTP2_PROTO_VERSION_ID_LEN, ==, outlen); out = nullptr; outlen = 0; @@ -218,224 +285,235 @@ void test_util_select_h2(void) { // Check the case where id is correct but length is invalid and too // long. const unsigned char t2[] = "\x6h2-14"; - CU_ASSERT(!util::select_h2(&out, &outlen, t2, sizeof(t2) - 1)); + assert_false(util::select_h2(&out, &outlen, t2, sizeof(t2) - 1)); // Check the case where h2 is located after bogus ID. const unsigned char t3[] = "\x2h3\x2h2"; - CU_ASSERT(util::select_h2(&out, &outlen, t3, sizeof(t3) - 1)); + assert_true(util::select_h2(&out, &outlen, t3, sizeof(t3) - 1)); - CU_ASSERT( - memcmp(NGHTTP2_PROTO_VERSION_ID, out, NGHTTP2_PROTO_VERSION_ID_LEN) == 0); - CU_ASSERT(NGHTTP2_PROTO_VERSION_ID_LEN == outlen); + assert_memory_equal(NGHTTP2_PROTO_VERSION_ID_LEN, NGHTTP2_PROTO_VERSION_ID, + out); + assert_uchar(NGHTTP2_PROTO_VERSION_ID_LEN, ==, outlen); out = nullptr; outlen = 0; // Check the case that last entry's length is invalid and too long. const unsigned char t4[] = "\x2h3\x6h2-14"; - CU_ASSERT(!util::select_h2(&out, &outlen, t4, sizeof(t4) - 1)); + assert_false(util::select_h2(&out, &outlen, t4, sizeof(t4) - 1)); // Check the case that all entries are not supported. const unsigned char t5[] = "\x2h3\x2h4"; - CU_ASSERT(!util::select_h2(&out, &outlen, t5, sizeof(t5) - 1)); + assert_false(util::select_h2(&out, &outlen, t5, sizeof(t5) - 1)); // Check the case where 2 values are eligible, but last one is // picked up because it has precedence over the other. const unsigned char t6[] = "\x5h2-14\x5h2-16"; - CU_ASSERT(util::select_h2(&out, &outlen, t6, sizeof(t6) - 1)); - CU_ASSERT(util::streq(NGHTTP2_H2_16, StringRef{out, outlen})); + assert_true(util::select_h2(&out, &outlen, t6, sizeof(t6) - 1)); + assert_true(util::streq(NGHTTP2_H2_16, StringRef{out, outlen})); } void test_util_ipv6_numeric_addr(void) { - CU_ASSERT(util::ipv6_numeric_addr("::1")); - CU_ASSERT(util::ipv6_numeric_addr("2001:0db8:85a3:0042:1000:8a2e:0370:7334")); + assert_true(util::ipv6_numeric_addr("::1")); + assert_true( + util::ipv6_numeric_addr("2001:0db8:85a3:0042:1000:8a2e:0370:7334")); // IPv4 - CU_ASSERT(!util::ipv6_numeric_addr("127.0.0.1")); + assert_false(util::ipv6_numeric_addr("127.0.0.1")); // not numeric address - CU_ASSERT(!util::ipv6_numeric_addr("localhost")); + assert_false(util::ipv6_numeric_addr("localhost")); } void test_util_utos(void) { uint8_t buf[32]; - CU_ASSERT(("0" == StringRef{buf, util::utos(buf, 0)})); - CU_ASSERT(("123" == StringRef{buf, util::utos(buf, 123)})); - CU_ASSERT(("18446744073709551615" == - StringRef{buf, util::utos(buf, 18446744073709551615ULL)})); + assert_stdstring_equal("0", (std::string{buf, util::utos(buf, 0)})); + assert_stdstring_equal("123", (std::string{buf, util::utos(buf, 123)})); + assert_stdstring_equal( + "18446744073709551615", + (std::string{buf, util::utos(buf, 18446744073709551615ULL)})); } void test_util_make_string_ref_uint(void) { BlockAllocator balloc(1024, 1024); - CU_ASSERT("0" == util::make_string_ref_uint(balloc, 0)); - CU_ASSERT("123" == util::make_string_ref_uint(balloc, 123)); - CU_ASSERT("18446744073709551615" == - util::make_string_ref_uint(balloc, 18446744073709551615ULL)); + assert_stdstring_equal("0", util::make_string_ref_uint(balloc, 0).str()); + assert_stdstring_equal("123", util::make_string_ref_uint(balloc, 123).str()); + assert_stdstring_equal( + "18446744073709551615", + util::make_string_ref_uint(balloc, 18446744073709551615ULL).str()); } void test_util_utos_unit(void) { - CU_ASSERT("0" == util::utos_unit(0)); - CU_ASSERT("1023" == util::utos_unit(1023)); - CU_ASSERT("1K" == util::utos_unit(1024)); - CU_ASSERT("1K" == util::utos_unit(1025)); - CU_ASSERT("1M" == util::utos_unit(1 << 20)); - CU_ASSERT("1G" == util::utos_unit(1 << 30)); - CU_ASSERT("1024G" == util::utos_unit(1LL << 40)); + assert_stdstring_equal("0", util::utos_unit(0)); + assert_stdstring_equal("1023", util::utos_unit(1023)); + assert_stdstring_equal("1K", util::utos_unit(1024)); + assert_stdstring_equal("1K", util::utos_unit(1025)); + assert_stdstring_equal("1M", util::utos_unit(1 << 20)); + assert_stdstring_equal("1G", util::utos_unit(1 << 30)); + assert_stdstring_equal("1024G", util::utos_unit(1LL << 40)); } void test_util_utos_funit(void) { - CU_ASSERT("0" == util::utos_funit(0)); - CU_ASSERT("1023" == util::utos_funit(1023)); - CU_ASSERT("1.00K" == util::utos_funit(1024)); - CU_ASSERT("1.00K" == util::utos_funit(1025)); - CU_ASSERT("1.09K" == util::utos_funit(1119)); - CU_ASSERT("1.27K" == util::utos_funit(1300)); - CU_ASSERT("1.00M" == util::utos_funit(1 << 20)); - CU_ASSERT("1.18M" == util::utos_funit(1234567)); - CU_ASSERT("1.00G" == util::utos_funit(1 << 30)); - CU_ASSERT("4492450797.23G" == util::utos_funit(4823732313248234343LL)); - CU_ASSERT("1024.00G" == util::utos_funit(1LL << 40)); + assert_stdstring_equal("0", util::utos_funit(0)); + assert_stdstring_equal("1023", util::utos_funit(1023)); + assert_stdstring_equal("1.00K", util::utos_funit(1024)); + assert_stdstring_equal("1.00K", util::utos_funit(1025)); + assert_stdstring_equal("1.09K", util::utos_funit(1119)); + assert_stdstring_equal("1.27K", util::utos_funit(1300)); + assert_stdstring_equal("1.00M", util::utos_funit(1 << 20)); + assert_stdstring_equal("1.18M", util::utos_funit(1234567)); + assert_stdstring_equal("1.00G", util::utos_funit(1 << 30)); + assert_stdstring_equal("4492450797.23G", + util::utos_funit(4823732313248234343LL)); + assert_stdstring_equal("1024.00G", util::utos_funit(1LL << 40)); } void test_util_parse_uint_with_unit(void) { - CU_ASSERT(0 == util::parse_uint_with_unit("0")); - CU_ASSERT(1023 == util::parse_uint_with_unit("1023")); - CU_ASSERT(1024 == util::parse_uint_with_unit("1k")); - CU_ASSERT(2048 == util::parse_uint_with_unit("2K")); - CU_ASSERT(1 << 20 == util::parse_uint_with_unit("1m")); - CU_ASSERT(1 << 21 == util::parse_uint_with_unit("2M")); - CU_ASSERT(1 << 30 == util::parse_uint_with_unit("1g")); - CU_ASSERT(1LL << 31 == util::parse_uint_with_unit("2G")); - CU_ASSERT(9223372036854775807LL == - util::parse_uint_with_unit("9223372036854775807")); + assert_int64(0, ==, util::parse_uint_with_unit("0")); + assert_int64(1023, ==, util::parse_uint_with_unit("1023")); + assert_int64(1024, ==, util::parse_uint_with_unit("1k")); + assert_int64(2048, ==, util::parse_uint_with_unit("2K")); + assert_int64(1 << 20, ==, util::parse_uint_with_unit("1m")); + assert_int64(1 << 21, ==, util::parse_uint_with_unit("2M")); + assert_int64(1 << 30, ==, util::parse_uint_with_unit("1g")); + assert_int64(1LL << 31, ==, util::parse_uint_with_unit("2G")); + assert_int64(9223372036854775807LL, ==, + util::parse_uint_with_unit("9223372036854775807")); // check overflow case - CU_ASSERT(-1 == util::parse_uint_with_unit("9223372036854775808")); - CU_ASSERT(-1 == util::parse_uint_with_unit("10000000000000000000")); - CU_ASSERT(-1 == util::parse_uint_with_unit("9223372036854775807G")); + assert_int64(-1, ==, util::parse_uint_with_unit("9223372036854775808")); + assert_int64(-1, ==, util::parse_uint_with_unit("10000000000000000000")); + assert_int64(-1, ==, util::parse_uint_with_unit("9223372036854775807G")); // bad characters - CU_ASSERT(-1 == util::parse_uint_with_unit("1.1")); - CU_ASSERT(-1 == util::parse_uint_with_unit("1a")); - CU_ASSERT(-1 == util::parse_uint_with_unit("a1")); - CU_ASSERT(-1 == util::parse_uint_with_unit("1T")); - CU_ASSERT(-1 == util::parse_uint_with_unit("")); + assert_int64(-1, ==, util::parse_uint_with_unit("1.1")); + assert_int64(-1, ==, util::parse_uint_with_unit("1a")); + assert_int64(-1, ==, util::parse_uint_with_unit("a1")); + assert_int64(-1, ==, util::parse_uint_with_unit("1T")); + assert_int64(-1, ==, util::parse_uint_with_unit("")); } void test_util_parse_uint(void) { - CU_ASSERT(0 == util::parse_uint("0")); - CU_ASSERT(1023 == util::parse_uint("1023")); - CU_ASSERT(-1 == util::parse_uint("1k")); - CU_ASSERT(9223372036854775807LL == util::parse_uint("9223372036854775807")); + assert_int64(0, ==, util::parse_uint("0")); + assert_int64(1023, ==, util::parse_uint("1023")); + assert_int64(-1, ==, util::parse_uint("1k")); + assert_int64(9223372036854775807LL, ==, + util::parse_uint("9223372036854775807")); // check overflow case - CU_ASSERT(-1 == util::parse_uint("9223372036854775808")); - CU_ASSERT(-1 == util::parse_uint("10000000000000000000")); + assert_int64(-1, ==, util::parse_uint("9223372036854775808")); + assert_int64(-1, ==, util::parse_uint("10000000000000000000")); // bad characters - CU_ASSERT(-1 == util::parse_uint("1.1")); - CU_ASSERT(-1 == util::parse_uint("1a")); - CU_ASSERT(-1 == util::parse_uint("a1")); - CU_ASSERT(-1 == util::parse_uint("1T")); - CU_ASSERT(-1 == util::parse_uint("")); + assert_int64(-1, ==, util::parse_uint("1.1")); + assert_int64(-1, ==, util::parse_uint("1a")); + assert_int64(-1, ==, util::parse_uint("a1")); + assert_int64(-1, ==, util::parse_uint("1T")); + assert_int64(-1, ==, util::parse_uint("")); } void test_util_parse_duration_with_unit(void) { - CU_ASSERT(0. == util::parse_duration_with_unit("0")); - CU_ASSERT(123. == util::parse_duration_with_unit("123")); - CU_ASSERT(123. == util::parse_duration_with_unit("123s")); - CU_ASSERT(0.500 == util::parse_duration_with_unit("500ms")); - CU_ASSERT(123. == util::parse_duration_with_unit("123S")); - CU_ASSERT(0.500 == util::parse_duration_with_unit("500MS")); - CU_ASSERT(180 == util::parse_duration_with_unit("3m")); - CU_ASSERT(3600 * 5 == util::parse_duration_with_unit("5h")); + assert_double(0., ==, util::parse_duration_with_unit("0")); + assert_double(123., ==, util::parse_duration_with_unit("123")); + assert_double(123., ==, util::parse_duration_with_unit("123s")); + assert_double(0.500, ==, util::parse_duration_with_unit("500ms")); + assert_double(123., ==, util::parse_duration_with_unit("123S")); + assert_double(0.500, ==, util::parse_duration_with_unit("500MS")); + assert_double(180, ==, util::parse_duration_with_unit("3m")); + assert_double(3600 * 5, ==, util::parse_duration_with_unit("5h")); auto err = std::numeric_limits::infinity(); // check overflow case - CU_ASSERT(err == util::parse_duration_with_unit("9223372036854775808")); + assert_double(err, ==, util::parse_duration_with_unit("9223372036854775808")); // bad characters - CU_ASSERT(err == util::parse_duration_with_unit("0u")); - CU_ASSERT(err == util::parse_duration_with_unit("0xs")); - CU_ASSERT(err == util::parse_duration_with_unit("0mt")); - CU_ASSERT(err == util::parse_duration_with_unit("0mss")); - CU_ASSERT(err == util::parse_duration_with_unit("s")); - CU_ASSERT(err == util::parse_duration_with_unit("ms")); + assert_double(err, ==, util::parse_duration_with_unit("0u")); + assert_double(err, ==, util::parse_duration_with_unit("0xs")); + assert_double(err, ==, util::parse_duration_with_unit("0mt")); + assert_double(err, ==, util::parse_duration_with_unit("0mss")); + assert_double(err, ==, util::parse_duration_with_unit("s")); + assert_double(err, ==, util::parse_duration_with_unit("ms")); } void test_util_duration_str(void) { - CU_ASSERT("0" == util::duration_str(0.)); - CU_ASSERT("1s" == util::duration_str(1.)); - CU_ASSERT("500ms" == util::duration_str(0.5)); - CU_ASSERT("1500ms" == util::duration_str(1.5)); - CU_ASSERT("2m" == util::duration_str(120.)); - CU_ASSERT("121s" == util::duration_str(121.)); - CU_ASSERT("1h" == util::duration_str(3600.)); + assert_stdstring_equal("0", util::duration_str(0.)); + assert_stdstring_equal("1s", util::duration_str(1.)); + assert_stdstring_equal("500ms", util::duration_str(0.5)); + assert_stdstring_equal("1500ms", util::duration_str(1.5)); + assert_stdstring_equal("2m", util::duration_str(120.)); + assert_stdstring_equal("121s", util::duration_str(121.)); + assert_stdstring_equal("1h", util::duration_str(3600.)); } void test_util_format_duration(void) { - CU_ASSERT("0us" == util::format_duration(std::chrono::microseconds(0))); - CU_ASSERT("999us" == util::format_duration(std::chrono::microseconds(999))); - CU_ASSERT("1.00ms" == util::format_duration(std::chrono::microseconds(1000))); - CU_ASSERT("1.09ms" == util::format_duration(std::chrono::microseconds(1090))); - CU_ASSERT("1.01ms" == util::format_duration(std::chrono::microseconds(1009))); - CU_ASSERT("999.99ms" == - util::format_duration(std::chrono::microseconds(999990))); - CU_ASSERT("1.00s" == - util::format_duration(std::chrono::microseconds(1000000))); - CU_ASSERT("1.05s" == - util::format_duration(std::chrono::microseconds(1050000))); - - CU_ASSERT("0us" == util::format_duration(0.)); - CU_ASSERT("999us" == util::format_duration(0.000999)); - CU_ASSERT("1.00ms" == util::format_duration(0.001)); - CU_ASSERT("1.09ms" == util::format_duration(0.00109)); - CU_ASSERT("1.01ms" == util::format_duration(0.001009)); - CU_ASSERT("999.99ms" == util::format_duration(0.99999)); - CU_ASSERT("1.00s" == util::format_duration(1.)); - CU_ASSERT("1.05s" == util::format_duration(1.05)); + assert_stdstring_equal("0us", + util::format_duration(std::chrono::microseconds(0))); + assert_stdstring_equal("999us", + util::format_duration(std::chrono::microseconds(999))); + assert_stdstring_equal( + "1.00ms", util::format_duration(std::chrono::microseconds(1000))); + assert_stdstring_equal( + "1.09ms", util::format_duration(std::chrono::microseconds(1090))); + assert_stdstring_equal( + "1.01ms", util::format_duration(std::chrono::microseconds(1009))); + assert_stdstring_equal( + "999.99ms", util::format_duration(std::chrono::microseconds(999990))); + assert_stdstring_equal( + "1.00s", util::format_duration(std::chrono::microseconds(1000000))); + assert_stdstring_equal( + "1.05s", util::format_duration(std::chrono::microseconds(1050000))); + + assert_stdstring_equal("0us", util::format_duration(0.)); + assert_stdstring_equal("999us", util::format_duration(0.000999)); + assert_stdstring_equal("1.00ms", util::format_duration(0.001)); + assert_stdstring_equal("1.09ms", util::format_duration(0.00109)); + assert_stdstring_equal("1.01ms", util::format_duration(0.001009)); + assert_stdstring_equal("999.99ms", util::format_duration(0.99999)); + assert_stdstring_equal("1.00s", util::format_duration(1.)); + assert_stdstring_equal("1.05s", util::format_duration(1.05)); } void test_util_starts_with(void) { - CU_ASSERT(util::starts_with(StringRef::from_lit("foo"), - StringRef::from_lit("foo"))); - CU_ASSERT(util::starts_with(StringRef::from_lit("fooo"), - StringRef::from_lit("foo"))); - CU_ASSERT(util::starts_with(StringRef::from_lit("ofoo"), StringRef{})); - CU_ASSERT(!util::starts_with(StringRef::from_lit("ofoo"), - StringRef::from_lit("foo"))); - - CU_ASSERT(util::istarts_with(StringRef::from_lit("FOO"), - StringRef::from_lit("fOO"))); - CU_ASSERT(util::istarts_with(StringRef::from_lit("ofoo"), StringRef{})); - CU_ASSERT(util::istarts_with(StringRef::from_lit("fOOo"), - StringRef::from_lit("Foo"))); - CU_ASSERT(!util::istarts_with(StringRef::from_lit("ofoo"), + assert_true(util::starts_with(StringRef::from_lit("foo"), + StringRef::from_lit("foo"))); + assert_true(util::starts_with(StringRef::from_lit("fooo"), StringRef::from_lit("foo"))); + assert_true(util::starts_with(StringRef::from_lit("ofoo"), StringRef{})); + assert_false(util::starts_with(StringRef::from_lit("ofoo"), + StringRef::from_lit("foo"))); - CU_ASSERT(util::istarts_with_l(StringRef::from_lit("fOOo"), "Foo")); - CU_ASSERT(!util::istarts_with_l(StringRef::from_lit("ofoo"), "foo")); + assert_true(util::istarts_with(StringRef::from_lit("FOO"), + StringRef::from_lit("fOO"))); + assert_true(util::istarts_with(StringRef::from_lit("ofoo"), StringRef{})); + assert_true(util::istarts_with(StringRef::from_lit("fOOo"), + StringRef::from_lit("Foo"))); + assert_false(util::istarts_with(StringRef::from_lit("ofoo"), + StringRef::from_lit("foo"))); + + assert_true(util::istarts_with_l(StringRef::from_lit("fOOo"), "Foo")); + assert_false(util::istarts_with_l(StringRef::from_lit("ofoo"), "foo")); } void test_util_ends_with(void) { - CU_ASSERT( + assert_true( util::ends_with(StringRef::from_lit("foo"), StringRef::from_lit("foo"))); - CU_ASSERT(util::ends_with(StringRef::from_lit("foo"), StringRef{})); - CU_ASSERT( + assert_true(util::ends_with(StringRef::from_lit("foo"), StringRef{})); + assert_true( util::ends_with(StringRef::from_lit("ofoo"), StringRef::from_lit("foo"))); - CU_ASSERT( - !util::ends_with(StringRef::from_lit("ofoo"), StringRef::from_lit("fo"))); + assert_false( + util::ends_with(StringRef::from_lit("ofoo"), StringRef::from_lit("fo"))); - CU_ASSERT( + assert_true( util::iends_with(StringRef::from_lit("fOo"), StringRef::from_lit("Foo"))); - CU_ASSERT(util::iends_with(StringRef::from_lit("foo"), StringRef{})); - CU_ASSERT(util::iends_with(StringRef::from_lit("oFoo"), - StringRef::from_lit("fOO"))); - CU_ASSERT(!util::iends_with(StringRef::from_lit("ofoo"), - StringRef::from_lit("fo"))); + assert_true(util::iends_with(StringRef::from_lit("foo"), StringRef{})); + assert_true(util::iends_with(StringRef::from_lit("oFoo"), + StringRef::from_lit("fOO"))); + assert_false( + util::iends_with(StringRef::from_lit("ofoo"), StringRef::from_lit("fo"))); - CU_ASSERT(util::iends_with_l(StringRef::from_lit("oFoo"), "fOO")); - CU_ASSERT(!util::iends_with_l(StringRef::from_lit("ofoo"), "fo")); + assert_true(util::iends_with_l(StringRef::from_lit("oFoo"), "fOO")); + assert_false(util::iends_with_l(StringRef::from_lit("ofoo"), "fo")); } void test_util_parse_http_date(void) { - CU_ASSERT(1001939696 == util::parse_http_date(StringRef::from_lit( - "Mon, 1 Oct 2001 12:34:56 GMT"))); + assert_int64(1001939696, ==, + util::parse_http_date( + StringRef::from_lit("Mon, 1 Oct 2001 12:34:56 GMT"))); } void test_util_localtime_date(void) { @@ -450,25 +528,28 @@ void test_util_localtime_date(void) { #endif // !__linux__ tzset(); - CU_ASSERT_STRING_EQUAL("02/Oct/2001:00:34:56 +1200", - util::common_log_date(1001939696).c_str()); - CU_ASSERT_STRING_EQUAL("2001-10-02T00:34:56.123+12:00", - util::iso8601_date(1001939696000LL + 123).c_str()); + assert_stdstring_equal("02/Oct/2001:00:34:56 +1200", + util::common_log_date(1001939696)); + assert_stdstring_equal("2001-10-02T00:34:56.123+12:00", + util::iso8601_date(1001939696000LL + 123)); std::array common_buf; - CU_ASSERT("02/Oct/2001:00:34:56 +1200" == - util::format_common_log(common_buf.data(), - std::chrono::system_clock::time_point( - std::chrono::seconds(1001939696)))); + assert_stdstring_equal( + "02/Oct/2001:00:34:56 +1200", + util::format_common_log(common_buf.data(), + std::chrono::system_clock::time_point( + std::chrono::seconds(1001939696))) + .str()); std::array iso8601_buf; - CU_ASSERT( - "2001-10-02T00:34:56.123+12:00" == + assert_stdstring_equal( + "2001-10-02T00:34:56.123+12:00", util::format_iso8601(iso8601_buf.data(), std::chrono::system_clock::time_point( - std::chrono::milliseconds(1001939696123LL)))); + std::chrono::milliseconds(1001939696123LL))) + .str()); if (tz) { setenv("TZ", tz, 1); @@ -486,7 +567,7 @@ void test_util_get_uint64(void) { auto n = util::get_uint64(v.data()); - CU_ASSERT(0x01123456ff9aabbcULL == n); + assert_uint64(0x01123456ff9aabbcULL, ==, n); } { auto v = std::array{ @@ -494,83 +575,91 @@ void test_util_get_uint64(void) { auto n = util::get_uint64(v.data()); - CU_ASSERT(0xffffffffffffffffULL == n); + assert_uint64(0xffffffffffffffffULL, ==, n); } } void test_util_parse_config_str_list(void) { auto res = util::parse_config_str_list(StringRef::from_lit("a")); - CU_ASSERT(1 == res.size()); - CU_ASSERT("a" == res[0]); + assert_size(1, ==, res.size()); + assert_stdstring_equal("a", res[0]); res = util::parse_config_str_list(StringRef::from_lit("a,")); - CU_ASSERT(2 == res.size()); - CU_ASSERT("a" == res[0]); - CU_ASSERT("" == res[1]); + assert_size(2, ==, res.size()); + assert_stdstring_equal("a", res[0]); + assert_stdstring_equal("", res[1]); res = util::parse_config_str_list(StringRef::from_lit(":a::"), ':'); - CU_ASSERT(4 == res.size()); - CU_ASSERT("" == res[0]); - CU_ASSERT("a" == res[1]); - CU_ASSERT("" == res[2]); - CU_ASSERT("" == res[3]); + assert_size(4, ==, res.size()); + assert_stdstring_equal("", res[0]); + assert_stdstring_equal("a", res[1]); + assert_stdstring_equal("", res[2]); + assert_stdstring_equal("", res[3]); res = util::parse_config_str_list(StringRef{}); - CU_ASSERT(1 == res.size()); - CU_ASSERT("" == res[0]); + assert_size(1, ==, res.size()); + assert_stdstring_equal("", res[0]); res = util::parse_config_str_list(StringRef::from_lit("alpha,bravo,charlie")); - CU_ASSERT(3 == res.size()); - CU_ASSERT("alpha" == res[0]); - CU_ASSERT("bravo" == res[1]); - CU_ASSERT("charlie" == res[2]); + assert_size(3, ==, res.size()); + assert_stdstring_equal("alpha", res[0]); + assert_stdstring_equal("bravo", res[1]); + assert_stdstring_equal("charlie", res[2]); } void test_util_make_http_hostport(void) { BlockAllocator balloc(4096, 4096); - CU_ASSERT("localhost" == util::make_http_hostport( - balloc, StringRef::from_lit("localhost"), 80)); - CU_ASSERT("[::1]" == - util::make_http_hostport(balloc, StringRef::from_lit("::1"), 443)); - CU_ASSERT( - "localhost:3000" == - util::make_http_hostport(balloc, StringRef::from_lit("localhost"), 3000)); + assert_stdstring_equal( + "localhost", + util::make_http_hostport(balloc, StringRef::from_lit("localhost"), 80) + .str()); + assert_stdstring_equal( + "[::1]", + util::make_http_hostport(balloc, StringRef::from_lit("::1"), 443).str()); + assert_stdstring_equal( + "localhost:3000", + util::make_http_hostport(balloc, StringRef::from_lit("localhost"), 3000) + .str()); } void test_util_make_hostport(void) { std::array hostport_buf; - CU_ASSERT("localhost:80" == - util::make_hostport(std::begin(hostport_buf), - StringRef::from_lit("localhost"), 80)); - CU_ASSERT("[::1]:443" == util::make_hostport(std::begin(hostport_buf), - StringRef::from_lit("::1"), - 443)); + assert_stdstring_equal( + "localhost:80", util::make_hostport(std::begin(hostport_buf), + StringRef::from_lit("localhost"), 80) + .str()); + assert_stdstring_equal("[::1]:443", + util::make_hostport(std::begin(hostport_buf), + StringRef::from_lit("::1"), 443) + .str()); BlockAllocator balloc(4096, 4096); - CU_ASSERT("localhost:80" == - util::make_hostport(balloc, StringRef::from_lit("localhost"), 80)); - CU_ASSERT("[::1]:443" == - util::make_hostport(balloc, StringRef::from_lit("::1"), 443)); + assert_stdstring_equal( + "localhost:80", + util::make_hostport(balloc, StringRef::from_lit("localhost"), 80).str()); + assert_stdstring_equal( + "[::1]:443", + util::make_hostport(balloc, StringRef::from_lit("::1"), 443).str()); } void test_util_strifind(void) { - CU_ASSERT(util::strifind(StringRef::from_lit("gzip, deflate, bzip2"), - StringRef::from_lit("gzip"))); + assert_true(util::strifind(StringRef::from_lit("gzip, deflate, bzip2"), + StringRef::from_lit("gzip"))); - CU_ASSERT(util::strifind(StringRef::from_lit("gzip, deflate, bzip2"), - StringRef::from_lit("dEflate"))); + assert_true(util::strifind(StringRef::from_lit("gzip, deflate, bzip2"), + StringRef::from_lit("dEflate"))); - CU_ASSERT(util::strifind(StringRef::from_lit("gzip, deflate, bzip2"), - StringRef::from_lit("BZIP2"))); + assert_true(util::strifind(StringRef::from_lit("gzip, deflate, bzip2"), + StringRef::from_lit("BZIP2"))); - CU_ASSERT(util::strifind(StringRef::from_lit("nghttp2"), StringRef{})); + assert_true(util::strifind(StringRef::from_lit("nghttp2"), StringRef{})); // Be aware this fact - CU_ASSERT(!util::strifind(StringRef{}, StringRef{})); + assert_false(util::strifind(StringRef{}, StringRef{})); - CU_ASSERT(!util::strifind(StringRef::from_lit("nghttp2"), - StringRef::from_lit("http1"))); + assert_false(util::strifind(StringRef::from_lit("nghttp2"), + StringRef::from_lit("http1"))); } void test_util_random_alpha_digit(void) { @@ -580,116 +669,117 @@ void test_util_random_alpha_digit(void) { auto p = util::random_alpha_digit(std::begin(data), std::end(data), gen); - CU_ASSERT(std::end(data) == p); + assert_true(std::end(data) == p); for (auto b : data) { - CU_ASSERT(('A' <= b && b <= 'Z') || ('a' <= b && b <= 'z') || - ('0' <= b && b <= '9')); + assert_true(('A' <= b && b <= 'Z') || ('a' <= b && b <= 'z') || + ('0' <= b && b <= '9')); } } void test_util_format_hex(void) { BlockAllocator balloc(4096, 4096); - CU_ASSERT("0ff0" == - util::format_hex(balloc, StringRef::from_lit("\x0f\xf0"))); - CU_ASSERT("" == util::format_hex(balloc, StringRef::from_lit(""))); + assert_stdstring_equal( + "0ff0", util::format_hex(balloc, StringRef::from_lit("\x0f\xf0")).str()); + assert_stdstring_equal( + "", util::format_hex(balloc, StringRef::from_lit("")).str()); } void test_util_is_hex_string(void) { - CU_ASSERT(util::is_hex_string(StringRef{})); - CU_ASSERT(util::is_hex_string(StringRef::from_lit("0123456789abcdef"))); - CU_ASSERT(util::is_hex_string(StringRef::from_lit("0123456789ABCDEF"))); - CU_ASSERT(!util::is_hex_string(StringRef::from_lit("000"))); - CU_ASSERT(!util::is_hex_string(StringRef::from_lit("XX"))); + assert_true(util::is_hex_string(StringRef{})); + assert_true(util::is_hex_string(StringRef::from_lit("0123456789abcdef"))); + assert_true(util::is_hex_string(StringRef::from_lit("0123456789ABCDEF"))); + assert_false(util::is_hex_string(StringRef::from_lit("000"))); + assert_false(util::is_hex_string(StringRef::from_lit("XX"))); } void test_util_decode_hex(void) { BlockAllocator balloc(4096, 4096); - CU_ASSERT("\x0f\xf0" == - util::decode_hex(balloc, StringRef::from_lit("0ff0"))); - CU_ASSERT("" == util::decode_hex(balloc, StringRef{})); + assert_stdstring_equal( + "\x0f\xf0", util::decode_hex(balloc, StringRef::from_lit("0ff0")).str()); + assert_stdstring_equal("", util::decode_hex(balloc, StringRef{}).str()); } void test_util_extract_host(void) { - CU_ASSERT(StringRef::from_lit("foo") == - util::extract_host(StringRef::from_lit("foo"))); - CU_ASSERT(StringRef::from_lit("foo") == - util::extract_host(StringRef::from_lit("foo:"))); - CU_ASSERT(StringRef::from_lit("foo") == - util::extract_host(StringRef::from_lit("foo:0"))); - CU_ASSERT(StringRef::from_lit("[::1]") == - util::extract_host(StringRef::from_lit("[::1]"))); - CU_ASSERT(StringRef::from_lit("[::1]") == - util::extract_host(StringRef::from_lit("[::1]:"))); - - CU_ASSERT(util::extract_host(StringRef::from_lit(":foo")).empty()); - CU_ASSERT(util::extract_host(StringRef::from_lit("[::1")).empty()); - CU_ASSERT(util::extract_host(StringRef::from_lit("[::1]0")).empty()); - CU_ASSERT(util::extract_host(StringRef{}).empty()); + assert_stdstring_equal("foo", + util::extract_host(StringRef::from_lit("foo")).str()); + assert_stdstring_equal("foo", + util::extract_host(StringRef::from_lit("foo:")).str()); + assert_stdstring_equal( + "foo", util::extract_host(StringRef::from_lit("foo:0")).str()); + assert_stdstring_equal( + "[::1]", util::extract_host(StringRef::from_lit("[::1]")).str()); + assert_stdstring_equal( + "[::1]", util::extract_host(StringRef::from_lit("[::1]:")).str()); + + assert_true(util::extract_host(StringRef::from_lit(":foo")).empty()); + assert_true(util::extract_host(StringRef::from_lit("[::1")).empty()); + assert_true(util::extract_host(StringRef::from_lit("[::1]0")).empty()); + assert_true(util::extract_host(StringRef{}).empty()); } void test_util_split_hostport(void) { - CU_ASSERT(std::make_pair(StringRef::from_lit("foo"), StringRef{}) == - util::split_hostport(StringRef::from_lit("foo"))); - CU_ASSERT( + assert_true(std::make_pair(StringRef::from_lit("foo"), StringRef{}) == + util::split_hostport(StringRef::from_lit("foo"))); + assert_true( std::make_pair(StringRef::from_lit("foo"), StringRef::from_lit("80")) == util::split_hostport(StringRef::from_lit("foo:80"))); - CU_ASSERT( + assert_true( std::make_pair(StringRef::from_lit("::1"), StringRef::from_lit("80")) == util::split_hostport(StringRef::from_lit("[::1]:80"))); - CU_ASSERT(std::make_pair(StringRef::from_lit("::1"), StringRef{}) == - util::split_hostport(StringRef::from_lit("[::1]"))); + assert_true(std::make_pair(StringRef::from_lit("::1"), StringRef{}) == + util::split_hostport(StringRef::from_lit("[::1]"))); - CU_ASSERT(std::make_pair(StringRef{}, StringRef{}) == - util::split_hostport(StringRef{})); - CU_ASSERT(std::make_pair(StringRef{}, StringRef{}) == - util::split_hostport(StringRef::from_lit("[::1]:"))); - CU_ASSERT(std::make_pair(StringRef{}, StringRef{}) == - util::split_hostport(StringRef::from_lit("foo:"))); - CU_ASSERT(std::make_pair(StringRef{}, StringRef{}) == - util::split_hostport(StringRef::from_lit("[::1:"))); - CU_ASSERT(std::make_pair(StringRef{}, StringRef{}) == - util::split_hostport(StringRef::from_lit("[::1]80"))); + assert_true(std::make_pair(StringRef{}, StringRef{}) == + util::split_hostport(StringRef{})); + assert_true(std::make_pair(StringRef{}, StringRef{}) == + util::split_hostport(StringRef::from_lit("[::1]:"))); + assert_true(std::make_pair(StringRef{}, StringRef{}) == + util::split_hostport(StringRef::from_lit("foo:"))); + assert_true(std::make_pair(StringRef{}, StringRef{}) == + util::split_hostport(StringRef::from_lit("[::1:"))); + assert_true(std::make_pair(StringRef{}, StringRef{}) == + util::split_hostport(StringRef::from_lit("[::1]80"))); } void test_util_split_str(void) { - CU_ASSERT(std::vector{StringRef::from_lit("")} == - util::split_str(StringRef::from_lit(""), ',')); - CU_ASSERT(std::vector{StringRef::from_lit("alpha")} == - util::split_str(StringRef::from_lit("alpha"), ',')); - CU_ASSERT((std::vector{StringRef::from_lit("alpha"), - StringRef::from_lit("")}) == - util::split_str(StringRef::from_lit("alpha,"), ',')); - CU_ASSERT((std::vector{StringRef::from_lit("alpha"), - StringRef::from_lit("bravo")}) == - util::split_str(StringRef::from_lit("alpha,bravo"), ',')); - CU_ASSERT((std::vector{StringRef::from_lit("alpha"), - StringRef::from_lit("bravo"), - StringRef::from_lit("charlie")}) == - util::split_str(StringRef::from_lit("alpha,bravo,charlie"), ',')); - CU_ASSERT( + assert_true(std::vector{StringRef::from_lit("")} == + util::split_str(StringRef::from_lit(""), ',')); + assert_true(std::vector{StringRef::from_lit("alpha")} == + util::split_str(StringRef::from_lit("alpha"), ',')); + assert_true((std::vector{StringRef::from_lit("alpha"), + StringRef::from_lit("")}) == + util::split_str(StringRef::from_lit("alpha,"), ',')); + assert_true((std::vector{StringRef::from_lit("alpha"), + StringRef::from_lit("bravo")}) == + util::split_str(StringRef::from_lit("alpha,bravo"), ',')); + assert_true((std::vector{StringRef::from_lit("alpha"), + StringRef::from_lit("bravo"), + StringRef::from_lit("charlie")}) == + util::split_str(StringRef::from_lit("alpha,bravo,charlie"), ',')); + assert_true( (std::vector{StringRef::from_lit("alpha"), StringRef::from_lit("bravo"), StringRef::from_lit("charlie")}) == util::split_str(StringRef::from_lit("alpha,bravo,charlie"), ',', 0)); - CU_ASSERT(std::vector{StringRef::from_lit("")} == - util::split_str(StringRef::from_lit(""), ',', 1)); - CU_ASSERT(std::vector{StringRef::from_lit("")} == - util::split_str(StringRef::from_lit(""), ',', 2)); - CU_ASSERT( + assert_true(std::vector{StringRef::from_lit("")} == + util::split_str(StringRef::from_lit(""), ',', 1)); + assert_true(std::vector{StringRef::from_lit("")} == + util::split_str(StringRef::from_lit(""), ',', 2)); + assert_true( (std::vector{StringRef::from_lit("alpha"), StringRef::from_lit("bravo,charlie")}) == util::split_str(StringRef::from_lit("alpha,bravo,charlie"), ',', 2)); - CU_ASSERT(std::vector{StringRef::from_lit("alpha")} == - util::split_str(StringRef::from_lit("alpha"), ',', 2)); - CU_ASSERT((std::vector{StringRef::from_lit("alpha"), - StringRef::from_lit("")}) == - util::split_str(StringRef::from_lit("alpha,"), ',', 2)); - CU_ASSERT(std::vector{StringRef::from_lit("alpha")} == - util::split_str(StringRef::from_lit("alpha"), ',', 0)); - CU_ASSERT( + assert_true(std::vector{StringRef::from_lit("alpha")} == + util::split_str(StringRef::from_lit("alpha"), ',', 2)); + assert_true((std::vector{StringRef::from_lit("alpha"), + StringRef::from_lit("")}) == + util::split_str(StringRef::from_lit("alpha,"), ',', 2)); + assert_true(std::vector{StringRef::from_lit("alpha")} == + util::split_str(StringRef::from_lit("alpha"), ',', 0)); + assert_true( std::vector{StringRef::from_lit("alpha,bravo,charlie")} == util::split_str(StringRef::from_lit("alpha,bravo,charlie"), ',', 1)); } @@ -697,11 +787,16 @@ void test_util_split_str(void) { void test_util_rstrip(void) { BlockAllocator balloc(4096, 4096); - CU_ASSERT("alpha" == util::rstrip(balloc, StringRef::from_lit("alpha"))); - CU_ASSERT("alpha" == util::rstrip(balloc, StringRef::from_lit("alpha "))); - CU_ASSERT("alpha" == util::rstrip(balloc, StringRef::from_lit("alpha \t"))); - CU_ASSERT("" == util::rstrip(balloc, StringRef::from_lit(""))); - CU_ASSERT("" == util::rstrip(balloc, StringRef::from_lit("\t\t\t "))); + assert_stdstring_equal( + "alpha", util::rstrip(balloc, StringRef::from_lit("alpha")).str()); + assert_stdstring_equal( + "alpha", util::rstrip(balloc, StringRef::from_lit("alpha ")).str()); + assert_stdstring_equal( + "alpha", util::rstrip(balloc, StringRef::from_lit("alpha \t")).str()); + assert_stdstring_equal("", + util::rstrip(balloc, StringRef::from_lit("")).str()); + assert_stdstring_equal( + "", util::rstrip(balloc, StringRef::from_lit("\t\t\t ")).str()); } } // namespace shrpx diff --git a/src/util_test.h b/src/util_test.h index 48925ab..8b9608b 100644 --- a/src/util_test.h +++ b/src/util_test.h @@ -29,46 +29,52 @@ # include #endif // HAVE_CONFIG_H +#define MUNIT_ENABLE_ASSERT_ALIASES + +#include "munit.h" + namespace shrpx { -void test_util_streq(void); -void test_util_strieq(void); -void test_util_inp_strlower(void); -void test_util_to_base64(void); -void test_util_to_token68(void); -void test_util_percent_encode_token(void); -void test_util_percent_decode(void); -void test_util_quote_string(void); -void test_util_utox(void); -void test_util_http_date(void); -void test_util_select_h2(void); -void test_util_ipv6_numeric_addr(void); -void test_util_utos(void); -void test_util_make_string_ref_uint(void); -void test_util_utos_unit(void); -void test_util_utos_funit(void); -void test_util_parse_uint_with_unit(void); -void test_util_parse_uint(void); -void test_util_parse_duration_with_unit(void); -void test_util_duration_str(void); -void test_util_format_duration(void); -void test_util_starts_with(void); -void test_util_ends_with(void); -void test_util_parse_http_date(void); -void test_util_localtime_date(void); -void test_util_get_uint64(void); -void test_util_parse_config_str_list(void); -void test_util_make_http_hostport(void); -void test_util_make_hostport(void); -void test_util_strifind(void); -void test_util_random_alpha_digit(void); -void test_util_format_hex(void); -void test_util_is_hex_string(void); -void test_util_decode_hex(void); -void test_util_extract_host(void); -void test_util_split_hostport(void); -void test_util_split_str(void); -void test_util_rstrip(void); +extern const MunitSuite util_suite; + +munit_void_test_decl(test_util_streq); +munit_void_test_decl(test_util_strieq); +munit_void_test_decl(test_util_inp_strlower); +munit_void_test_decl(test_util_to_base64); +munit_void_test_decl(test_util_to_token68); +munit_void_test_decl(test_util_percent_encode_token); +munit_void_test_decl(test_util_percent_decode); +munit_void_test_decl(test_util_quote_string); +munit_void_test_decl(test_util_utox); +munit_void_test_decl(test_util_http_date); +munit_void_test_decl(test_util_select_h2); +munit_void_test_decl(test_util_ipv6_numeric_addr); +munit_void_test_decl(test_util_utos); +munit_void_test_decl(test_util_make_string_ref_uint); +munit_void_test_decl(test_util_utos_unit); +munit_void_test_decl(test_util_utos_funit); +munit_void_test_decl(test_util_parse_uint_with_unit); +munit_void_test_decl(test_util_parse_uint); +munit_void_test_decl(test_util_parse_duration_with_unit); +munit_void_test_decl(test_util_duration_str); +munit_void_test_decl(test_util_format_duration); +munit_void_test_decl(test_util_starts_with); +munit_void_test_decl(test_util_ends_with); +munit_void_test_decl(test_util_parse_http_date); +munit_void_test_decl(test_util_localtime_date); +munit_void_test_decl(test_util_get_uint64); +munit_void_test_decl(test_util_parse_config_str_list); +munit_void_test_decl(test_util_make_http_hostport); +munit_void_test_decl(test_util_make_hostport); +munit_void_test_decl(test_util_strifind); +munit_void_test_decl(test_util_random_alpha_digit); +munit_void_test_decl(test_util_format_hex); +munit_void_test_decl(test_util_is_hex_string); +munit_void_test_decl(test_util_decode_hex); +munit_void_test_decl(test_util_extract_host); +munit_void_test_decl(test_util_split_hostport); +munit_void_test_decl(test_util_split_str); +munit_void_test_decl(test_util_rstrip); } // namespace shrpx -- cgit v1.2.3