From 1b6ce8e697224a7221df0b111a2684b4f5fe2c26 Mon Sep 17 00:00:00 2001 From: stefanocasazza Date: Tue, 8 Aug 2017 18:38:15 +0200 Subject: [PATCH] fix --- Makefile.am | 2 +- Makefile.in | 2 +- README.md | 6 + configure | 79 +- configure.ac | 27 +- examples/WiAuth/cdbmake.cpp | 29 +- examples/WiAuth/rdbgen.cpp | 68 +- examples/lrp_session/common2.cpp | 2 +- examples/test_manager/test_manager.cpp | 1 - fuzz/Makefile.am | 11 +- fuzz/Makefile.in | 43 +- fuzz/uhttp_parser_fuzzer.cpp | 80 + include/ulib/all.h | 1 - include/ulib/application.h | 6 + include/ulib/base/base.h | 3 + include/ulib/base/macro.h | 8 +- include/ulib/base/utility.h | 23 +- include/ulib/db/cdb.h | 2 + include/ulib/db/rdb.h | 1 + include/ulib/internal/macro.h | 1 - include/ulib/internal/memory_pool.h | 2 + include/ulib/log.h | 152 +- include/ulib/net/client/client.h | 21 +- include/ulib/net/server/server.h | 101 +- include/ulib/net/socket.h | 4 +- include/ulib/notifier.h | 3 +- include/ulib/ssl/net/sslsocket.h | 2 +- include/ulib/string.h | 4 + include/ulib/url.h | 129 +- include/ulib/utility/lock.h | 20 +- include/ulib/utility/uhttp.h | 7 +- m4/ac_check_package.m4 | 5 +- m4/ac_compilation_options.m4 | 26 +- m4/ax_lib_postgresql.m4 | 13 +- src/ulib/Makefile.am | 6 +- src/ulib/Makefile.in | 4 +- src/ulib/base/utility.c | 58 +- src/ulib/base/win32/mingw32.c | 2 +- src/ulib/date.cpp | 4 - src/ulib/db/cdb.cpp | 35 +- src/ulib/db/rdb.cpp | 2 +- src/ulib/debug/debug_common.cpp | 6 +- src/ulib/file.cpp | 4 +- src/ulib/internal/common.cpp | 2 + src/ulib/internal/error.cpp | 2 +- src/ulib/internal/memory_pool.cpp | 2 +- src/ulib/ldap/ldap.cpp | 2 +- src/ulib/log.cpp | 436 ++-- src/ulib/net/client/client.cpp | 78 +- src/ulib/net/client/http.cpp | 9 +- src/ulib/net/server/client_image.cpp | 34 +- src/ulib/net/server/plugin/mod_http.cpp | 15 +- src/ulib/net/server/plugin/mod_nocat.cpp | 8 +- src/ulib/net/server/plugin/mod_proxy.cpp | 2 +- src/ulib/net/server/server.cpp | 424 ++-- src/ulib/net/socket.cpp | 4 +- src/ulib/orm/driver/Makefile.am | 6 +- src/ulib/orm/driver/Makefile.in | 6 +- src/ulib/orm/orm_driver.cpp | 8 +- src/ulib/ssl/net/sslsocket.cpp | 11 +- src/ulib/string.cpp | 40 +- src/ulib/url.cpp | 437 ++-- src/ulib/utility/http2.cpp | 8 +- src/ulib/utility/services.cpp | 2 +- src/ulib/utility/socket_ext.cpp | 2 +- src/ulib/utility/string_ext.cpp | 3 +- src/ulib/utility/uhttp.cpp | 413 ++-- tests/base/test_utility.c | 2 +- tests/examples/Makefile.am | 5 +- tests/examples/Makefile.in | 67 +- tests/examples/bench_http_parser.cpp | 2 +- .../FrameworkBenchmarks/fbenchmark.cfg | 4 +- tests/examples/ctest_http_parser.c | 2162 +++++++++++++++++ tests/examples/test_http_parser.cpp | 1201 +++++++++ tests/examples/test_http_parser.h | 163 ++ tests/examples/web_server.sh | 14 +- tests/ulib/ok/url.ok | 42 +- tests/ulib/test_date.cpp | 3 +- tests/ulib/test_http.cpp | 2 +- tests/ulib/test_log.cpp | 6 +- tests/ulib/test_url.cpp | 27 +- 81 files changed, 5435 insertions(+), 1224 deletions(-) create mode 100644 fuzz/uhttp_parser_fuzzer.cpp create mode 100644 tests/examples/ctest_http_parser.c create mode 100644 tests/examples/test_http_parser.cpp create mode 100644 tests/examples/test_http_parser.h diff --git a/Makefile.am b/Makefile.am index 966cac775..2f1fad3bb 100644 --- a/Makefile.am +++ b/Makefile.am @@ -9,7 +9,7 @@ EXTRA_DIST = $(configfiles:%=%.in) \ cdb configure.help TODO LICENSE* README* *.spec* \ ULib.m4 rpm.sh rpmpkgreq.lst rpmpkgreq.lst.suse openwrt \ doc/Doxyfile doc/readme.txt shtool *.awk .travis.yml autogen.sh nativejson-benchmark \ - fuzz/http1-corpus fuzz/http2-corpus fuzz/build_libFuzzer.sh fuzz/Makefile.in fuzz/Makefile.am fuzz/uclient_fuzzer.cpp fuzz/uclient.cfg + fuzz/http1-corpus fuzz/http2-corpus fuzz/build_libFuzzer.sh fuzz/Makefile.in fuzz/Makefile.am fuzz/*.cpp fuzz/uclient.cfg MAINTAINERCLEANFILES = configure aclocal.m4 libtool Makefile.in Makefile INSTALL diff --git a/Makefile.in b/Makefile.in index dec39a5ee..9fd2c3d73 100644 --- a/Makefile.in +++ b/Makefile.in @@ -452,7 +452,7 @@ EXTRA_DIST = $(configfiles:%=%.in) \ cdb configure.help TODO LICENSE* README* *.spec* \ ULib.m4 rpm.sh rpmpkgreq.lst rpmpkgreq.lst.suse openwrt \ doc/Doxyfile doc/readme.txt shtool *.awk .travis.yml autogen.sh nativejson-benchmark \ - fuzz/http1-corpus fuzz/http2-corpus fuzz/build_libFuzzer.sh fuzz/Makefile.in fuzz/Makefile.am fuzz/uclient_fuzzer.cpp fuzz/uclient.cfg + fuzz/http1-corpus fuzz/http2-corpus fuzz/build_libFuzzer.sh fuzz/Makefile.in fuzz/Makefile.am fuzz/*.cpp fuzz/uclient.cfg MAINTAINERCLEANFILES = configure aclocal.m4 libtool Makefile.in Makefile INSTALL moduledir = @ULIB_MODULEDIR@ diff --git a/README.md b/README.md index d2d4bdc52..effa04ed1 100644 --- a/README.md +++ b/README.md @@ -101,3 +101,9 @@ Comments and suggestions are welcome. stefano casazza Please, excuse me for my bad english, it's not my natural language, if some parts of this page seems wrong to you, feel free to suggest me better ones. + +## Donation + +If this project help you reduce time to develop, you can give me a cup of coffee :) + +[![Donate](https://img.shields.io/badge/Donate-PayPal-green.svg)](https://paypal.me/stefanocasazza) diff --git a/configure b/configure index c84e6c0a8..c624eaaae 100755 --- a/configure +++ b/configure @@ -26244,7 +26244,9 @@ if test "${enable_CRPWS+set}" = set; then : fi if test -z "$enable_CRPWS"; then - if test "$enable_debug" = "yes"; then + if test "$USP_FLAGS" = "-DAS_cpoll_cppsp_DO"; then + enable_CRPWS="no" + elif test "$enable_debug" = "yes"; then enable_CRPWS="yes" else enable_CRPWS="no" @@ -26266,7 +26268,11 @@ if test "${enable_captive_portal+set}" = set; then : fi if test -z "$enable_captive_portal"; then - enable_captive_portal="no" + if test "$USP_FLAGS" = "-DAS_cpoll_cppsp_DO"; then + enable_captive_portal="yes" + else + enable_captive_portal="no" + fi fi if test "$enable_captive_portal" = "yes"; then @@ -26302,7 +26308,9 @@ if test "${enable_HIS+set}" = set; then : fi if test -z "$enable_HIS" ; then - if test "$enable_debug" = "yes"; then + if test "$USP_FLAGS" = "-DAS_cpoll_cppsp_DO"; then + enable_HIS="no" + elif test "$enable_debug" = "yes"; then enable_HIS="yes" else enable_HIS="no" @@ -26346,7 +26354,9 @@ if test "${enable_GSDS+set}" = set; then : fi if test -z "$enable_GSDS"; then - if test "$enable_debug" = "yes"; then + if test "$USP_FLAGS" = "-DAS_cpoll_cppsp_DO"; then + enable_GSDS="no" + elif test "$enable_debug" = "yes"; then enable_GSDS="yes" else enable_GSDS="no" @@ -26430,7 +26440,9 @@ if test "${enable_check_time+set}" = set; then : fi if test -z "$enable_check_time"; then - if test "$enable_debug" = "yes" -a "$enable_http2" != "yes"; then + if test "$USP_FLAGS" = "-DAS_cpoll_cppsp_DO"; then + enable_check_time="no" + elif test "$enable_debug" = "yes" -a "$enable_http2" != "yes"; then enable_check_time="yes" else enable_check_time="no" @@ -26582,7 +26594,9 @@ if test "${enable_HSTS+set}" = set; then : fi if test -z "$enable_HSTS"; then - if test "$enable_debug" = "yes"; then + if test "$USP_FLAGS" = "-DAS_cpoll_cppsp_DO"; then + enable_HSTS="no" + elif test "$enable_debug" = "yes"; then enable_HSTS="yes" else enable_HSTS="no" @@ -28342,7 +28356,7 @@ fi MYSQL_INCLUDE=`mysql_config --include` libmysql_version=$(grep LIBMYSQL_VERSION /usr/include/mysql/mysql_version.h 2>/dev/null | head -n1 | cut -d'"' -f2) else - MYSQL_INCLUDE=-I$ac_mysql_incdir + MYSQL_INCLUDE=$ac_mysql_incdir libmysql_version=$(grep LIBMYSQL_VERSION $ac_mysql_incdir/mysql/mysql_version.h 2>/dev/null | head -n1 | cut -d'"' -f2) fi if test "$ac_mysql_libdir" = "no"; then @@ -28471,11 +28485,18 @@ fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for PostgreSQL libraries" >&5 $as_echo_n "checking for PostgreSQL libraries... " >&6; } - POSTGRESQL_CPPFLAGS="`$PG_CONFIG --includedir` -I`$PG_CONFIG --includedir-server`" - POSTGRESQL_LDFLAGS=-L"`$PG_CONFIG --libdir`" - POSTGRESQL_LIBS="-lpq" + postgresql_libdir=`$PG_CONFIG --libdir` + + POSTGRESQL_LDFLAGS=-L"$postgresql_libdir" + POSTGRESQL_CPPFLAGS="-I`$PG_CONFIG --includedir` -I`$PG_CONFIG --includedir-server`" POSTGRESQL_VERSION=`$PG_CONFIG --version | sed -e 's#PostgreSQL ##'` + if test -f "$postgresql_libdir/libpgport.a"; then + POSTGRESQL_LIBS="-lpq -lpgport" + else + POSTGRESQL_LIBS="-lpq" + fi + $as_echo "#define HAVE_POSTGRESQL 1" >>confdefs.h @@ -31537,7 +31558,7 @@ if test "${enable_static_server_plugin+set}" = set; then : fi -for mod in $modules; do +for mod in $use_static_module; do { $as_echo "$as_me:${as_lineno-$LINENO}: checking server plugin \"$mod\"" >&5 $as_echo_n "checking server plugin \"$mod\"... " >&6; } @@ -31781,7 +31802,7 @@ if test "${enable_static_orm_driver+set}" = set; then : fi -for drv in $drivers; do +for drv in $use_static_driver; do { $as_echo "$as_me:${as_lineno-$LINENO}: checking ORM driver \"$drv\"" >&5 $as_echo_n "checking ORM driver \"$drv\"... " >&6; } @@ -31793,26 +31814,26 @@ $as_echo_n "checking ORM driver \"$drv\"... " >&6; } static_handler_sqlite="yes" ULIB_LIBS="$ULIB_LIBS $SQLITE3_LIBS" LDFLAGS="$SQLITE3_LDFLAGS $LDFLAGS" - CPPFLAGS="$SQLITE3_INCLUDE $CPPFLAGS" + CXXFLAGS="$SQLITE3_INCLUDE $CXXFLAGS" $as_echo "#define U_STATIC_ORM_DRIVER_SQLITE /**/" >>confdefs.h - elif test "$drv" = "mysql"; then - static_handler_mysql="yes" - ULIB_LIBS="$ULIB_LIBS $MYSQL_LIBS" - LDFLAGS="$MYSQL_LDFLAGS $LDFLAGS" - CPPFLAGS="$MYSQL_INCLUDE $CPPFLAGS" - -$as_echo "#define U_STATIC_ORM_DRIVER_MYSQL /**/" >>confdefs.h - elif test "$drv" = "pgsql"; then static_handler_pgsql="yes" ULIB_LIBS="$ULIB_LIBS $POSTGRESQL_LIBS" LDFLAGS="$POSTGRESQL_LDFLAGS $LDFLAGS" - CPPFLAGS="$POSTGRESQL_CPPFLAGS $CPPFLAGS" + CXXFLAGS="$POSTGRESQL_CPPFLAGS $CXXFLAGS" $as_echo "#define U_STATIC_ORM_DRIVER_PGSQL /**/" >>confdefs.h + elif test "$drv" = "mysql"; then + static_handler_mysql="yes" + ULIB_LIBS="$ULIB_LIBS $MYSQL_LIBS" + LDFLAGS="$MYSQL_LDFLAGS $LDFLAGS" + CXXFLAGS="$MYSQL_INCLUDE $CXXFLAGS" + +$as_echo "#define U_STATIC_ORM_DRIVER_MYSQL /**/" >>confdefs.h + fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: static" >&5 @@ -32087,6 +32108,13 @@ CXXFLAGS="$CXXFLAGS -fno-exceptions -fno-rtti" if test "$ac_cv_c_compiler_gnu" = "yes" -a "x$GCC_IS_CLANG" = xno -a "x$OPERATINGSYSTEM" = xlinux; then + +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: " >&5 +$as_echo "" >&6; } +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: ${T_MD}Checking for gcc compiler flags:${T_ME}" >&5 +$as_echo "${T_MD}Checking for gcc compiler flags:${T_ME}" >&6; } + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to use libgcc" >&5 $as_echo_n "checking whether to use libgcc... " >&6; } # Check whether --enable-libgcc was given. @@ -32108,13 +32136,6 @@ $as_echo "no" >&6; } fi - -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: " >&5 -$as_echo "" >&6; } -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: ${T_MD}Checking for gcc compiler flags:${T_ME}" >&5 -$as_echo "${T_MD}Checking for gcc compiler flags:${T_ME}" >&6; } - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC supports " >&5 $as_echo_n "checking whether $CC supports ... " >&6; } diff --git a/configure.ac b/configure.ac index b46f7cf24..912829409 100644 --- a/configure.ac +++ b/configure.ac @@ -2001,7 +2001,7 @@ AC_ARG_ENABLE(static-server-plugin, AS_HELP_STRING([--enable-static-server-plugin=MODULES],[ rpc shib stream socket scgi fcgi geoip proxy soap ssi tsa nocat http echo ]), [use_static_module="$enableval"]) -for mod in $modules; do +for mod in $use_static_module; do AC_MSG_CHECKING([server plugin "$mod"]) if echo $use_static_module | grep -w $mod >/dev/null || echo $use_static_module | grep all >/dev/null; then @@ -2103,10 +2103,11 @@ static_handler_mysql="" static_handler_sqlite="" static_handler_pgsql="" -AC_ARG_ENABLE(static-orm-driver, AS_HELP_STRING([--enable-static-orm-driver=DRIVERS],[ sqlite mysql pgsql ]), +AC_ARG_ENABLE(static-orm-driver, + AS_HELP_STRING([--enable-static-orm-driver=DRIVERS],[ sqlite mysql pgsql ]), [use_static_driver="$enableval"]) -for drv in $drivers; do +for drv in $use_static_driver; do AC_MSG_CHECKING([ORM driver "$drv"]) if echo $use_static_driver | grep -w $drv >/dev/null || echo $use_static_driver | grep all >/dev/null; then @@ -2117,20 +2118,20 @@ for drv in $drivers; do static_handler_sqlite="yes" ULIB_LIBS="$ULIB_LIBS $SQLITE3_LIBS" LDFLAGS="$SQLITE3_LDFLAGS $LDFLAGS" - CPPFLAGS="$SQLITE3_INCLUDE $CPPFLAGS" + CXXFLAGS="$SQLITE3_INCLUDE $CXXFLAGS" AC_DEFINE(U_STATIC_ORM_DRIVER_SQLITE,, [STATIC_ORM_DRIVER_SQLITE]) - elif test "$drv" = "mysql"; then - static_handler_mysql="yes" - ULIB_LIBS="$ULIB_LIBS $MYSQL_LIBS" - LDFLAGS="$MYSQL_LDFLAGS $LDFLAGS" - CPPFLAGS="$MYSQL_INCLUDE $CPPFLAGS" - AC_DEFINE(U_STATIC_ORM_DRIVER_MYSQL,, [STATIC_ORM_DRIVER_MYSQL]) elif test "$drv" = "pgsql"; then static_handler_pgsql="yes" ULIB_LIBS="$ULIB_LIBS $POSTGRESQL_LIBS" LDFLAGS="$POSTGRESQL_LDFLAGS $LDFLAGS" - CPPFLAGS="$POSTGRESQL_CPPFLAGS $CPPFLAGS" + CXXFLAGS="$POSTGRESQL_CPPFLAGS $CXXFLAGS" AC_DEFINE(U_STATIC_ORM_DRIVER_PGSQL,, [STATIC_ORM_DRIVER_PGSQL]) + elif test "$drv" = "mysql"; then + static_handler_mysql="yes" + ULIB_LIBS="$ULIB_LIBS $MYSQL_LIBS" + LDFLAGS="$MYSQL_LDFLAGS $LDFLAGS" + CXXFLAGS="$MYSQL_INCLUDE $CXXFLAGS" + AC_DEFINE(U_STATIC_ORM_DRIVER_MYSQL,, [STATIC_ORM_DRIVER_MYSQL]) fi AC_MSG_RESULT([static]) @@ -2253,6 +2254,8 @@ CXXFLAGS="$CXXFLAGS -fno-exceptions -fno-rtti" if test "$ac_cv_c_compiler_gnu" = "yes" -a "x$GCC_IS_CLANG" = xno -a "x$OPERATINGSYSTEM" = xlinux; then + TWOCAN_CONF_MSG(Checking for gcc compiler flags) + AC_MSG_CHECKING([whether to use libgcc]) AC_ARG_ENABLE(libgcc, AC_HELP_STRING([--enable-libgcc],[use libgcc when linking]), @@ -2267,8 +2270,6 @@ if test "$ac_cv_c_compiler_gnu" = "yes" -a "x$GCC_IS_CLANG" = xno -a "x$OPERATIN AC_MSG_RESULT(no) ) - TWOCAN_CONF_MSG(Checking for gcc compiler flags) - AC_CC_TRY_FLAG MAYBE_FLAGS="-Wstrict-aliasing=2 -Wall -Wextra -Wsign-compare -Wpointer-arith -Wwrite-strings \ diff --git a/examples/WiAuth/cdbmake.cpp b/examples/WiAuth/cdbmake.cpp index 5851fb5d8..83ba6772f 100644 --- a/examples/WiAuth/cdbmake.cpp +++ b/examples/WiAuth/cdbmake.cpp @@ -1,6 +1,7 @@ // cdbmake.cpp #include +#include #include #undef PACKAGE @@ -27,9 +28,20 @@ class Application : public UApplication { UApplication::run(argc, argv, env); - UString records = UFile::contentOf(UString(argv[optind])); + uint32_t len; + const char* path_of_record_file = argv[optind]; + + if (path_of_record_file == U_NULLPTR || + (len = u__strlen(path_of_record_file, __PRETTY_FUNCTION__)) == 0) + { + U_ERROR("missing argument"); + } + + UString filename = UString(path_of_record_file, len); # ifdef U_STDCPP_ENABLE + UString records = UFile::contentOf(filename); + if (records) { UCDB x(false); @@ -38,9 +50,7 @@ class Application : public UApplication { x.UFile::ftruncate(UCDB::sizeFor(1) + records.size() * 2) && x.UFile::memmap(PROT_READ | PROT_WRITE)) { - const char* bcheck = argv[++optind]; - - if (bcheck) + if (argv[++optind]) { // +11,10:74@10.8.1.5->0 10.8.1.5 // .... @@ -86,6 +96,17 @@ class Application : public UApplication { records = output; } + UString basename = UStringExt::basename(filename); + + const char* p = basename.data(); + +# ifdef U_EVASIVE_SUPPORT + if (memcmp(p, U_CONSTANT_TO_PARAM("Evasive")) == 0) UCDB::getValueFromBuffer = UServer_Base::getEvasiveRecFromBuffer; +# endif +# ifdef U_THROTTLING_SUPPORT + if (memcmp(p, U_CONSTANT_TO_PARAM("BandWidthThrottling")) == 0) UCDB::getValueFromBuffer = UServer_Base::getThrottlingRecFromBuffer; +# endif + istrstream is(U_STRING_TO_PARAM(records)); is >> x; // NB: this do ftruncate() e munmap()... diff --git a/examples/WiAuth/rdbgen.cpp b/examples/WiAuth/rdbgen.cpp index f9055efc8..6ca298fc3 100644 --- a/examples/WiAuth/rdbgen.cpp +++ b/examples/WiAuth/rdbgen.cpp @@ -1,6 +1,7 @@ // rdbgen.cpp #include +#include #undef PACKAGE #define PACKAGE "rdbgen" @@ -43,19 +44,17 @@ class Application : public UApplication { UApplication::run(argc, argv, env); - const char* p = argv[optind++]; + uint32_t plen; + const char* p = argv[optind++]; - UString path_of_db_file(p, strlen(p)); - - if (path_of_db_file.empty()) U_ERROR("missing argument"); - - URDB x(path_of_db_file, false); - - if (x.UFile::getSuffix().equal(U_CONSTANT_TO_PARAM("jnl"))) + if (p == U_NULLPTR || + (plen = u__strlen(p, __PRETTY_FUNCTION__)) == 0) { - U_ERROR("you must avoid the jnl suffix, exiting"); + U_ERROR("missing argument"); } + U_INTERNAL_DUMP("optind = %d argv[optind] = %S", optind, argv[optind]) + const char* method = argv[optind++]; if (method == U_NULLPTR) U_ERROR(" argument is missing"); @@ -63,12 +62,42 @@ class Application : public UApplication { if (u__isdigit(*method) == false) U_ERROR(" argument is not numeric"); int op = method[0] - '0'; + bool bjournal2remove = false; + const char* suffix = u_getsuffix(p, plen); - if (x.open(10 * 1024 * 1024, false, op == 6, true)) // bool open(uint32_t log_size, bool btruncate, bool cdb_brdonly, bool breference) + if (suffix) { - if (method[1] == 's') x.setShared(U_NULLPTR,U_NULLPTR); // POSIX shared memory object (interprocess - can be used by unrelated processes) + U_INTERNAL_DUMP("suffix = %S", suffix) + + if (memcmp(suffix+1, U_CONSTANT_TO_PARAM("cdb")) == 0) + { + char buffer[U_PATH_MAX]; + + (void) memcmp(buffer, p, plen); + (void) memcmp(buffer+plen, ".jnl", sizeof(".jnl")); + + if (UFile::access(buffer, R_OK) == false) bjournal2remove = true; + } + else if (memcmp(suffix+1, U_CONSTANT_TO_PARAM("jnl")) == 0) + { + plen -= U_CONSTANT_SIZE(".jnl"); + + U_WARNING("you must avoid the jnl suffix"); + } + } + + URDB x(UString(p, plen), false); + + if (x.open(10 * 1024 * 1024, false, (op == 6), true)) // bool open(uint32_t log_size, bool btruncate, bool cdb_brdonly, bool breference) + { + if (bjournal2remove) (void) x.getJournal()._unlink(); // NB: we have only the constant db + if (x.UFile::st_size == 0) (void) x.UFile::_unlink(); // NB: we have only the journal + + if (method[1] == 's') x.setShared(U_NULLPTR, U_NULLPTR); // POSIX shared memory object (interprocess - can be used by unrelated processes) else x.resetReference(); + U_INTERNAL_DUMP("optind = %d argv[optind] = %S", optind, argv[optind]) + switch (op) { case 1: // get @@ -127,10 +156,21 @@ class Application : public UApplication { case 5: // dump { - UString value = x.print(); + UString y = x.UFile::getName(); + + p = y.data(); + +# ifdef U_EVASIVE_SUPPORT + if (memcmp(p, U_CONSTANT_TO_PARAM("Evasive")) == 0) UString::printValueToBuffer = UServer_Base::printEvasiveRecToBuffer; +# endif +# ifdef U_THROTTLING_SUPPORT + if (memcmp(p, U_CONSTANT_TO_PARAM("BandWidthThrottling")) == 0) UString::printValueToBuffer = UServer_Base::printThrottlingRecToBuffer; +# endif + + y = x.print(); - if (value.empty()) (void) UFile::_unlink(U_DIR_OUTPUT U_FILE_OUTPUT); - else (void) UFile::writeToTmp(U_STRING_TO_PARAM(value), O_RDWR | O_TRUNC, U_CONSTANT_TO_PARAM(U_FILE_OUTPUT), 0); + if (y.empty()) (void) UFile::_unlink(U_DIR_OUTPUT U_FILE_OUTPUT); + else (void) UFile::writeToTmp(U_STRING_TO_PARAM(y), O_RDWR | O_TRUNC, U_CONSTANT_TO_PARAM(U_FILE_OUTPUT), 0); } break; diff --git a/examples/lrp_session/common2.cpp b/examples/lrp_session/common2.cpp index aefc32062..561305f39 100644 --- a/examples/lrp_session/common2.cpp +++ b/examples/lrp_session/common2.cpp @@ -13,7 +13,7 @@ if (log.isOpen()) { - log.setShared(0, 0); + log.setShared(0); log.init("%P|%4D|"); } diff --git a/examples/test_manager/test_manager.cpp b/examples/test_manager/test_manager.cpp index 214f8202d..1dffe42ed 100644 --- a/examples/test_manager/test_manager.cpp +++ b/examples/test_manager/test_manager.cpp @@ -3,7 +3,6 @@ #include #include -#include #include #include #include diff --git a/fuzz/Makefile.am b/fuzz/Makefile.am index 26108a0b7..f5b02db38 100644 --- a/fuzz/Makefile.am +++ b/fuzz/Makefile.am @@ -13,8 +13,17 @@ uclient_fuzzer_CFLAGS = -fno-omit-frame-pointer -fsanitize=address -fsanitize-c uclient_fuzzer_CXXFLAGS = -fno-omit-frame-pointer -fsanitize=address -fsanitize-coverage=edge,indirect-calls,8bit-counters uclient_fuzzer_LDFLAGS = -fsanitize=address +uhttp_parser_fuzzer_CC = clang +uhttp_parser_fuzzer_CXX = clang++ +uhttp_parser_fuzzer_CPPFLAGS = -D_GLIBCXX_GCC_GTHR_H +uhttp_parser_fuzzer_SOURCES = uhttp_parser_fuzzer.cpp +uhttp_parser_fuzzer_LDADD = $(ulib_la) libFuzzer.a +uhttp_parser_fuzzer_CFLAGS = -fno-omit-frame-pointer -fsanitize=address -fsanitize-coverage=edge,indirect-calls,8bit-counters +uhttp_parser_fuzzer_CXXFLAGS = -fno-omit-frame-pointer -fsanitize=address -fsanitize-coverage=edge,indirect-calls,8bit-counters +uhttp_parser_fuzzer_LDFLAGS = -fsanitize=address + if CLANG -noinst_PROGRAMS = uclient_fuzzer +noinst_PROGRAMS = uclient_fuzzer uhttp_parser_fuzzer endif clean-local: diff --git a/fuzz/Makefile.in b/fuzz/Makefile.in index e0b07a015..70ab6e789 100644 --- a/fuzz/Makefile.in +++ b/fuzz/Makefile.in @@ -89,7 +89,8 @@ POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ target_triplet = @target@ -@CLANG_TRUE@noinst_PROGRAMS = uclient_fuzzer$(EXEEXT) +@CLANG_TRUE@noinst_PROGRAMS = uclient_fuzzer$(EXEEXT) \ +@CLANG_TRUE@ uhttp_parser_fuzzer$(EXEEXT) subdir = fuzz ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ac_check_package.m4 \ @@ -129,6 +130,14 @@ uclient_fuzzer_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ $(uclient_fuzzer_CXXFLAGS) $(CXXFLAGS) \ $(uclient_fuzzer_LDFLAGS) $(LDFLAGS) -o $@ +am_uhttp_parser_fuzzer_OBJECTS = \ + uhttp_parser_fuzzer-uhttp_parser_fuzzer.$(OBJEXT) +uhttp_parser_fuzzer_OBJECTS = $(am_uhttp_parser_fuzzer_OBJECTS) +uhttp_parser_fuzzer_DEPENDENCIES = $(am__DEPENDENCIES_1) libFuzzer.a +uhttp_parser_fuzzer_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \ + $(uhttp_parser_fuzzer_CXXFLAGS) $(CXXFLAGS) \ + $(uhttp_parser_fuzzer_LDFLAGS) $(LDFLAGS) -o $@ AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false @@ -162,8 +171,9 @@ AM_V_CXXLD = $(am__v_CXXLD_@AM_V@) am__v_CXXLD_ = $(am__v_CXXLD_@AM_DEFAULT_V@) am__v_CXXLD_0 = @echo " CXXLD " $@; am__v_CXXLD_1 = -SOURCES = $(uclient_fuzzer_SOURCES) -DIST_SOURCES = $(uclient_fuzzer_SOURCES) +SOURCES = $(uclient_fuzzer_SOURCES) $(uhttp_parser_fuzzer_SOURCES) +DIST_SOURCES = $(uclient_fuzzer_SOURCES) \ + $(uhttp_parser_fuzzer_SOURCES) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ @@ -392,6 +402,14 @@ uclient_fuzzer_LDADD = $(ulib_la) libFuzzer.a uclient_fuzzer_CFLAGS = -fno-omit-frame-pointer -fsanitize=address -fsanitize-coverage=edge,indirect-calls,8bit-counters uclient_fuzzer_CXXFLAGS = -fno-omit-frame-pointer -fsanitize=address -fsanitize-coverage=edge,indirect-calls,8bit-counters uclient_fuzzer_LDFLAGS = -fsanitize=address +uhttp_parser_fuzzer_CC = clang +uhttp_parser_fuzzer_CXX = clang++ +uhttp_parser_fuzzer_CPPFLAGS = -D_GLIBCXX_GCC_GTHR_H +uhttp_parser_fuzzer_SOURCES = uhttp_parser_fuzzer.cpp +uhttp_parser_fuzzer_LDADD = $(ulib_la) libFuzzer.a +uhttp_parser_fuzzer_CFLAGS = -fno-omit-frame-pointer -fsanitize=address -fsanitize-coverage=edge,indirect-calls,8bit-counters +uhttp_parser_fuzzer_CXXFLAGS = -fno-omit-frame-pointer -fsanitize=address -fsanitize-coverage=edge,indirect-calls,8bit-counters +uhttp_parser_fuzzer_LDFLAGS = -fsanitize=address all: all-am .SUFFIXES: @@ -439,6 +457,10 @@ uclient_fuzzer$(EXEEXT): $(uclient_fuzzer_OBJECTS) $(uclient_fuzzer_DEPENDENCIES @rm -f uclient_fuzzer$(EXEEXT) $(AM_V_CXXLD)$(uclient_fuzzer_LINK) $(uclient_fuzzer_OBJECTS) $(uclient_fuzzer_LDADD) $(LIBS) +uhttp_parser_fuzzer$(EXEEXT): $(uhttp_parser_fuzzer_OBJECTS) $(uhttp_parser_fuzzer_DEPENDENCIES) $(EXTRA_uhttp_parser_fuzzer_DEPENDENCIES) + @rm -f uhttp_parser_fuzzer$(EXEEXT) + $(AM_V_CXXLD)$(uhttp_parser_fuzzer_LINK) $(uhttp_parser_fuzzer_OBJECTS) $(uhttp_parser_fuzzer_LDADD) $(LIBS) + mostlyclean-compile: -rm -f *.$(OBJEXT) @@ -446,6 +468,7 @@ distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/uclient_fuzzer-uclient_fuzzer.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/uhttp_parser_fuzzer-uhttp_parser_fuzzer.Po@am__quote@ .cpp.o: @am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ @@ -485,6 +508,20 @@ uclient_fuzzer-uclient_fuzzer.obj: uclient_fuzzer.cpp @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(uclient_fuzzer_CPPFLAGS) $(CPPFLAGS) $(uclient_fuzzer_CXXFLAGS) $(CXXFLAGS) -c -o uclient_fuzzer-uclient_fuzzer.obj `if test -f 'uclient_fuzzer.cpp'; then $(CYGPATH_W) 'uclient_fuzzer.cpp'; else $(CYGPATH_W) '$(srcdir)/uclient_fuzzer.cpp'; fi` +uhttp_parser_fuzzer-uhttp_parser_fuzzer.o: uhttp_parser_fuzzer.cpp +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(uhttp_parser_fuzzer_CPPFLAGS) $(CPPFLAGS) $(uhttp_parser_fuzzer_CXXFLAGS) $(CXXFLAGS) -MT uhttp_parser_fuzzer-uhttp_parser_fuzzer.o -MD -MP -MF $(DEPDIR)/uhttp_parser_fuzzer-uhttp_parser_fuzzer.Tpo -c -o uhttp_parser_fuzzer-uhttp_parser_fuzzer.o `test -f 'uhttp_parser_fuzzer.cpp' || echo '$(srcdir)/'`uhttp_parser_fuzzer.cpp +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/uhttp_parser_fuzzer-uhttp_parser_fuzzer.Tpo $(DEPDIR)/uhttp_parser_fuzzer-uhttp_parser_fuzzer.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='uhttp_parser_fuzzer.cpp' object='uhttp_parser_fuzzer-uhttp_parser_fuzzer.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(uhttp_parser_fuzzer_CPPFLAGS) $(CPPFLAGS) $(uhttp_parser_fuzzer_CXXFLAGS) $(CXXFLAGS) -c -o uhttp_parser_fuzzer-uhttp_parser_fuzzer.o `test -f 'uhttp_parser_fuzzer.cpp' || echo '$(srcdir)/'`uhttp_parser_fuzzer.cpp + +uhttp_parser_fuzzer-uhttp_parser_fuzzer.obj: uhttp_parser_fuzzer.cpp +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(uhttp_parser_fuzzer_CPPFLAGS) $(CPPFLAGS) $(uhttp_parser_fuzzer_CXXFLAGS) $(CXXFLAGS) -MT uhttp_parser_fuzzer-uhttp_parser_fuzzer.obj -MD -MP -MF $(DEPDIR)/uhttp_parser_fuzzer-uhttp_parser_fuzzer.Tpo -c -o uhttp_parser_fuzzer-uhttp_parser_fuzzer.obj `if test -f 'uhttp_parser_fuzzer.cpp'; then $(CYGPATH_W) 'uhttp_parser_fuzzer.cpp'; else $(CYGPATH_W) '$(srcdir)/uhttp_parser_fuzzer.cpp'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/uhttp_parser_fuzzer-uhttp_parser_fuzzer.Tpo $(DEPDIR)/uhttp_parser_fuzzer-uhttp_parser_fuzzer.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='uhttp_parser_fuzzer.cpp' object='uhttp_parser_fuzzer-uhttp_parser_fuzzer.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(uhttp_parser_fuzzer_CPPFLAGS) $(CPPFLAGS) $(uhttp_parser_fuzzer_CXXFLAGS) $(CXXFLAGS) -c -o uhttp_parser_fuzzer-uhttp_parser_fuzzer.obj `if test -f 'uhttp_parser_fuzzer.cpp'; then $(CYGPATH_W) 'uhttp_parser_fuzzer.cpp'; else $(CYGPATH_W) '$(srcdir)/uhttp_parser_fuzzer.cpp'; fi` + mostlyclean-libtool: -rm -f *.lo diff --git a/fuzz/uhttp_parser_fuzzer.cpp b/fuzz/uhttp_parser_fuzzer.cpp new file mode 100644 index 000000000..63e55e095 --- /dev/null +++ b/fuzz/uhttp_parser_fuzzer.cpp @@ -0,0 +1,80 @@ +/** + * uhttp_parser_fuzzer.cpp + * + * This file implements a test harness for UHTTP parser with LibFuzzer + * + * See http://llvm.org/docs/LibFuzzer.html for more info + */ + +#include + +#define MARKER "\n--MARK--\n" + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* Data, size_t Size) // Entry point for libfuzzer +{ + if (Size == 0) + { + // Perform one-time initialization + + U_ULIB_INIT(0); + + u_init_ulib_hostname(); + + UClientImage_Base::init(); + + UString::str_allocate(STR_ALLOCATE_HTTP); + + return true; + } + + U_TRACE(5, "::LLVMFuzzerTestOneInput(%.*S,%u)", Size, Data, Size) + + U_INTERNAL_ASSERT_MAJOR(Size, 0) + + bool binary; + const char* p1; + const char* p2; + uint32_t len, cnt = 0, pos = 0; + const char* pend = (const char*)Data+Size; + +loop: + p1 = (const char*)Data+pos; + + binary = (u__istext(*p1) == false); + + if (binary == false && + u__isspace(*p1)) + { + do { + if (++p1 == pend) return 0; + } + while (u__isspace(*p1)); + } + + p2 = (const char*)memmem(p1, Size-pos, U_CONSTANT_TO_PARAM(MARKER)); + + len = (p2 ? p2-p1 : pend-p1); + + U_INTERNAL_DUMP("len = %u binary = %u", len, binary) + + if (binary || + len > U_CONSTANT_SIZE("GET /")) + { + UHTTP::parserExecute(p1, len); + + if (p2) + { + pos += len + U_CONSTANT_SIZE(MARKER); + + U_INTERNAL_DUMP("pos = %u cnt = %u", pos, cnt) + + if (pos < Size && + cnt++ < 20) + { + goto loop; + } + } + } + + return 0; +} diff --git a/include/ulib/all.h b/include/ulib/all.h index 7434f96d4..29850df29 100644 --- a/include/ulib/all.h +++ b/include/ulib/all.h @@ -1,7 +1,6 @@ // all.h #include -#include #include #include #include diff --git a/include/ulib/application.h b/include/ulib/application.h index 0570e6e29..616e71877 100644 --- a/include/ulib/application.h +++ b/include/ulib/application.h @@ -14,6 +14,7 @@ #ifndef ULIB_APPLICATION_H #define ULIB_APPLICATION_H 1 +#include #include #define U_PRINT_MEM_USAGE @@ -35,6 +36,7 @@ int U_EXPORT main(int argc, char* argv[], char* env[]) \ U_TRACE(5, "::main(%d,%p,%p)", argc, argv, env) \ Application application; \ application.run(argc, argv, env); \ + U_INTERNAL_ASSERT_EQUALS(ULog::first, U_NULLPTR) \ U_PRINT_MEM_USAGE \ U_MAIN_END(UApplication::exit_value); \ } @@ -50,6 +52,8 @@ int WINAPI WinMain (HINSTANCE hinstance, HINSTANCE hPrevInstance, LPSTR command_ U_TRACE(5, "::main(%d,%p,%p)", argc, __argv, 0) \ _class application; \ application.run(argc, argv, 0); \ + U_INTERNAL_ASSERT_EQUALS(ULog::first, U_NULLPTR) \ + U_PRINT_MEM_USAGE \ U_MAIN_END(UApplication::exit_value); \ } */ @@ -130,6 +134,8 @@ class U_EXPORT UApplication { num_args = opt.getopt(argc, argv, &optind); } + + U_INTERNAL_DUMP("optind = %d argv[optind] = %S", optind, argv[optind]) } static bool isOptions() diff --git a/include/ulib/base/base.h b/include/ulib/base/base.h index 710fd09ff..b36216422 100644 --- a/include/ulib/base/base.h +++ b/include/ulib/base/base.h @@ -209,6 +209,7 @@ typedef int (*iPFpv) (void*); typedef bool (*bPFpc) (const char*); typedef void (*vPFpc) (const char*); typedef void* (*pvPFpv) (void*); +typedef void (*vpFpcu) (const char*,uint32_t); typedef bool (*bPFpcu) (const char*,uint32_t); typedef void (*vPFpvu) (void*,uint32_t); typedef int (*iPFpvpv) (void*,void*); @@ -254,6 +255,8 @@ typedef struct ustringrep { typedef struct ustring { struct ustringrep* rep; } ustring; +#define U_PATH_MAX (1024U - (1 + sizeof(ustringrep))) + /* Internal buffer */ extern U_EXPORT char* u_buffer; diff --git a/include/ulib/base/macro.h b/include/ulib/base/macro.h index d6690dba4..48ddfdaed 100644 --- a/include/ulib/base/macro.h +++ b/include/ulib/base/macro.h @@ -70,7 +70,7 @@ #endif #if defined(DEBUG) || defined(U_TEST) -# if !defined(U_LINUX) || defined(U_SERVER_CAPTIVE_PORTAL) +# if !defined(U_LINUX) || (defined(U_SERVER_CAPTIVE_PORTAL) && !defined(ENABLE_THREAD)) # define U_NULL_POINTER (const void*)0 # else # define U_NULL_POINTER (const void*)0x0000ffff @@ -463,7 +463,7 @@ static inline void u_put_unalignedp64( void* p, uint64_t val) { s /* Memory alignment for pointer */ -#define U_MEMORY_ALIGNMENT(ptr, alignment) ptr += alignment - ((long)ptr & (alignment - 1)) +#define U_MEMORY_ALIGNMENT(ptr, alignment) ptr += alignment-((long)ptr & (alignment-1)) /* Manage number suffix */ @@ -478,8 +478,8 @@ static inline void u_put_unalignedp64( void* p, uint64_t val) { s /* Optimization if it is enough a resolution of one second */ #if defined(U_LINUX) && defined(ENABLE_THREAD) -# if defined(U_LOG_DISABLE) && !defined(USE_LIBZ) -# define U_gettimeofday +# ifdef U_SERVER_CAPTIVE_PORTAL +# define U_gettimeofday U_INTERNAL_ASSERT(u_pthread_time) # else # define U_gettimeofday { if (u_pthread_time == U_NULLPTR) u_now->tv_sec = time(U_NULLPTR); } # endif diff --git a/include/ulib/base/utility.h b/include/ulib/base/utility.h index 95d5f0d4b..1635149b7 100644 --- a/include/ulib/base/utility.h +++ b/include/ulib/base/utility.h @@ -78,6 +78,10 @@ typedef uint64_t cpu_set_t; # define CPUSET_BITS(set) (set) #endif +#ifndef UINT32_MAX +#define UINT32_MAX 4294967295U +#endif + /** * TOKEN ID */ @@ -623,23 +627,8 @@ static inline uint64_t u_strtoull(const char* restrict s, const char* restrict e #endif } -static inline unsigned long u_strtoulp(const char** restrict s) -{ - const char* restrict ptr; - const char* restrict p = *s; - - U_INTERNAL_TRACE("u_strtolp(%p)", s) - - U_INTERNAL_ASSERT_POINTER(s) - - while (u__isdigitw0(*p) == false) ++p; - - ptr = p; - - while (u__isdigit(*p)) ++p; - - return u_strtoul(ptr, *s = p); -} +extern U_EXPORT unsigned long u_strtoulp( const char** restrict s); +extern U_EXPORT uint64_t u_strtoullp(const char** restrict s); extern U_EXPORT unsigned long u__atoi(const char* restrict s) __pure; diff --git a/include/ulib/db/cdb.h b/include/ulib/db/cdb.h index 9be7433c8..e5170cddd 100644 --- a/include/ulib/db/cdb.h +++ b/include/ulib/db/cdb.h @@ -225,6 +225,8 @@ class U_EXPORT UCDB : public UFile { UString print(); #ifdef U_STDCPP_ENABLE + static vpFpcu getValueFromBuffer; + friend U_EXPORT istream& operator>>(istream& is, UCDB& cdb); friend U_EXPORT ostream& operator<<(ostream& os, UCDB& cdb); diff --git a/include/ulib/db/rdb.h b/include/ulib/db/rdb.h index 445a6e07e..e2df5572e 100644 --- a/include/ulib/db/rdb.h +++ b/include/ulib/db/rdb.h @@ -199,6 +199,7 @@ class U_EXPORT URDB : public UCDB { bool find(const UString& _key) { return find(U_STRING_TO_PARAM(_key)); } bool find(const char* _key, uint32_t keylen); + UFile& getJournal() { return journal; } uint32_t getCapacity() const { return RDB_capacity(this); } uint32_t getDataSize() const { return RDB_node_data_sz(this); } void* getDataPointer() const { return RDB_node_data(this); } diff --git a/include/ulib/internal/macro.h b/include/ulib/internal/macro.h index d169d2466..692d27f59 100644 --- a/include/ulib/internal/macro.h +++ b/include/ulib/internal/macro.h @@ -21,7 +21,6 @@ // NB: to avoid mis-aligned we use 4 bytes... #define U_MINIZ_COMPRESS "\x89MNZ" // "\211MNZ" "\x89\x4d\x4e\x5a" -#define U_PATH_MAX (1024U - (1 + sizeof(ustringrep))) // --------------------------------------------------------------------------------- // NB: the value must be a stack type boundary, see UStringRep::checkIfMReserve()... // --------------------------------------------------------------------------------- diff --git a/include/ulib/internal/memory_pool.h b/include/ulib/internal/memory_pool.h index ff1adebc9..e1e5dc9a8 100644 --- a/include/ulib/internal/memory_pool.h +++ b/include/ulib/internal/memory_pool.h @@ -14,6 +14,8 @@ #ifndef ULIB_MEMORY_POOL_H #define ULIB_MEMORY_POOL_H 1 +#include + // --------------------------------------------------------------------------------------------------------------- // U_STACK_TYPE_[0-9] 'type' stack for which the request is serviced with preallocation diff --git a/include/ulib/log.h b/include/ulib/log.h index 15ad40e3e..35cd06440 100644 --- a/include/ulib/log.h +++ b/include/ulib/log.h @@ -16,7 +16,9 @@ #include #include +#include +class ULib; class UHTTP; class UHTTP2; class Application; @@ -51,7 +53,6 @@ class U_EXPORT ULog : public UFile { // --------------> maybe unnamed array of char for gzip compression... } log_data; - static ULog* pthis; static log_date date; static const char* prefix; static uint32_t prefix_len; @@ -61,8 +62,20 @@ class U_EXPORT ULog : public UFile { static pthread_rwlock_t* prwlock; #endif - ULog(const UString& path, uint32_t size, const char* dir_log_gz = U_NULLPTR); - ~ULog(); + ULog(const UString& path, uint32_t size); + + ~ULog() + { + U_TRACE_UNREGISTER_OBJECT(0, ULog) + + if (lock) delete lock; + +# ifdef USE_LIBZ + if (buf_path_compress) delete buf_path_compress; +# endif + } + + void closeLog(); void reopen() { @@ -86,78 +99,155 @@ class U_EXPORT ULog : public UFile { ptr_log_data->file_page = ptr_log_data->file_ptr; } - void closeLog(); - void setShared(log_data* ptr, uint32_t size, bool breference = true); + void init(const char* _prefix, uint32_t _prefix_len) // server + { + U_TRACE(0, "ULog::init(%.*S,%u)", _prefix_len, _prefix, _prefix_len) + + U_INTERNAL_ASSERT_EQUALS(U_Log_syslog(this), false) + + prefix = _prefix; + prefix_len = _prefix_len; + U_Log_start_stop_msg(this) = true; + + startup(); + } + + void setPrefix(const char* _prefix, uint32_t _prefix_len) // client + { + U_TRACE(0, "ULog::setPrefix(%.*S,%u)", _prefix_len, _prefix, _prefix_len) - void init(const char* prefix, uint32_t prefix_len); // server - void setPrefix(const char* prefix, uint32_t prefix_len); // client + if (U_Log_syslog(this) == false) + { + prefix = _prefix; + prefix_len = _prefix_len; + U_Log_start_stop_msg(this) = true; + + startup(); + } + } // manage shared log - static bool isMemoryMapped() + bool isMemoryMapped() { U_TRACE_NO_PARAM(0, "ULog::isMemoryMapped()") - U_INTERNAL_ASSERT_POINTER(pthis) - - if (pthis->log_file_sz == 0) U_RETURN(false); + if (log_file_sz == 0) U_RETURN(false); U_RETURN(true); } + uint32_t getSizeLogRotateData() + { + U_TRACE_NO_PARAM(0, "ULog::getSizeLogRotateData()") + + U_INTERNAL_DUMP("log_file_sz = %u", log_file_sz) + + U_ASSERT(isMemoryMapped()) + + uint32_t x = log_file_sz + (log_file_sz / 10) + 12U; // The zlib documentation states that destination buffer size must be at least 0.1% larger than avail_in plus 12 bytes + + U_RETURN(x); + } + +#ifdef USE_LIBZ + void setShared(log_data* ptr); + void checkForLogRotateDataToWrite(); + void setLogRotate(const char* dir_log_gz = U_NULLPTR); +#endif + + UString getDirLogGz() + { + U_TRACE_NO_PARAM(0, "ULog::getDirLogGz()") + + U_ASSERT(isMemoryMapped()) + + UString result; + +# ifdef USE_LIBZ + U_INTERNAL_ASSERT_POINTER(buf_path_compress) + + result = UStringExt::dirname(*buf_path_compress); +# endif + + U_RETURN_STRING(result); + } + // write with prefix - static void write(const char* msg, uint32_t len); - static void log(const char* format, uint32_t fmt_size, ...); // (buffer write == 8196) + void write(const char* msg, uint32_t len); + + void log(const char* fmt, uint32_t fmt_size, ...) + { + U_TRACE(0, "ULog::log(%.*S,%u)", fmt_size, fmt, fmt_size) + + uint32_t len; + char buffer[8196]; + + va_list argp; + va_start(argp, fmt_size); + + len = u__vsnprintf(buffer, sizeof(buffer), fmt, fmt_size, argp); + + va_end(argp); + + write(buffer, len); + } // write without prefix - static void log(int _fd, const char* format, uint32_t fmt_size, ...); // (buffer write == 8196) + static void log(int _fd, const char* format, uint32_t fmt_size, ...); // (buffer write == 8196) // logger - static int getPriorityForLogger(const char* s) __pure; // decode a symbolic name to a numeric value + void logger(const char* ident, int priority, const char* format, uint32_t fmt_size, ...); // (buffer write == 4096) - static void logger(const char* ident, int priority, const char* format, uint32_t fmt_size, ...); // (buffer write == 4096) + static int getPriorityForLogger(const char* s) __pure; // decode a symbolic name to a numeric value -#if defined(U_STDCPP_ENABLE) && defined(DEBUG) +#ifdef DEBUG + static ULog* first; // active list +# ifdef U_STDCPP_ENABLE const char* dump(bool reset) const; +# endif #endif protected: ULock* lock; log_data* ptr_log_data; - uint32_t log_file_sz, log_gzip_sz; + uint32_t log_file_sz, + log_data_sz, + log_gzip_sz; unsigned char flag[4]; -#ifdef USE_LIBZ - UString* buf_path_compress; - uint32_t index_path_compress; - void checkForLogRotateDataToWrite(); -#endif - static uint32_t log_data_sz; - static long tv_sec_old_1, tv_sec_old_2, tv_sec_old_3; +#ifdef DEBUG + ULog* next; + static void close(); +#endif + void startup(); + void closeLogInternal(); void write(const struct iovec* iov, int n); + void logResponse(const UString& data, const char* name, const char* format, uint32_t fmt_size, ...); + void log(const struct iovec* iov, const char* name, const char* type, int ncount, const char* msg, uint32_t msg_len, const char* format, uint32_t fmt_size, ...); #ifdef USE_LIBZ - static UString getDirLogGz(); + UString* buf_path_compress; + uint32_t index_path_compress; #endif - static void close(); - static void startup(); + static long tv_sec_old_1, tv_sec_old_2, tv_sec_old_3; + static void initDate(); static void updateDate1(); static void updateDate2(); static void updateDate3(char* ptr_date); - static void logResponse(const UString& data, const char* name, const char* format, uint32_t fmt_size, ...); - static void log(const struct iovec* iov, const char* name, const char* type, int ncount, const char* msg, uint32_t msg_len, const char* format, uint32_t fmt_size, ...); private: static int decode(const char* name, uint32_t len, bool bfacility) __pure U_NO_EXPORT; U_DISALLOW_COPY_AND_ASSIGN(ULog) + friend class ULib; friend class UHTTP; friend class UHTTP2; friend class Application; @@ -168,6 +258,8 @@ class U_EXPORT ULog : public UFile { friend class UClient_Base; friend class UHttpClient_Base; friend class UClientImage_Base; + +// friend int main(int, char**, char**); }; #endif diff --git a/include/ulib/net/client/client.h b/include/ulib/net/client/client.h index bd2cc196d..b87e67960 100644 --- a/include/ulib/net/client/client.h +++ b/include/ulib/net/client/client.h @@ -29,7 +29,6 @@ * @brief Handles a connections with a server */ -class ULog; class UHTTP; class USSLSocket; class UHttpPlugIn; @@ -156,22 +155,6 @@ class U_EXPORT UClient_Base { // LOG - static void closeLog() - { - U_TRACE_NO_PARAM(0, "UClient_Base::closeLog()") - -# ifndef U_LOG_DISABLE - if (log && - log_shared_with_server == false) - { - u_unatexit(&ULog::close); // unregister function of close at exit()... - ULog::close(); - - log = U_NULLPTR; - } -# endif - } - void clearData() { U_TRACE_NO_PARAM(0, "UClient_Base::clearData()") @@ -180,6 +163,8 @@ class U_EXPORT UClient_Base { response.setEmpty(); } + static void closeLog(); + static void setLogShared() { U_TRACE_NO_PARAM(0, "UClient_Base::setLogShared()") @@ -247,7 +232,7 @@ class U_EXPORT UClient_Base { // Transmit token name (4 characters) and value (32-bit int, as 8 hex characters) bool sendTokenInt( const char* token, uint32_t value) { buffer.setEmpty(); return URPC::sendTokenInt( socket, token, value, buffer); } - bool sendTokenString(const char* token, const UString& data) { buffer.setEmpty(); return URPC::sendTokenString(socket, token, data, buffer); } // Write token, then the string data + bool sendTokenString(const char* token, const UString& data) { buffer.setEmpty(); return URPC::sendTokenString(socket, token, data, buffer); } // Write token and string data bool sendTokenVector(const char* token, UVector& vec) { buffer.setEmpty(); return URPC::sendTokenVector(socket, token, vec, buffer); } // Transmit an vector of string // DEBUG diff --git a/include/ulib/net/server/server.h b/include/ulib/net/server/server.h index ed6e39c36..11002f758 100644 --- a/include/ulib/net/server/server.h +++ b/include/ulib/net/server/server.h @@ -90,9 +90,9 @@ vClientImage = new client_type[UNotifier::max_connection]; } } # define U_SET_MODULE_NAME(name) { if (UServer_Base::isLog()) { (void) strcpy(UServer_Base::mod_name[1], UServer_Base::mod_name[0]); \ (void) strcpy(UServer_Base::mod_name[0], "["#name"] "); } } -# define U_SRV_LOG( fmt,args...) { if (UServer_Base::isLog()) ULog::log(U_CONSTANT_TO_PARAM("%s" fmt), UServer_Base::mod_name[0] , ##args); } -# define U_SRV_LOG_WITH_ADDR(fmt,args...) { if (UServer_Base::isLog()) ULog::log(U_CONSTANT_TO_PARAM("%s" fmt " %v"), UServer_Base::mod_name[0] , ##args, \ - UServer_Base::pClientImage->logbuf->rep); } +# define U_SRV_LOG( fmt,args...) { if (UServer_Base::isLog()) UServer_Base::log->log(U_CONSTANT_TO_PARAM("%s" fmt), UServer_Base::mod_name[0] , ##args); } +# define U_SRV_LOG_WITH_ADDR(fmt,args...) { if (UServer_Base::isLog()) UServer_Base::log->log(U_CONSTANT_TO_PARAM("%s" fmt " %v"), UServer_Base::mod_name[0] , ##args, \ + UServer_Base::pClientImage->logbuf->rep); } #endif class UHTTP; @@ -337,7 +337,6 @@ class U_EXPORT UServer_Base : public UEventFd { bool daylight_shared; # endif ULog::log_data log_data_shared; - char buffer[1]; // -> maybe unnamed array of char for gzip compression (log rotate) // -------------------------------------------------------------------------------- } shared_data; @@ -396,10 +395,12 @@ class U_EXPORT UServer_Base : public UEventFd { char spinlock_evasive[1]; char spinlock_db_not_found[1]; char spinlock_base[U_SHM_LOCK_NENTRY]; - char buffer[1]; + ULog::log_data log_data_shared; + // -> maybe unnamed array of char for gzip compression (apache log like rotate) } shm_data; static shm_data* ptr_shm_data; + static uint32_t shm_data_add, shm_size; #define U_SHM_LOCK_EVASIVE &(UServer_Base::ptr_shm_data->lock_evasive) #define U_SHM_LOCK_DB_NOT_FOUND &(UServer_Base::ptr_shm_data->lock_db_not_found) @@ -448,6 +449,16 @@ class U_EXPORT UServer_Base : public UEventFd { U_RETURN_POINTER(offset, void); } + static void* getOffsetToDataShm(uint32_t shm_data_size) + { + U_TRACE(0, "UServer_Base::getOffsetToDataShm(%u)", shm_data_size) + + long offset = sizeof(shm_data) + shm_data_add; + shm_data_add += shm_data_size; + + U_RETURN_POINTER(offset, void); + } + static void* getPointerToDataShare(void* shared_data_ptr) { U_TRACE(0, "UServer_Base::getPointerToDataShare(%p)", shared_data_ptr) @@ -459,6 +470,17 @@ class U_EXPORT UServer_Base : public UEventFd { U_RETURN_POINTER(shared_data_ptr, void); } + static void* getPointerToDataShm(void* shm_data_ptr) + { + U_TRACE(0, "UServer_Base::getPointerToDataShm(%p)", shm_data_ptr) + + U_INTERNAL_ASSERT_POINTER(ptr_shm_data) + + shm_data_ptr = (void*)((ptrdiff_t)ptr_shm_data + (ptrdiff_t)shm_data_ptr); + + U_RETURN_POINTER(shm_data_ptr, void); + } + static uint32_t nClientIndex; static UClientImage_Base* vClientImage; static UClientImage_Base* pClientImage; @@ -587,7 +609,7 @@ class U_EXPORT UServer_Base : public UEventFd { # ifndef U_LOG_DISABLE if (isLog()) { - if (UCommand::setMsgError(cmd, !balways) || balways) ULog::log(U_CONSTANT_TO_PARAM("%s%.*s"), mod_name[0], u_buffer_len, u_buffer); + if (UCommand::setMsgError(cmd, !balways) || balways) log->log(U_CONSTANT_TO_PARAM("%s%.*s"), mod_name[0], u_buffer_len, u_buffer); errno = 0; u_buffer_len = 0; @@ -701,6 +723,40 @@ class U_EXPORT UServer_Base : public UEventFd { uint32_t krate, min_limit, max_limit, num_sending; } uthrottling; + static void getThrottlingRecFromBuffer(const char* data, uint32_t datalen) + { + U_TRACE(0, "UServer_Base::getThrottlingRecFromBuffer(%.*S,%u)", datalen, data, datalen) + + throttling_rec = (uthrottling*)u_buffer; + + u_buffer_len = sizeof(uthrottling); + + const char* ptr = data; + + throttling_rec->bytes_since_avg = u_strtoullp(&ptr); + throttling_rec->krate = u_strtoulp(&ptr); + throttling_rec->min_limit = u_strtoulp(&ptr); + throttling_rec->max_limit = u_strtoulp(&ptr); + throttling_rec->num_sending = u_strtoulp(&ptr); + + U_INTERNAL_DUMP("throttling_rec = { %llu %u %u %u %u }", throttling_rec->bytes_since_avg, throttling_rec->krate, + throttling_rec->min_limit, throttling_rec->max_limit, throttling_rec->num_sending) + + U_INTERNAL_ASSERT_EQUALS(ptr, data+datalen+1) + } + + static void printThrottlingRecToBuffer(const char* data, uint32_t datalen) + { + U_TRACE(0, "UServer_Base::printThrottlingRecToBuffer(%.*S,%u)", datalen, data, datalen) + + U_INTERNAL_ASSERT_EQUALS(datalen, sizeof(uthrottling)) + + throttling_rec = (uthrottling*)data; + + u_buffer_len = u__snprintf(u_buffer, U_BUFFER_SIZE, U_CONSTANT_TO_PARAM("%llu %u %u %u %u"), throttling_rec->bytes_since_avg, + throttling_rec->krate, throttling_rec->min_limit, throttling_rec->max_limit, throttling_rec->num_sending); + } + static bool throttling_chk; static UString* throttling_mask; static uthrottling* throttling_rec; @@ -719,6 +775,35 @@ class U_EXPORT UServer_Base : public UEventFd { uint32_t timestamp, count; } uevasive; + static void getEvasiveRecFromBuffer(const char* data, uint32_t datalen) + { + U_TRACE(0, "UServer_Base::getEvasiveRecFromBuffer(%.*S,%u)", datalen, data, datalen) + + evasive_rec = (uevasive*)u_buffer; + + u_buffer_len = sizeof(uevasive); + + const char* ptr = data; + + evasive_rec->timestamp = u_strtoulp(&ptr); + evasive_rec->count = u_strtoulp(&ptr); + + U_INTERNAL_DUMP("evasive_rec->timestamp = %u evasive_rec->count = %u", evasive_rec->timestamp, evasive_rec->count) + + U_INTERNAL_ASSERT_EQUALS(ptr, data+datalen+1) + } + + static void printEvasiveRecToBuffer(const char* data, uint32_t datalen) + { + U_TRACE(0, "UServer_Base::printEvasiveRecToBuffer(%.*S,%u)", datalen, data, datalen) + + U_INTERNAL_ASSERT_EQUALS(datalen, sizeof(uevasive)) + + evasive_rec = (uevasive*)data; + + u_buffer_len = u__snprintf(u_buffer, U_BUFFER_SIZE, U_CONSTANT_TO_PARAM("%u %u"), evasive_rec->timestamp, evasive_rec->count); + } + static UFile* dos_LOG; static bool bwhitelist; static uevasive* evasive_rec; @@ -787,7 +872,7 @@ class U_EXPORT UServer_Base : public UEventFd { U_INTERNAL_DUMP("U_ClientImage_pipeline = %b U_ClientImage_parallelization = %d UNotifier::num_connection - UNotifier::min_connection = %d", U_ClientImage_pipeline, U_ClientImage_parallelization, UNotifier::num_connection - UNotifier::min_connection) -# ifndef U_SERVER_CAPTIVE_PORTAL +# if defined(U_LINUX) && (!defined(U_SERVER_CAPTIVE_PORTAL) || defined(ENABLE_THREAD)) if (U_ClientImage_parallelization != U_PARALLELIZATION_CHILD && (UNotifier::num_connection - UNotifier::min_connection) >= nclient) { @@ -840,7 +925,7 @@ class U_EXPORT UServer_Base : public UEventFd { u_get_memusage(&vsz, &rss); - ULog::log(U_CONSTANT_TO_PARAM("%s (Interrupt): " + log->log(U_CONSTANT_TO_PARAM("%s (Interrupt): " "address space usage: %.2f MBytes - " "rss usage: %.2f MBytes"), signame, (double)vsz / (1024.0 * 1024.0), diff --git a/include/ulib/net/socket.h b/include/ulib/net/socket.h index 6776092a4..5908c568b 100644 --- a/include/ulib/net/socket.h +++ b/include/ulib/net/socket.h @@ -515,7 +515,7 @@ class U_EXPORT USocket { { U_TRACE_NO_PARAM(0, "USocket::setTcpFastOpen()") -# if !defined(U_SERVER_CAPTIVE_PORTAL) && defined(U_LINUX) // && LINUX_VERSION_CODE >= KERNEL_VERSION(3,6,0) +# if defined(U_LINUX) && (!defined(U_SERVER_CAPTIVE_PORTAL) || defined(ENABLE_THREAD)) // && LINUX_VERSION_CODE >= KERNEL_VERSION(3,6,0) # ifndef TCP_FASTOPEN # define TCP_FASTOPEN 23 /* Enable FastOpen on listeners */ # endif @@ -756,7 +756,7 @@ class U_EXPORT USocket { * distributes datagrams evenly across all of the receiving threads */ -# if defined(U_LINUX) && !defined(U_SERVER_CAPTIVE_PORTAL) // && LINUX_VERSION_CODE >= KERNEL_VERSION(3,9,0) +# if defined(U_LINUX) && (!defined(U_SERVER_CAPTIVE_PORTAL) || defined(ENABLE_THREAD)) // && LINUX_VERSION_CODE >= KERNEL_VERSION(3,9,0) # ifndef SO_REUSEPORT # define SO_REUSEPORT 15 # endif diff --git a/include/ulib/notifier.h b/include/ulib/notifier.h index 6be58f561..b50e919f3 100644 --- a/include/ulib/notifier.h +++ b/include/ulib/notifier.h @@ -44,8 +44,7 @@ #define EPOLLROUNDROBIN 0 // (1 << 27) #endif -#if defined(HAVE_EPOLL_WAIT) && !defined(USE_LIBEVENT) && !defined(U_SERVER_CAPTIVE_PORTAL) && \ - (!defined(U_LINUX) || !defined(ENABLE_THREAD) || !defined(U_LOG_DISABLE) || defined(USE_LIBZ)) +#if defined(HAVE_EPOLL_WAIT) && !defined(USE_LIBEVENT) && !defined(U_SERVER_CAPTIVE_PORTAL) # define U_EPOLLET_POSTPONE_STRATEGY #endif diff --git a/include/ulib/ssl/net/sslsocket.h b/include/ulib/ssl/net/sslsocket.h index 9a7165664..0ac2d71f1 100644 --- a/include/ulib/ssl/net/sslsocket.h +++ b/include/ulib/ssl/net/sslsocket.h @@ -233,7 +233,7 @@ class U_EXPORT USSLSocket : public USocket { * downloading OCSP responses */ -#if !defined(OPENSSL_NO_OCSP) && defined(SSL_CTRL_SET_TLSEXT_STATUS_REQ_CB) +#if defined(ENABLE_THREAD) && !defined(OPENSSL_NO_OCSP) && defined(SSL_CTRL_SET_TLSEXT_STATUS_REQ_CB) typedef struct stapling { void* data; X509* cert; diff --git a/include/ulib/string.h b/include/ulib/string.h index e199af97f..65d6163fd 100644 --- a/include/ulib/string.h +++ b/include/ulib/string.h @@ -1806,6 +1806,7 @@ class U_EXPORT UString { // STREAM #ifdef U_STDCPP_ENABLE + istream& getline(istream& is, unsigned char delim = '\n'); friend U_EXPORT istream& operator>>(istream& is, UString& str); @@ -1937,6 +1938,9 @@ class U_EXPORT UString { void setBuffer(uint32_t n); void moveToBeginDataInBuffer(uint32_t n); + + static vpFpcu printValueToBuffer; + void printKeyValue(const char* key, uint32_t keylen, const char* data, uint32_t datalen); void snprintf(const char* format, uint32_t fmt_size, ...) diff --git a/include/ulib/url.h b/include/ulib/url.h index bc438078f..48612f0b9 100644 --- a/include/ulib/url.h +++ b/include/ulib/url.h @@ -101,7 +101,13 @@ class U_EXPORT Url { { U_TRACE_REGISTER_OBJECT(0, Url, "", 0) - service_end = user_begin = user_end = host_begin = host_end = path_begin = path_end = query = -1; + service_end = + user_begin = + user_end = + host_begin = + host_end = + path_begin = + path_end = -1; } /** @@ -154,7 +160,6 @@ class U_EXPORT Url { host_end = u.host_end; path_begin = u.path_begin; path_end = u.path_end; - query = u.query; } Url(const Url& u) : url(u.url) @@ -204,8 +209,7 @@ class U_EXPORT Url { host_begin = host_end = path_begin = - path_end = - query = -1; + path_end = -1; } /** @@ -217,7 +221,16 @@ class U_EXPORT Url { * @return str */ - UString getService() const; + UString getService() const + { + U_TRACE_NO_PARAM(0, "Url::getService()") + + UString srv; + + if (service_end > 0) srv = url.substr(0U, (uint32_t)service_end); + + U_RETURN_STRING(srv); + } bool isHTTP() const { @@ -283,7 +296,16 @@ class U_EXPORT Url { * @return str */ - UString getUser(); + UString getUser() + { + U_TRACE_NO_PARAM(0, "Url::getUser()") + + UString usr; + + if (user_begin < user_end) usr = url.substr(user_begin, user_end - user_begin); + + U_RETURN_STRING(usr); + } /** * This methode set the user of the url @@ -339,7 +361,16 @@ class U_EXPORT Url { * @return str */ - UString getHost(); + UString getHost() + { + U_TRACE_NO_PARAM(0, "Url::getHost()") + + UString host; + + if (host_begin < host_end) host = url.substr(host_begin, host_end - host_begin); + + U_RETURN_STRING(host); + } /** * This methode set the host @@ -362,7 +393,8 @@ class U_EXPORT Url { * @retval 0 no port specified */ - unsigned int getPort(); + UString getPort(); + uint32_t getPortNumber(); /** * Set the port number @@ -399,7 +431,19 @@ class U_EXPORT Url { * @return str */ - UString getPath(); + UString getPath() + { + U_TRACE_NO_PARAM(0, "Url::getPath()") + + UString path(U_CAPACITY); + + if (path_begin < path_end) decode(url.c_pointer(path_begin), path_end - path_begin, path); + else path.push_back('/'); + + (void) path.shrink(); + + U_RETURN_STRING(path); + } /** * This methode set the path of the url @@ -418,7 +462,17 @@ class U_EXPORT Url { * @c http://www.google.com/search?q=xml */ - UString getPathAndQuery(); + UString getPathAndQuery() + { + U_TRACE_NO_PARAM(0, "Url::getPathAndQuery()") + + UString file; + + if (path_begin < path_end) file = url.substr(path_begin); + else file.push_back('/'); + + U_RETURN_STRING(file); + } /** * This methode check the existence of the query from the url @@ -461,17 +515,7 @@ class U_EXPORT Url { * This methode erase the query from the url */ - void eraseQuery() - { - U_TRACE_NO_PARAM(0, "Url::eraseQuery()") - - if (path_end < (int)url.size()) - { - (void) url.erase(path_end); - - query = path_end; - } - } + void eraseQuery(); /** * This methode add's a new entry to the query @@ -487,6 +531,19 @@ class U_EXPORT Url { void addQuery(const char* entry, uint32_t entry_len, const char* value, uint32_t value_len); + enum UrlFieldType { + U_SCHEMA = 0x0001, + U_HOST = 0x0002, + U_PORT = 0x0004, + U_PATH = 0x0008, + U_QUERY = 0x0010, + U_FRAGMENT = 0x0020, + U_USERINFO = 0x0040 + }; + + UString getFragment(); + UString getFieldValue(int field_type); + /** * Converts a Unicode string into the MIME @c x-www-form-urlencoded format * @@ -546,20 +603,26 @@ class U_EXPORT Url { #endif protected: - UString url; // content string - int service_end, // End position of the service - user_begin, // begin position of the user - user_end, // end position of the user - host_begin, // begin position of the host - host_end, // end position of the host - path_begin, // begin position of the path - path_end, // end position of the path - query; // start position of the last readed query entry - - void findpos(); // scans the structure of the url and is updating the position attributs of the class + UString url; // content string + int service_end, // End position of the service + user_begin, // begin position of the user + user_end, // end position of the user + host_begin, // begin position of the host + host_end, // end position of the host + path_begin, // begin position of the path + path_end; // end position of the path + +#ifdef DEBUG + uint32_t field_mask; +#endif + + void findpos(); // scans the structure of the url and is updating the position attributs of the class private: - bool prepareForQuery() U_NO_EXPORT; // prepare the string to add a query + uint32_t getPosQuery() U_NO_EXPORT __pure; + uint32_t getPosFragment() U_NO_EXPORT __pure; + bool prepareForQuery() U_NO_EXPORT; // prepare the string to add a query + uint32_t getSizeQuery(uint32_t pos) U_NO_EXPORT __pure; }; #endif diff --git a/include/ulib/utility/lock.h b/include/ulib/utility/lock.h index 4fa389f5d..760130d38 100644 --- a/include/ulib/utility/lock.h +++ b/include/ulib/utility/lock.h @@ -68,28 +68,32 @@ class U_EXPORT ULock { // ATOMIC COUNTER - static long atomicIncrement(long* pvalue, long offset) + static void atomicIncrement(long* pvalue, long offset) { - U_TRACE(0, "ULock::atomicIncrement(%ld,%ld)", *pvalue, offset) + U_TRACE(0, "ULock::atomicIncrement(%p,%ld)", pvalue, offset) # if defined(HAVE_GCC_ATOMICS) && defined(ENABLE_THREAD) - return __sync_add_and_fetch(pvalue, offset); + (void) __sync_add_and_fetch(pvalue, offset); # else - return (*pvalue += offset); + *pvalue += offset; # endif } - static long atomicDecrement(long* pvalue, long offset) + static void atomicIncrement(sig_atomic_t& value) { atomicIncrement((long*)&value, 1L); } + + static void atomicDecrement(long* pvalue, long offset) { - U_TRACE(0, "ULock::atomicDecrement(%ld,%ld)", *pvalue, offset) + U_TRACE(0, "ULock::atomicDecrement(%p,%ld)", pvalue, offset) # if defined(HAVE_GCC_ATOMICS) && defined(ENABLE_THREAD) - return __sync_sub_and_fetch(pvalue, offset); + (void) __sync_sub_and_fetch(pvalue, offset); # else - return (*pvalue -= offset); + *pvalue -= offset; # endif } + static void atomicDecrement(sig_atomic_t& value) { atomicDecrement((long*)&value, 1L); } + // STREAM #if defined(U_STDCPP_ENABLE) && defined(DEBUG) diff --git a/include/ulib/utility/uhttp.h b/include/ulib/utility/uhttp.h index 593b4063f..2d8b4d7c6 100644 --- a/include/ulib/utility/uhttp.h +++ b/include/ulib/utility/uhttp.h @@ -200,6 +200,7 @@ class U_EXPORT UHTTP { static bool callService(const UString& path); static bool isUriRequestNeedCertificate() __pure; static bool isValidMethod(const char* ptr) __pure; + static bool checkContentLength(const UString& response); static bool manageSendfile(const char* ptr, uint32_t len); static bool checkContentLength(uint32_t length, uint32_t pos); static bool scanfHeaderRequest(const char* ptr, uint32_t size); @@ -277,15 +278,12 @@ class U_EXPORT UHTTP { static bool manageRequestOnRemoteServer(); #endif -#if !defined(U_LOG_DISABLE) || defined(USE_LIBZ) - static void parserExecute(const char* ptr, uint32_t len); -#endif - static void setHostname(const char* ptr, uint32_t len); static void setHostname(const UString& name) { setHostname(U_STRING_TO_PARAM(name)); } static const char* getStatusDescription(uint32_t* plen = U_NULLPTR); + static uint32_t parserExecute(const char* ptr, uint32_t len, bool response = false); static uint32_t getUserAgent() { @@ -1323,6 +1321,7 @@ class U_EXPORT UHTTP { static void setAcceptEncoding(const char* ptr) U_NO_EXPORT; static inline void setContentLength(const char* ptr1, const char* ptr2) U_NO_EXPORT; + static inline bool checkDataChunked(UString* pbuffer) U_NO_EXPORT; static inline void setRange(const char* ptr, uint32_t len) U_NO_EXPORT; static inline void setCookie(const char* ptr, uint32_t len) U_NO_EXPORT; static inline void setUserAgent(const char* ptr, uint32_t len) U_NO_EXPORT; diff --git a/m4/ac_check_package.m4 b/m4/ac_check_package.m4 index 0b2467155..b98370130 100644 --- a/m4/ac_check_package.m4 +++ b/m4/ac_check_package.m4 @@ -386,7 +386,8 @@ AC_DEFUN([AC_CHECK_PACKAGE],[ with_curl="no"; fi - AC_ARG_ENABLE(curl-staticlib-deps, [ --enable-curl-staticlib-deps link with dependencies of cURL's static libraries. Must be specified in addition to --with-curl [[default=no]]]) + AC_ARG_ENABLE(curl-staticlib-deps, + [ --enable-curl-staticlib-deps link with dependencies of cURL's static libraries. Must be specified in addition to --with-curl [[default=no]]]) if test -z "$enable_curl_staticlib_deps"; then enable_curl_staticlib_deps="no" fi @@ -934,7 +935,7 @@ else MYSQL_INCLUDE=`mysql_config --include` libmysql_version=$(grep LIBMYSQL_VERSION /usr/include/mysql/mysql_version.h 2>/dev/null | head -n1 | cut -d'"' -f2) else - MYSQL_INCLUDE=-I$ac_mysql_incdir + MYSQL_INCLUDE=$ac_mysql_incdir libmysql_version=$(grep LIBMYSQL_VERSION $ac_mysql_incdir/mysql/mysql_version.h 2>/dev/null | head -n1 | cut -d'"' -f2) fi if test "$ac_mysql_libdir" = "no"; then diff --git a/m4/ac_compilation_options.m4 b/m4/ac_compilation_options.m4 index d389c0177..19a02713e 100644 --- a/m4/ac_compilation_options.m4 +++ b/m4/ac_compilation_options.m4 @@ -91,7 +91,9 @@ AC_DEFUN([AC_COMPILATION_OPTIONS],[ AC_ARG_ENABLE(CRPWS, [ --enable-CRPWS enable Client Response Partial Write Support [[default=no]]]) if test -z "$enable_CRPWS"; then - if test "$enable_debug" = "yes"; then + if test "$USP_FLAGS" = "-DAS_cpoll_cppsp_DO"; then + enable_CRPWS="no" + elif test "$enable_debug" = "yes"; then enable_CRPWS="yes" else enable_CRPWS="no" @@ -106,7 +108,11 @@ AC_DEFUN([AC_COMPILATION_OPTIONS],[ AC_ARG_ENABLE(captive-portal, [ --enable-captive-portal enable server captive portal mode [[default=no]]]) if test -z "$enable_captive_portal"; then - enable_captive_portal="no" + if test "$USP_FLAGS" = "-DAS_cpoll_cppsp_DO"; then + enable_captive_portal="yes" + else + enable_captive_portal="no" + fi fi if test "$enable_captive_portal" = "yes"; then AC_DEFINE(U_SERVER_CAPTIVE_PORTAL, 1, [enable server captive portal mode]) @@ -128,7 +134,9 @@ AC_DEFUN([AC_COMPILATION_OPTIONS],[ AC_ARG_ENABLE(HIS, [ --enable-HIS enable HTTP Inotify Support [[default=no]]]) if test -z "$enable_HIS" ; then - if test "$enable_debug" = "yes"; then + if test "$USP_FLAGS" = "-DAS_cpoll_cppsp_DO"; then + enable_HIS="no" + elif test "$enable_debug" = "yes"; then enable_HIS="yes" else enable_HIS="no" @@ -158,7 +166,9 @@ AC_DEFUN([AC_COMPILATION_OPTIONS],[ AC_ARG_ENABLE(GSDS, [ --enable-GSDS enable GDB Stack Dump Support [[default=no]]]) if test -z "$enable_GSDS"; then - if test "$enable_debug" = "yes"; then + if test "$USP_FLAGS" = "-DAS_cpoll_cppsp_DO"; then + enable_GSDS="no" + elif test "$enable_debug" = "yes"; then enable_GSDS="yes" else enable_GSDS="no" @@ -214,7 +224,9 @@ AC_DEFUN([AC_COMPILATION_OPTIONS],[ AC_ARG_ENABLE(check-time, [ --enable-check-time enable server check time between request for parallelization [[default=no]]]) if test -z "$enable_check_time"; then - if test "$enable_debug" = "yes" -a "$enable_http2" != "yes"; then + if test "$USP_FLAGS" = "-DAS_cpoll_cppsp_DO"; then + enable_check_time="no" + elif test "$enable_debug" = "yes" -a "$enable_http2" != "yes"; then enable_check_time="yes" else enable_check_time="no" @@ -310,7 +322,9 @@ AC_DEFUN([AC_COMPILATION_OPTIONS],[ AC_ARG_ENABLE(HSTS, [ --enable-HSTS enable HTTP Strict Transport Security support [[default=no]]]) if test -z "$enable_HSTS"; then - if test "$enable_debug" = "yes"; then + if test "$USP_FLAGS" = "-DAS_cpoll_cppsp_DO"; then + enable_HSTS="no" + elif test "$enable_debug" = "yes"; then enable_HSTS="yes" else enable_HSTS="no" diff --git a/m4/ax_lib_postgresql.m4 b/m4/ax_lib_postgresql.m4 index 229287a67..7605fa089 100644 --- a/m4/ax_lib_postgresql.m4 +++ b/m4/ax_lib_postgresql.m4 @@ -91,11 +91,18 @@ AC_DEFUN([AX_LIB_POSTGRESQL], if test "$PG_CONFIG" != "no"; then AC_MSG_CHECKING([for PostgreSQL libraries]) - POSTGRESQL_CPPFLAGS="`$PG_CONFIG --includedir` -I`$PG_CONFIG --includedir-server`" - POSTGRESQL_LDFLAGS=-L"`$PG_CONFIG --libdir`" - POSTGRESQL_LIBS="-lpq" + postgresql_libdir=`$PG_CONFIG --libdir` + + POSTGRESQL_LDFLAGS=-L"$postgresql_libdir" + POSTGRESQL_CPPFLAGS="-I`$PG_CONFIG --includedir` -I`$PG_CONFIG --includedir-server`" POSTGRESQL_VERSION=`$PG_CONFIG --version | sed -e 's#PostgreSQL ##'` + if test -f "$postgresql_libdir/libpgport.a"; then + POSTGRESQL_LIBS="-lpq -lpgport" + else + POSTGRESQL_LIBS="-lpq" + fi + AC_DEFINE([HAVE_POSTGRESQL], [1], [Define to 1 if PostgreSQL libraries are available]) diff --git a/src/ulib/Makefile.am b/src/ulib/Makefile.am index 3a3a7ae2b..bf661781e 100644 --- a/src/ulib/Makefile.am +++ b/src/ulib/Makefile.am @@ -288,9 +288,6 @@ endif # Handler static orm driver -#lib@ULIB@_la_CXXFLAGS = -lib@ULIB@_la_LDFLAGS = @ULIB_LIBS@ -version-info 1:0:0 -release @ULIB_VERSION@ - if STATIC_ORM_DRIVER_SQLITE SRC_CPP += orm/driver/orm_driver_sqlite.cpp endif @@ -314,6 +311,9 @@ endif ##endif endif +#lib@ULIB@_la_CXXFLAGS = +lib@ULIB@_la_LDFLAGS = @ULIB_LIBS@ -version-info 1:0:0 -release @ULIB_VERSION@ + if FINAL lib@ULIB@_la_SOURCES = all_c.c base/xxhash/xxhash.c all_cpp.cpp else diff --git a/src/ulib/Makefile.in b/src/ulib/Makefile.in index 014f0b78e..c7ebcefc0 100644 --- a/src/ulib/Makefile.in +++ b/src/ulib/Makefile.in @@ -157,6 +157,8 @@ target_triplet = @target@ @STATIC_HANDLER_TSA_TRUE@am__append_59 = net/server/plugin/mod_tsa.cpp @STATIC_HANDLER_HTTP_TRUE@am__append_60 = net/server/plugin/mod_http.cpp @STATIC_HANDLER_ECHO_TRUE@am__append_61 = net/server/plugin/mod_echo.cpp + +# Handler static orm driver @STATIC_ORM_DRIVER_SQLITE_TRUE@am__append_62 = orm/driver/orm_driver_sqlite.cpp @STATIC_ORM_DRIVER_MYSQL_TRUE@am__append_63 = orm/driver/orm_driver_mysql.cpp @STATIC_ORM_DRIVER_PGSQL_TRUE@am__append_64 = orm/driver/orm_driver_pgsql.cpp @@ -768,8 +770,6 @@ SRC_CPP = internal/common.cpp internal/error.cpp ui/dialog.cpp \ $(am__append_61) $(am__append_62) $(am__append_63) \ $(am__append_64) $(am__append_65) -# Handler static orm driver - #lib@ULIB@_la_CXXFLAGS = lib@ULIB@_la_LDFLAGS = @ULIB_LIBS@ -version-info 1:0:0 -release \ @ULIB_VERSION@ $(am__append_66) diff --git a/src/ulib/base/utility.c b/src/ulib/base/utility.c index e591ebc00..13f508b24 100644 --- a/src/ulib/base/utility.c +++ b/src/ulib/base/utility.c @@ -161,6 +161,62 @@ __pure uint64_t u__strtoull(const char* restrict s, uint32_t len) return val; } +unsigned long u_strtoulp(const char** restrict s) +{ + const char* restrict ptr; + const char* restrict p = *s; + + U_INTERNAL_TRACE("u_strtolp(%p)", s) + + U_INTERNAL_ASSERT_POINTER(s) + + if (u__isdigitw0(*p) == false && + u__isspace(*++p)) + { + /* NB: we have something as '0 12 ..' */ + + *s = p+1; + + return 0UL; + } + + ptr = p; + + while (u__isdigit(*p)) ++p; + + *s = p+1; + + return u_strtoul(ptr, p); +} + +uint64_t u_strtoullp(const char** restrict s) +{ + const char* restrict ptr; + const char* restrict p = *s; + + U_INTERNAL_TRACE("u_strtollp(%p)", s) + + U_INTERNAL_ASSERT_POINTER(s) + + if (u__isdigitw0(*p) == false && + u__isspace(*++p)) + { + /* NB: we have something as '0 12 ..' */ + + *s = p+1; + + return 0ULL; + } + + ptr = p; + + while (u__isdigit(*p)) ++p; + + *s = p+1; + + return u_strtoull(ptr, p); +} + __pure long u__strtol(const char* restrict s, uint32_t len) { int sign = 1; @@ -2248,7 +2304,7 @@ static const char* u_check_for_suffix_exe(const char* restrict program) bool u_pathfind(char* restrict result, const char* restrict path, uint32_t path_len, const char* restrict filename, int mode) { uint32_t p_index = 0; - char zPath[PATH_MAX + 1]; + char zPath[U_PATH_MAX + 1]; U_INTERNAL_TRACE("u_pathfind(%p,%.*s,%u,%s,%d)", result, path_len, path, path_len, filename, mode) diff --git a/src/ulib/base/win32/mingw32.c b/src/ulib/base/win32/mingw32.c index c41b81b9a..e076eb077 100644 --- a/src/ulib/base/win32/mingw32.c +++ b/src/ulib/base/win32/mingw32.c @@ -198,7 +198,7 @@ char* realpath(const char* name, char* resolved_path) char* u_slashify(const char* src, char slash_from, char slash_to) { - static char u_slashify_buffer[PATH_MAX]; + static char u_slashify_buffer[U_PATH_MAX]; char* dst = u_slashify_buffer; diff --git a/src/ulib/date.cpp b/src/ulib/date.cpp index e6c80b489..e01dd3502 100644 --- a/src/ulib/date.cpp +++ b/src/ulib/date.cpp @@ -272,8 +272,6 @@ time_t UTimeDate::getSecondFromDate(const char* str, bool gmt, struct tm* tm, co tm->tm_mday = u_strtoulp(&str); - ++str; - tm->tm_mon = u_getMonth(str); str += 4; @@ -304,8 +302,6 @@ time_t UTimeDate::getSecondFromDate(const char* str, bool gmt, struct tm* tm, co tm->tm_mday = u_strtoulp(&str); - ++str; - tm->tm_hour = u__strtoul(str, 2); str += 3; diff --git a/src/ulib/db/cdb.cpp b/src/ulib/db/cdb.cpp index 425623298..e707e58ba 100644 --- a/src/ulib/db/cdb.cpp +++ b/src/ulib/db/cdb.cpp @@ -913,6 +913,13 @@ U_NO_EXPORT void UCDB::checkForAllEntry() // STREAM #ifdef U_STDCPP_ENABLE +vpFpcu UCDB::getValueFromBuffer; + +class mystreambuf : public streambuf { +public: + char* gptr() { return streambuf::gptr(); } // expose the terribly named cur pointer +}; + U_EXPORT istream& operator>>(istream& is, UCDB& cdb) { U_TRACE(0+256, "UCDB::operator>>(%p,%p)", &is, &cdb) @@ -950,7 +957,6 @@ U_EXPORT istream& operator>>(istream& is, UCDB& cdb) U_INTERNAL_DUMP("hr = { %u, %u }", klen, dlen) u_put_unaligned32(hr->klen, klen); - u_put_unaligned32(hr->dlen, dlen); ptr += sizeof(UCDB::cdb_record_header); @@ -965,13 +971,30 @@ U_EXPORT istream& operator>>(istream& is, UCDB& cdb) ptr += klen; -# ifndef U_COVERITY_FALSE_POSITIVE /* TAINTED_SCALAR */ - is.read(ptr, dlen); -# endif + if (UCDB::getValueFromBuffer == U_NULLPTR) + { + u_put_unaligned32(hr->dlen, dlen); + + is.read(ptr, dlen); - U_INTERNAL_DUMP("data = %.*S", dlen, ptr) + U_INTERNAL_DUMP("data = %.*S", dlen, ptr) - ptr += dlen; + ptr += dlen; + } + else + { + streambuf* sb = is.rdbuf(); + + UCDB::getValueFromBuffer(((mystreambuf*)sb)->gptr(), dlen); + + is.seekg(dlen, ios::cur); + + u_put_unaligned32(hr->dlen, u_buffer_len); + + U_MEMCPY(ptr, u_buffer, u_buffer_len); + ptr += u_buffer_len; + u_buffer_len = 0; + } cdb.nrecord++; diff --git a/src/ulib/db/rdb.cpp b/src/ulib/db/rdb.cpp index e9c5be874..711eeb564 100644 --- a/src/ulib/db/rdb.cpp +++ b/src/ulib/db/rdb.cpp @@ -844,7 +844,7 @@ U_NO_EXPORT void URDB::callForEntryNotInCache(UCDB* pcdb, vPFpvpc function2) U_INTERNAL_DUMP("nrecord = %u", UCDB::nrecord) - U_INTERNAL_ASSERT_MAJOR(UFile::st_size,0) + U_INTERNAL_ASSERT_MAJOR(UFile::st_size, 0) U_INTERNAL_ASSERT_DIFFERS(UFile::map, MAP_FAILED) char* ptr; diff --git a/src/ulib/debug/debug_common.cpp b/src/ulib/debug/debug_common.cpp index 90b332b72..33dc19c82 100644 --- a/src/ulib/debug/debug_common.cpp +++ b/src/ulib/debug/debug_common.cpp @@ -270,12 +270,14 @@ __noreturn void U_EXPORT u_debug_exec(const char* pathname, char* const argv[], (void) write(STDERR_FILENO, iov[2].iov_base, iov[2].iov_len); for (i = 0; argv[i]; ++i) (void) write(STDERR_FILENO, buffer, u__snprintf(buffer, sizeof(buffer), U_CONSTANT_TO_PARAM("argv[%2u] = %p %S\n"), i, argv[i], argv[i])); - (void) write(STDERR_FILENO, buffer, u__snprintf(buffer, sizeof(buffer), U_CONSTANT_TO_PARAM("argv[%2u] = %p %S\n"), i, argv[i], argv[i])); + + (void) write(STDERR_FILENO, buffer, u__snprintf(buffer, sizeof(buffer), U_CONSTANT_TO_PARAM("argv[%2u] = %p %S\n"), i, argv[i], argv[i])); if (envp) { for (i = 0; envp[i]; ++i) (void) write(STDERR_FILENO, buffer, u__snprintf(buffer, sizeof(buffer), U_CONSTANT_TO_PARAM("envp[%2u] = %p %S\n"), i, envp[i], envp[i])); - (void) write(STDERR_FILENO, buffer, u__snprintf(buffer, sizeof(buffer), U_CONSTANT_TO_PARAM("envp[%2u] = %p %S\n"), i, envp[i], envp[i])); + + (void) write(STDERR_FILENO, buffer, u__snprintf(buffer, sizeof(buffer), U_CONSTANT_TO_PARAM("envp[%2u] = %p %S\n"), i, envp[i], envp[i])); } } else diff --git a/src/ulib/file.cpp b/src/ulib/file.cpp index 6ca2edc36..ae12f4291 100644 --- a/src/ulib/file.cpp +++ b/src/ulib/file.cpp @@ -570,7 +570,7 @@ char* UFile::mmap(uint32_t* plength, int _fd, int prot, int flags, uint32_t offs if (*plength >= rlimit_memalloc) // NB: we try to avoid strong swap pressure... { -#ifndef U_SERVER_CAPTIVE_PORTAL +#if defined(U_LINUX) && (!defined(U_SERVER_CAPTIVE_PORTAL) || defined(ENABLE_THREAD)) try_from_file_system: #endif *plength = (*plength + U_PAGEMASK) & ~U_PAGEMASK; @@ -606,7 +606,7 @@ char* UFile::mmap(uint32_t* plength, int _fd, int prot, int flags, uint32_t offs } } -#ifdef U_SERVER_CAPTIVE_PORTAL +#if !defined(U_LINUX) || (defined(U_SERVER_CAPTIVE_PORTAL) && !defined(ENABLE_THREAD)) _ptr = (char*) U_SYSCALL(malloc, "%u", *plength); return _ptr; diff --git a/src/ulib/internal/common.cpp b/src/ulib/internal/common.cpp index 8dbe88656..8cb21e8e4 100644 --- a/src/ulib/internal/common.cpp +++ b/src/ulib/internal/common.cpp @@ -312,6 +312,8 @@ void ULib::init(const char* mempool, char** argv) void ULib::end() { + U_INTERNAL_ASSERT_EQUALS(ULog::first, U_NULLPTR) + #if defined(U_STDCPP_ENABLE) && defined(DEBUG) UApplication::printMemUsage(); #endif diff --git a/src/ulib/internal/error.cpp b/src/ulib/internal/error.cpp index 14ca38abf..8fe123f03 100644 --- a/src/ulib/internal/error.cpp +++ b/src/ulib/internal/error.cpp @@ -96,7 +96,7 @@ void UError::stackDump() char name[128]; -#ifndef U_SERVER_CAPTIVE_PORTAL +#if defined(U_LINUX) && (!defined(U_SERVER_CAPTIVE_PORTAL) || defined(ENABLE_THREAD)) (void) u__snprintf(name, sizeof(name), U_CONSTANT_TO_PARAM("stack.%N.%P"), 0); #else (void) u__snprintf(name, sizeof(name), U_CONSTANT_TO_PARAM("/tmp/stack.%N.%P"), 0); diff --git a/src/ulib/internal/memory_pool.cpp b/src/ulib/internal/memory_pool.cpp index 63b279748..7835bd1ed 100644 --- a/src/ulib/internal/memory_pool.cpp +++ b/src/ulib/internal/memory_pool.cpp @@ -510,7 +510,7 @@ void* UMemoryPool::_malloc(uint32_t* pnum, uint32_t type_size, bool bzero) U_RETURN(ptr); } -#if defined(ENABLE_MEMPOOL) && !defined(U_SERVER_CAPTIVE_PORTAL) +#if defined(ENABLE_MEMPOOL) && (!defined(U_SERVER_CAPTIVE_PORTAL) || defined(ENABLE_THREAD)) void UMemoryPool::deallocate(void* ptr, uint32_t length) { U_TRACE(1, "UMemoryPool::deallocate(%p,%u)", ptr, length) diff --git a/src/ulib/ldap/ldap.cpp b/src/ulib/ldap/ldap.cpp index d7c7406fc..18952299e 100644 --- a/src/ulib/ldap/ldap.cpp +++ b/src/ulib/ldap/ldap.cpp @@ -382,7 +382,7 @@ bool ULDAP::init(const char* url) ludpp = (LDAPURLDesc*) calloc(1, sizeof(LDAPURLDesc)); ludpp->lud_host = _url.getHost().c_strdup(); - ludpp->lud_port = _url.getPort(); + ludpp->lud_port = _url.getPortNumber(); ludpp->lud_dn = _url.getPath().c_strndup(1); ludpp->lud_scope = LDAP_SCOPE_BASE; diff --git a/src/ulib/log.cpp b/src/ulib/log.cpp index 969367c82..c1966f31c 100644 --- a/src/ulib/log.cpp +++ b/src/ulib/log.cpp @@ -11,10 +11,8 @@ // // ============================================================================ -#include #include -#include -#include +#include #ifndef _MSWINDOWS_ # ifdef __clang__ @@ -29,17 +27,14 @@ #ifdef USE_LIBZ // check for crc32 # include # include -# include #endif -#define U_MARK_END "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n" // 24 +#define U_MARK_END "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n" // 24 #define U_FMT_START_STOP "*** %s %N (%ubit, pid %P) [%U@%H] ***" long ULog::tv_sec_old_1; long ULog::tv_sec_old_2; long ULog::tv_sec_old_3; -ULog* ULog::pthis; -uint32_t ULog::log_data_sz; uint32_t ULog::prefix_len; const char* ULog::prefix; struct iovec ULog::iov_vec[5]; @@ -49,13 +44,21 @@ ULog::log_date* ULog::ptr_shared_date; pthread_rwlock_t* ULog::prwlock; #endif -ULog::ULog(const UString& path, uint32_t _size, const char* dir_log_gz) : UFile(path, U_NULLPTR) +ULog::ULog(const UString& path, uint32_t _size) : UFile(path, U_NULLPTR) { - U_TRACE_REGISTER_OBJECT(0, ULog, "%V,%u,%S", path.rep, _size, dir_log_gz) + U_TRACE_REGISTER_OBJECT(0, ULog, "%V,%u", path.rep, _size) + +#ifdef DEBUG + next = first; + first = this; + + U_INTERNAL_DUMP("first = %p next = %p this = %p", first, next, this) +#endif lock = U_NULLPTR; ptr_log_data = U_NULLPTR; log_file_sz = + log_data_sz = log_gzip_sz = 0; U_Log_start_stop_msg(this) = false; @@ -81,8 +84,6 @@ ULog::ULog(const UString& path, uint32_t _size, const char* dir_log_gz) : UFile( # ifndef U_COVERITY_FALSE_POSITIVE U_ERROR("Cannot creat log file %.*S", U_FILE_TO_TRACE(*this)); # endif - - return; } /** @@ -110,29 +111,20 @@ ULog::ULog(const UString& path, uint32_t _size, const char* dir_log_gz) : UFile( UFile::memmap(PROT_READ | PROT_WRITE) == false) { U_ERROR("Cannot init log file %.*S", U_FILE_TO_TRACE(*this)); - - return; } + U_INTERNAL_DUMP("bsize = %b", bsize) + if (bsize) ptr_log_data->file_ptr = file_size; // append mode else { - // NB: we can have a previous crash without resizing the file or we are an other process (apache like log)... + // NB: we can have a previous crash (so the file is not truncate) or there are an other process that already use this file... char* ptr = (char*) u_find(UFile::map, file_size, U_CONSTANT_TO_PARAM(U_MARK_END)); - if (ptr) - { - ptr_log_data->file_ptr = ptr - UFile::map; - - // NB: we can be an other process that manage this file (apache like log)... + if (ptr == U_NULLPTR) ptr = (char*) u_find(UFile::map, file_size, "\0\0\0\0\0\0\0\0", 8); - u_put_unalignedp64(ptr, U_MULTICHAR_CONSTANT64('\n','\n','\n','\n','\n','\n','\n','\n')); - u_put_unalignedp64(ptr+8, U_MULTICHAR_CONSTANT64('\n','\n','\n','\n','\n','\n','\n','\n')); - u_put_unalignedp64(ptr+16, U_MULTICHAR_CONSTANT64('\n','\n','\n','\n','\n','\n','\n','\n')); - - UFile::msync(ptr + U_CONSTANT_SIZE(U_MARK_END), UFile::map, MS_SYNC); - } + if (ptr) ptr_log_data->file_ptr = ptr - UFile::map; U_INTERNAL_ASSERT_MINOR(ptr_log_data->file_ptr, UFile::st_size) } @@ -140,6 +132,8 @@ ULog::ULog(const UString& path, uint32_t _size, const char* dir_log_gz) : UFile( log_file_sz = UFile::st_size; } + U_INTERNAL_DUMP("UFile::map = %p ptr_log_data->file_ptr = %u log_file_sz = %u", UFile::map, ptr_log_data->file_ptr, log_file_sz) + U_INTERNAL_ASSERT(ptr_log_data->file_ptr <= UFile::st_size) U_NEW(ULock, lock, ULock); @@ -147,55 +141,6 @@ ULog::ULog(const UString& path, uint32_t _size, const char* dir_log_gz) : UFile( U_Log_syslog(this) = false; ptr_log_data->gzip_len = 0; ptr_log_data->file_page = ptr_log_data->file_ptr; - -#ifdef USE_LIBZ - char suffix[32]; - uint32_t len_suffix = u__snprintf(suffix, sizeof(suffix), U_CONSTANT_TO_PARAM(".%4D.gz")); - - U_NEW(UString, buf_path_compress, UString(MAX_FILENAME_LEN)); - - char* ptr = buf_path_compress->data(); - - if (dir_log_gz == U_NULLPTR) - { -# ifndef U_COVERITY_FALSE_POSITIVE // Uninitialized pointer read (UNINIT) - (void) UFile::setPathFromFile(*this, ptr, suffix, len_suffix); -# endif - - buf_path_compress->size_adjust(); - - index_path_compress = (buf_path_compress->size() - len_suffix + 1); - } - else - { - UString name = UFile::getName(); - uint32_t len = u__strlen(dir_log_gz, __PRETTY_FUNCTION__), sz = name.size(); - - U_MEMCPY(ptr, dir_log_gz, len); - - ptr += len; - *ptr++ = '/'; - - buf_path_compress->size_adjust(len + 1 + sz + len_suffix); - - U_MEMCPY(ptr, name.data(), sz); - ptr += sz; - U_MEMCPY(ptr, suffix, len_suffix); - - index_path_compress = buf_path_compress->distance(ptr) + 1; - } -#endif -} - -ULog::~ULog() -{ - U_TRACE_UNREGISTER_OBJECT(0, ULog) - - if (lock) delete lock; - -#ifdef USE_LIBZ - if (buf_path_compress) delete buf_path_compress; -#endif } void ULog::initDate() @@ -244,39 +189,6 @@ void ULog::startup() #endif } -void ULog::init(const char* _prefix, uint32_t _prefix_len) -{ - U_TRACE(0, "ULog::init(%.*S,%u)", _prefix_len, _prefix, _prefix_len) - - U_INTERNAL_ASSERT_EQUALS(pthis, U_NULLPTR) - U_INTERNAL_ASSERT_EQUALS(U_Log_syslog(this), false) - - pthis = this; - prefix = _prefix; - prefix_len = _prefix_len; - U_Log_start_stop_msg(this) = true; - - startup(); -} - -void ULog::setPrefix(const char* _prefix, uint32_t _prefix_len) -{ - U_TRACE(0, "ULog::setPrefix(%.*S,%u)", _prefix_len, _prefix, _prefix_len) - - U_INTERNAL_ASSERT_EQUALS(pthis, U_NULLPTR) - - pthis = this; - - if (U_Log_syslog(this) == false) - { - prefix = _prefix; - prefix_len = _prefix_len; - U_Log_start_stop_msg(this) = true; - - startup(); - } -} - void ULog::updateDate1() { U_TRACE_NO_PARAM(1, "ULog::updateDate1()") @@ -513,77 +425,6 @@ void ULog::updateDate3(char* ptr_date) #endif } -void ULog::setShared(log_data* ptr, uint32_t _size, bool breference) -{ - U_TRACE(0, "ULog::setShared(%p,%u,%b)", ptr, _size, breference) - - U_INTERNAL_ASSERT_POINTER(lock) - U_INTERNAL_ASSERT_POINTER(ptr_log_data) - U_INTERNAL_ASSERT_EQUALS(U_Log_syslog(this), false) - - if (ptr) log_gzip_sz = _size; - else - { - if (_size == 0) - { - log_data_sz = sizeof(log_data); - - ptr = (log_data*) UFile::mmap(&log_data_sz); - - U_INTERNAL_ASSERT_DIFFERS(ptr, MAP_FAILED) - } - else - { - char somename[256]; - - // ------------------------------------------------------------------------------------------------------------------- - // For portable use, a shared memory object should be identified by a name of the form /somename; - // that is, a null-terminated string of up to NAME_MAX (i.e., 255) characters consisting of an - // initial slash, followed by one or more characters, none of which are slashes - // ------------------------------------------------------------------------------------------------------------------- - - UString basename = UFile::getName(); - - (void) u__snprintf(somename, sizeof(somename), U_CONSTANT_TO_PARAM("/%v"), basename.rep); - - // ------------------------------------------------------------------------------------------------------------------- - // ULog::log_data log_data_shared; - // -> unnamed array of char for gzip compression (log rotate)... - // ------------------------------------------------------------------------------------------------------------------- - // The zlib documentation states that destination buffer size must be at least 0.1% larger than avail_in plus 12 bytes - // ------------------------------------------------------------------------------------------------------------------- - - ptr = (log_data*) UFile::shm_open(somename, sizeof(log_data) + _size); - - U_INTERNAL_DUMP("ptr->file_ptr = %u", ptr->file_ptr) - - log_gzip_sz = _size; - } - } - - if (breference == false) - { - ptr->file_ptr = - ptr->file_page = 0; - } - else - { - ptr->file_ptr = ptr_log_data->file_ptr; - ptr->file_page = ptr_log_data->file_page; - } - - U_FREE_TYPE(ptr_log_data, log_data); - - ptr_log_data = ptr; - ptr_log_data->gzip_len = 0; - - lock->init(&(ptr_log_data->lock_shared), ptr_log_data->spinlock_shared); - - U_INTERNAL_DUMP("ptr_log_data->file_ptr = %u UFile::st_size = %u log_gzip_sz = %u", ptr_log_data->file_ptr, UFile::st_size, log_gzip_sz) - - U_INTERNAL_ASSERT(ptr_log_data->file_ptr <= UFile::st_size) -} - void ULog::write(const struct iovec* iov, int n) { U_TRACE(1+256, "ULog::write(%p,%d)", iov, n) @@ -629,7 +470,7 @@ void ULog::write(const struct iovec* iov, int n) U_INTERNAL_DUMP("u_gz_deflate(%u) = %u", file_ptr, ptr_log_data->gzip_len) } - else + else if (buf_path_compress) { U_INTERNAL_ASSERT_EQUALS(ptr_log_data->gzip_len, 0) @@ -660,7 +501,7 @@ void ULog::write(const struct iovec* iov, int n) U_INTERNAL_DUMP("ptr_log_data->file_ptr = %u", file_ptr) - if ((log_file_sz-file_ptr) > U_CONSTANT_SIZE(U_MARK_END)) + if ((log_file_sz - file_ptr) > U_CONSTANT_SIZE(U_MARK_END)) { char* ptr = UFile::map + file_ptr; @@ -679,7 +520,7 @@ void ULog::write(const char* msg, uint32_t len) { U_TRACE(0+256, "ULog::write(%.*S,%u)", len, msg, len) - if (U_Log_syslog(pthis)) + if (U_Log_syslog(this)) { # ifndef _MSWINDOWS_ U_SYSCALL_VOID(syslog, "%d,%S,%d,%p", LOG_INFO, "%.*s", (int)len, (char*)msg); @@ -707,28 +548,11 @@ void ULog::write(const char* msg, uint32_t len) updateDate1(); - pthis->write(iov_vec, 5); + write(iov_vec, 5); if (prefix_len) iov_vec[2].iov_len = 0; } -void ULog::log(const char* fmt, uint32_t fmt_size, ...) -{ - U_TRACE(0, "ULog::log(%.*S,%u)", fmt_size, fmt, fmt_size) - - uint32_t len; - char buffer[8196]; - - va_list argp; - va_start(argp, fmt_size); - - len = u__vsnprintf(buffer, sizeof(buffer), fmt, fmt_size, argp); - - va_end(argp); - - write(buffer, len); -} - void ULog::log(int _fd, const char* fmt, uint32_t fmt_size, ...) { U_TRACE(1, "ULog::log(%d,%.*S,%u)", _fd, fmt_size, fmt, fmt_size) @@ -745,16 +569,23 @@ void ULog::log(int _fd, const char* fmt, uint32_t fmt_size, ...) va_end(argp); - U_INTERNAL_ASSERT_EQUALS(iov_vec[0].iov_len, 17) - U_INTERNAL_ASSERT_EQUALS(iov_vec[1].iov_len, 1) - U_INTERNAL_ASSERT_EQUALS(iov_vec[4].iov_len, 1) + if (_fd != -1) + { + U_INTERNAL_ASSERT_EQUALS(iov_vec[0].iov_len, 17) + U_INTERNAL_ASSERT_EQUALS(iov_vec[1].iov_len, 1) + U_INTERNAL_ASSERT_EQUALS(iov_vec[4].iov_len, 1) - iov_vec[3].iov_len = len; - iov_vec[3].iov_base = (caddr_t)buffer; + iov_vec[3].iov_len = len; + iov_vec[3].iov_base = (caddr_t)buffer; - updateDate1(); + updateDate1(); + + (void) U_SYSCALL(writev, "%d,%p,%d", _fd, iov_vec, 5); - (void) U_SYSCALL(writev, "%d,%p,%d", _fd, iov_vec, 5); + return; + } + + if (UServer_Base::isLog()) UServer_Base::log->write(buffer, len); } void ULog::log(const struct iovec* iov, const char* name, const char* type, int ncount, const char* msg, uint32_t msg_len, const char* format, uint32_t fmt_size, ...) @@ -892,7 +723,7 @@ void ULog::logger(const char* ident, int priority, const char* format, uint32_t U_TRACE(1, "ULog::logger(%S,%d,%.*S,%u)", ident, priority, fmt_size, format, fmt_size) #ifndef _MSWINDOWS_ - U_INTERNAL_ASSERT(U_Log_syslog(pthis)) + U_INTERNAL_ASSERT(U_Log_syslog(this)) if (format == U_NULLPTR) { @@ -962,96 +793,204 @@ __pure int ULog::getPriorityForLogger(const char* s) U_RETURN(res); } -void ULog::closeLog() +void ULog::closeLogInternal() { - U_TRACE_NO_PARAM(1, "ULog::closeLog()") + U_TRACE_NO_PARAM(1, "ULog::closeLogInternal()") + + if (U_Log_start_stop_msg(this)) log(U_CONSTANT_TO_PARAM(U_FMT_START_STOP), "SHUTDOWN", sizeof(void*) * 8); if (U_Log_syslog(this)) { # ifndef _MSWINDOWS_ U_SYSCALL_VOID_NO_PARAM(closelog); # endif + } + else + { + U_INTERNAL_DUMP("log_file_sz = %u", log_file_sz) - return; + U_INTERNAL_ASSERT_POINTER(ptr_log_data) + + if (log_file_sz) + { + U_INTERNAL_ASSERT_MINOR(ptr_log_data->file_ptr, UFile::st_size) + + // msync(); + +# ifdef USE_LIBZ + checkForLogRotateDataToWrite(); // check for previous data to write +# endif + + U_INTERNAL_ASSERT_EQUALS(ptr_log_data->gzip_len, 0) + + UFile::munmap(); + (void) UFile::ftruncate(ptr_log_data->file_ptr); + UFile::fsync(); + } + + UFile::close(); + + U_INTERNAL_DUMP("log_data_sz = %u", log_data_sz) + + if (log_data_sz) UFile::munmap(ptr_log_data, log_data_sz); } +} - U_INTERNAL_DUMP("log_file_sz = %u", log_file_sz) +void ULog::closeLog() +{ + U_TRACE_NO_PARAM(0, "ULog::closeLog()") - if (log_file_sz) +#ifdef DEBUG + ULog* item; + + for (ULog** ptr = &first; (item = *ptr); ptr = &(*ptr)->next) { - U_INTERNAL_ASSERT_MINOR(ptr_log_data->file_ptr, UFile::st_size) + if (item == this) + { + U_INTERNAL_DUMP("*ptr = %p item->next = %p", *ptr, item->next) - // msync(); + *ptr = item->next; // remove it from its active list +#endif + + closeLogInternal(); + +#ifdef DEBUG + break; + } + } +#endif +} + +#ifdef USE_LIBZ +void ULog::setLogRotate(const char* dir_log_gz) +{ + U_TRACE(0, "ULog::setLogRotate(%S)", dir_log_gz) + + U_INTERNAL_ASSERT_POINTER(ptr_log_data) + U_INTERNAL_ASSERT_EQUALS(U_Log_syslog(this), false) + U_INTERNAL_ASSERT_EQUALS(buf_path_compress, U_NULLPTR) -# ifdef USE_LIBZ - checkForLogRotateDataToWrite(); // check for previous data to write + char suffix[32]; + uint32_t len_suffix = u__snprintf(suffix, sizeof(suffix), U_CONSTANT_TO_PARAM(".%4D.gz")); + + U_NEW(UString, buf_path_compress, UString(MAX_FILENAME_LEN)); + + char* p = buf_path_compress->data(); + + if (dir_log_gz == U_NULLPTR) + { +# ifndef U_COVERITY_FALSE_POSITIVE // Uninitialized pointer read (UNINIT) + (void) UFile::setPathFromFile(*this, p, suffix, len_suffix); # endif - U_INTERNAL_ASSERT_EQUALS(ptr_log_data->gzip_len, 0) + buf_path_compress->size_adjust(); - UFile::munmap(); - (void) UFile::ftruncate(ptr_log_data->file_ptr); - UFile::fsync(); + index_path_compress = (buf_path_compress->size() - len_suffix + 1); } + else + { + UString name = UFile::getName(); + uint32_t len = u__strlen(dir_log_gz, __PRETTY_FUNCTION__), sz = name.size(); + + U_MEMCPY(p, dir_log_gz, len); - UFile::close(); + p += len; + *p++ = '/'; + + buf_path_compress->size_adjust(len + 1 + sz + len_suffix); - if (log_gzip_sz == sizeof(log_data)) UFile::munmap(ptr_log_data, log_data_sz); + U_MEMCPY(p, name.data(), sz); + p += sz; + U_MEMCPY(p, suffix, len_suffix); + + index_path_compress = buf_path_compress->distance(p) + 1; + } } -void ULog::close() +void ULog::setShared(log_data* ptr) { - U_TRACE_NO_PARAM(0, "ULog::close()") + U_TRACE(0, "ULog::setShared(%p)", ptr) - // NB: we need this check because all child try to close the log... (inherits from its parent) + U_INTERNAL_ASSERT_POINTER(lock) + U_INTERNAL_ASSERT_POINTER(ptr_log_data) + U_INTERNAL_ASSERT_EQUALS(U_Log_syslog(this), false) - if (pthis) + log_gzip_sz = getSizeLogRotateData(); + + if (ptr == U_NULLPTR) { - U_INTERNAL_DUMP("pthis = %p", pthis) + U_INTERNAL_ASSERT_EQUALS(log_data_sz, 0) - if (U_Log_start_stop_msg(pthis)) log(U_CONSTANT_TO_PARAM(U_FMT_START_STOP), "SHUTDOWN", sizeof(void*) * 8); + log_data_sz = sizeof(log_data) + log_gzip_sz; - pthis->closeLog(); + ptr = (log_data*) UFile::mmap(&log_data_sz); - pthis = U_NULLPTR; + U_INTERNAL_ASSERT_DIFFERS(ptr, MAP_FAILED) } -} -#ifdef USE_LIBZ -UString ULog::getDirLogGz() -{ - U_TRACE_NO_PARAM(0, "ULog::getDirLogGz()") + ptr->file_ptr = ptr_log_data->file_ptr; + ptr->file_page = ptr_log_data->file_page; + + U_FREE_TYPE(ptr_log_data, log_data); - U_INTERNAL_ASSERT_POINTER(pthis) - U_INTERNAL_ASSERT_POINTER(pthis->buf_path_compress) + (ptr_log_data = ptr)->gzip_len = 0; - UString result = UStringExt::dirname(*(pthis->buf_path_compress)); + lock->init(&(ptr_log_data->lock_shared), ptr_log_data->spinlock_shared); - U_RETURN_STRING(result); + U_INTERNAL_DUMP("ptr_log_data->file_ptr = %u UFile::st_size = %u log_gzip_sz = %u", ptr_log_data->file_ptr, UFile::st_size, log_gzip_sz) + + U_INTERNAL_ASSERT(ptr_log_data->file_ptr <= UFile::st_size) } void ULog::checkForLogRotateDataToWrite() { U_TRACE_NO_PARAM(0, "ULog::checkForLogRotateDataToWrite()") - if (ptr_log_data->gzip_len) - { - // there are previous data to write + uint32_t gzip_len = ptr_log_data->gzip_len; - char* ptr1 = buf_path_compress->c_pointer(index_path_compress); + if (gzip_len) // there are previous data to write + { + ptr_log_data->gzip_len = 0; - ptr1[u__snprintf(ptr1, 17, U_CONSTANT_TO_PARAM("%4D"))] = '.'; + char* ptr = buf_path_compress->c_pointer(index_path_compress); - (void) UFile::writeTo(*buf_path_compress, (char*)ptr_log_data+sizeof(log_data), ptr_log_data->gzip_len, O_RDWR | O_EXCL, false); + ptr[u__snprintf(ptr, 17, U_CONSTANT_TO_PARAM("%4D"))] = '.'; - ptr_log_data->gzip_len = 0; + (void) UFile::writeTo(*buf_path_compress, (char*)ptr_log_data+sizeof(log_data), gzip_len, O_RDWR | O_EXCL, false); } } #endif // DEBUG -#if defined(U_STDCPP_ENABLE) && defined(DEBUG) +#ifdef DEBUG +ULog* ULog::first; + +void ULog::close() +{ + U_TRACE_NO_PARAM(0, "ULog::close()") + + ULog* next; + ULog* item; + + if (first) + { + next = first; + first = U_NULLPTR; + + do { + item = next; + next = item->next; + + U_INTERNAL_DUMP("item = %p next = %p", item, next) + + item->closeLogInternal(); + } + while (next); + } +} + +#ifdef U_STDCPP_ENABLE const char* ULog::dump(bool _reset) const { UFile::dump(false); @@ -1059,6 +998,8 @@ const char* ULog::dump(bool _reset) const *UObjectIO::os << '\n' << "prefix_len " << prefix_len << '\n' << "log_file_sz " << log_file_sz << '\n' + << "log_data_sz " << log_data_sz << '\n' + << "log_gzip_sz " << log_gzip_sz << '\n' << "lock (ULock " << (void*)lock << ')'; if (_reset) @@ -1071,3 +1012,4 @@ const char* ULog::dump(bool _reset) const return U_NULLPTR; } #endif +#endif diff --git a/src/ulib/net/client/client.cpp b/src/ulib/net/client/client.cpp index 0788c4702..31cb7493f 100644 --- a/src/ulib/net/client/client.cpp +++ b/src/ulib/net/client/client.cpp @@ -55,17 +55,9 @@ UClient_Base::~UClient_Base() { U_TRACE_UNREGISTER_OBJECT(0, UClient_Base) - U_INTERNAL_ASSERT_POINTER(socket) - -#ifndef U_LOG_DISABLE - if (log && - log_shared_with_server == false) - { - u_unatexit(&ULog::close); // unregister function of close at exit()... + closeLog(); - delete log; - } -#endif + U_INTERNAL_ASSERT_POINTER(socket) delete socket; @@ -78,6 +70,22 @@ UClient_Base::~UClient_Base() #endif } +void UClient_Base::closeLog() +{ + U_TRACE_NO_PARAM(0, "UClient_Base::closeLog()") + +#ifndef U_LOG_DISABLE + if (log && + log_shared_with_server == false) + { + log->closeLog(); + + delete log; + log = U_NULLPTR; + } +#endif +} + #ifdef USE_LIBSSL void UClient_Base::setSSLContext() { @@ -214,9 +222,9 @@ void UClient_Base::loadConfigParam() } else { - U_NEW(ULog, log, ULog(x, cfg->readLong(U_CONSTANT_TO_PARAM("LOG_FILE_SZ")))); + U_INTERNAL_ASSERT_EQUALS(log, U_NULLPTR) - u_atexit(&ULog::close); // register function of close at exit()... + U_NEW(ULog, log, ULog(x, cfg->readLong(U_CONSTANT_TO_PARAM("LOG_FILE_SZ")))); log->setPrefix(U_CONSTANT_TO_PARAM(U_SERVER_LOG_PREFIX)); } @@ -272,7 +280,7 @@ bool UClient_Base::connect() response.snprintf(U_CONSTANT_TO_PARAM("Sorry, couldn't connect to server %v%R"), host_port.rep, 0); // NB: the last argument (0) is necessary... #ifndef U_LOG_DISABLE - if (log) ULog::log(U_CONSTANT_TO_PARAM("%s%v"), log_shared_with_server ? UServer_Base::mod_name[0] : "", response.rep); + if (log) log->log(U_CONSTANT_TO_PARAM("%s%v"), log_shared_with_server ? UServer_Base::mod_name[0] : "", response.rep); #endif U_RETURN(false); @@ -386,7 +394,7 @@ bool UClient_Base::setUrl(const char* str, uint32_t len) // NB: return if it has modified host or port... - if (setHostPort(url.getHost(), url.getPort())) U_RETURN(true); + if (setHostPort(url.getHost(), url.getPortNumber())) U_RETURN(true); U_RETURN(false); } @@ -424,7 +432,7 @@ bool UClient_Base::sendRequest(bool bread_response) if (connect()) { # ifndef U_LOG_DISABLE - if (log) ULog::log(iov, name, "request", ncount, "", 0, U_CONSTANT_TO_PARAM(" to %v"), host_port.rep); + if (log) log->log(iov, name, "request", ncount, "", 0, U_CONSTANT_TO_PARAM(" to %v"), host_port.rep); # endif ok = (USocketExt::writev(socket, iov, iovcnt, ncount, timeoutMS, 1) == ncount); @@ -436,7 +444,7 @@ bool UClient_Base::sendRequest(bool bread_response) if (++counter <= 2) goto resend; # ifndef U_LOG_DISABLE - if (log) ULog::log(U_CONSTANT_TO_PARAM("%serror on sending data to %V%R"), name, host_port.rep, 0); // NB: the last argument (0) is necessary... + if (log) log->log(U_CONSTANT_TO_PARAM("%serror on sending data to %V%R"), name, host_port.rep, 0); // NB: the last argument (0) is necessary... # endif goto end; @@ -458,7 +466,7 @@ bool UClient_Base::sendRequest(bool bread_response) } # ifndef U_LOG_DISABLE - if (log) ULog::log(U_CONSTANT_TO_PARAM("%serror on reading data from %V%R"), name, host_port.rep, 0); // NB: the last argument (0) is necessary... + if (log) log->log(U_CONSTANT_TO_PARAM("%serror on reading data from %V%R"), name, host_port.rep, 0); // NB: the last argument (0) is necessary... # endif goto end; @@ -468,7 +476,7 @@ bool UClient_Base::sendRequest(bool bread_response) if (log && response) { - ULog::logResponse(response, name, U_CONSTANT_TO_PARAM(" from %v"), host_port.rep); + log->logResponse(response, name, U_CONSTANT_TO_PARAM(" from %v"), host_port.rep); } # endif @@ -534,7 +542,7 @@ bool UClient_Base::readResponse(uint32_t count) if (log && response) { - ULog::logResponse(response, (log_shared_with_server ? UServer_Base::mod_name[0] : ""), U_CONSTANT_TO_PARAM(" from %V"), host_port.rep); + log->logResponse(response, (log_shared_with_server ? UServer_Base::mod_name[0] : ""), U_CONSTANT_TO_PARAM(" from %V"), host_port.rep); } # endif @@ -554,34 +562,20 @@ bool UClient_Base::readHTTPResponse() if (UHTTP::readHeaderResponse(socket, buffer)) { - uint32_t pos = U_STRING_FIND_EXT(buffer, U_http_info.startHeader, "Content-Length", U_http_info.endHeader - U_CONSTANT_SIZE(U_CRLF2) - U_http_info.startHeader); - - if (pos != U_NOT_FOUND) + if (UHTTP::checkContentLength(buffer)) { - uint32_t end = buffer.findWhiteSpace(pos += U_CONSTANT_SIZE("Content-Length") + 2); - - U_http_info.clength = (end != U_NOT_FOUND ? u__strtoul(buffer.c_pointer(pos), end-pos) : 0); + if (UHTTP::readBodyResponse(socket, &buffer, response) == false) U_RETURN(false); - if (U_http_info.clength == 0) - { - U_http_flag &= ~HTTP_IS_DATA_CHUNKED; - - U_INTERNAL_DUMP("U_http_data_chunked = %b", U_http_data_chunked) - } - - if (UHTTP::readBodyResponse(socket, &buffer, response)) +# ifndef U_LOG_DISABLE + if (log && + response) { -# ifndef U_LOG_DISABLE - if (log && - response) - { - ULog::logResponse(response, (log_shared_with_server ? UServer_Base::mod_name[0] : ""), U_CONSTANT_TO_PARAM(" from %V"), host_port.rep); - } -# endif - - U_RETURN(true); + log->logResponse(response, (log_shared_with_server ? UServer_Base::mod_name[0] : ""), U_CONSTANT_TO_PARAM(" from %V"), host_port.rep); } +# endif } + + U_RETURN(true); } U_RETURN(false); diff --git a/src/ulib/net/client/http.cpp b/src/ulib/net/client/http.cpp index bc8364aa8..df5d5e42d 100644 --- a/src/ulib/net/client/http.cpp +++ b/src/ulib/net/client/http.cpp @@ -667,14 +667,7 @@ loop: if (UClient_Base::isOpen() == false) UClient_Base::socket->_socket(); } # ifndef U_LOG_DISABLE - if (log_msg) - { - uint32_t sz = strlen(log_msg); - const char* str = (num_attempts < U_MAX_ATTEMPTS ? "success" : "FAILED"); - - if (log_fd == -1) ULog::log( log_msg, sz, str, num_attempts); - else ULog::log(log_fd, log_msg, sz, str, num_attempts); - } + if (log_msg) ULog::log(log_fd, log_msg, u__strlen(log_msg, __PRETTY_FUNCTION__), (num_attempts < U_MAX_ATTEMPTS ? "success" : "FAILED"), num_attempts); # endif } diff --git a/src/ulib/net/server/client_image.cpp b/src/ulib/net/server/client_image.cpp index dd390e81f..a65a2af54 100644 --- a/src/ulib/net/server/client_image.cpp +++ b/src/ulib/net/server/client_image.cpp @@ -111,11 +111,11 @@ void UClientImage_Base::logRequest() U_INTERNAL_DUMP("u_printf_string_max_length = %d U_ClientImage_pipeline = %b", u_printf_string_max_length, U_ClientImage_pipeline) - ULog::log(U_CONSTANT_TO_PARAM("%sreceived request (%u bytes) %.*s%.*s%#.*S from %v"), - UServer_Base::mod_name[0], sz, - (U_ClientImage_pipeline ? U_CONSTANT_SIZE("[pipeline] ") : 0), "[pipeline] ", - str_partial_len, str_partial, - sz, ptr, logbuf->rep); + UServer_Base::log->log(U_CONSTANT_TO_PARAM("%sreceived request (%u bytes) %.*s%.*s%#.*S from %v"), + UServer_Base::mod_name[0], sz, + (U_ClientImage_pipeline ? U_CONSTANT_SIZE("[pipeline] ") : 0), "[pipeline] ", + str_partial_len, str_partial, + sz, ptr, logbuf->rep); u_printf_string_max_length = u_printf_string_max_length_save; } @@ -485,7 +485,7 @@ void UClientImage_Base::handlerDelete() uint32_t len = UServer_Base::setNumConnection(buffer); const char* agent = (bsocket_open == false || UServer_Base::isParallelizationParent() ? "Server" : "Client"); - ULog::log(U_CONSTANT_TO_PARAM("%s%.6s close connection from %v, %.*s clients still connected"), UServer_Base::mod_name[0], agent, logbuf->rep, len, buffer); + UServer_Base::log->log(U_CONSTANT_TO_PARAM("%s%.6s close connection from %v, %.*s clients still connected"), UServer_Base::mod_name[0], agent, logbuf->rep, len, buffer); # ifdef DEBUG int fd_logbuf = ::strtoul(logbuf->data(), U_NULLPTR, 10); @@ -505,10 +505,11 @@ void UClientImage_Base::handlerDelete() } #endif - uint32_t u_srv_tot_connection = U_SRV_TOT_CONNECTION-1; - U_SRV_TOT_CONNECTION = u_srv_tot_connection; +#ifndef U_LOG_DISABLE + ULock::atomicDecrement(U_SRV_TOT_CONNECTION); - U_INTERNAL_DUMP("U_SRV_TOT_CONNECTION = %u", u_srv_tot_connection) + U_INTERNAL_DUMP("U_SRV_TOT_CONNECTION = %u", U_SRV_TOT_CONNECTION) +#endif #ifdef U_CLASSIC_SUPPORT if (UServer_Base::isClassic()) U_EXIT(0); @@ -529,7 +530,7 @@ void UClientImage_Base::handlerDelete() { logbuf->setEmpty(); - if (UNotifier::num_connection == UNotifier::min_connection) ULog::log(U_CONSTANT_TO_PARAM("Waiting for connection on port %u"), UServer_Base::port); + if (UNotifier::num_connection == UNotifier::min_connection) UServer_Base::log->log(U_CONSTANT_TO_PARAM("Waiting for connection on port %u"), UServer_Base::port); } #endif @@ -819,7 +820,6 @@ void UClientImage_Base::endRequest() if (time_run > 0L) ptr1 += u__snprintf(ptr1, sizeof(buffer1)-(ptr1-buffer1), U_CONSTANT_TO_PARAM("%ld ms"), time_run); else ptr1 += u__snprintf(ptr1, sizeof(buffer1)-(ptr1-buffer1), U_CONSTANT_TO_PARAM( "%g ms"), chronometer->getTimeElapsed()); -# ifndef U_SERVER_CAPTIVE_PORTAL if (UServer_Base::csocket->isOpen()) { uint32_t len = 0; @@ -838,13 +838,12 @@ void UClientImage_Base::endRequest() U_INTERNAL_DUMP("USocket::incoming_cpu = %d USocket::bincoming_cpu = %b sched cpu = %d socket cpu = %d", USocket::incoming_cpu, USocket::bincoming_cpu, cpu, scpu) - if (len) ptr1 += u__snprintf(ptr1, sizeof(buffer1)-(ptr1-buffer1), U_CONSTANT_TO_PARAM(", CPU: %d sched(%d) socket(%d)%.*s"), USocket::incoming_cpu, cpu, scpu, len, " [DIFFER]"); + if (len) ptr1 += u__snprintf(ptr1,sizeof(buffer1)-(ptr1-buffer1),U_CONSTANT_TO_PARAM(", CPU: %d sched(%d) socket(%d)%.*s"),USocket::incoming_cpu,cpu,scpu,len," [DIFFER]"); } -# endif U_INTERNAL_ASSERT_MINOR((ptrdiff_t)(ptr1-buffer1), (ptrdiff_t)sizeof(buffer1)) - ULog::write(buffer1, ptr1-buffer1); + UServer_Base::log->write(buffer1, ptr1-buffer1); } # endif } @@ -1472,6 +1471,9 @@ check: U_INTERNAL_DUMP("nrequest = %u resto = %u", nrequest, resto) { // NB: we are managing a sendfile() request... + U_INTERNAL_DUMP("U_http_sendfile = %b", U_http_sendfile) + + U_INTERNAL_ASSERT(U_http_sendfile) U_INTERNAL_ASSERT_EQUALS(nrequest, 0) U_INTERNAL_ASSERT_DIFFERS(U_http_version, '2') U_INTERNAL_ASSERT_EQUALS(UEventFd::op_mask, EPOLLIN | EPOLLRDHUP | EPOLLET) @@ -1594,7 +1596,7 @@ bool UClientImage_Base::writeResponse() U_INTERNAL_ASSERT_MAJOR(iov_sav[0].iov_len, 0) -# if defined(U_LINUX) && defined(ENABLE_THREAD) && defined(U_LOG_DISABLE) && !defined(USE_LIBZ) +# if defined(U_LINUX) && defined(ENABLE_THREAD) U_INTERNAL_ASSERT_POINTER(u_pthread_time) U_INTERNAL_ASSERT_EQUALS(iov_vec[1].iov_base, ULog::ptr_shared_date->date3) # else @@ -1604,7 +1606,7 @@ bool UClientImage_Base::writeResponse() # endif # ifndef U_LOG_DISABLE - if (logbuf) ULog::log(iov_vec+idx, UServer_Base::mod_name[0], "response", ncount, "[pipeline] ", msg_len, U_CONSTANT_TO_PARAM(" to %v"), logbuf->rep); + if (logbuf) UServer_Base::log->log(iov_vec+idx, UServer_Base::mod_name[0], "response", ncount, "[pipeline] ", msg_len, U_CONSTANT_TO_PARAM(" to %v"), logbuf->rep); # endif } diff --git a/src/ulib/net/server/plugin/mod_http.cpp b/src/ulib/net/server/plugin/mod_http.cpp index 49880b493..2eccd31f0 100644 --- a/src/ulib/net/server/plugin/mod_http.cpp +++ b/src/ulib/net/server/plugin/mod_http.cpp @@ -370,22 +370,18 @@ int UHttpPlugIn::handlerConfig(UFileConfig& cfg) UServer_Base::update_date = UServer_Base::update_date2 = true; - uint32_t size = cfg.readLong(U_CONSTANT_TO_PARAM("LOG_FILE_SIZE")); - U_INTERNAL_ASSERT_EQUALS(UServer_Base::apache_like_log, U_NULLPTR) + uint32_t size = cfg.readLong(U_CONSTANT_TO_PARAM("LOG_FILE_SZ")); + U_NEW(ULog, UServer_Base::apache_like_log, ULog(x, size)); -# ifdef USE_LIBZ if (size) { - uint32_t log_rotate_size = size + (size / 10) + 12U; + U_INTERNAL_ASSERT_EQUALS(UServer_Base::shm_data_add, 0) - UServer_Base::apache_like_log->setShared(U_NULLPTR, log_rotate_size, (UServer_Base::bssl == false)); - - U_SRV_LOG("Mapped %u bytes (%u KB) of shared memory for apache like log", log_rotate_size, log_rotate_size / 1024); + UServer_Base::shm_data_add += UServer_Base::apache_like_log->getSizeLogRotateData(); } -# endif } # endif @@ -539,8 +535,9 @@ int UHttpPlugIn::handlerRun() // NB: we use this method instead of handlerInit() UClientImage_Base::iov_vec[1].iov_len = 6+29+2+12+2+17+2; UClientImage_Base::iov_vec[1].iov_base = (caddr_t)ULog::date.date3; // Date: Wed, 20 Jun 2012 11:43:17 GMT\r\nServer: ULib\r\nConnection: close\r\n -# if defined(U_LINUX) && defined(ENABLE_THREAD) && defined(U_LOG_DISABLE) && !defined(USE_LIBZ) +# if defined(U_LINUX) && defined(ENABLE_THREAD) U_INTERNAL_ASSERT_POINTER(u_pthread_time) + U_INTERNAL_ASSERT_POINTER(UServer_Base::ptr_shared_data) UClientImage_Base::iov_vec[1].iov_base = (caddr_t)UServer_Base::ptr_shared_data->log_date_shared.date3; # endif diff --git a/src/ulib/net/server/plugin/mod_nocat.cpp b/src/ulib/net/server/plugin/mod_nocat.cpp index 9f58f503b..af2cd5b9d 100644 --- a/src/ulib/net/server/plugin/mod_nocat.cpp +++ b/src/ulib/net/server/plugin/mod_nocat.cpp @@ -2411,7 +2411,11 @@ int UNoCatPlugIn::handlerFork() U_INTERNAL_ASSERT_EQUALS(dirwalk, U_NULLPTR) #if !defined(U_LOG_DISABLE) && defined(USE_LIBZ) - if (UServer_Base::isLog()) U_NEW(UDirWalk, dirwalk, UDirWalk(ULog::getDirLogGz(), U_CONSTANT_TO_PARAM("*.gz"))); + if (UServer_Base::isLog() && + UServer_Base::log->isMemoryMapped()) + { + U_NEW(UDirWalk, dirwalk, UDirWalk(UServer_Base::log->getDirLogGz(), U_CONSTANT_TO_PARAM("*.gz"))); + } #endif U_RETURN(U_PLUGIN_HANDLER_PROCESSED | U_PLUGIN_HANDLER_GO_ON); @@ -2789,7 +2793,7 @@ next: (void) getARPCache(); UEscape::encode(data, printable); - ULog::log(U_CONSTANT_TO_PARAM("%sauth message: %v"), UServer_Base::mod_name[0], printable.rep); + UServer_Base::log->log(U_CONSTANT_TO_PARAM("%sauth message: %v"), UServer_Base::mod_name[0], printable.rep); } # endif diff --git a/src/ulib/net/server/plugin/mod_proxy.cpp b/src/ulib/net/server/plugin/mod_proxy.cpp index 47a451c91..b00bdac91 100644 --- a/src/ulib/net/server/plugin/mod_proxy.cpp +++ b/src/ulib/net/server/plugin/mod_proxy.cpp @@ -220,7 +220,7 @@ int UProxyPlugIn::handlerRequest() } } # ifndef U_LOG_DISABLE - else if (UServer_Base::isLog()) ULog::logResponse(*UClientImage_Base::wbuffer, UServer_Base::mod_name[0], U_CONSTANT_TO_PARAM(""), 0); + else if (UServer_Base::isLog()) UServer_Base::log->logResponse(*UClientImage_Base::wbuffer, UServer_Base::mod_name[0], U_CONSTANT_TO_PARAM(""), 0); # endif client_http->reset(); // reset reference to request... diff --git a/src/ulib/net/server/server.cpp b/src/ulib/net/server/server.cpp index c3ea44bfe..a2d64863d 100644 --- a/src/ulib/net/server/server.cpp +++ b/src/ulib/net/server/server.cpp @@ -106,11 +106,9 @@ ULog* UServer_Base::apache_like_log; char* UServer_Base::client_address; ULock* UServer_Base::lock_user1; ULock* UServer_Base::lock_user2; -uint32_t UServer_Base::map_size; uint32_t UServer_Base::vplugin_size; uint32_t UServer_Base::nClientIndex; uint32_t UServer_Base::crash_count; -uint32_t UServer_Base::shared_data_add; uint32_t UServer_Base::client_address_len; uint32_t UServer_Base::document_root_size; uint32_t UServer_Base::num_client_threshold; @@ -144,15 +142,21 @@ USmtpClient* UServer_Base::emailClient; UFileConfig* UServer_Base::cfg; UServer_Base* UServer_Base::pthis; +uint32_t UServer_Base::map_size; +uint32_t UServer_Base::shared_data_add; +UServer_Base::shared_data* UServer_Base::ptr_shared_data; + +uint32_t UServer_Base::shm_size; +uint32_t UServer_Base::shm_data_add; +UServer_Base::shm_data* UServer_Base::ptr_shm_data; + UVector* UServer_Base::vplugin_name; UVector* UServer_Base::vplugin_name_static; UClientImage_Base* UServer_Base::vClientImage; UClientImage_Base* UServer_Base::pClientImage; UClientImage_Base* UServer_Base::eClientImage; -UServer_Base::shm_data* UServer_Base::ptr_shm_data; UVector* UServer_Base::vplugin; UVector* UServer_Base::vplugin_static; -UServer_Base::shared_data* UServer_Base::ptr_shared_data; UVector* UServer_Base::vlog; #ifdef U_WELCOME_SUPPORT @@ -264,8 +268,6 @@ class U_NO_EXPORT UTimeoutConnection : public UEventTime { { U_TRACE_NO_PARAM(0, "UTimeoutConnection::handlerTime()") - U_INTERNAL_ASSERT_POINTER(UServer_Base::ptr_shared_data) - // there are idle connection... (timeout) # if !defined(U_LOG_DISABLE) || (!defined(USE_LIBEVENT) && defined(HAVE_EPOLL_WAIT) && defined(DEBUG)) @@ -437,17 +439,17 @@ class U_NO_EXPORT UBandWidthThrottling : public UEventTime { { if (UServer_Base::throttling_rec->krate > UServer_Base::throttling_rec->max_limit) { - ULog::log(U_CONSTANT_TO_PARAM("throttle %V: krate %u %sexceeding limit %u; %u sending"), UServer_Base::db_throttling->getKeyID().rep, - UServer_Base::throttling_rec->krate, - (UServer_Base::throttling_rec->krate > UServer_Base::throttling_rec->max_limit * 2 ? "greatly " : ""), - UServer_Base::throttling_rec->max_limit, UServer_Base::throttling_rec->num_sending); + UServer_Base::log->log(U_CONSTANT_TO_PARAM("throttle %V: krate %u %sexceeding limit %u; %u sending"), UServer_Base::db_throttling->getKeyID().rep, + UServer_Base::throttling_rec->krate, + (UServer_Base::throttling_rec->krate > UServer_Base::throttling_rec->max_limit * 2 ? "greatly " : ""), + UServer_Base::throttling_rec->max_limit, UServer_Base::throttling_rec->num_sending); } if (UServer_Base::throttling_rec->krate < UServer_Base::throttling_rec->min_limit) { - ULog::log(U_CONSTANT_TO_PARAM("throttle %V: krate %u lower than minimum %u; %u sending"), UServer_Base::db_throttling->getKeyID().rep, - UServer_Base::throttling_rec->krate, - UServer_Base::throttling_rec->min_limit, UServer_Base::throttling_rec->num_sending); + UServer_Base::log->log(U_CONSTANT_TO_PARAM("throttle %V: krate %u lower than minimum %u; %u sending"), UServer_Base::db_throttling->getKeyID().rep, + UServer_Base::throttling_rec->krate, + UServer_Base::throttling_rec->min_limit, UServer_Base::throttling_rec->num_sending); } } } @@ -1008,7 +1010,7 @@ bool UServer_Base::checkHitStats(const char* key, uint32_t key_len, uint32_t int bool UServer_Base::checkHitSiteStats() { - U_TRACE_NO_PARAM(0, "UServer_Base::checkHitSiteStats()") + U_TRACE_NO_PARAM(0+256, "UServer_Base::checkHitSiteStats()") U_INTERNAL_ASSERT_POINTER(db_evasive) @@ -1026,7 +1028,7 @@ bool UServer_Base::checkHitSiteStats() bool UServer_Base::checkHitUriStats() { - U_TRACE_NO_PARAM(0, "UServer_Base::checkHitUriStats()") + U_TRACE_NO_PARAM(0+256, "UServer_Base::checkHitUriStats()") U_INTERNAL_ASSERT_POINTER(db_evasive) @@ -1137,7 +1139,7 @@ class UTimeThread : public UThread { continue; } -# if !defined(U_LOG_DISABLE) && defined(USE_LIBZ) +# ifndef U_SERVER_CAPTIVE_PORTAL if (UServer_Base::log) UServer_Base::log->checkForLogRotateDataToWrite(); if (UServer_Base::apache_like_log) UServer_Base::apache_like_log->checkForLogRotateDataToWrite(); # endif @@ -1200,7 +1202,7 @@ class UTimeThread : public UThread { sec = u_now->tv_sec; -# if !defined(U_LOG_DISABLE) && defined(USE_LIBZ) +# ifndef U_SERVER_CAPTIVE_PORTAL if (daylight && (sec % U_ONE_HOUR_IN_SECOND) == 0) { @@ -1210,7 +1212,7 @@ class UTimeThread : public UThread { if (UServer_Base::update_date) { -# if !defined(U_LOG_DISABLE) && defined(USE_LIBZ) +# ifndef U_SERVER_CAPTIVE_PORTAL (void) U_SYSCALL(pthread_rwlock_wrlock, "%p", ULog::prwlock); # endif @@ -1229,7 +1231,7 @@ class UTimeThread : public UThread { if (UServer_Base::update_date3) (void) u_strftime2(ULog::ptr_shared_date->date3+6, 29-4, U_CONSTANT_TO_PARAM("%a, %d %b %Y %T"), sec); } -# if !defined(U_LOG_DISABLE) && defined(USE_LIBZ) +# ifndef U_SERVER_CAPTIVE_PORTAL (void) U_SYSCALL(pthread_rwlock_unlock, "%p", ULog::prwlock); # endif } @@ -1423,9 +1425,7 @@ UServer_Base::~UServer_Base() delete socket; delete vplugin_name; -#ifndef U_SERVER_CAPTIVE_PORTAL delete vplugin; -#endif UOrmDriver::clear(); @@ -1500,7 +1500,7 @@ UServer_Base::~UServer_Base() if (lock_user1) delete lock_user1; if (lock_user2) delete lock_user2; - UFile::munmap(ptr_shared_data, map_size); + if (ptr_shared_data) UFile::munmap(ptr_shared_data, map_size); delete as_user; delete dh_file; @@ -1530,7 +1530,7 @@ void UServer_Base::closeLog() if (log && log->isOpen()) { - ULog::close(); + log->closeLog(); # ifdef DEBUG delete log; @@ -1758,29 +1758,53 @@ void UServer_Base::loadConfigParam() if ((port == 80 || port == 443) && UServices::isSetuidRoot() == false) { - port = 8080; + unsigned int _port = (port == 80 ? 8080 : 4433); + + U_WARNING("Sorry, it is required root privilege to listen on port %u but I am not setuid root, I must try %u", port, _port); - U_WARNING("Sorry, it is required root privilege to listen on port 80 but I am not setuid root, I must try 8080"); + port = _port; } set_tcp_keep_alive = cfg->readBoolean(U_CONSTANT_TO_PARAM("TCP_KEEP_ALIVE")); set_realtime_priority = cfg->readBoolean(U_CONSTANT_TO_PARAM("SET_REALTIME_PRIORITY"), true); + crash_count = cfg->readLong(U_CONSTANT_TO_PARAM("CRASH_COUNT"), 5); tcp_linger_set = cfg->readLong(U_CONSTANT_TO_PARAM("TCP_LINGER_SET"), -2); USocket::iBackLog = cfg->readLong(U_CONSTANT_TO_PARAM("LISTEN_BACKLOG"), SOMAXCONN); + min_size_for_sendfile = cfg->readLong(U_CONSTANT_TO_PARAM("MIN_SIZE_FOR_SENDFILE"), 500 * 1024); // 500k: for major size we assume is better to use sendfile() UNotifier::max_connection = cfg->readLong(U_CONSTANT_TO_PARAM("MAX_KEEP_ALIVE")); u_printf_string_max_length = cfg->readLong(U_CONSTANT_TO_PARAM("LOG_MSG_SIZE")); num_client_threshold = cfg->readLong(U_CONSTANT_TO_PARAM("CLIENT_THRESHOLD")); num_client_for_parallelization = cfg->readLong(U_CONSTANT_TO_PARAM("CLIENT_FOR_PARALLELIZATION")); + x = cfg->at(U_CONSTANT_TO_PARAM("CRASH_EMAIL_NOTIFY")); + + if (x) + { + U_INTERNAL_ASSERT_EQUALS(crashEmailAddress, U_NULLPTR) + + U_NEW(UString, crashEmailAddress, UString(x)); + + if (emailClient == U_NULLPTR) + { + U_NEW(USmtpClient, emailClient, USmtpClient(UClientImage_Base::bIPv6)); + } + } + +#ifdef U_WELCOME_SUPPORT + x = cfg->at(U_CONSTANT_TO_PARAM("WELCOME_MSG")); + + if (x) setMsgWelcome(x); +#endif + x = cfg->at(U_CONSTANT_TO_PARAM("PREFORK_CHILD")); if (x) { preforked_num_kids = x.strtol(); -# ifdef U_SERVER_CAPTIVE_PORTAL +# if defined(U_SERVER_CAPTIVE_PORTAL) && !defined(ENABLE_THREAD) if (x.c_char(0) == '0') monitoring_process = true; # endif @@ -1824,16 +1848,6 @@ void UServer_Base::loadConfigParam() if (preforked_num_kids > 1) monitoring_process = true; -#ifdef U_WELCOME_SUPPORT - x = cfg->at(U_CONSTANT_TO_PARAM("WELCOME_MSG")); - - if (x) setMsgWelcome(x); -#endif - - min_size_for_sendfile = cfg->readLong(U_CONSTANT_TO_PARAM("MIN_SIZE_FOR_SENDFILE")); - - if (min_size_for_sendfile == 0) min_size_for_sendfile = 500 * 1024; // 500k: for major size we assume is better to use sendfile() - #ifdef USE_LIBSSL *password = cfg->at(U_CONSTANT_TO_PARAM("PASSWORD")); *ca_file = cfg->at(U_CONSTANT_TO_PARAM("CA_FILE")); @@ -1849,22 +1863,6 @@ void UServer_Base::loadConfigParam() U_INTERNAL_DUMP("min_size_for_sendfile = %u", min_size_for_sendfile) - crash_count = cfg->readLong(U_CONSTANT_TO_PARAM("CRASH_COUNT"), 5); - - x = cfg->at(U_CONSTANT_TO_PARAM("CRASH_EMAIL_NOTIFY")); - - if (x) - { - U_INTERNAL_ASSERT_EQUALS(crashEmailAddress, U_NULLPTR) - - U_NEW(UString, crashEmailAddress, UString(x)); - - if (emailClient == U_NULLPTR) - { - U_NEW(USmtpClient, emailClient, USmtpClient(UClientImage_Base::bIPv6)); - } - } - // Instructs server to accept connections from the IP address IPADDR. A CIDR mask length can be // supplied optionally after a trailing slash, e.g. 192.168.0.0/24, in which case addresses that // match in the most significant MASK bits will be allowed. If no options are specified, all clients @@ -1951,37 +1949,9 @@ void UServer_Base::loadConfigParam() # endif } - x = cfg->at(U_CONSTANT_TO_PARAM("PID_FILE")); - - if (x) - { - // write pid on file - - U_INTERNAL_ASSERT(x.isNullTerminated()) - - int old_pid = (int) UFile::getSysParam(x.data()); - - if (old_pid > 0) - { -# ifndef U_LOG_DISABLE - if (isLog()) ULog::log(U_CONSTANT_TO_PARAM("Trying to kill another instance of userver that is running with pid %d"), old_pid); -# endif - - U_INTERNAL_ASSERT_DIFFERS(old_pid, u_pid) - - UProcess::kill(old_pid, SIGTERM); // SIGTERM is sent to every process in the process group of the calling process... - } - - UString pid_str = UString(u_pid_str, u_pid_str_len); - - (void) UFile::writeTo(x, pid_str); - - U_DEBUG("We have %s the PID_FILE %V with content: %V", (old_pid > 0 ? "updated" : "created"), x.rep, pid_str.rep); - } - // DOCUMENT_ROOT: The directory out of which we will serve your documents - if (setDocumentRoot(cfg->at(U_CONSTANT_TO_PARAM("DOCUMENT_ROOT"))) == false) U_ERROR("Setting DOCUMENT ROOT %V failed", document_root->rep); + if (setDocumentRoot(cfg->at(U_CONSTANT_TO_PARAM("DOCUMENT_ROOT"))) == false) U_ERROR("Setting DOCUMENT ROOT to %V failed", document_root->rep); #ifndef U_LOG_DISABLE x = cfg->at(U_CONSTANT_TO_PARAM("LOG_FILE")); @@ -2003,6 +1973,30 @@ void UServer_Base::loadConfigParam() } #endif + x = cfg->at(U_CONSTANT_TO_PARAM("PID_FILE")); + + if (x) + { + // write pid on file + + U_INTERNAL_ASSERT(x.isNullTerminated()) + + int old_pid = (int) UFile::getSysParam(x.data()); + + if (old_pid > 0) + { + U_SRV_LOG("Trying to kill another instance of userver that is running with pid %d", old_pid); + + U_INTERNAL_ASSERT_DIFFERS(old_pid, u_pid) + + UProcess::kill(old_pid, SIGTERM); // SIGTERM is sent to every process in the process group of the calling process... + } + + (void) UFile::writeTo(x, u_pid_str, u_pid_str_len); + + U_DEBUG("We have %s the PID_FILE %V with content: %P", (old_pid > 0 ? "updated" : "created"), x.rep); + } + #ifdef USE_LOAD_BALANCE x = cfg->at(U_CONSTANT_TO_PARAM("LOAD_BALANCE_DEVICE_NETWORK")); @@ -2159,14 +2153,14 @@ U_NO_EXPORT void UServer_Base::loadStaticLinkedModules(const char* name) U_INTERNAL_ASSERT_POINTER(vplugin_name) U_INTERNAL_ASSERT_MAJOR(vplugin_size, 0) - UString x(name, u__strlen(name, __PRETTY_FUNCTION__)); + uint32_t name_len; + UString x(name, (name_len = u__strlen(name, __PRETTY_FUNCTION__))); if (vplugin_name->find(x) != U_NOT_FOUND) // NB: we load only the plugin that we want from configuration (PLUGIN var)... { # ifndef U_LOG_DISABLE - const char* fmt = "WARNING: Link phase of static plugin %s failed\n"; + bool ok = false; # endif - #if defined(U_STATIC_HANDLER_RPC) || defined(U_STATIC_HANDLER_SHIB) || defined(U_STATIC_HANDLER_ECHO) || \ defined(U_STATIC_HANDLER_STREAM) || defined(U_STATIC_HANDLER_SOCKET) || defined(U_STATIC_HANDLER_SCGI) || \ defined(U_STATIC_HANDLER_FCGI) || defined(U_STATIC_HANDLER_GEOIP) || defined(U_STATIC_HANDLER_PROXY) || \ @@ -2217,18 +2211,22 @@ U_NO_EXPORT void UServer_Base::loadStaticLinkedModules(const char* name) # endif next: if (_plugin) { +# ifndef U_LOG_DISABLE + ok = true; +# endif + vplugin_name_static->push_back(x); vplugin_static->push_back(_plugin); - -# ifndef U_LOG_DISABLE - fmt = "Link phase of static plugin %s success"; -# endif } #endif # ifndef U_LOG_DISABLE - if (isLog()) ULog::log(fmt, strlen(fmt), name); + if (isLog()) + { + if (ok) log->log(U_CONSTANT_TO_PARAM( "Link phase of static plugin %.*s success"), name_len, name); + else log->log(U_CONSTANT_TO_PARAM("WARNING: Link phase of static plugin %.*s failed"), name_len, name); + } # endif } } @@ -2255,7 +2253,7 @@ int UServer_Base::loadPlugins(UString& plugin_dir, const UString& plugin_list) U_NEW(UVector, vplugin, UVector(10U)); U_NEW(UVector, vplugin_static, UVector(10U)); - uint32_t i; + uint32_t i, pos = 0; UString item, _name; UServerPlugIn* _plugin; int result = U_PLUGIN_HANDLER_ERROR; @@ -2280,7 +2278,7 @@ int UServer_Base::loadPlugins(UString& plugin_dir, const UString& plugin_list) { item = vplugin_name->at(i); - uint32_t pos = vplugin_name_static->find(item); + pos = vplugin_name_static->find(item); U_INTERNAL_DUMP("i = %u pos = %u item = %V", i, pos, item.rep) @@ -2304,10 +2302,10 @@ int UServer_Base::loadPlugins(UString& plugin_dir, const UString& plugin_list) # ifndef U_LOG_DISABLE if (isLog()) { - (void) u__snprintf(mod_name[0], sizeof(mod_name[0]), U_CONSTANT_TO_PARAM("[%v] "), item.rep); + pos = u__snprintf(mod_name[0], sizeof(mod_name[0]), U_CONSTANT_TO_PARAM("[%v] "), item.rep); - if (_plugin == U_NULLPTR) ULog::log(U_CONSTANT_TO_PARAM("%sWARNING: Load phase of plugin %v failed"), mod_name[0], item.rep); - else ULog::log(U_CONSTANT_TO_PARAM("%sLoad phase of plugin %v success"), mod_name[0], item.rep); + if (_plugin) log->log(U_CONSTANT_TO_PARAM( "%.*sLoad phase of plugin %v success"), pos, mod_name[0], item.rep); + else log->log(U_CONSTANT_TO_PARAM("%.*sWARNING: Load phase of plugin %v failed"), pos, mod_name[0], item.rep); mod_name[0][0] = '\0'; } @@ -2338,7 +2336,7 @@ int UServer_Base::loadPlugins(UString& plugin_dir, const UString& plugin_list) _plugin = vplugin->at(i); # ifndef U_LOG_DISABLE - if (isLog()) (void) u__snprintf(mod_name[0], sizeof(mod_name[0]), U_CONSTANT_TO_PARAM("[%v] "), item.rep); + if (isLog()) pos = u__snprintf(mod_name[0], sizeof(mod_name[0]), U_CONSTANT_TO_PARAM("[%v] "), item.rep); # endif result = _plugin->handlerConfig(*cfg); @@ -2348,11 +2346,8 @@ int UServer_Base::loadPlugins(UString& plugin_dir, const UString& plugin_list) { if ((result & (U_PLUGIN_HANDLER_ERROR | U_PLUGIN_HANDLER_PROCESSED)) != 0) { - const char* fmt = ((result & U_PLUGIN_HANDLER_ERROR) == 0 - ? "%sConfiguration phase of plugin %v success" - : "%sWARNING: Configuration phase of plugin %v failed"); - - ULog::log(fmt, strlen(fmt), mod_name[0], item.rep); + if ((result & U_PLUGIN_HANDLER_ERROR) == 0) log->log(U_CONSTANT_TO_PARAM( "%.*sConfiguration phase of plugin %v success"), pos, mod_name[0], item.rep); + else log->log(U_CONSTANT_TO_PARAM("%.*sWARNING: Configuration phase of plugin %v failed"), pos, mod_name[0], item.rep); } mod_name[0][0] = '\0'; @@ -2404,9 +2399,8 @@ int UServer_Base::pluginsHandler##xxx() U_INTERNAL_ASSERT_POINTER(vplugin) \ U_INTERNAL_ASSERT_MAJOR(vplugin_size, 0) \ \ - int result; \ - uint32_t i = 0; \ - const char* fmt; \ + int result, ilog; \ + uint32_t i = 0, sz; \ UServerPlugIn* _plugin; \ \ do { \ @@ -2417,29 +2411,39 @@ int UServer_Base::pluginsHandler##xxx() { \ UString name = vplugin_name->at(i); \ \ - (void) u__snprintf(mod_name[0],sizeof(mod_name[0]), \ - U_CONSTANT_TO_PARAM("[%v] "),name.rep); \ + sz = u__snprintf(mod_name[0], sizeof(mod_name[0]), U_CONSTANT_TO_PARAM("[%v] "), name.rep); \ \ result = _plugin->handler##xxx(); \ \ if ((result & (U_PLUGIN_HANDLER_ERROR | \ U_PLUGIN_HANDLER_PROCESSED)) != 0) \ { \ + ilog = 0; \ + \ if ((result & U_PLUGIN_HANDLER_ERROR) != 0) \ { \ - fmt = ((result & U_PLUGIN_HANDLER_FINISHED) != 0 \ - ? U_NULLPTR \ - : "%sWARNING: "#xxx" phase of plugin %v failed"); \ + if ((result & U_PLUGIN_HANDLER_FINISHED) != 0) ilog = 2; \ } \ else \ { \ - fmt = (U_ClientImage_parallelization == U_PARALLELIZATION_PARENT || \ - (result & U_PLUGIN_HANDLER_PROCESSED) == 0 \ - ? U_NULLPTR \ - : "%s"#xxx" phase of plugin %v success"); \ + if ((result & U_PLUGIN_HANDLER_PROCESSED) == 0 || \ + U_ClientImage_parallelization == U_PARALLELIZATION_PARENT) \ + { \ + ilog = 1; \ + } \ } \ \ - if (fmt) ULog::log(fmt, strlen(fmt), mod_name[0], name.rep); \ + if (ilog) \ + { \ + if (ilog == 1) \ + { \ + log->log(U_CONSTANT_TO_PARAM("%.*s"#xxx" phase of plugin %v success"), sz, mod_name[0], name.rep); \ + } \ + else \ + { \ + log->log(U_CONSTANT_TO_PARAM("%.*sWARNING: "#xxx" phase of plugin %v failed"), sz, mod_name[0], name.rep); \ + } \ + } \ } \ \ mod_name[0][0] = '\0'; \ @@ -2488,8 +2492,8 @@ int UServer_Base::pluginsHandler##xxx() U_INTERNAL_ASSERT_POINTER(vplugin) \ U_INTERNAL_ASSERT_MAJOR(vplugin_size, 0) \ \ - int result; \ - const char* fmt; \ + uint32_t sz; \ + int result, ilog; \ UServerPlugIn* _plugin; \ uint32_t i = vplugin_size; \ \ @@ -2501,29 +2505,39 @@ int UServer_Base::pluginsHandler##xxx() { \ UString name = vplugin_name->at(i); \ \ - (void) u__snprintf(mod_name[0],sizeof(mod_name[0]), \ - U_CONSTANT_TO_PARAM("[%v] "),name.rep); \ + sz = u__snprintf(mod_name[0], sizeof(mod_name[0]), U_CONSTANT_TO_PARAM("[%v] "), name.rep); \ \ result = _plugin->handler##xxx(); \ \ if ((result & (U_PLUGIN_HANDLER_ERROR | \ U_PLUGIN_HANDLER_PROCESSED)) != 0) \ { \ + ilog = 0; \ + \ if ((result & U_PLUGIN_HANDLER_ERROR) != 0) \ { \ - fmt = ((result & U_PLUGIN_HANDLER_FINISHED) != 0 \ - ? U_NULLPTR \ - : "%sWARNING: "#xxx" phase of plugin %v failed"); \ + if ((result & U_PLUGIN_HANDLER_FINISHED) != 0) ilog = 2; \ } \ else \ { \ - fmt = (U_ClientImage_parallelization == U_PARALLELIZATION_PARENT || \ - (result & U_PLUGIN_HANDLER_PROCESSED) == 0 \ - ? U_NULLPTR \ - : "%s"#xxx" phase of plugin %v success"); \ + if ((result & U_PLUGIN_HANDLER_PROCESSED) == 0 || \ + U_ClientImage_parallelization == U_PARALLELIZATION_PARENT) \ + { \ + ilog = 1; \ + } \ } \ \ - if (fmt) ULog::log(fmt, strlen(fmt), mod_name[0], name.rep); \ + if (ilog) \ + { \ + if (ilog == 1) \ + { \ + log->log(U_CONSTANT_TO_PARAM("%.*s"#xxx" phase of plugin %v success"), sz, mod_name[0], name.rep); \ + } \ + else \ + { \ + log->log(U_CONSTANT_TO_PARAM("%.*sWARNING: "#xxx" phase of plugin %v failed"), sz, mod_name[0], name.rep); \ + } \ + } \ } \ \ mod_name[0][0] = '\0'; \ @@ -2752,54 +2766,52 @@ void UServer_Base::init() proc->setProcessGroup(); -#ifndef U_LOG_DISABLE - uint32_t log_rotate_size = 0; - -# ifdef USE_LIBZ - if (isLog()) +#if !defined(U_LOG_DISABLE) && defined(USE_LIBZ) + if (isLog() && + log->isMemoryMapped()) { - // The zlib documentation states that destination buffer size must be at least 0.1% larger than avail_in plus 12 bytes + U_INTERNAL_ASSERT_EQUALS(shared_data_add, 0) - log_rotate_size = - shared_data_add = log->UFile::st_size + (log->UFile::st_size / 10) + 12U; + shared_data_add = log->getSizeLogRotateData(); } # endif - U_INTERNAL_DUMP("log_rotate_size = %u", log_rotate_size) -#endif - // init plugin modules, must run after the setting for shared log if (pluginsHandlerInit() != U_PLUGIN_HANDLER_FINISHED) U_ERROR("Plugins stage init failed"); // manage shared data... - U_INTERNAL_DUMP("shared_data_add = %u", shared_data_add) + U_INTERNAL_DUMP("shared_data_add = %u shm_data_add = %u", shared_data_add, shm_data_add) + U_INTERNAL_ASSERT_EQUALS(ptr_shm_data, U_NULLPTR) U_INTERNAL_ASSERT_EQUALS(ptr_shared_data, U_NULLPTR) - map_size = sizeof(shared_data) + shared_data_add; - ptr_shared_data = (shared_data*) UFile::mmap(&map_size); - - U_INTERNAL_ASSERT_POINTER(ptr_shared_data) - U_INTERNAL_ASSERT_DIFFERS(ptr_shared_data, MAP_FAILED) + U_DEBUG("sizeof(shared_data) = %u sizeof(shm_data) = %u shared_data_add = %u shm_data_add = %u", sizeof(shared_data), sizeof(shm_data), shared_data_add, shm_data_add); // For portable use, a shared memory object should be identified by a name of the form /somename; that is, a null-terminated string of // up to NAME_MAX (i.e., 255) characters consisting of an initial slash, followed by one or more characters, none of which are slashes -#if defined(U_LINUX) && !defined(U_LOG_DISABLE) && defined(USE_LIBZ) - ptr_shm_data = (shm_data*) UFile::shm_open("/userver", sizeof(shm_data)); -#endif +#ifndef U_SERVER_CAPTIVE_PORTAL + shm_size = sizeof(shm_data) + shm_data_add; + ptr_shm_data = (shm_data*) UFile::shm_open("/userver", shm_size); - U_DEBUG("sizeof(shared_data) = %u sizeof(shm_data) = %u", sizeof(shared_data), sizeof(shm_data)); + U_INTERNAL_ASSERT_POINTER(ptr_shm_data) +#endif #ifndef U_LOG_DISABLE if (isLog() == false) #endif ULog::initDate(); + flag_loop = true; // NB: UTimeThread loop depend on this setting... + #if defined(U_LINUX) && defined(ENABLE_THREAD) + map_size = sizeof(shared_data) + shared_data_add; + ptr_shared_data = (shared_data*) UFile::mmap(&map_size); + U_INTERNAL_ASSERT_POINTER(ptr_shared_data) + U_INTERNAL_ASSERT_DIFFERS(ptr_shared_data, MAP_FAILED) U_INTERNAL_ASSERT_EQUALS(ULog::ptr_shared_date, U_NULLPTR) bool _daylight = *u_pdaylight; @@ -2813,9 +2825,7 @@ void UServer_Base::init() ULog::ptr_shared_date = &(ptr_shared_data->log_date_shared); U_MEMCPY(ULog::ptr_shared_date, &ULog::date, sizeof(ULog::log_date)); -#endif -#if defined(U_LINUX) && defined(ENABLE_THREAD) // NB: we block SIGHUP and SIGTERM; the threads created will inherit a copy of the signal mask... # ifdef sigemptyset sigemptyset(&mask); @@ -2832,11 +2842,7 @@ void UServer_Base::init() # endif (void) U_SYSCALL(pthread_sigmask, "%d,%p,%p", SIG_BLOCK, &mask, U_NULLPTR); -#endif - - flag_loop = true; // NB: UTimeThread loop depend on this setting... -#if defined(U_LINUX) && defined(ENABLE_THREAD) U_INTERNAL_ASSERT_EQUALS(ULog::prwlock, U_NULLPTR) U_INTERNAL_ASSERT_EQUALS(u_pthread_time, U_NULLPTR) @@ -2847,20 +2853,29 @@ void UServer_Base::init() ((UTimeThread*)u_pthread_time)->start(50); #endif -#ifndef U_LOG_DISABLE - if (isLog()) +#if !defined(U_LOG_DISABLE) && defined(USE_LIBZ) + if (isLog() && + log->isMemoryMapped()) { - // NB: if log is mapped must be always shared because the possibility of fork() by parallelization... + log->setLogRotate(); - if (log->isMemoryMapped()) log->setShared(&(ptr_shared_data->log_data_shared), log_rotate_size); + log->setShared(&(ptr_shared_data->log_data_shared)); // NB: if log is memory mapped must be shared because the possibility of fork() by parallelization U_SRV_LOG("Mapped %u bytes (%u KB) of shared memory for %d preforked process", sizeof(shared_data) + shared_data_add, map_size / 1024, preforked_num_kids); } + + if (apache_like_log && + apache_like_log->isMemoryMapped()) + { + apache_like_log->setLogRotate(); + + apache_like_log->setShared(&(ptr_shm_data->log_data_shared)); // NB: if apache like log is memory mapped must be shared because the possibility of condivision with userver_ssl + + U_SRV_LOG("Mapped %u bytes (%u KB) of shared memory for apache like log", apache_like_log->getSizeLogRotateData(), apache_like_log->getSizeLogRotateData() / 1024); + } #endif -#ifndef U_LOG_DISABLE U_INTERNAL_ASSERT_EQUALS(U_SRV_TOT_CONNECTION, 0) -#endif #ifdef DEBUG UEventTime* pstat; @@ -3159,9 +3174,10 @@ RETSIGTYPE UServer_Base::handlerForSigTERM(int signo) # endif # endif -# ifndef U_LOG_DISABLE +# ifndef U_LOG_DISABLE if (isLog()) logMemUsage("SIGTERM"); -# endif +# endif + U_EXIT(0); } } @@ -3216,7 +3232,6 @@ int UServer_Base::handlerRead() U_INTERNAL_DUMP("nClientIndex = %u", nClientIndex) - U_INTERNAL_ASSERT_POINTER(ptr_shared_data) U_INTERNAL_ASSERT_MINOR(nClientIndex, UNotifier::max_connection) // This loops until the accept() fails, trying to start new connections as fast as possible so we don't overrun the listen queue @@ -3230,9 +3245,6 @@ int UServer_Base::handlerRead() UClientImage_Base* lClientIndex = pClientImage; #endif int cround = 0; -#ifndef U_LOG_DISABLE - uint32_t u_srv_tot_connection; -#endif #ifdef DEBUG CLIENT_ADDRESS_LEN = 0; uint32_t numc, nothing = 0; @@ -3362,7 +3374,7 @@ int UServer_Base::handlerRead() if (u_buffer_len) { - ULog::log(U_CONSTANT_TO_PARAM("WARNING: accept new client failed %.*S"), u_buffer_len, u_buffer); + log->log(U_CONSTANT_TO_PARAM("WARNING: accept new client failed %.*S"), u_buffer_len, u_buffer); u_buffer_len = 0; } @@ -3471,10 +3483,9 @@ int UServer_Base::handlerRead() #endif #ifndef U_LOG_DISABLE - u_srv_tot_connection = U_SRV_TOT_CONNECTION+1; - U_SRV_TOT_CONNECTION = u_srv_tot_connection; + ULock::atomicIncrement(U_SRV_TOT_CONNECTION); - U_INTERNAL_DUMP("U_SRV_TOT_CONNECTION = %u", u_srv_tot_connection) + U_INTERNAL_DUMP("U_SRV_TOT_CONNECTION = %u", U_SRV_TOT_CONNECTION) #endif ++UNotifier::num_connection; @@ -3523,17 +3534,15 @@ retry: pid = UProcess::waitpid(-1, &status, WNOHANG); // NB: to avoid too much { char buffer[128]; - ULog::log(U_CONSTANT_TO_PARAM("%sChild (pid %d) exited with value %d (%s), down to %u children"), - UServer_Base::mod_name[0], pid, status, UProcess::exitInfo(buffer, status), UNotifier::num_connection - UNotifier::min_connection); + log->log(U_CONSTANT_TO_PARAM("%sChild (pid %d) exited with value %d (%s), down to %u children"), + mod_name[0], pid, status, UProcess::exitInfo(buffer, status), UNotifier::num_connection - UNotifier::min_connection); } # endif goto retry; } -# ifndef U_LOG_DISABLE - if (isLog()) ULog::log(U_CONSTANT_TO_PARAM("Waiting for connection on port %u"), port); -# endif + U_SRV_LOG("Waiting for connection on port %u", port); U_RETURN(U_NOTIFIER_OK); } @@ -3569,10 +3578,10 @@ retry: pid = UProcess::waitpid(-1, &status, WNOHANG); // NB: to avoid too much char buffer[32]; uint32_t len = setNumConnection(buffer); - ULog::log(U_CONSTANT_TO_PARAM("New client connected from %v, %.*s clients currently connected"), CLIENT_IMAGE->logbuf->rep, len, buffer); + log->log(U_CONSTANT_TO_PARAM("New client connected from %v, %.*s clients currently connected"), CLIENT_IMAGE->logbuf->rep, len, buffer); # ifdef U_WELCOME_SUPPORT - if (msg_welcome) ULog::log(U_CONSTANT_TO_PARAM("Sending welcome message to %v"), CLIENT_IMAGE->logbuf->rep); + if (msg_welcome) log->log(U_CONSTANT_TO_PARAM("Sending welcome message to %v"), CLIENT_IMAGE->logbuf->rep); # endif } #endif @@ -3594,7 +3603,7 @@ retry: pid = UProcess::waitpid(-1, &status, WNOHANG); // NB: to avoid too much else #endif { -#if defined(DEBUG) && !defined(U_SERVER_CAPTIVE_PORTAL) +#if defined(DEBUG) && (!defined(U_SERVER_CAPTIVE_PORTAL) || defined(ENABLE_THREAD)) uint32_t len = 0; int cpu = U_SYSCALL_NO_PARAM(sched_getcpu), scpu = -1; @@ -3737,13 +3746,13 @@ bool UServer_Base::handlerTimeoutConnection(void* cimg) { if (called_from_handlerTime) { - ULog::log(U_CONSTANT_TO_PARAM("%shandlerTime: client connected didn't send any request in %u secs (timeout), close connection %v"), - UServer_Base::mod_name[0], ptime->UTimeVal::tv_sec, ((UClientImage_Base*)cimg)->logbuf->rep); + log->log(U_CONSTANT_TO_PARAM("%shandlerTime: client connected didn't send any request in %u secs (timeout), close connection %v"), + mod_name[0], ptime->UTimeVal::tv_sec, ((UClientImage_Base*)cimg)->logbuf->rep); } else { - ULog::log(U_CONSTANT_TO_PARAM("%shandlerTimeoutConnection: client connected didn't send any request in %u secs, close connection %v"), - UServer_Base::mod_name[0], UNotifier::last_event - ((UClientImage_Base*)cimg)->last_event, ((UClientImage_Base*)cimg)->logbuf->rep); + log->log(U_CONSTANT_TO_PARAM("%shandlerTimeoutConnection: client connected didn't send any request in %u secs, close connection %v"), + mod_name[0], UNotifier::last_event - ((UClientImage_Base*)cimg)->last_event, ((UClientImage_Base*)cimg)->logbuf->rep); } } # endif @@ -3752,17 +3761,17 @@ bool UServer_Base::handlerTimeoutConnection(void* cimg) { U_DEBUG("%shandlerTime: client connected didn't send any request in %u secs (timeout %u sec) - " "UEventFd::fd = %d socket->iSockDesc = %d UNotifier::num_connection = %d UNotifier::min_connection = %d", - UServer_Base::mod_name[0], UNotifier::last_event - ((UClientImage_Base*)cimg)->last_event, ptime->UTimeVal::tv_sec, - ((UClientImage_Base*)cimg)->UEventFd::fd, - ((UClientImage_Base*)cimg)->socket->iSockDesc, UNotifier::num_connection, UNotifier::min_connection) + mod_name[0], UNotifier::last_event - ((UClientImage_Base*)cimg)->last_event, ptime->UTimeVal::tv_sec, + ((UClientImage_Base*)cimg)->UEventFd::fd, + ((UClientImage_Base*)cimg)->socket->iSockDesc, UNotifier::num_connection, UNotifier::min_connection) } else { U_DEBUG("%shandlerTimeoutConnection: client connected didn't send any request in %u secs - " "UEventFd::fd = %d socket->iSockDesc = %d UNotifier::num_connection = %d UNotifier::min_connection = %d", - UServer_Base::mod_name[0], UNotifier::last_event - ((UClientImage_Base*)cimg)->last_event, - ((UClientImage_Base*)cimg)->UEventFd::fd, - ((UClientImage_Base*)cimg)->socket->iSockDesc, UNotifier::num_connection, UNotifier::min_connection) + mod_name[0], UNotifier::last_event - ((UClientImage_Base*)cimg)->last_event, + ((UClientImage_Base*)cimg)->UEventFd::fd, + ((UClientImage_Base*)cimg)->socket->iSockDesc, UNotifier::num_connection, UNotifier::min_connection) } # endif @@ -3812,7 +3821,7 @@ void UServer_Base::runLoop(const char* user) * (This is a one-time option) */ -# if defined(U_LINUX) && !defined(U_SERVER_CAPTIVE_PORTAL) +# if defined(U_LINUX) && (!defined(U_SERVER_CAPTIVE_PORTAL) || defined(ENABLE_THREAD)) socket->setTcpNoDelay(); socket->setTcpFastOpen(); socket->setTcpDeferAccept(); @@ -3853,15 +3862,13 @@ void UServer_Base::runLoop(const char* user) if (handler_inotify) UNotifier::insert(handler_inotify, EPOLLEXCLUSIVE | EPOLLROUNDROBIN); // NB: we ask to be notified for change of file system (=> inotify) } -#ifndef U_LOG_DISABLE - if (isLog()) ULog::log(U_CONSTANT_TO_PARAM("Waiting for connection on port %u"), port); -#endif + U_SRV_LOG("Waiting for connection on port %u", port); #if defined(ENABLE_THREAD) && !defined(USE_LIBEVENT) && defined(U_SERVER_THREAD_APPROACH_SUPPORT) + U_INTERNAL_ASSERT_EQUALS(UNotifier::pthread, U_NULLPTR) + if (preforked_num_kids == -1) { - U_INTERNAL_ASSERT_EQUALS(UNotifier::pthread, U_NULLPTR) - U_NEW(UClientThread, UNotifier::pthread, UClientThread); # ifdef _MSWINDOWS_ @@ -3874,12 +3881,6 @@ void UServer_Base::runLoop(const char* user) U_ASSERT(proc->parent()) } -# ifdef DEBUG - else - { - U_INTERNAL_ASSERT_EQUALS(UNotifier::pthread, U_NULLPTR) - } -# endif #endif #if defined(U_LINUX) && defined(ENABLE_THREAD) @@ -3977,7 +3978,7 @@ void UServer_Base::run() cpu_set_t cpuset; pid_t pid, pid_to_wait; -#if defined(HAVE_SCHED_GETAFFINITY) && !defined(U_SERVER_CAPTIVE_PORTAL) +#if defined(HAVE_SCHED_GETAFFINITY) && (!defined(U_SERVER_CAPTIVE_PORTAL) || defined(ENABLE_THREAD)) if (u_get_num_cpu() > 1 && (preforked_num_kids % u_num_cpu) == 0) { @@ -4015,7 +4016,7 @@ void UServer_Base::run() { U_INTERNAL_DUMP("child = %P UNotifier::num_connection = %d", UNotifier::num_connection) -# ifndef U_SERVER_CAPTIVE_PORTAL +# if defined(HAVE_SCHED_GETAFFINITY) && (!defined(U_SERVER_CAPTIVE_PORTAL) || defined(ENABLE_THREAD)) if (baffinity) { CPU_ZERO(&cpuset); @@ -4043,7 +4044,7 @@ void UServer_Base::run() # endif sz = 0; - ULog::log(U_CONSTANT_TO_PARAM("%sNew child started, affinity mask: %x, cpu: %d%.*s"), mod_name[0], CPUSET_BITS(&cpuset)[0], cpu, sz, buffer); + log->log(U_CONSTANT_TO_PARAM("%sNew child started, affinity mask: %x, cpu: %d%.*s"), mod_name[0], CPUSET_BITS(&cpuset)[0], cpu, sz, buffer); } # endif } @@ -4089,7 +4090,7 @@ void UServer_Base::run() to_sleep.nanosleep(); -# ifdef U_SERVER_CAPTIVE_PORTAL +# if defined(U_SERVER_CAPTIVE_PORTAL) && !defined(ENABLE_THREAD) if (proc->_pid == -1) // If the child don't start (not enough memory) we disable the monitoring process... { monitoring_process = false; @@ -4141,7 +4142,8 @@ void UServer_Base::run() { char buffer[128]; - ULog::log(U_CONSTANT_TO_PARAM("%sWARNING: child (pid %d) exited with value %d (%s), down to %u children"), mod_name[0], pid, status, UProcess::exitInfo(buffer, status), rkids); + log->log(U_CONSTANT_TO_PARAM("%sWARNING: child (pid %d) exited with value %d (%s), down to %u children"), + mod_name[0], pid, status, UProcess::exitInfo(buffer, status), rkids); } # endif @@ -4222,11 +4224,11 @@ pid_t UServer_Base::startNewChild() # ifdef U_LOG_DISABLE (void) UProcess::removeZombies(); # else - uint32_t n = UProcess::removeZombies(), - u_srv_cnt_parallelization = U_SRV_CNT_PARALLELIZATION+1; - U_SRV_CNT_PARALLELIZATION = u_srv_cnt_parallelization; + uint32_t n = UProcess::removeZombies(); - U_SRV_LOG("Started new child (pid %d) for parallelization (%d) - removed %u zombies", pid, u_srv_cnt_parallelization, n); + ULock::atomicIncrement(U_SRV_TOT_CONNECTION); + + U_SRV_LOG("Started new child (pid %d) for parallelization (%d) - removed %u zombies", pid, U_SRV_TOT_CONNECTION, n); # endif U_RETURN(pid); // parent @@ -4242,13 +4244,11 @@ __noreturn void UServer_Base::endNewChild() U_TRACE_NO_PARAM(0, "UServer_Base::endNewChild()") #ifndef U_LOG_DISABLE - uint32_t u_srv_cnt_parallelization = U_SRV_CNT_PARALLELIZATION; - - if (LIKELY(u_srv_cnt_parallelization)) U_SRV_CNT_PARALLELIZATION = --u_srv_cnt_parallelization; + ULock::atomicDecrement(U_SRV_TOT_CONNECTION); - U_INTERNAL_DUMP("cnt_parallelization = %u U_SRV_FLAG_SIGTERM = %b", u_srv_cnt_parallelization, U_SRV_FLAG_SIGTERM) + U_INTERNAL_DUMP("cnt_parallelization = %u U_SRV_FLAG_SIGTERM = %b", U_SRV_TOT_CONNECTION, U_SRV_FLAG_SIGTERM) - if (U_SRV_FLAG_SIGTERM == false) U_SRV_LOG("child for parallelization ended (%u)", u_srv_cnt_parallelization); + if (U_SRV_FLAG_SIGTERM == false) U_SRV_LOG("child for parallelization ended (%u)", U_SRV_TOT_CONNECTION); #endif U_EXIT(0); diff --git a/src/ulib/net/socket.cpp b/src/ulib/net/socket.cpp index eca95e516..d4e70f280 100644 --- a/src/ulib/net/socket.cpp +++ b/src/ulib/net/socket.cpp @@ -507,7 +507,7 @@ void USocket::reusePort(int _flags) U_CHECK_MEMORY -#if !defined(U_SERVER_CAPTIVE_PORTAL) && defined(U_LINUX) +#if defined(U_LINUX) && (!defined(U_SERVER_CAPTIVE_PORTAL) || defined(ENABLE_THREAD)) U_INTERNAL_DUMP("breuseport = %b", breuseport) if (breuseport) @@ -784,7 +784,7 @@ void USocket::_close_socket() U_INTERNAL_ASSERT(isOpen()) -#ifdef U_SERVER_CAPTIVE_PORTAL +#if defined(U_LINUX) && (defined(U_SERVER_CAPTIVE_PORTAL) && !defined(ENABLE_THREAD)) (void) U_SYSCALL(shutdown, "%d,%d", iSockDesc, SHUT_WR); #endif diff --git a/src/ulib/orm/driver/Makefile.am b/src/ulib/orm/driver/Makefile.am index db6f2d68e..5f07c345f 100644 --- a/src/ulib/orm/driver/Makefile.am +++ b/src/ulib/orm/driver/Makefile.am @@ -18,7 +18,7 @@ if HAVE_SQLITE3 if !STATIC_ORM_DRIVER_SQLITE module_LTLIBRARIES += orm_driver_sqlite.la orm_driver_sqlite_la_SOURCES = orm_driver_sqlite.cpp -orm_driver_sqlite_la_CXXFLAGS = -I@SQLITE3_INCLUDE@ +orm_driver_sqlite_la_CXXFLAGS = @SQLITE3_INCLUDE@ orm_driver_sqlite_la_LIBADD = $(ulib_la) orm_driver_sqlite_la_LDFLAGS = @SQLITE3_LDFLAGS@ -Wl,--start-group @SQLITE3_LIBS@ -Wl,--end-group -module @MODULE_LIBTOOL_OPTIONS@ endif @@ -28,7 +28,7 @@ if HAVE_MYSQL if !STATIC_ORM_DRIVER_MYSQL module_LTLIBRARIES += orm_driver_mysql.la orm_driver_mysql_la_SOURCES = orm_driver_mysql.cpp -orm_driver_mysql_la_CXXFLAGS = -I@MYSQL_INCLUDE@ +orm_driver_mysql_la_CXXFLAGS = @MYSQL_INCLUDE@ orm_driver_mysql_la_LIBADD = $(ulib_la) orm_driver_mysql_la_LDFLAGS = @MYSQL_LDFLAGS@ -Wl,--start-group @MYSQL_LIBS@ -Wl,--end-group -module @MODULE_LIBTOOL_OPTIONS@ endif @@ -38,7 +38,7 @@ if HAVE_PGSQL if !STATIC_ORM_DRIVER_PGSQL module_LTLIBRARIES += orm_driver_pgsql.la orm_driver_pgsql_la_SOURCES = orm_driver_pgsql.cpp -orm_driver_pgsql_la_CXXFLAGS = -I@POSTGRESQL_CPPFLAGS@ +orm_driver_pgsql_la_CXXFLAGS = @POSTGRESQL_CPPFLAGS@ orm_driver_pgsql_la_LIBADD = $(ulib_la) orm_driver_pgsql_la_LDFLAGS = @POSTGRESQL_LDFLAGS@ -Wl,--start-group @POSTGRESQL_LIBS@ -Wl,--end-group -module @MODULE_LIBTOOL_OPTIONS@ endif diff --git a/src/ulib/orm/driver/Makefile.in b/src/ulib/orm/driver/Makefile.in index 584973bbc..bb1f9af6e 100644 --- a/src/ulib/orm/driver/Makefile.in +++ b/src/ulib/orm/driver/Makefile.in @@ -450,15 +450,15 @@ ulib_la = $(top_builddir)/src/ulib/lib@ULIB@.la moduledir = @ULIB_MODULEDIR@ module_LTLIBRARIES = $(am__append_1) $(am__append_2) $(am__append_3) @HAVE_SQLITE3_TRUE@@STATIC_ORM_DRIVER_SQLITE_FALSE@orm_driver_sqlite_la_SOURCES = orm_driver_sqlite.cpp -@HAVE_SQLITE3_TRUE@@STATIC_ORM_DRIVER_SQLITE_FALSE@orm_driver_sqlite_la_CXXFLAGS = -I@SQLITE3_INCLUDE@ +@HAVE_SQLITE3_TRUE@@STATIC_ORM_DRIVER_SQLITE_FALSE@orm_driver_sqlite_la_CXXFLAGS = @SQLITE3_INCLUDE@ @HAVE_SQLITE3_TRUE@@STATIC_ORM_DRIVER_SQLITE_FALSE@orm_driver_sqlite_la_LIBADD = $(ulib_la) @HAVE_SQLITE3_TRUE@@STATIC_ORM_DRIVER_SQLITE_FALSE@orm_driver_sqlite_la_LDFLAGS = @SQLITE3_LDFLAGS@ -Wl,--start-group @SQLITE3_LIBS@ -Wl,--end-group -module @MODULE_LIBTOOL_OPTIONS@ @HAVE_MYSQL_TRUE@@STATIC_ORM_DRIVER_MYSQL_FALSE@orm_driver_mysql_la_SOURCES = orm_driver_mysql.cpp -@HAVE_MYSQL_TRUE@@STATIC_ORM_DRIVER_MYSQL_FALSE@orm_driver_mysql_la_CXXFLAGS = -I@MYSQL_INCLUDE@ +@HAVE_MYSQL_TRUE@@STATIC_ORM_DRIVER_MYSQL_FALSE@orm_driver_mysql_la_CXXFLAGS = @MYSQL_INCLUDE@ @HAVE_MYSQL_TRUE@@STATIC_ORM_DRIVER_MYSQL_FALSE@orm_driver_mysql_la_LIBADD = $(ulib_la) @HAVE_MYSQL_TRUE@@STATIC_ORM_DRIVER_MYSQL_FALSE@orm_driver_mysql_la_LDFLAGS = @MYSQL_LDFLAGS@ -Wl,--start-group @MYSQL_LIBS@ -Wl,--end-group -module @MODULE_LIBTOOL_OPTIONS@ @HAVE_PGSQL_TRUE@@STATIC_ORM_DRIVER_PGSQL_FALSE@orm_driver_pgsql_la_SOURCES = orm_driver_pgsql.cpp -@HAVE_PGSQL_TRUE@@STATIC_ORM_DRIVER_PGSQL_FALSE@orm_driver_pgsql_la_CXXFLAGS = -I@POSTGRESQL_CPPFLAGS@ +@HAVE_PGSQL_TRUE@@STATIC_ORM_DRIVER_PGSQL_FALSE@orm_driver_pgsql_la_CXXFLAGS = @POSTGRESQL_CPPFLAGS@ @HAVE_PGSQL_TRUE@@STATIC_ORM_DRIVER_PGSQL_FALSE@orm_driver_pgsql_la_LIBADD = $(ulib_la) @HAVE_PGSQL_TRUE@@STATIC_ORM_DRIVER_PGSQL_FALSE@orm_driver_pgsql_la_LDFLAGS = @POSTGRESQL_LDFLAGS@ -Wl,--start-group @POSTGRESQL_LIBS@ -Wl,--end-group -module @MODULE_LIBTOOL_OPTIONS@ all: all-am diff --git a/src/ulib/orm/orm_driver.cpp b/src/ulib/orm/orm_driver.cpp index 92e43d5d3..75bb6ede2 100644 --- a/src/ulib/orm/orm_driver.cpp +++ b/src/ulib/orm/orm_driver.cpp @@ -79,9 +79,7 @@ U_NO_EXPORT void UOrmDriver::loadStaticLinkedModules(const char* name) vdriver->push_back(_driver); vdriver_name_static->push_back(x); -# ifndef U_LOG_DISABLE - if (UServer_Base::isLog()) ULog::log(U_CONSTANT_TO_PARAM("[%s] Link of static driver ok"), name); -# endif + U_SRV_LOG("[%s] Link of static driver ok", name); } #endif } @@ -169,9 +167,7 @@ bool UOrmDriver::loadDriver(const UString& dir, const UString& driver_list) vdriver->push_back(_driver); vdriver_name_static->push_back(item); -# ifndef U_LOG_DISABLE - if (UServer_Base::isLog()) ULog::log(U_CONSTANT_TO_PARAM("[%v] Load of driver success"), item.rep); -# endif + U_SRV_LOG("[%v] Load of driver success", item.rep); } } diff --git a/src/ulib/ssl/net/sslsocket.cpp b/src/ulib/ssl/net/sslsocket.cpp index 00be8b7f4..2ab229ad3 100644 --- a/src/ulib/ssl/net/sslsocket.cpp +++ b/src/ulib/ssl/net/sslsocket.cpp @@ -37,7 +37,7 @@ int USSLSocket::session_cache_index; SSL_CTX* USSLSocket::cctx; // client SSL_CTX* USSLSocket::sctx; // server -#if !defined(OPENSSL_NO_OCSP) && defined(SSL_CTRL_SET_TLSEXT_STATUS_REQ_CB) +#if defined(ENABLE_THREAD) && !defined(OPENSSL_NO_OCSP) && defined(SSL_CTRL_SET_TLSEXT_STATUS_REQ_CB) bool USSLSocket::ocsp_nonce; USSLSocket::stapling USSLSocket::staple; #endif @@ -539,7 +539,7 @@ bool USSLSocket::setContext(const char* dh_file, const char* cert_file, const ch if (result == 0) U_RETURN(false); -# if !defined(OPENSSL_NO_OCSP) && defined(SSL_CTRL_SET_TLSEXT_STATUS_REQ_CB) +# if defined(ENABLE_THREAD) && !defined(OPENSSL_NO_OCSP) && defined(SSL_CTRL_SET_TLSEXT_STATUS_REQ_CB) UString str(cert_file, u__strlen(cert_file, __PRETTY_FUNCTION__)); staple.cert = UCertificate::readX509(UFile::contentOf(str), "PEM"); @@ -587,7 +587,7 @@ bool USSLSocket::setContext(const char* dh_file, const char* cert_file, const ch if (result == 0) U_RETURN(false); -# if !defined(OPENSSL_NO_OCSP) && defined(SSL_CTRL_SET_TLSEXT_STATUS_REQ_CB) +# if defined(ENABLE_THREAD) && !defined(OPENSSL_NO_OCSP) && defined(SSL_CTRL_SET_TLSEXT_STATUS_REQ_CB) // staple.pkey = UServices::loadKey(UFile::contentOf(UString(private_key_file, u__strlen(private_key_file, __PRETTY_FUNCTION__))), "PEM", true, passwd, 0); U_INTERNAL_DUMP("staple.pkey = %p", staple.pkey) @@ -1206,11 +1206,10 @@ int USSLSocket::send(const char* pData, uint32_t iDataLen) U_RETURN(iBytesWrite); } -#if !defined(OPENSSL_NO_TLSEXT) && defined(SSL_set_tlsext_host_name) - // This callback function is executed when OpenSSL encounters an extended // client hello with a server name indication extension ("SNI", cf. RFC 6066) +#if !defined(OPENSSL_NO_TLSEXT) && defined(SSL_set_tlsext_host_name) int USSLSocket::callback_ServerNameIndication(SSL* _ssl, int* alert, void* data) { U_TRACE(1, "USSLSocket::callback_ServerNameIndication(%p,%p,%p)", _ssl, alert, data) @@ -1256,7 +1255,7 @@ int USSLSocket::callback_ServerNameIndication(SSL* _ssl, int* alert, void* data) * downloading OCSP responses */ -#if !defined(OPENSSL_NO_OCSP) && defined(SSL_CTRL_SET_TLSEXT_STATUS_REQ_CB) +#if defined(ENABLE_THREAD) && !defined(OPENSSL_NO_OCSP) && defined(SSL_CTRL_SET_TLSEXT_STATUS_REQ_CB) bool USSLSocket::setDataForStapling() { U_TRACE_NO_PARAM(1, "USSLSocket::setDataForStapling()") diff --git a/src/ulib/string.cpp b/src/ulib/string.cpp index 0ed75d9f3..d4425602d 100644 --- a/src/ulib/string.cpp +++ b/src/ulib/string.cpp @@ -16,6 +16,7 @@ #include #include +vpFpcu UString::printValueToBuffer; UString* UString::string_null = ULib::uustringnull.p2; UStringRep* UStringRep::string_rep_null = ULib::uustringrepnull.p2; @@ -1315,7 +1316,8 @@ void UString::_reserve(UString& buffer, uint32_t n) else if (need > U_CAPACITY) { if (need < 2*1024*1024) need = (need * 2) + (PAGESIZE * 2); - need += PAGESIZE; // NB: to avoid duplication on realloc... + + need += PAGESIZE; // NB: to avoid duplication on realloc... } buffer._set(UStringRep::create(rep->_length, need, rep->str)); @@ -1956,7 +1958,7 @@ long double UStringRep::strtold() const if (isNullTerminated() == false && writeable()) *eos = '\0'; # ifndef DEBUG - long double result = ::strtold(str, 0); + long double result = ::strtold(str, U_NULLPTR); # else char* endptr; long double result = ::strtold(str, &endptr); @@ -2062,9 +2064,21 @@ double UString::strtod() const void UString::printKeyValue(const char* key, uint32_t keylen, const char* _data, uint32_t datalen) { - U_TRACE(0, "UString::printKeyValue(%.*S,%u,%.*S,%u,%d)", keylen, key, keylen, datalen, _data, datalen) + U_TRACE(0, "UString::printKeyValue(%.*S,%u,%.*S,%u)", keylen, key, keylen, datalen, _data, datalen) + + uint32_t n = 5 + 18 + keylen; + + if (printValueToBuffer == U_NULLPTR) n += datalen; + else + { + U_INTERNAL_ASSERT_EQUALS(u_buffer_len, 0) + + printValueToBuffer(_data, datalen); + + U_INTERNAL_ASSERT_MINOR(u_buffer_len, U_BUFFER_SIZE) - uint32_t n = 5 + 18 + keylen + datalen; + n += u_buffer_len; + } if (rep->space() < n) _reserve(*this, n); @@ -2078,8 +2092,17 @@ void UString::printKeyValue(const char* key, uint32_t keylen, const char* _data, U_MEMCPY(ptr, "->", U_CONSTANT_SIZE("->")); ptr += U_CONSTANT_SIZE("->"); - U_MEMCPY(ptr, _data, datalen); - ptr += datalen; + if (printValueToBuffer) + { + U_MEMCPY(ptr, u_buffer, u_buffer_len); + ptr += u_buffer_len; + u_buffer_len = 0; + } + else + { + U_MEMCPY(ptr, _data, datalen); + ptr += datalen; + } u_put_unalignedp16(ptr, U_MULTICHAR_CONSTANT16('\n','\0')); @@ -2327,8 +2350,9 @@ void UStringRep::write(ostream& os) const os.write(s, p - s); if (*(p-1) == '\\') os.put('\\'); - os.put('\\'); - os.put('"'); + + os.put('\\'); + os.put('"'); s = p + 1; } diff --git a/src/ulib/url.cpp b/src/ulib/url.cpp index 6c5e051a2..62deba0dd 100644 --- a/src/ulib/url.cpp +++ b/src/ulib/url.cpp @@ -16,17 +16,6 @@ // gcc: call is unlikely and code size would grow -UString Url::getService() const -{ - U_TRACE_NO_PARAM(0, "Url::getService()") - - UString srv; - - if (service_end > 0) srv = url.substr(0U, (uint32_t)service_end); - - U_RETURN_STRING(srv); -} - void Url::setService(const char* service, uint32_t n) { U_TRACE(0, "Url::setService(%S,%u)", service, n) @@ -44,17 +33,6 @@ void Url::setService(const char* service, uint32_t n) findpos(); } -UString Url::getUser() -{ - U_TRACE_NO_PARAM(0, "Url::getUser()") - - UString usr; - - if (user_begin < user_end) usr = url.substr(user_begin, user_end - user_begin); - - U_RETURN_STRING(usr); -} - bool Url::setUser(const char* user, uint32_t n) { U_TRACE(0, "Url::setUser(%S,%u)", user, n) @@ -65,7 +43,7 @@ bool Url::setUser(const char* user, uint32_t n) if (host_begin < host_end) { - if (user_begin < user_end) (void) url.replace(user_begin, user_end - user_begin, user, n); + if (user_begin < user_end) (void) url.replace(user_begin, user_end-user_begin, user, n); else { char buffer[128]; @@ -81,48 +59,49 @@ bool Url::setUser(const char* user, uint32_t n) U_RETURN(false); } -UString Url::getHost() +void Url::setHost(const char* lhost, uint32_t n) { - U_TRACE_NO_PARAM(0, "Url::getHost()") - - UString host; + U_TRACE(0, "Url::setHost(%S,%u)", lhost, n) - if (host_begin < host_end) host = url.substr(host_begin, host_end - host_begin); - - U_RETURN_STRING(host); -} - -void Url::setHost(const char* _host, uint32_t n) -{ - U_TRACE(0, "Url::setHost(%S,%u)", _host, n) + U_INTERNAL_ASSERT_POINTER(lhost) - U_INTERNAL_ASSERT_POINTER(_host) - - if (host_begin < host_end) (void) url.replace(host_begin, host_end - host_begin, _host, n); - else (void) url.insert( host_begin, _host, n); + if (host_begin < host_end) (void) url.replace(host_begin, host_end-host_begin, lhost, n); + else (void) url.insert( host_begin, lhost, n); findpos(); } -unsigned int Url::getPort() +UString Url::getPort() { U_TRACE_NO_PARAM(0, "Url::getPort()") if (host_end < path_begin) { - int size = path_begin - host_end - 1; + int size = path_begin-host_end-1; if (size > 0 && size <= 5) { - char buffer[6]; + UString port = url.substr(host_end+1, size); + + U_RETURN_STRING(port); + } + } - url.copy(buffer, size, host_end + 1); + return UString::getStringNull(); +} - unsigned int port = u_atoi(buffer); +uint32_t Url::getPortNumber() +{ + U_TRACE_NO_PARAM(0, "Url::getPortNumber()") - U_RETURN(port); - } + UString _port = getPort(); + + if (_port) + { + uint32_t port = _port.strtoul(); + + U_RETURN(port); } if (service_end > 0) @@ -179,7 +158,7 @@ bool Url::setPort(unsigned int port) char* ptr = buffer+1; - (void) url.replace(host_end, path_begin - host_end, buffer, u_num2str32(port, ptr) - ptr); + (void) url.replace(host_end, path_begin-host_end, buffer, u_num2str32(port, ptr) - ptr); findpos(); @@ -199,7 +178,7 @@ void Url::setPath(const char* path, uint32_t n) { if (*path != '/') ++path_begin; - (void) url.replace(path_begin, path_end - path_begin, path, n); + (void) url.replace(path_begin, path_end-path_begin, path, n); } else { @@ -216,138 +195,14 @@ void Url::setPath(const char* path, uint32_t n) findpos(); } -UString Url::getPath() -{ - U_TRACE_NO_PARAM(0, "Url::getPath()") - - UString path(U_CAPACITY); - - if (path_begin < path_end) decode(url.c_pointer(path_begin), path_end - path_begin, path); - else path.push_back('/'); - - (void) path.shrink(); - - U_RETURN_STRING(path); -} - -UString Url::getQuery() -{ - U_TRACE_NO_PARAM(0, "Url::getQuery()") - - int _end = url.size() - 1; - - if (path_end < _end) - { - uint32_t sz = _end - path_end; - - UString _query(sz); - - decode(url.c_pointer(path_end + 1), sz, _query); - - U_RETURN_STRING(_query); - } - - return UString::getStringNull(); -} - -uint32_t Url::getQuery(UVector& vec) -{ - U_TRACE(0, "Url::getQuery(%p)", &vec) - - int _end = url.size() - 1; - - if (path_end < _end) return UStringExt::getNameValueFromData(url.substr(path_end + 1, _end - path_end), vec, U_CONSTANT_TO_PARAM("&")); - - U_RETURN(0); -} - -bool Url::setQuery(const char* query_, uint32_t query_len) -{ - U_TRACE(0, "Url::setQuery(%S,%u)", query_, query_len) - - U_INTERNAL_ASSERT_POINTER(query_) - - if (prepareForQuery()) - { - if (*query_ == '?') ++query_; - - (void) url.replace(path_end + 1, url.size() - path_end - 1, query_, query_len); - - U_RETURN(true); - } - - U_RETURN(false); -} - -bool Url::setQuery(UVector& vec) -{ - U_TRACE(0, "Url::setQuery(%p)", &vec) - - U_INTERNAL_ASSERT_EQUALS(vec.empty(), false) - - if (prepareForQuery()) - { - UString name, value; - - for (int32_t i = 0, n = vec.size(); i < n; ++i) - { - name = vec[i++]; - value = vec[i]; - - addQuery(U_STRING_TO_PARAM(name), U_STRING_TO_PARAM(value)); - } - - U_RETURN(true); - } - - U_RETURN(false); -} - -UString Url::getQueryBody(UVector& vec) -{ - U_TRACE(0, "Url::getQueryBody(%p)", &vec) - - U_INTERNAL_ASSERT_EQUALS(vec.empty(), false) - - char buffer[4096]; - uint32_t sz, value_sz; - UString name, value, query(U_CAPACITY); - - for (int32_t i = 0, n = vec.size(); i < n; ++i) - { - name = vec[i++]; - value = vec[i]; - - (void) query.reserve(3U + name.size() + - ( sz = query.size()) + - (value_sz = value.size())); - - uint32_t encoded_sz = u_url_encode((const unsigned char*)value.data(), value_sz, (unsigned char*)buffer); - - U_INTERNAL_ASSERT_MINOR(encoded_sz, sizeof(buffer)) - - query.snprintf_add(U_CONSTANT_TO_PARAM("%.*s%v=%.*s"), (sz > 0), "&", name.rep, encoded_sz, buffer); - } - - U_RETURN_STRING(query); -} - -UString Url::getPathAndQuery() -{ - U_TRACE_NO_PARAM(0, "Url::getPathAndQuery()") - - UString file; - - if (path_begin < path_end) file = url.substr(path_begin); - else file.push_back('/'); - - U_RETURN_STRING(file); -} - void Url::findpos() { U_TRACE_NO_PARAM(0, "Url::findpos()") +#ifdef DEBUG + field_mask = 0; +#endif + // proto://[user[:password]@]hostname[:port]/[path]?[query] service_end = U_STRING_FIND(url, 0, "//"); @@ -360,15 +215,14 @@ void Url::findpos() host_begin = host_end = path_begin = - path_end = - query = 0; + path_end = 0; return; } U_INTERNAL_ASSERT(u_isUrlScheme(U_STRING_TO_PARAM(url))) - user_begin = service_end + 2; + user_begin = service_end+2; --service_end; // cut ':' @@ -392,7 +246,7 @@ void Url::findpos() if (temp < 0 || temp > path_begin) { - service_end = path_begin - 1; + service_end = path_begin-1; user_begin = service_end; user_end = user_begin; } @@ -408,7 +262,7 @@ void Url::findpos() } else { - host_begin = user_end + 1; + host_begin = user_end+1; } // find ipv6 adresses @@ -436,16 +290,30 @@ void Url::findpos() path_end = url.find('?', path_begin); - if (path_end < path_begin) path_end = url.size(); + if (path_end < path_begin) + { + path_end = url.find('#', path_begin); - query = path_end; + if (path_end < path_begin) path_end = url.size(); + } - U_INTERNAL_DUMP("service_end = %d user_begin = %d user_end = %d host_begin = %d host_end = %d path_begin = %d path_end = %d query = %d", - service_end, user_begin, user_end, host_begin, host_end, path_begin, path_end, query) + U_INTERNAL_DUMP("service_end = %u user_begin = %u user_end = %u host_begin = %u host_end = %u path_begin = %u path_end = %u", + service_end, user_begin, user_end, host_begin, host_end, path_begin, path_end) #ifdef DEBUG - if (service_end > 0 && - user_begin == user_end && + if (service_end > 0) field_mask |= U_SCHEMA; + if (host_begin < host_end) field_mask |= U_HOST; + if (user_begin < user_end) field_mask |= U_USERINFO; + if (host_end < path_begin) field_mask |= U_PORT; + if (path_begin < path_end) field_mask |= U_PATH; + + if (getPosQuery() != U_NOT_FOUND) field_mask |= U_QUERY; + if (getPosFragment() != U_NOT_FOUND) field_mask |= U_FRAGMENT; + + U_INTERNAL_DUMP("field_mask = %u %B", field_mask, field_mask) + + if (user_begin == user_end && + (field_mask | U_SCHEMA) != 0 && strncmp(url.data(), U_CONSTANT_TO_PARAM("http")) == 0) { U_ASSERT(u_isURL(U_STRING_TO_PARAM(url))) @@ -453,6 +321,143 @@ void Url::findpos() #endif } +U_NO_EXPORT __pure uint32_t Url::getPosQuery() +{ + U_TRACE_NO_PARAM(0, "Url::getPosQuery()") + + int lend = url.size()-1; + + if (path_end < lend && + url.c_char(path_end) == '?') + { + U_RETURN(path_end+1); + } + + U_RETURN(U_NOT_FOUND); +} + +U_NO_EXPORT __pure uint32_t Url::getSizeQuery(uint32_t pos) +{ + U_TRACE(0, "Url::getSizeQuery(%u)", pos) + + U_INTERNAL_ASSERT_EQUALS(url.c_char(pos-1), '?') + + uint32_t fpos = url.find('#', pos), + size = (fpos != U_NOT_FOUND ? fpos : url.size()) - pos; + + U_RETURN(size); +} + +UString Url::getQuery() +{ + U_TRACE_NO_PARAM(0, "Url::getQuery()") + + uint32_t pos = getPosQuery(); + + if (pos != U_NOT_FOUND) + { + uint32_t sz; + UString lquery(sz = getSizeQuery(pos)); + + decode(url.c_pointer(pos), sz, lquery); + + U_RETURN_STRING(lquery); + } + + return UString::getStringNull(); +} + +uint32_t Url::getQuery(UVector& vec) +{ + U_TRACE(0, "Url::getQuery(%p)", &vec) + + uint32_t pos = getPosQuery(); + + if (pos != U_NOT_FOUND) return UStringExt::getNameValueFromData(url.substr(pos, getSizeQuery(pos)), vec, U_CONSTANT_TO_PARAM("&")); + + U_RETURN(0); +} + +void Url::eraseQuery() +{ + U_TRACE_NO_PARAM(0, "Url::eraseQuery()") + + uint32_t pos = getPosQuery(); + + if (pos != U_NOT_FOUND) (void) url.erase(path_end); +} + +bool Url::setQuery(const char* lquery, uint32_t lquery_len) +{ + U_TRACE(0, "Url::setQuery(%S,%u)", lquery, lquery_len) + + U_INTERNAL_ASSERT_POINTER(lquery) + + if (prepareForQuery()) + { + if (*lquery == '?') ++lquery; + + (void) url.replace(path_end+1, url.size()-path_end-1, lquery, lquery_len); + + U_RETURN(true); + } + + U_RETURN(false); +} + +bool Url::setQuery(UVector& vec) +{ + U_TRACE(0, "Url::setQuery(%p)", &vec) + + U_INTERNAL_ASSERT_EQUALS(vec.empty(), false) + + if (prepareForQuery()) + { + UString name, value; + + for (int32_t i = 0, n = vec.size(); i < n; ++i) + { + name = vec[i++]; + value = vec[i]; + + addQuery(U_STRING_TO_PARAM(name), U_STRING_TO_PARAM(value)); + } + + U_RETURN(true); + } + + U_RETURN(false); +} + +UString Url::getQueryBody(UVector& vec) +{ + U_TRACE(0, "Url::getQueryBody(%p)", &vec) + + U_INTERNAL_ASSERT_EQUALS(vec.empty(), false) + + char buffer[4096]; + uint32_t sz, value_sz; + UString name, value, lquery(U_CAPACITY); + + for (int32_t i = 0, n = vec.size(); i < n; ++i) + { + name = vec[i++]; + value = vec[i]; + + (void) lquery.reserve(3U + name.size() + + ( sz = lquery.size()) + + (value_sz = value.size())); + + uint32_t encoded_sz = u_url_encode((const unsigned char*)value.data(), value_sz, (unsigned char*)buffer); + + U_INTERNAL_ASSERT_MINOR(encoded_sz, sizeof(buffer)) + + lquery.snprintf_add(U_CONSTANT_TO_PARAM("%.*s%v=%.*s"), (sz > 0), "&", name.rep, encoded_sz, buffer); + } + + U_RETURN_STRING(lquery); +} + U_NO_EXPORT bool Url::prepareForQuery() { U_TRACE_NO_PARAM(0, "Url::prepareForQuery()") @@ -521,6 +526,63 @@ void Url::addQuery(const char* entry, uint32_t entry_len, const char* value, uin } } +U_NO_EXPORT __pure uint32_t Url::getPosFragment() +{ + U_TRACE_NO_PARAM(0, "Url::getPosFragment()") + + /** + * https://tools.ietf.org/id/draft-snell-link-method-01.html#rfc.section.5 (len = 71) + * + * service_end = 5 user_begin = 8 user_end = 8 host_begin = 8 host_end = 22 path_begin = 22 path_end = 57 + * + * http://a:b@host.com:8080/p/a/t/h?query=string#hash (len = 50) + * + * service_end = 4 user_begin = 7 user_end = 10 host_begin = 11 host_end = 19 path_begin = 24 path_end = 32 + */ + + U_INTERNAL_DUMP("url = %V service_end = %u user_begin = %u user_end = %u host_begin = %u host_end = %u path_begin = %u path_end = %u", + url.rep, service_end, user_begin, user_end, host_begin, host_end, path_begin, path_end) + + int lend = url.size()-1; + + if (path_end < lend) + { + char c = url.c_char(path_end); + + if (c == '#') U_RETURN(path_end); + + if (c == '?') return url.find('#', path_end+1); + } + + U_RETURN(U_NOT_FOUND); +} + +UString Url::getFragment() +{ + U_TRACE_NO_PARAM(0, "Url::getFragment()") + + uint32_t pos = getPosFragment(); + + if (pos != U_NOT_FOUND) return url.substr(pos+1); + + return UString::getStringNull(); +} + +UString Url::getFieldValue(int field_type) +{ + U_TRACE(0, "Url::getFieldValue(%u)", field_type) + + UString result = (field_type == U_SCHEMA ? getService() : + field_type == U_HOST ? getHost() : + field_type == U_USERINFO ? getUser() : + field_type == U_PORT ? getPort() : + field_type == U_PATH ? getPath() : + field_type == U_QUERY ? getQuery() : + field_type == U_FRAGMENT ? getFragment() : url); + + U_RETURN_STRING(result); +} + // STREAM #ifdef U_STDCPP_ENABLE @@ -554,7 +616,6 @@ const char* Url::dump(bool reset) const << "host_end " << host_end << '\n' << "path_begin " << path_begin << '\n' << "path_end " << path_end << '\n' - << "query " << query << '\n' << "url (UString " << (void*)&url << ')'; if (reset) diff --git a/src/ulib/utility/http2.cpp b/src/ulib/utility/http2.cpp index 793ed54d0..bd7e7070f 100644 --- a/src/ulib/utility/http2.cpp +++ b/src/ulib/utility/http2.cpp @@ -98,10 +98,6 @@ UHTTP2::HpackError UHTTP2::hpack_error[8]; "\x01" \ "\x00\x00\x00\x00" -#ifndef UINT32_MAX -#define UINT32_MAX 4294967295U -#endif - #define u_http2_parse_sid(p) (u_parse_unalignedp32(p) & 0x7fffffff) #define u_http2_parse_type(p) ((p) & 0xff) #define u_http2_parse_length(p) ((p) >> 8) @@ -2682,7 +2678,7 @@ void UHTTP2::handlerResponse() if (dyntbl->num_entries == 0) { -# if defined(U_LINUX) && defined(ENABLE_THREAD) && defined(U_LOG_DISABLE) && !defined(USE_LIBZ) +# if defined(U_LINUX) && defined(ENABLE_THREAD) U_INTERNAL_ASSERT_POINTER(u_pthread_time) U_INTERNAL_ASSERT_EQUALS(UClientImage_Base::iov_vec[1].iov_base, ULog::ptr_shared_date->date3) # else @@ -2712,7 +2708,7 @@ void UHTTP2::handlerResponse() char* ptr_date = entry->value->data(); -# if defined(U_LINUX) && defined(ENABLE_THREAD) && defined(U_LOG_DISABLE) && !defined(USE_LIBZ) +# if defined(U_LINUX) && defined(ENABLE_THREAD) U_INTERNAL_ASSERT_POINTER(u_pthread_time) U_INTERNAL_ASSERT_EQUALS(UClientImage_Base::iov_vec[1].iov_base, ULog::ptr_shared_date->date3) # else diff --git a/src/ulib/utility/services.cpp b/src/ulib/utility/services.cpp index 1dc5f6265..7a65d6a86 100644 --- a/src/ulib/utility/services.cpp +++ b/src/ulib/utility/services.cpp @@ -157,7 +157,7 @@ bool UServices::read(int fd, UString& buffer, uint32_t count, int timeoutMS) if (value == (ssize_t)ncount) { -# ifndef U_SERVER_CAPTIVE_PORTAL +# if defined(U_LINUX) && (!defined(U_SERVER_CAPTIVE_PORTAL) || defined(ENABLE_THREAD)) U_DEBUG("UServices::read(%u) ran out of buffer space(%u)", count, ncount) # endif diff --git a/src/ulib/utility/socket_ext.cpp b/src/ulib/utility/socket_ext.cpp index 71e5d7236..324453520 100644 --- a/src/ulib/utility/socket_ext.cpp +++ b/src/ulib/utility/socket_ext.cpp @@ -206,7 +206,7 @@ error: U_INTERNAL_DUMP("errno = %d", errno) if (UNotifier::bepollet == false) #endif { -#if !defined(U_LINUX) || !defined(ENABLE_THREAD) || !defined(U_LOG_DISABLE) || defined(USE_LIBZ) +#if !defined(ENABLE_THREAD) || !defined(U_LOG_DISABLE) || defined(USE_LIBZ) if (sk->isBlocking() == false) { /** diff --git a/src/ulib/utility/string_ext.cpp b/src/ulib/utility/string_ext.cpp index 53e1ba8c1..ffd905356 100644 --- a/src/ulib/utility/string_ext.cpp +++ b/src/ulib/utility/string_ext.cpp @@ -473,7 +473,8 @@ UString UStringExt::prepareForEnvironmentVar(const char* s, uint32_t n) sz += len; if (quoted) str[sz++] = '\''; - str[sz++] = '\n'; + + str[sz++] = '\n'; } end: diff --git a/src/ulib/utility/uhttp.cpp b/src/ulib/utility/uhttp.cpp index 83214d957..a7ebea3bf 100644 --- a/src/ulib/utility/uhttp.cpp +++ b/src/ulib/utility/uhttp.cpp @@ -125,8 +125,8 @@ UVector* UHTTP::vservice; URDBObjectHandler* UHTTP::db_session; UHTTP::UFileCacheData* UHTTP::file_data; - UHTTP::UFileCacheData* UHTTP::file_not_in_cache_data; UHTTP::UFileCacheData* UHTTP::file_gzip_bomb; + UHTTP::UFileCacheData* UHTTP::file_not_in_cache_data; UHashMap* UHTTP::cache_file; #ifdef USE_PHP @@ -1958,9 +1958,7 @@ U_NO_EXPORT bool UHTTP::readHeaderRequest() { # ifndef U_HTTP2_DISABLE if (ptr[3] <= UHTTP2::CONTINUATION) U_http_version = '2'; - else # endif - UClientImage_Base::abortive_close(); } U_RETURN(false); @@ -2012,12 +2010,47 @@ U_NO_EXPORT bool UHTTP::readHeaderRequest() U_RETURN(true); } +bool UHTTP::checkContentLength(const UString& response) +{ + U_TRACE(0, "UHTTP::checkContentLength(%V)", response.rep) + + uint32_t pos = U_STRING_FIND_EXT(response, U_http_info.startHeader, "Content-Length", U_http_info.endHeader-U_CONSTANT_SIZE(U_CRLF2)-U_http_info.startHeader); + + if (pos != U_NOT_FOUND) + { + uint32_t end = response.findWhiteSpace(pos += U_CONSTANT_SIZE("Content-Length") + 2); + + if (end != U_NOT_FOUND) + { + uint32_t len = end - pos; + + U_INTERNAL_DUMP("len = %u", len) + + if (len <= U_CONSTANT_SIZE("1844674407370955160")) + { + U_http_info.clength = u__strtoul(response.c_pointer(pos), len); + + U_INTERNAL_DUMP("len = %u U_http_info.clength = %u", len, U_http_info.clength) + + if (U_http_info.clength == 0) + { + U_http_flag &= ~HTTP_IS_DATA_CHUNKED; + + U_INTERNAL_DUMP("U_http_data_chunked = %b", U_http_data_chunked) + } + + U_RETURN(true); + } + } + } + + U_RETURN(false); +} + bool UHTTP::readHeaderResponse(USocket* sk, UString& buffer) { U_TRACE(0, "UHTTP::readHeaderResponse(%p,%V)", sk, buffer.rep) - U_INTERNAL_ASSERT_POINTER(sk) - void* p; const char* ptr; uint32_t sz = buffer.size(); @@ -2135,11 +2168,10 @@ const char* UHTTP::getHeaderValuePtr(const char* name, uint32_t name_len, bool n } #endif -U_NO_EXPORT bool UHTTP::readDataChunked(USocket* sk, UString* pbuffer, UString& body) +U_NO_EXPORT inline bool UHTTP::checkDataChunked(UString* pbuffer) { - U_TRACE(0, "UHTTP::readDataChunked(%p,%V,%V)", sk, pbuffer->rep, body.rep) + U_TRACE(0, "UHTTP::checkDataChunked(%V)", pbuffer->rep) - U_ASSERT(body.empty()) U_INTERNAL_ASSERT_EQUALS(U_line_terminator_len, 2) U_INTERNAL_DUMP("U_http_data_chunked = %b", U_http_data_chunked) @@ -2156,7 +2188,18 @@ U_NO_EXPORT bool UHTTP::readDataChunked(USocket* sk, UString* pbuffer, UString& } } - if (U_http_data_chunked) + if (U_http_data_chunked) U_RETURN(true); + + U_RETURN(false); +} + +U_NO_EXPORT bool UHTTP::readDataChunked(USocket* sk, UString* pbuffer, UString& body) +{ + U_TRACE(0, "UHTTP::readDataChunked(%p,%V,%V)", sk, pbuffer->rep, body.rep) + + U_ASSERT(body.empty()) + + if (checkDataChunked(pbuffer)) { char* out; const char* inp; @@ -3173,35 +3216,55 @@ next: U_INTERNAL_DUMP("char (after cr/newline) = %C U_http_version = %C U_Client } } -#if !defined(U_LOG_DISABLE) || defined(USE_LIBZ) -void UHTTP::parserExecute(const char* ptr, uint32_t len) +uint32_t UHTTP::parserExecute(const char* ptr, uint32_t len, bool bresponse) { - U_TRACE(0, "UHTTP::parserExecute(%.*S,%u)", len, ptr, len) + U_TRACE(0, "UHTTP::parserExecute(%.*S,%u,%b)", len, ptr, len, bresponse) - UClientImage_Base::request->assign(ptr, len); + U_INTERNAL_ASSERT_POINTER(UClientImage_Base::request) U_HTTP_INFO_RESET(0); - if (readHeaderRequest()) - { - U_INTERNAL_ASSERT_DIFFERS(U_http_method_type, 0) + u_clientimage_info.flag.u = 0; - if (U_http_info.endHeader) - { - checkRequestForHeader(); + (void) UClientImage_Base::request->assign(ptr, len); - U_INTERNAL_DUMP("U_http_version = %C U_http_method_type = %u", U_http_version, U_http_method_type) + if (bresponse) + { + if (readHeaderResponse(U_NULLPTR, *UClientImage_Base::request) && + (checkContentLength(*UClientImage_Base::request) || + checkDataChunked(UClientImage_Base::request))) + { + U_RETURN(len); } + } + else + { + if (readHeaderRequest()) + { + U_INTERNAL_ASSERT_DIFFERS(U_http_method_type, 0) + + if (U_http_info.endHeader) + { + checkRequestForHeader(); + + U_INTERNAL_DUMP("U_http_version = %C U_http_method_type = %u", U_http_version, U_http_method_type) + } + + U_INTERNAL_DUMP("U_HTTP_HOST(%u) = %.*S", U_http_host_len, U_HTTP_HOST_TO_TRACE) - U_INTERNAL_DUMP("U_HTTP_HOST(%u) = %.*S", U_http_host_len, U_HTTP_HOST_TO_TRACE) + UClientImage_Base::size_request = (U_http_info.endHeader ? U_http_info.endHeader + : U_http_info.startHeader + U_CONSTANT_SIZE(U_CRLF2)); - UClientImage_Base::size_request = (U_http_info.endHeader ? U_http_info.endHeader - : U_http_info.startHeader + U_CONSTANT_SIZE(U_CRLF2)); + U_INTERNAL_DUMP("UClientImage_Base::size_request = %u U_http_info.clength = %u", UClientImage_Base::size_request, U_http_info.clength) - U_INTERNAL_DUMP("UClientImage_Base::size_request = %u U_http_info.clength = %u", UClientImage_Base::size_request, U_http_info.clength) + U_RETURN(len); + } + + U_INTERNAL_DUMP("U_http_version = %C U_ClientImage_data_missing = %b", U_http_version, U_ClientImage_data_missing) } + + U_RETURN(0); } -#endif // manage dynamic page request (CGI - C/ULib Servlet Page - RUBY - PHP - PYTHON) @@ -3895,8 +3958,8 @@ int UHTTP::handlerREAD() U_RETURN(U_PLUGIN_HANDLER_FINISHED); } } -#ifndef U_LOG_DISABLE - else if (UServer_Base::public_address && // NB: as protection from DNS rebinding attack web servers can reject HTTP requests with an unrecognized Host header... +#ifndef U_SERVER_CAPTIVE_PORTAL + else if (UServer_Base::public_address && // NB: as protection from DNS rebinding attack web servers can reject HTTP requests with an unrecognized Host header ((U_http_host_len - U_http_host_vlen) > (1 + 5) || // NB: ':' + 0-65536 u_isHostName(U_HTTP_VHOST_TO_PARAM) == false)) { @@ -3965,7 +4028,7 @@ int UHTTP::handlerREAD() U_INTERNAL_DUMP("UClientImage_Base::size_request = %u UClientImage_Base::bsendGzipBomp = %b", UClientImage_Base::size_request, UClientImage_Base::bsendGzipBomp) -#if !defined(U_LOG_DISABLE) || defined(USE_LIBZ) +#ifndef U_SERVER_CAPTIVE_PORTAL if (UClientImage_Base::bsendGzipBomp) { UClientImage_Base::bsendGzipBomp = false; @@ -3987,7 +4050,7 @@ int UHTTP::handlerREAD() U_http_info.nResponseCode = HTTP_OK; - *ext = file_gzip_bomb->array->operator[](1); + *ext = file_gzip_bomb->array->operator[](0); handlerResponse(); @@ -4927,8 +4990,6 @@ int UHTTP::processRequest() { if (file_data->size) { - U_INTERNAL_ASSERT_EQUALS(U_http_sendfile, false) - processGetRequest(); U_INTERNAL_DUMP("U_http_is_nocache_file = %b", U_http_is_nocache_file) @@ -5596,7 +5657,8 @@ remove: removeCookieSession(); else if (cookie) { if (*cookie) (void) cookie->append(U_CONSTANT_TO_PARAM("; ")); - (void) cookie->append(item); + + (void) cookie->append(item); } } @@ -6897,7 +6959,7 @@ void UHTTP::setDynamicResponse() } else { -# if defined(U_LINUX) && defined(ENABLE_THREAD) && defined(U_LOG_DISABLE) && !defined(USE_LIBZ) +# ifdef U_SERVER_CAPTIVE_PORTAL u_put_unalignedp64(ptr1, U_MULTICHAR_CONSTANT64('/','p','l','a','i','n','\r','\n')); sz += U_CONSTANT_SIZE("Content-Type: text/plain\r\n"); @@ -7629,7 +7691,8 @@ UString UHTTP::getHeaderMimeType(const char* content, uint32_t size, const char* if (u__isdigit(mime_index)) goto next; // NB: check for dynamic page... if (expire) header.snprintf_add(U_CONSTANT_TO_PARAM("Expires: %#8D\r\n"), expire); - header.snprintf_add(U_CONSTANT_TO_PARAM("Last-Modified: %#8D\r\n"), file->st_mtime); + + header.snprintf_add(U_CONSTANT_TO_PARAM("Last-Modified: %#8D\r\n"), file->st_mtime); } U_INTERNAL_DUMP("u_is_css(%d) = %b u_is_js(%d) = %b", mime_index, u_is_css(mime_index), mime_index, u_is_js(mime_index)) @@ -7701,7 +7764,8 @@ U_NO_EXPORT void UHTTP::putDataInCache(const UString& fmt, UString& content) int ratio = 100; bool gzip = false; UString header(U_CAPACITY); - const char* motivation = U_NULLPTR; + const char* motivation = (file_data->size <= U_MIN_SIZE_FOR_DEFLATE ? " (size too small)" : + file_data->size >= UServer_Base::min_size_for_sendfile ? " (size exceeded)" : ""); // NB: for major size we assume is better to use sendfile() U_NEW(UVector, file_data->array, UVector(4U)); #ifndef U_HTTP2_DISABLE @@ -7727,6 +7791,8 @@ U_NO_EXPORT void UHTTP::putDataInCache(const UString& fmt, UString& content) file_data->http2->push_back(hpack); #endif + if (content.empty()) goto end; + if (u_is_img(mime_index)) { U_INTERNAL_ASSERT(u_endsWith(U_FILE_TO_PARAM(*file), U_CONSTANT_TO_PARAM(".gif")) || @@ -7735,13 +7801,13 @@ U_NO_EXPORT void UHTTP::putDataInCache(const UString& fmt, UString& content) u_endsWith(U_FILE_TO_PARAM(*file), U_CONSTANT_TO_PARAM(".jpg")) || u_endsWith(U_FILE_TO_PARAM(*file), U_CONSTANT_TO_PARAM(".jpeg"))) -#if defined(USE_PAGE_SPEED) && defined(DEBUG) +# if defined(USE_PAGE_SPEED) && defined(DEBUG) if (u_is_gif(mime_index)) page_speed->optimize_gif(content); else if (u_is_png(mime_index)) page_speed->optimize_png(content); else page_speed->optimize_jpg(content); - if (content.size() < file_data->size) U_SRV_LOG("WARNING: found not optimized image: %V", pathname->rep); -#endif + if (content.size() < file_data->size) U_SRV_LOG("WARNING: found image not optimized: %V", pathname->rep); +# endif goto next2; } @@ -7774,8 +7840,6 @@ U_NO_EXPORT void UHTTP::putDataInCache(const UString& fmt, UString& content) } content = UStringExt::minifyCssJs(content); // minifies CSS/JS by removing comments and whitespaces... - - if (content.empty()) goto end; } #ifdef USE_PAGE_SPEED else if (u_is_html(mime_index)) @@ -7790,11 +7854,10 @@ U_NO_EXPORT void UHTTP::putDataInCache(const UString& fmt, UString& content) #endif next1: - if (file_data->size >= UServer_Base::min_size_for_sendfile) motivation = " (size exceeded)"; // NB: for major size we assume is better to use sendfile() - else if (file_data->size <= U_MIN_SIZE_FOR_DEFLATE) motivation = " (size too small)"; #ifdef USE_LIBZ - else if (u_is_ssi(mime_index) == false && - u_is_gz( mime_index) == false) + if (*motivation == '\0' && + u_is_ssi(mime_index) == false && + u_is_gz( mime_index) == false) { /** * http://zoompf.com/blog/2012/02/lose-the-wait-http-compression @@ -7840,14 +7903,15 @@ U_NO_EXPORT void UHTTP::putDataInCache(const UString& fmt, UString& content) // NB: we accept new data only if ratio compression is better than 15%... if (ratio < 85 && - motivation == U_NULLPTR) + *motivation == '\0') { - file_data->array->push_back(content); + file_data->array->push_back(content); // compressed... header.setBuffer(U_CAPACITY); - if (gzip) (void) header.assign(U_CONSTANT_TO_PARAM("Content-Encoding: gzip\r\n")); - header.snprintf_add(U_STRING_TO_PARAM(fmt), size); + if (gzip) (void) header.replace(U_CONSTANT_TO_PARAM("Content-Encoding: gzip\r\n")); + + header.snprintf_add(U_STRING_TO_PARAM(fmt), size); (void) header.shrink(); @@ -7868,7 +7932,7 @@ U_NO_EXPORT void UHTTP::putDataInCache(const UString& fmt, UString& content) } end: - U_SRV_LOG("File cached: %V - %u bytes - (%d%%) compression ratio%s", pathname->rep, file_data->size, 100 - ratio, (motivation ? motivation : "")); + U_SRV_LOG("File cached: %V - %u bytes - (%d%%) compression ratio%s", pathname->rep, file_data->size, 100-ratio, motivation); } bool UHTTP::callInitForAllUSP(UStringRep* key, void* value) @@ -8088,7 +8152,7 @@ U_NO_EXPORT bool UHTTP::compileUSP(const char* path, uint32_t len) { UServer_Base::logCommandMsgError(cmd.getCommand(), false); - if (ok == false) ULog::log(U_CONSTANT_TO_PARAM("%sWARNING: USP compile failed: %.*S"), UServer_Base::mod_name[0], path, len); + if (ok == false) UServer_Base::log->log(U_CONSTANT_TO_PARAM("%sWARNING: USP compile failed: %.*S"), UServer_Base::mod_name[0], path, len); } #endif @@ -8255,11 +8319,22 @@ U_NO_EXPORT void UHTTP::manageDataForCache(const UString& file_name) } else if (file->open()) { - UString content = file->getContent(true, false, true); + UString content; - if (content.empty()) goto error; + if (file_data->size >= UServer_Base::min_size_for_sendfile) // NB: for major size we assume is better to use sendfile() + { + file_data->fd = file->fd; + + putDataInCache(getHeaderMimeType(U_NULLPTR, 0, setMimeIndex(suffix_ptr), U_TIME_FOR_EXPIRE), content); + } + else + { + content = file->getContent(true, false, true); - putDataInCache(getHeaderMimeType(content.data(), 0, setMimeIndex(suffix_ptr), U_TIME_FOR_EXPIRE), content); + if (content.empty()) goto error; + + putDataInCache(getHeaderMimeType(content.data(), 0, setMimeIndex(suffix_ptr), U_TIME_FOR_EXPIRE), content); + } } goto end; @@ -8386,44 +8461,35 @@ U_NO_EXPORT void UHTTP::manageDataForCache(const UString& file_name) goto end; } - goto chk; + goto chk2; } // manage gzip bomb... if (suffix_len == 2 && - file_gzip_bomb == U_NULLPTR && u_get_unalignedp16( suffix_ptr) == U_MULTICHAR_CONSTANT16('g','z') && u_get_unalignedp64(file_name_ptr) == U_MULTICHAR_CONSTANT64('_','_','B','o','m','B','_','_')) { + U_INTERNAL_ASSERT_EQUALS(file_gzip_bomb, U_NULLPTR) + if (file->open()) { - UString content; - - file_data->fd = file->fd; - file_data->size = file->st_size; - file_data->mime_index = U_gz; + file_gzip_bomb = file_data; - if (file->memmap(PROT_READ, &content)) - { - UString header(U_CAPACITY); - - file_gzip_bomb = file_data; - - U_NEW(UVector, file_gzip_bomb->array, UVector(2U)); + file_gzip_bomb->fd = file->fd; + file_gzip_bomb->mime_index = U_gz; - file_gzip_bomb->array->push_back(content); + U_NEW(UVector, file_gzip_bomb->array, UVector(1U)); - header.snprintf(U_CONSTANT_TO_PARAM("Content-Encoding: gzip\r\n" - "Content-Type: application/octet-stream\r\n" - "Content-Length: %u\r\n\r\n"), file_data->size); + UString header(100U); - (void) header.shrink(); + header.snprintf(U_CONSTANT_TO_PARAM("Content-Encoding: gzip\r\n" + "Content-Type: application/octet-stream\r\n" + "Content-Length: %u\r\n\r\n"), file_data->size); - file_gzip_bomb->array->push_back(header); + file_gzip_bomb->array->push_back(header); - U_SRV_LOG("File gzip bomb: ../__BomB__.gz loaded - %u bytes", file_gzip_bomb->size); - } + U_SRV_LOG("Find gzip bomb: %V - %u bytes", pathname->rep, file_gzip_bomb->size); } goto end; @@ -8450,9 +8516,6 @@ U_NO_EXPORT void UHTTP::manageDataForCache(const UString& file_name) bool exist; uint32_t sz; struct stat st; -# ifndef U_LOG_DISABLE - uint32_t link_sz; -# endif UServletPage* usp_page; ptr = file->getPathRelativ(); @@ -8472,7 +8535,7 @@ U_NO_EXPORT void UHTTP::manageDataForCache(const UString& file_name) (usp_src && (!exist || st.st_mtime < file->st_mtime))) && compileUSP(ptr, len-1) == false)) { - goto check; + goto chk1; } // NB: dlopen() fail if the name of the module is not prefixed with "./"... @@ -8487,12 +8550,12 @@ fail: U_SRV_LOG("WARNING: USP load failed: %.*S", sz, buffer); delete usp_page; -check: if (usp_src) goto end; +chk1: if (usp_src) goto end; goto error; } - (void) u__snprintf(run_dynamic_page, sizeof(run_dynamic_page), U_CONSTANT_TO_PARAM("runDynamicPage_%.*s"), file_name_len - suffix_len - 1, file_name_ptr); + (void) u__snprintf(run_dynamic_page, sizeof(run_dynamic_page), U_CONSTANT_TO_PARAM("runDynamicPage_%.*s"), file_name_len-suffix_len-1, file_name_ptr); usp_page->runDynamicPage = (vPFi)(*usp_page)[run_dynamic_page]; @@ -8516,18 +8579,14 @@ check: if (usp_src) goto end; } # endif + (void) pathname->replace(buffer+2, len-1); + file_data->ptr = usp_page; file_data->mime_index = U_usp; -# ifdef U_LOG_DISABLE - cache_file->callForAllEntry(checkIfUSPLink); -# else - if (cache_file->callForAllEntry(checkIfUSPLink), file_data->link) link_sz = U_CONSTANT_SIZE(" (link)"); -# endif - - (void) pathname->replace(buffer+2, len-1); + cache_file->callForAllEntry(checkIfUSPLink); - U_SRV_LOG("USP found: %.*S%.*s, USP service registered (URI): %V", sz, buffer, link_sz, " (link)", pathname->rep); + U_SRV_LOG("USP found: %.*S%.*s, USP service registered (URI): %V", sz, buffer, (file_data->link ? U_CONSTANT_SIZE(" (link)") : 0), " (link)", pathname->rep); if (bcallInitForAllUSP) { @@ -8548,7 +8607,7 @@ check: if (usp_src) goto end; if (program.empty() == false && csp_page->compile(program) == false) { - U_SRV_LOG("WARNING: CSP load failed: %.*S", U_FILE_TO_TRACE(*file)); + U_SRV_LOG("WARNING: CSP load failed: %.*S", file_len, file_ptr); delete csp_page; @@ -8560,34 +8619,45 @@ check: if (usp_src) goto end; file_data->ptr = csp_page; file_data->mime_index = U_csp; - len = u__snprintf(buffer, sizeof(buffer), U_CONSTANT_TO_PARAM("%.*s"), U_FILE_TO_TRACE(*file)); + (void) pathname->replace(file_ptr, file_len - U_CONSTANT_SIZE(".c")); - (void) pathname->replace(buffer, len - U_CONSTANT_SIZE(".c")); - - U_SRV_LOG("CSP found: %.*S, CSP service registered (URI): %V", len, buffer, pathname->rep); + U_SRV_LOG("CSP found: %.*S, CSP service registered (URI): %V", file_len, file_ptr, pathname->rep); } # endif goto end; } -chk: ctype = u_get_mimetype(suffix_ptr, &file_data->mime_index); +chk2: ctype = u_get_mimetype(suffix_ptr, &file_data->mime_index); U_INTERNAL_DUMP("u_is_cacheable(%d) = %b ctype = %S", file_data->mime_index, u_is_cacheable(file_data->mime_index), ctype) if (u_is_cacheable(file_data->mime_index)) { - UString content = file->getContent(true, false, true); - - if (content.empty()) + if (file_data->size == 0) { U_SRV_LOG("WARNING: found empty file: %V", pathname->rep); } - else + else if (file->open()) { + UString content; + mime_index = file_data->mime_index; - putDataInCache(getHeaderMimeType(content.data(), 0, ctype, U_TIME_FOR_EXPIRE), content); + if (file_data->size >= UServer_Base::min_size_for_sendfile) // NB: for major size we assume is better to use sendfile() + { + file_data->fd = file->fd; + + putDataInCache(getHeaderMimeType(U_NULLPTR, 0, ctype, U_TIME_FOR_EXPIRE), content); + } + else + { + content = file->getContent(true, false, true); + + if (content.empty()) goto error; + + putDataInCache(getHeaderMimeType(content.data(), 0, ctype, U_TIME_FOR_EXPIRE), content); + } } } } @@ -8621,9 +8691,7 @@ void UHTTP::renewFileDataInCache() U_INTERNAL_DUMP("file_data->fd = %d cache_file->key = %V", file_data->fd, key) - pathname->setBuffer(key->size()); - - pathname->snprintf(U_CONSTANT_TO_PARAM("%v"), key); + (void) pathname->replace(U_STRING_TO_PARAM(*key)); U_DEBUG("renewFileDataInCache() called for file: %V - inotify %s enabled, expired=%b", pathname->rep, UServer_Base::handler_inotify ? "is" : "NOT", (u_now->tv_sec > file_data->expire)) @@ -8672,12 +8740,7 @@ U_NO_EXPORT bool UHTTP::processFileCache() U_INTERNAL_ASSERT_POINTER(file_data) U_ASSERT(UClientImage_Base::isRequestInFileCache()) - if (checkGetRequestIfModified() == false) - { - UClientImage_Base::setRequestFileCacheProcessed(); - - U_RETURN(true); - } + if (checkGetRequestIfModified() == false) goto end; #ifdef USE_LIBZ U_INTERNAL_DUMP("U_http_is_accept_gzip = %b", U_http_is_accept_gzip) @@ -8693,9 +8756,7 @@ U_NO_EXPORT bool UHTTP::processFileCache() *UClientImage_Base::body = getBodyCompressFromCache(); - UClientImage_Base::setRequestFileCacheProcessed(); - - U_RETURN(true); + goto end; } #endif @@ -8709,18 +8770,13 @@ U_NO_EXPORT bool UHTTP::processFileCache() // Range: bytes=0-31 // -------------------------------------------------------------------------------------------------------------- - range_size = sz = file_data->size; range_start = 0; + sz = (range_size = file_data->size); if (U_http_range_len && checkGetRequestIfRange()) { - if (checkGetRequestForRange(getBodyFromCache()) != U_PARTIAL) - { - UClientImage_Base::setRequestFileCacheProcessed(); - - U_RETURN(true); - } + if (checkGetRequestForRange(getBodyFromCache()) != U_PARTIAL) goto end; // NB: range_start is modified only if we have as response U_PARTIAL from checkGetRequestForRange()... @@ -8729,22 +8785,22 @@ U_NO_EXPORT bool UHTTP::processFileCache() U_http_info.nResponseCode = HTTP_PARTIAL; } - if (isSizeForSendfile(sz) == false) + if (isSizeForSendfile(sz) == false) *UClientImage_Base::body = getBodyFromCache().substr(range_start, range_size); + else { - UClientImage_Base::setRequestFileCacheProcessed(); - - *UClientImage_Base::body = getBodyFromCache().substr(range_start, range_size); + U_INTERNAL_ASSERT_DIFFERS(U_http_version, '2') - U_RETURN(true); - } + U_http_flag |= HTTP_IS_SENDFILE; - U_INTERNAL_ASSERT_DIFFERS(U_http_version, '2') + U_INTERNAL_DUMP("U_http_sendfile = %b", U_http_sendfile) - U_http_flag |= HTTP_IS_SENDFILE; + UClientImage_Base::setSendfile(file_data->fd, range_start, range_size); + } - U_INTERNAL_DUMP("U_http_sendfile = %b", U_http_sendfile) +end: + UClientImage_Base::setRequestFileCacheProcessed(); - U_RETURN(false); + U_RETURN(true); } U_NO_EXPORT bool UHTTP::checkPathName(uint32_t len) @@ -8849,30 +8905,39 @@ U_NO_EXPORT void UHTTP::checkPathName() return; } - // check for zombies... - - if (u_get_unalignedp64(ptr) == U_MULTICHAR_CONSTANT64('c','h','e','c','k','Z','o','m') && - u_get_unalignedp32(ptr+8) == U_MULTICHAR_CONSTANT32('b','i','e','s')) + if (len >= 9) { - UServer_Base::removeZombies(); + // check for zombies... - goto nocontent; - } + if (u_get_unalignedp64(ptr) == U_MULTICHAR_CONSTANT64('c','h','e','c','k','Z','o','m') && + u_get_unalignedp32(ptr+8) == U_MULTICHAR_CONSTANT32('b','i','e','s')) + { + UServer_Base::removeZombies(); - // we don't wont to process this kind of request (usually aliased)... + goto nocontent; + } - if (len >= U_PATH_MAX || - u_isFileName(ptr, len) == false || - UStringExt::endsWith(ptr, len, U_CONSTANT_TO_PARAM("nocontent"))) - { -nocontent: - UClientImage_Base::setCloseConnection(); + // we don't wont to process this kind of request (usually aliased)... - U_http_info.nResponseCode = HTTP_NO_CONTENT; + if ( ptr[len-9] == 'n' && + u_get_unalignedp64(ptr+len-8) == U_MULTICHAR_CONSTANT64('o','c','o','n','t','e','n','t')) + { + U_ASSERT(UStringExt::endsWith(ptr, len, U_CONSTANT_TO_PARAM("nocontent"))) - setResponse(); + goto nocontent; + } - return; + if (len >= U_PATH_MAX || + u_isFileName(ptr, len) == false) + { +nocontent: UClientImage_Base::setCloseConnection(); + + U_http_info.nResponseCode = HTTP_NO_CONTENT; + + setResponse(); + + return; + } } # ifdef USE_RUBY @@ -8902,51 +8967,47 @@ U_NO_EXPORT void UHTTP::checkPathName() } # endif + U_INTERNAL_DUMP("U_http_is_nocache_file = %b", U_http_is_nocache_file) + # if defined(HAVE_SYS_INOTIFY_H) && defined(U_HTTP_INOTIFY_SUPPORT) bool bstat = false; - if (db_not_found) + if (db_not_found && + U_http_is_nocache_file == false) { - U_INTERNAL_ASSERT_EQUALS(UServer_Base::bssl, false) + db_not_found->lock(); - U_INTERNAL_DUMP("U_http_is_nocache_file = %b", U_http_is_nocache_file) + db_not_found->UCDB::setKey(ptr, len); - if (U_http_is_nocache_file == false) - { - db_not_found->lock(); - - db_not_found->UCDB::setKey(ptr, len); - -# ifndef USE_HARDWARE_CRC32 - db_not_found->UCDB::setHash(ptr, len); -# else - db_not_found->UCDB::setHash(cache_file->hash); -# endif +# ifndef USE_HARDWARE_CRC32 + db_not_found->UCDB::setHash(ptr, len); +# else + db_not_found->UCDB::setHash(cache_file->hash); +# endif - if (db_not_found->_fetch()) - { - db_not_found->unlock(); + if (db_not_found->_fetch()) + { + db_not_found->unlock(); - return; - } + return; + } - if (file->stat() == false) - { - db_not_found->UCDB::setData(U_CLIENT_ADDRESS_TO_PARAM); + if (file->stat() == false) + { + db_not_found->UCDB::setData(U_CLIENT_ADDRESS_TO_PARAM); - int ko = db_not_found->_store(RDB_INSERT, false); + int ko = db_not_found->_store(RDB_INSERT, false); - db_not_found->unlock(); + db_not_found->unlock(); - if (ko) U_WARNING("Insert data on db %.*S failed with error %d", U_FILE_TO_TRACE(*db_not_found), ko); + if (ko) U_WARNING("Insert data on db %.*S failed with error %d", U_FILE_TO_TRACE(*db_not_found), ko); - return; - } + return; + } - db_not_found->unlock(); + db_not_found->unlock(); - bstat = true; - } + bstat = true; } if (bstat || diff --git a/tests/base/test_utility.c b/tests/base/test_utility.c index 0e7f426d7..441cab61e 100644 --- a/tests/base/test_utility.c +++ b/tests/base/test_utility.c @@ -282,7 +282,7 @@ int main(int argc, char* argv[]) char* sargv[128]; uint32_t x, path_len; const char* path_rel; - char path[PATH_MAX + 1]; + char path[U_PATH_MAX + 1]; const char* vec[] = { "libpng-1.0.10.tar.gz", diff --git a/tests/examples/Makefile.am b/tests/examples/Makefile.am index b6bd84b69..72dcf70ee 100644 --- a/tests/examples/Makefile.am +++ b/tests/examples/Makefile.am @@ -5,12 +5,13 @@ MAINTAINERCLEANFILES = Makefile.in DEFAULT_INCLUDES = -I. -I$(top_srcdir) -I$(top_srcdir)/include -I$(top_srcdir)/examples/http_header/include EXTRA_DIST = inp ok CA CSP LCSP TSA RSIGN XAdES nocat wi-auth WAGSM RA IR/WEB IR/benchmark IR/doc_dir *.cfg .htpasswd .htdigest python \ - *.properties *.test *.sh error_msg workflow doc_parse robots.txt alias.txt throttling.txt css js benchmark websocket docroot php.sh + *.properties *.test *.sh error_msg workflow doc_parse robots.txt alias.txt throttling.txt css js benchmark websocket docroot php.sh test_http_parser.h ## DEFS = -DU_TEST @DEFS@ -PRG = bench_http_parser +PRG = bench_http_parser test_http_parser bench_http_parser_SOURCES = bench_http_parser.cpp +test_http_parser_SOURCES = test_http_parser.cpp ctest_http_parser.c TESTS = client_server.test test_manager.test IR.test web_server.test web_server_multiclient.test web_socket.test ## workflow.test diff --git a/tests/examples/Makefile.in b/tests/examples/Makefile.in index cecd6cace..28eff8e71 100644 --- a/tests/examples/Makefile.in +++ b/tests/examples/Makefile.in @@ -123,7 +123,7 @@ mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/include/ulib/internal/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = -am__EXEEXT_1 = bench_http_parser$(EXEEXT) +am__EXEEXT_1 = bench_http_parser$(EXEEXT) test_http_parser$(EXEEXT) am_bench_http_parser_OBJECTS = bench_http_parser.$(OBJEXT) bench_http_parser_OBJECTS = $(am_bench_http_parser_OBJECTS) bench_http_parser_LDADD = $(LDADD) @@ -133,6 +133,11 @@ AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) am__v_lt_0 = --silent am__v_lt_1 = +am_test_http_parser_OBJECTS = test_http_parser.$(OBJEXT) \ + ctest_http_parser.$(OBJEXT) +test_http_parser_OBJECTS = $(am_test_http_parser_OBJECTS) +test_http_parser_LDADD = $(LDADD) +test_http_parser_DEPENDENCIES = $(top_builddir)/src/ulib/lib@ULIB@.la AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false @@ -148,6 +153,24 @@ am__v_at_1 = depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CFLAGS) $(CFLAGS) +AM_V_CC = $(am__v_CC_@AM_V@) +am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) +am__v_CC_0 = @echo " CC " $@; +am__v_CC_1 = +CCLD = $(CC) +LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CCLD = $(am__v_CCLD_@AM_V@) +am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) +am__v_CCLD_0 = @echo " CCLD " $@; +am__v_CCLD_1 = CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) LTCXXCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \ @@ -166,8 +189,9 @@ AM_V_CXXLD = $(am__v_CXXLD_@AM_V@) am__v_CXXLD_ = $(am__v_CXXLD_@AM_DEFAULT_V@) am__v_CXXLD_0 = @echo " CXXLD " $@; am__v_CXXLD_1 = -SOURCES = $(bench_http_parser_SOURCES) -DIST_SOURCES = $(bench_http_parser_SOURCES) +SOURCES = $(bench_http_parser_SOURCES) $(test_http_parser_SOURCES) +DIST_SOURCES = $(bench_http_parser_SOURCES) \ + $(test_http_parser_SOURCES) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ @@ -594,10 +618,11 @@ top_srcdir = @top_srcdir@ MAINTAINERCLEANFILES = Makefile.in DEFAULT_INCLUDES = -I. -I$(top_srcdir) -I$(top_srcdir)/include -I$(top_srcdir)/examples/http_header/include EXTRA_DIST = inp ok CA CSP LCSP TSA RSIGN XAdES nocat wi-auth WAGSM RA IR/WEB IR/benchmark IR/doc_dir *.cfg .htpasswd .htdigest python \ - *.properties *.test *.sh error_msg workflow doc_parse robots.txt alias.txt throttling.txt css js benchmark websocket docroot php.sh + *.properties *.test *.sh error_msg workflow doc_parse robots.txt alias.txt throttling.txt css js benchmark websocket docroot php.sh test_http_parser.h -PRG = bench_http_parser +PRG = bench_http_parser test_http_parser bench_http_parser_SOURCES = bench_http_parser.cpp +test_http_parser_SOURCES = test_http_parser.cpp ctest_http_parser.c TESTS = client_server.test test_manager.test IR.test web_server.test \ web_server_multiclient.test web_socket.test $(am__append_1) \ $(am__append_2) $(am__append_3) $(am__append_4) \ @@ -607,7 +632,7 @@ LDADD = @ULIBS@ $(HTTP_LIB) $(top_builddir)/src/ulib/lib@ULIB@.la @ULIB_LIBS@ all: all-am .SUFFIXES: -.SUFFIXES: .cpp .lo .log .o .obj .test .test$(EXEEXT) .trs +.SUFFIXES: .c .cpp .lo .log .o .obj .test .test$(EXEEXT) .trs $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ @@ -651,6 +676,10 @@ bench_http_parser$(EXEEXT): $(bench_http_parser_OBJECTS) $(bench_http_parser_DEP @rm -f bench_http_parser$(EXEEXT) $(AM_V_CXXLD)$(CXXLINK) $(bench_http_parser_OBJECTS) $(bench_http_parser_LDADD) $(LIBS) +test_http_parser$(EXEEXT): $(test_http_parser_OBJECTS) $(test_http_parser_DEPENDENCIES) $(EXTRA_test_http_parser_DEPENDENCIES) + @rm -f test_http_parser$(EXEEXT) + $(AM_V_CXXLD)$(CXXLINK) $(test_http_parser_OBJECTS) $(test_http_parser_LDADD) $(LIBS) + mostlyclean-compile: -rm -f *.$(OBJEXT) @@ -658,6 +687,32 @@ distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bench_http_parser.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ctest_http_parser.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_http_parser.Po@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ +@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< + +.c.obj: +@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\ +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\ +@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\ +@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ +@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< .cpp.o: @am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ diff --git a/tests/examples/bench_http_parser.cpp b/tests/examples/bench_http_parser.cpp index 636d46827..bb8e13783 100644 --- a/tests/examples/bench_http_parser.cpp +++ b/tests/examples/bench_http_parser.cpp @@ -69,7 +69,7 @@ static int bench(int iter_count, int silent) return 0; } -int main(int argc, char** argv) +int main(int argc, char** argv, char** env) { U_ULIB_INIT(argv); diff --git a/tests/examples/benchmark/FrameworkBenchmarks/fbenchmark.cfg b/tests/examples/benchmark/FrameworkBenchmarks/fbenchmark.cfg index a7e699aec..725a92965 100644 --- a/tests/examples/benchmark/FrameworkBenchmarks/fbenchmark.cfg +++ b/tests/examples/benchmark/FrameworkBenchmarks/fbenchmark.cfg @@ -5,12 +5,14 @@ userver { TCP_LINGER_SET 0 LISTEN_BACKLOG 16384 DOCUMENT_ROOT benchmark/FrameworkBenchmarks/ULib/www - PID_FILE benchmark/FrameworkBenchmarks/ULib/userver_tcp.pid + PID_FILE ../userver_tcp.pid # LOG_FILE ../../benchmark.log # LOG_FILE_SZ 50M # LOG_MSG_SIZE -1 + DOS_WHITE_LIST 127.0.0.1 + PLUGIN_DIR ../../../../../../src/ulib/net/server/plugin/.libs ORM_DRIVER_DIR ../../../../../../src/ulib/orm/driver/.libs } diff --git a/tests/examples/ctest_http_parser.c b/tests/examples/ctest_http_parser.c new file mode 100644 index 000000000..0295e0ae4 --- /dev/null +++ b/tests/examples/ctest_http_parser.c @@ -0,0 +1,2162 @@ +/* ctest_http_parser.c */ + +#include "test_http_parser.h" + +/* * R E Q U E S T S * */ +const struct message requests[] = +{ {.name= "curl get" + ,.type= HTTP_REQUEST + ,.raw= "GET /test HTTP/1.1\r\n" + "User-Agent: curl/7.18.0 (i486-pc-linux-gnu) libcurl/7.18.0 OpenSSL/0.9.8g zlib/1.2.3.3 libidn/1.1\r\n" + "Host: 0.0.0.0=5000\r\n" + "Accept: */*\r\n" + "\r\n" + ,.should_keep_alive= true + ,.message_complete_on_eof= false + ,.http_major= 1 + ,.http_minor= 1 + ,.method= HTTP_GET + ,.query_string= "" + ,.fragment= "" + ,.request_path= "/test" + ,.request_url= "/test" + ,.num_headers= 3 + ,.headers= + { { "User-Agent", "curl/7.18.0 (i486-pc-linux-gnu) libcurl/7.18.0 OpenSSL/0.9.8g zlib/1.2.3.3 libidn/1.1" } + , { "Host", "0.0.0.0=5000" } + , { "Accept", "*/*" } + } + ,.body= "" + } + +, {.name= "firefox get" + ,.type= HTTP_REQUEST + ,.raw= "GET /favicon.ico HTTP/1.1\r\n" + "Host: 0.0.0.0=5000\r\n" + "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9) Gecko/2008061015 Firefox/3.0\r\n" + "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n" + "Accept-Language: en-us,en;q=0.5\r\n" + "Accept-Encoding: gzip,deflate\r\n" + "Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7\r\n" + "Keep-Alive: 300\r\n" + "Connection: keep-alive\r\n" + "\r\n" + ,.should_keep_alive= true + ,.message_complete_on_eof= false + ,.http_major= 1 + ,.http_minor= 1 + ,.method= HTTP_GET + ,.query_string= "" + ,.fragment= "" + ,.request_path= "/favicon.ico" + ,.request_url= "/favicon.ico" + ,.num_headers= 8 + ,.headers= + { { "Host", "0.0.0.0=5000" } + , { "User-Agent", "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9) Gecko/2008061015 Firefox/3.0" } + , { "Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8" } + , { "Accept-Language", "en-us,en;q=0.5" } + , { "Accept-Encoding", "gzip,deflate" } + , { "Accept-Charset", "ISO-8859-1,utf-8;q=0.7,*;q=0.7" } + , { "Keep-Alive", "300" } + , { "Connection", "keep-alive" } + } + ,.body= "" + } + +, {.name= "dumbfuck" + ,.type= HTTP_REQUEST + ,.raw= "GET /dumbfuck HTTP/1.1\r\n" + "aaaaaaaaaaaaa:++++++++++\r\n" + "\r\n" + ,.should_keep_alive= true + ,.message_complete_on_eof= false + ,.http_major= 1 + ,.http_minor= 1 + ,.method= HTTP_GET + ,.query_string= "" + ,.fragment= "" + ,.request_path= "/dumbfuck" + ,.request_url= "/dumbfuck" + ,.num_headers= 1 + ,.headers= + { { "aaaaaaaaaaaaa", "++++++++++" } + } + ,.body= "" + } + +, {.name= "fragment in url" + ,.type= HTTP_REQUEST + ,.raw= "GET /forums/1/topics/2375?page=1#posts-17408 HTTP/1.1\r\n" + "\r\n" + ,.should_keep_alive= true + ,.message_complete_on_eof= false + ,.http_major= 1 + ,.http_minor= 1 + ,.method= HTTP_GET + ,.query_string= "page=1" + ,.fragment= "posts-17408" + ,.request_path= "/forums/1/topics/2375" + /* XXX request url does include fragment? */ + ,.request_url= "/forums/1/topics/2375?page=1#posts-17408" + ,.num_headers= 0 + ,.body= "" + } + +, {.name= "get no headers no body" + ,.type= HTTP_REQUEST + ,.raw= "GET /get_no_headers_no_body/world HTTP/1.1\r\n" + "\r\n" + ,.should_keep_alive= true + ,.message_complete_on_eof= false /* would need Connection: close */ + ,.http_major= 1 + ,.http_minor= 1 + ,.method= HTTP_GET + ,.query_string= "" + ,.fragment= "" + ,.request_path= "/get_no_headers_no_body/world" + ,.request_url= "/get_no_headers_no_body/world" + ,.num_headers= 0 + ,.body= "" + } + +, {.name= "get one header no body" + ,.type= HTTP_REQUEST + ,.raw= "GET /get_one_header_no_body HTTP/1.1\r\n" + "Accept: */*\r\n" + "\r\n" + ,.should_keep_alive= true + ,.message_complete_on_eof= false /* would need Connection: close */ + ,.http_major= 1 + ,.http_minor= 1 + ,.method= HTTP_GET + ,.query_string= "" + ,.fragment= "" + ,.request_path= "/get_one_header_no_body" + ,.request_url= "/get_one_header_no_body" + ,.num_headers= 1 + ,.headers= + { { "Accept" , "*/*" } + } + ,.body= "" + } + +, {.name= "get funky content length body hello" + ,.type= HTTP_REQUEST + ,.raw= "GET /get_funky_content_length_body_hello HTTP/1.0\r\n" + "conTENT-Length: 5\r\n" + "\r\n" + "HELLO" + ,.should_keep_alive= false + ,.message_complete_on_eof= false + ,.http_major= 1 + ,.http_minor= 0 + ,.method= HTTP_GET + ,.query_string= "" + ,.fragment= "" + ,.request_path= "/get_funky_content_length_body_hello" + ,.request_url= "/get_funky_content_length_body_hello" + ,.num_headers= 1 + ,.headers= + { { "conTENT-Length" , "5" } + } + ,.body= "HELLO" + } + +, {.name= "post identity body world" + ,.type= HTTP_REQUEST + ,.raw= "POST /post_identity_body_world?q=search#hey HTTP/1.1\r\n" + "Accept: */*\r\n" + "Transfer-Encoding: identity\r\n" + "Content-Length: 5\r\n" + "\r\n" + "World" + ,.should_keep_alive= true + ,.message_complete_on_eof= false + ,.http_major= 1 + ,.http_minor= 1 + ,.method= HTTP_POST + ,.query_string= "q=search" + ,.fragment= "hey" + ,.request_path= "/post_identity_body_world" + ,.request_url= "/post_identity_body_world?q=search#hey" + ,.num_headers= 3 + ,.headers= + { { "Accept", "*/*" } + , { "Transfer-Encoding", "identity" } + , { "Content-Length", "5" } + } + ,.body= "World" + } + +, {.name= "post - chunked body: all your base are belong to us" + ,.type= HTTP_REQUEST + ,.raw= "POST /post_chunked_all_your_base HTTP/1.1\r\n" + "Transfer-Encoding: chunked\r\n" + "\r\n" + "1e\r\nall your base are belong to us\r\n" + "0\r\n" + "\r\n" + ,.should_keep_alive= true + ,.message_complete_on_eof= false + ,.http_major= 1 + ,.http_minor= 1 + ,.method= HTTP_POST + ,.query_string= "" + ,.fragment= "" + ,.request_path= "/post_chunked_all_your_base" + ,.request_url= "/post_chunked_all_your_base" + ,.num_headers= 1 + ,.headers= + { { "Transfer-Encoding" , "chunked" } + } + ,.body= "all your base are belong to us" + ,.num_chunks_complete= 2 + ,.chunk_lengths= { 0x1e } + } + +, {.name= "two chunks ; triple zero ending" + ,.type= HTTP_REQUEST + ,.raw= "POST /two_chunks_mult_zero_end HTTP/1.1\r\n" + "Transfer-Encoding: chunked\r\n" + "\r\n" + "5\r\nhello\r\n" + "6\r\n world\r\n" + "000\r\n" + "\r\n" + ,.should_keep_alive= true + ,.message_complete_on_eof= false + ,.http_major= 1 + ,.http_minor= 1 + ,.method= HTTP_POST + ,.query_string= "" + ,.fragment= "" + ,.request_path= "/two_chunks_mult_zero_end" + ,.request_url= "/two_chunks_mult_zero_end" + ,.num_headers= 1 + ,.headers= + { { "Transfer-Encoding", "chunked" } + } + ,.body= "hello world" + ,.num_chunks_complete= 3 + ,.chunk_lengths= { 5, 6 } + } + +, {.name= "chunked with trailing headers. blech." + ,.type= HTTP_REQUEST + ,.raw= "POST /chunked_w_trailing_headers HTTP/1.1\r\n" + "Transfer-Encoding: chunked\r\n" + "\r\n" + "5\r\nhello\r\n" + "6\r\n world\r\n" + "0\r\n" + "Vary: *\r\n" + "Content-Type: text/plain\r\n" + "\r\n" + ,.should_keep_alive= true + ,.message_complete_on_eof= false + ,.http_major= 1 + ,.http_minor= 1 + ,.method= HTTP_POST + ,.query_string= "" + ,.fragment= "" + ,.request_path= "/chunked_w_trailing_headers" + ,.request_url= "/chunked_w_trailing_headers" + ,.num_headers= 3 + ,.headers= + { { "Transfer-Encoding", "chunked" } + , { "Vary", "*" } + , { "Content-Type", "text/plain" } + } + ,.body= "hello world" + ,.num_chunks_complete= 3 + ,.chunk_lengths= { 5, 6 } + } + +, {.name= "with bullshit after the length" + ,.type= HTTP_REQUEST + ,.raw= "POST /chunked_w_bullshit_after_length HTTP/1.1\r\n" + "Transfer-Encoding: chunked\r\n" + "\r\n" + "5; ihatew3;whatthefuck=aretheseparametersfor\r\nhello\r\n" + "6; blahblah; blah\r\n world\r\n" + "0\r\n" + "\r\n" + ,.should_keep_alive= true + ,.message_complete_on_eof= false + ,.http_major= 1 + ,.http_minor= 1 + ,.method= HTTP_POST + ,.query_string= "" + ,.fragment= "" + ,.request_path= "/chunked_w_bullshit_after_length" + ,.request_url= "/chunked_w_bullshit_after_length" + ,.num_headers= 1 + ,.headers= + { { "Transfer-Encoding", "chunked" } + } + ,.body= "hello world" + ,.num_chunks_complete= 3 + ,.chunk_lengths= { 5, 6 } + } + +, {.name= "with quotes" + ,.type= HTTP_REQUEST + ,.raw= "GET /with_\"stupid\"_quotes?foo=\"bar\" HTTP/1.1\r\n\r\n" + ,.should_keep_alive= true + ,.message_complete_on_eof= false + ,.http_major= 1 + ,.http_minor= 1 + ,.method= HTTP_GET + ,.query_string= "foo=\"bar\"" + ,.fragment= "" + ,.request_path= "/with_\"stupid\"_quotes" + ,.request_url= "/with_\"stupid\"_quotes?foo=\"bar\"" + ,.num_headers= 0 + ,.headers= { } + ,.body= "" + } + +/* The server receiving this request SHOULD NOT wait for EOF + * to know that content-length == 0. + * How to represent this in a unit test? message_complete_on_eof + * Compare with NO_CONTENT_LENGTH_RESPONSE. + */ +, {.name = "apachebench get" + ,.type= HTTP_REQUEST + ,.raw= "GET /test HTTP/1.0\r\n" + "Host: 0.0.0.0:5000\r\n" + "User-Agent: ApacheBench/2.3\r\n" + "Accept: */*\r\n\r\n" + ,.should_keep_alive= false + ,.message_complete_on_eof= false + ,.http_major= 1 + ,.http_minor= 0 + ,.method= HTTP_GET + ,.query_string= "" + ,.fragment= "" + ,.request_path= "/test" + ,.request_url= "/test" + ,.num_headers= 3 + ,.headers= { { "Host", "0.0.0.0:5000" } + , { "User-Agent", "ApacheBench/2.3" } + , { "Accept", "*/*" } + } + ,.body= "" + } + +/* Some clients include '?' characters in query strings. + */ +, {.name = "query url with question mark" + ,.type= HTTP_REQUEST + ,.raw= "GET /test.cgi?foo=bar?baz HTTP/1.1\r\n\r\n" + ,.should_keep_alive= true + ,.message_complete_on_eof= false + ,.http_major= 1 + ,.http_minor= 1 + ,.method= HTTP_GET + ,.query_string= "foo=bar?baz" + ,.fragment= "" + ,.request_path= "/test.cgi" + ,.request_url= "/test.cgi?foo=bar?baz" + ,.num_headers= 0 + ,.headers= {} + ,.body= "" + } + +/* Some clients, especially after a POST in a keep-alive connection, + * will send an extra CRLF before the next request + */ +, {.name = "newline prefix get" + ,.type= HTTP_REQUEST + ,.raw= "\r\nGET /test HTTP/1.1\r\n\r\n" + ,.should_keep_alive= true + ,.message_complete_on_eof= false + ,.http_major= 1 + ,.http_minor= 1 + ,.method= HTTP_GET + ,.query_string= "" + ,.fragment= "" + ,.request_path= "/test" + ,.request_url= "/test" + ,.num_headers= 0 + ,.headers= { } + ,.body= "" + } + +, {.name = "upgrade request" + ,.type= HTTP_REQUEST + ,.raw= "GET /demo HTTP/1.1\r\n" + "Host: example.com\r\n" + "Connection: Upgrade\r\n" + "Sec-WebSocket-Key2: 12998 5 Y3 1 .P00\r\n" + "Sec-WebSocket-Protocol: sample\r\n" + "Upgrade: WebSocket\r\n" + "Sec-WebSocket-Key1: 4 @1 46546xW%0l 1 5\r\n" + "Origin: http://example.com\r\n" + "\r\n" + "Hot diggity dogg" + ,.should_keep_alive= true + ,.message_complete_on_eof= false + ,.http_major= 1 + ,.http_minor= 1 + ,.method= HTTP_GET + ,.query_string= "" + ,.fragment= "" + ,.request_path= "/demo" + ,.request_url= "/demo" + ,.num_headers= 7 + ,.upgrade="Hot diggity dogg" + ,.headers= { { "Host", "example.com" } + , { "Connection", "Upgrade" } + , { "Sec-WebSocket-Key2", "12998 5 Y3 1 .P00" } + , { "Sec-WebSocket-Protocol", "sample" } + , { "Upgrade", "WebSocket" } + , { "Sec-WebSocket-Key1", "4 @1 46546xW%0l 1 5" } + , { "Origin", "http://example.com" } + } + ,.body= "" + } + +, {.name = "connect request" + ,.type= HTTP_REQUEST + ,.raw= "CONNECT 0-home0.netscape.com:443 HTTP/1.0\r\n" + "User-agent: Mozilla/1.1N\r\n" + "Proxy-authorization: basic aGVsbG86d29ybGQ=\r\n" + "\r\n" + "some data\r\n" + "and yet even more data" + ,.should_keep_alive= false + ,.message_complete_on_eof= false + ,.http_major= 1 + ,.http_minor= 0 + ,.method= HTTP_CONNECT + ,.query_string= "" + ,.fragment= "" + ,.request_path= "" + ,.request_url= "0-home0.netscape.com:443" + ,.num_headers= 2 + ,.upgrade="some data\r\nand yet even more data" + ,.headers= { { "User-agent", "Mozilla/1.1N" } + , { "Proxy-authorization", "basic aGVsbG86d29ybGQ=" } + } + ,.body= "" + } + +, {.name= "report request" + ,.type= HTTP_REQUEST + ,.raw= "REPORT /test HTTP/1.1\r\n" + "\r\n" + ,.should_keep_alive= true + ,.message_complete_on_eof= false + ,.http_major= 1 + ,.http_minor= 1 + ,.method= HTTP_REPORT + ,.query_string= "" + ,.fragment= "" + ,.request_path= "/test" + ,.request_url= "/test" + ,.num_headers= 0 + ,.headers= {} + ,.body= "" + } + +, {.name= "request with no http version" + ,.type= HTTP_REQUEST + ,.raw= "GET /\r\n" + "\r\n" + ,.should_keep_alive= false + ,.message_complete_on_eof= false + ,.http_major= 0 + ,.http_minor= 9 + ,.method= HTTP_GET + ,.query_string= "" + ,.fragment= "" + ,.request_path= "/" + ,.request_url= "/" + ,.num_headers= 0 + ,.headers= {} + ,.body= "" + } + +, {.name= "m-search request" + ,.type= HTTP_REQUEST + ,.raw= "M-SEARCH * HTTP/1.1\r\n" + "HOST: 239.255.255.250:1900\r\n" + "MAN: \"ssdp:discover\"\r\n" + "ST: \"ssdp:all\"\r\n" + "\r\n" + ,.should_keep_alive= true + ,.message_complete_on_eof= false + ,.http_major= 1 + ,.http_minor= 1 + ,.method= HTTP_MSEARCH + ,.query_string= "" + ,.fragment= "" + ,.request_path= "*" + ,.request_url= "*" + ,.num_headers= 3 + ,.headers= { { "HOST", "239.255.255.250:1900" } + , { "MAN", "\"ssdp:discover\"" } + , { "ST", "\"ssdp:all\"" } + } + ,.body= "" + } + +, {.name= "line folding in header value" + ,.type= HTTP_REQUEST + ,.raw= "GET / HTTP/1.1\r\n" + "Line1: abc\r\n" + "\tdef\r\n" + " ghi\r\n" + "\t\tjkl\r\n" + " mno \r\n" + "\t \tqrs\r\n" + "Line2: \t line2\t\r\n" + "Line3:\r\n" + " line3\r\n" + "Line4: \r\n" + " \r\n" + "Connection:\r\n" + " close\r\n" + "\r\n" + ,.should_keep_alive= false + ,.message_complete_on_eof= false + ,.http_major= 1 + ,.http_minor= 1 + ,.method= HTTP_GET + ,.query_string= "" + ,.fragment= "" + ,.request_path= "/" + ,.request_url= "/" + ,.num_headers= 5 + ,.headers= { { "Line1", "abc\tdef ghi\t\tjkl mno \t \tqrs" } + , { "Line2", "line2\t" } + , { "Line3", "line3" } + , { "Line4", "" } + , { "Connection", "close" }, + } + ,.body= "" + } + + +, {.name= "host terminated by a query string" + ,.type= HTTP_REQUEST + ,.raw= "GET http://hypnotoad.org?hail=all HTTP/1.1\r\n" + "\r\n" + ,.should_keep_alive= true + ,.message_complete_on_eof= false + ,.http_major= 1 + ,.http_minor= 1 + ,.method= HTTP_GET + ,.query_string= "hail=all" + ,.fragment= "" + ,.request_path= "" + ,.request_url= "http://hypnotoad.org?hail=all" + ,.host= "hypnotoad.org" + ,.num_headers= 0 + ,.headers= { } + ,.body= "" + } + +, {.name= "host:port terminated by a query string" + ,.type= HTTP_REQUEST + ,.raw= "GET http://hypnotoad.org:1234?hail=all HTTP/1.1\r\n" + "\r\n" + ,.should_keep_alive= true + ,.message_complete_on_eof= false + ,.http_major= 1 + ,.http_minor= 1 + ,.method= HTTP_GET + ,.query_string= "hail=all" + ,.fragment= "" + ,.request_path= "" + ,.request_url= "http://hypnotoad.org:1234?hail=all" + ,.host= "hypnotoad.org" + ,.port= 1234 + ,.num_headers= 0 + ,.headers= { } + ,.body= "" + } + +, {.name= "host:port terminated by a space" + ,.type= HTTP_REQUEST + ,.raw= "GET http://hypnotoad.org:1234 HTTP/1.1\r\n" + "\r\n" + ,.should_keep_alive= true + ,.message_complete_on_eof= false + ,.http_major= 1 + ,.http_minor= 1 + ,.method= HTTP_GET + ,.query_string= "" + ,.fragment= "" + ,.request_path= "" + ,.request_url= "http://hypnotoad.org:1234" + ,.host= "hypnotoad.org" + ,.port= 1234 + ,.num_headers= 0 + ,.headers= { } + ,.body= "" + } + +, {.name = "PATCH request" + ,.type= HTTP_REQUEST + ,.raw= "PATCH /file.txt HTTP/1.1\r\n" + "Host: www.example.com\r\n" + "Content-Type: application/example\r\n" + "If-Match: \"e0023aa4e\"\r\n" + "Content-Length: 10\r\n" + "\r\n" + "cccccccccc" + ,.should_keep_alive= true + ,.message_complete_on_eof= false + ,.http_major= 1 + ,.http_minor= 1 + ,.method= HTTP_PATCH + ,.query_string= "" + ,.fragment= "" + ,.request_path= "/file.txt" + ,.request_url= "/file.txt" + ,.num_headers= 4 + ,.headers= { { "Host", "www.example.com" } + , { "Content-Type", "application/example" } + , { "If-Match", "\"e0023aa4e\"" } + , { "Content-Length", "10" } + } + ,.body= "cccccccccc" + } + +, {.name = "connect caps request" + ,.type= HTTP_REQUEST + ,.raw= "CONNECT HOME0.NETSCAPE.COM:443 HTTP/1.0\r\n" + "User-agent: Mozilla/1.1N\r\n" + "Proxy-authorization: basic aGVsbG86d29ybGQ=\r\n" + "\r\n" + ,.should_keep_alive= false + ,.message_complete_on_eof= false + ,.http_major= 1 + ,.http_minor= 0 + ,.method= HTTP_CONNECT + ,.query_string= "" + ,.fragment= "" + ,.request_path= "" + ,.request_url= "HOME0.NETSCAPE.COM:443" + ,.num_headers= 2 + ,.upgrade="" + ,.headers= { { "User-agent", "Mozilla/1.1N" } + , { "Proxy-authorization", "basic aGVsbG86d29ybGQ=" } + } + ,.body= "" + } + +, {.name= "utf-8 path request" + ,.type= HTTP_REQUEST + ,.raw= "GET /δ¶/δt/pope?q=1#narf HTTP/1.1\r\n" + "Host: github.com\r\n" + "\r\n" + ,.should_keep_alive= true + ,.message_complete_on_eof= false + ,.http_major= 1 + ,.http_minor= 1 + ,.method= HTTP_GET + ,.query_string= "q=1" + ,.fragment= "narf" + ,.request_path= "/δ¶/δt/pope" + ,.request_url= "/δ¶/δt/pope?q=1#narf" + ,.num_headers= 1 + ,.headers= { {"Host", "github.com" } + } + ,.body= "" + } + +, {.name = "hostname underscore" + ,.type= HTTP_REQUEST + ,.raw= "CONNECT home_0.netscape.com:443 HTTP/1.0\r\n" + "User-agent: Mozilla/1.1N\r\n" + "Proxy-authorization: basic aGVsbG86d29ybGQ=\r\n" + "\r\n" + ,.should_keep_alive= false + ,.message_complete_on_eof= false + ,.http_major= 1 + ,.http_minor= 0 + ,.method= HTTP_CONNECT + ,.query_string= "" + ,.fragment= "" + ,.request_path= "" + ,.request_url= "home_0.netscape.com:443" + ,.num_headers= 2 + ,.upgrade="" + ,.headers= { { "User-agent", "Mozilla/1.1N" } + , { "Proxy-authorization", "basic aGVsbG86d29ybGQ=" } + } + ,.body= "" + } + +/* see https://github.com/ry/http-parser/issues/47 */ +, {.name = "eat CRLF between requests, no \"Connection: close\" header" + ,.raw= "POST / HTTP/1.1\r\n" + "Host: www.example.com\r\n" + "Content-Type: application/x-www-form-urlencoded\r\n" + "Content-Length: 4\r\n" + "\r\n" + "q=42\r\n" /* note the trailing CRLF */ + ,.should_keep_alive= true + ,.message_complete_on_eof= false + ,.http_major= 1 + ,.http_minor= 1 + ,.method= HTTP_POST + ,.query_string= "" + ,.fragment= "" + ,.request_path= "/" + ,.request_url= "/" + ,.num_headers= 3 + ,.upgrade= 0 + ,.headers= { { "Host", "www.example.com" } + , { "Content-Type", "application/x-www-form-urlencoded" } + , { "Content-Length", "4" } + } + ,.body= "q=42" + } + +/* see https://github.com/ry/http-parser/issues/47 */ +, {.name = "eat CRLF between requests even if \"Connection: close\" is set" + ,.raw= "POST / HTTP/1.1\r\n" + "Host: www.example.com\r\n" + "Content-Type: application/x-www-form-urlencoded\r\n" + "Content-Length: 4\r\n" + "Connection: close\r\n" + "\r\n" + "q=42\r\n" /* note the trailing CRLF */ + ,.should_keep_alive= false + ,.message_complete_on_eof= false /* input buffer isn't empty when on_message_complete is called */ + ,.http_major= 1 + ,.http_minor= 1 + ,.method= HTTP_POST + ,.query_string= "" + ,.fragment= "" + ,.request_path= "/" + ,.request_url= "/" + ,.num_headers= 4 + ,.upgrade= 0 + ,.headers= { { "Host", "www.example.com" } + , { "Content-Type", "application/x-www-form-urlencoded" } + , { "Content-Length", "4" } + , { "Connection", "close" } + } + ,.body= "q=42" + } + +, {.name = "PURGE request" + ,.type= HTTP_REQUEST + ,.raw= "PURGE /file.txt HTTP/1.1\r\n" + "Host: www.example.com\r\n" + "\r\n" + ,.should_keep_alive= true + ,.message_complete_on_eof= false + ,.http_major= 1 + ,.http_minor= 1 + ,.method= HTTP_PURGE + ,.query_string= "" + ,.fragment= "" + ,.request_path= "/file.txt" + ,.request_url= "/file.txt" + ,.num_headers= 1 + ,.headers= { { "Host", "www.example.com" } } + ,.body= "" + } + +, {.name = "SEARCH request" + ,.type= HTTP_REQUEST + ,.raw= "SEARCH / HTTP/1.1\r\n" + "Host: www.example.com\r\n" + "\r\n" + ,.should_keep_alive= true + ,.message_complete_on_eof= false + ,.http_major= 1 + ,.http_minor= 1 + ,.method= HTTP_SEARCH + ,.query_string= "" + ,.fragment= "" + ,.request_path= "/" + ,.request_url= "/" + ,.num_headers= 1 + ,.headers= { { "Host", "www.example.com" } } + ,.body= "" + } + +, {.name= "host:port and basic_auth" + ,.type= HTTP_REQUEST + ,.raw= "GET http://a%12:b!&*$@hypnotoad.org:1234/toto HTTP/1.1\r\n" + "\r\n" + ,.should_keep_alive= true + ,.message_complete_on_eof= false + ,.http_major= 1 + ,.http_minor= 1 + ,.method= HTTP_GET + ,.fragment= "" + ,.request_path= "/toto" + ,.request_url= "http://a%12:b!&*$@hypnotoad.org:1234/toto" + ,.host= "hypnotoad.org" + ,.userinfo= "a%12:b!&*$" + ,.port= 1234 + ,.num_headers= 0 + ,.headers= { } + ,.body= "" + } + +, {.name= "line folding in header value" + ,.type= HTTP_REQUEST + ,.raw= "GET / HTTP/1.1\n" + "Line1: abc\n" + "\tdef\n" + " ghi\n" + "\t\tjkl\n" + " mno \n" + "\t \tqrs\n" + "Line2: \t line2\t\n" + "Line3:\n" + " line3\n" + "Line4: \n" + " \n" + "Connection:\n" + " close\n" + "\n" + ,.should_keep_alive= false + ,.message_complete_on_eof= false + ,.http_major= 1 + ,.http_minor= 1 + ,.method= HTTP_GET + ,.query_string= "" + ,.fragment= "" + ,.request_path= "/" + ,.request_url= "/" + ,.num_headers= 5 + ,.headers= { { "Line1", "abc\tdef ghi\t\tjkl mno \t \tqrs" } + , { "Line2", "line2\t" } + , { "Line3", "line3" } + , { "Line4", "" } + , { "Connection", "close" }, + } + ,.body= "" + } + +, {.name = "multiple connection header values with folding" + ,.type= HTTP_REQUEST + ,.raw= "GET /demo HTTP/1.1\r\n" + "Host: example.com\r\n" + "Connection: Something,\r\n" + " Upgrade, ,Keep-Alive\r\n" + "Sec-WebSocket-Key2: 12998 5 Y3 1 .P00\r\n" + "Sec-WebSocket-Protocol: sample\r\n" + "Upgrade: WebSocket\r\n" + "Sec-WebSocket-Key1: 4 @1 46546xW%0l 1 5\r\n" + "Origin: http://example.com\r\n" + "\r\n" + "Hot diggity dogg" + ,.should_keep_alive= true + ,.message_complete_on_eof= false + ,.http_major= 1 + ,.http_minor= 1 + ,.method= HTTP_GET + ,.query_string= "" + ,.fragment= "" + ,.request_path= "/demo" + ,.request_url= "/demo" + ,.num_headers= 7 + ,.upgrade="Hot diggity dogg" + ,.headers= { { "Host", "example.com" } + , { "Connection", "Something, Upgrade, ,Keep-Alive" } + , { "Sec-WebSocket-Key2", "12998 5 Y3 1 .P00" } + , { "Sec-WebSocket-Protocol", "sample" } + , { "Upgrade", "WebSocket" } + , { "Sec-WebSocket-Key1", "4 @1 46546xW%0l 1 5" } + , { "Origin", "http://example.com" } + } + ,.body= "" + } + +, {.name = "multiple connection header values with folding and lws" + ,.type= HTTP_REQUEST + ,.raw= "GET /demo HTTP/1.1\r\n" + "Connection: keep-alive, upgrade\r\n" + "Upgrade: WebSocket\r\n" + "\r\n" + "Hot diggity dogg" + ,.should_keep_alive= true + ,.message_complete_on_eof= false + ,.http_major= 1 + ,.http_minor= 1 + ,.method= HTTP_GET + ,.query_string= "" + ,.fragment= "" + ,.request_path= "/demo" + ,.request_url= "/demo" + ,.num_headers= 2 + ,.upgrade="Hot diggity dogg" + ,.headers= { { "Connection", "keep-alive, upgrade" } + , { "Upgrade", "WebSocket" } + } + ,.body= "" + } + +, {.name = "multiple connection header values with folding and lws" + ,.type= HTTP_REQUEST + ,.raw= "GET /demo HTTP/1.1\r\n" + "Connection: keep-alive, \r\n upgrade\r\n" + "Upgrade: WebSocket\r\n" + "\r\n" + "Hot diggity dogg" + ,.should_keep_alive= true + ,.message_complete_on_eof= false + ,.http_major= 1 + ,.http_minor= 1 + ,.method= HTTP_GET + ,.query_string= "" + ,.fragment= "" + ,.request_path= "/demo" + ,.request_url= "/demo" + ,.num_headers= 2 + ,.upgrade="Hot diggity dogg" + ,.headers= { { "Connection", "keep-alive, upgrade" } + , { "Upgrade", "WebSocket" } + } + ,.body= "" + } + +, {.name = "upgrade post request" + ,.type= HTTP_REQUEST + ,.raw= "POST /demo HTTP/1.1\r\n" + "Host: example.com\r\n" + "Connection: Upgrade\r\n" + "Upgrade: HTTP/2.0\r\n" + "Content-Length: 15\r\n" + "\r\n" + "sweet post body" + "Hot diggity dogg" + ,.should_keep_alive= true + ,.message_complete_on_eof= false + ,.http_major= 1 + ,.http_minor= 1 + ,.method= HTTP_POST + ,.request_path= "/demo" + ,.request_url= "/demo" + ,.num_headers= 4 + ,.upgrade="Hot diggity dogg" + ,.headers= { { "Host", "example.com" } + , { "Connection", "Upgrade" } + , { "Upgrade", "HTTP/2.0" } + , { "Content-Length", "15" } + } + ,.body= "sweet post body" + } + +, {.name = "connect with body request" + ,.type= HTTP_REQUEST + ,.raw= "CONNECT foo.bar.com:443 HTTP/1.0\r\n" + "User-agent: Mozilla/1.1N\r\n" + "Proxy-authorization: basic aGVsbG86d29ybGQ=\r\n" + "Content-Length: 10\r\n" + "\r\n" + "blarfcicle" + ,.should_keep_alive= false + ,.message_complete_on_eof= false + ,.http_major= 1 + ,.http_minor= 0 + ,.method= HTTP_CONNECT + ,.request_url= "foo.bar.com:443" + ,.num_headers= 3 + ,.upgrade="blarfcicle" + ,.headers= { { "User-agent", "Mozilla/1.1N" } + , { "Proxy-authorization", "basic aGVsbG86d29ybGQ=" } + , { "Content-Length", "10" } + } + ,.body= "" + } + +/* Examples from the Internet draft for LINK/UNLINK methods: + * https://tools.ietf.org/id/draft-snell-link-method-01.html#rfc.section.5 + */ + +, {.name = "link request" + ,.type= HTTP_REQUEST + ,.raw= "LINK /images/my_dog.jpg HTTP/1.1\r\n" + "Host: example.com\r\n" + "Link: ; rel=\"tag\"\r\n" + "Link: ; rel=\"tag\"\r\n" + "\r\n" + ,.should_keep_alive= true + ,.message_complete_on_eof= false + ,.http_major= 1 + ,.http_minor= 1 + ,.method= HTTP_LINK + ,.request_path= "/images/my_dog.jpg" + ,.request_url= "/images/my_dog.jpg" + ,.query_string= "" + ,.fragment= "" + ,.num_headers= 3 + ,.headers= { { "Host", "example.com" } + , { "Link", "; rel=\"tag\"" } + , { "Link", "; rel=\"tag\"" } + } + ,.body= "" + } + +, {.name = "link request" + ,.type= HTTP_REQUEST + ,.raw= "UNLINK /images/my_dog.jpg HTTP/1.1\r\n" + "Host: example.com\r\n" + "Link: ; rel=\"tag\"\r\n" + "\r\n" + ,.should_keep_alive= true + ,.message_complete_on_eof= false + ,.http_major= 1 + ,.http_minor= 1 + ,.method= HTTP_UNLINK + ,.request_path= "/images/my_dog.jpg" + ,.request_url= "/images/my_dog.jpg" + ,.query_string= "" + ,.fragment= "" + ,.num_headers= 2 + ,.headers= { { "Host", "example.com" } + , { "Link", "; rel=\"tag\"" } + } + ,.body= "" + } + +, {.name= NULL } /* sentinel */ +}; + +/* * R E S P O N S E S * */ +const struct message responses[] = +{ {.name= "google 301" + ,.type= HTTP_RESPONSE + ,.raw= "HTTP/1.1 301 Moved Permanently\r\n" + "Location: http://www.google.com/\r\n" + "Content-Type: text/html; charset=UTF-8\r\n" + "Date: Sun, 26 Apr 2009 11:11:49 GMT\r\n" + "Expires: Tue, 26 May 2009 11:11:49 GMT\r\n" + "X-$PrototypeBI-Version: 1.6.0.3\r\n" /* $ char in header field */ + "Cache-Control: public, max-age=2592000\r\n" + "Server: gws\r\n" + "Content-Length: 219 \r\n" + "\r\n" + "\n" + "301 Moved\n" + "

301 Moved

\n" + "The document has moved\n" + "here.\r\n" + "\r\n" + ,.should_keep_alive= true + ,.message_complete_on_eof= false + ,.http_major= 1 + ,.http_minor= 1 + ,.status_code= 301 + ,.response_status= "Moved Permanently" + ,.num_headers= 8 + ,.headers= + { { "Location", "http://www.google.com/" } + , { "Content-Type", "text/html; charset=UTF-8" } + , { "Date", "Sun, 26 Apr 2009 11:11:49 GMT" } + , { "Expires", "Tue, 26 May 2009 11:11:49 GMT" } + , { "X-$PrototypeBI-Version", "1.6.0.3" } + , { "Cache-Control", "public, max-age=2592000" } + , { "Server", "gws" } + , { "Content-Length", "219 " } + } + ,.body= "\n" + "301 Moved\n" + "

301 Moved

\n" + "The document has moved\n" + "here.\r\n" + "\r\n" + } + +/* The client should wait for the server's EOF. That is, when content-length + * is not specified, and "Connection: close", the end of body is specified + * by the EOF. + * Compare with APACHEBENCH_GET + */ +, {.name= "no content-length response" + ,.type= HTTP_RESPONSE + ,.raw= "HTTP/1.1 200 OK\r\n" + "Date: Tue, 04 Aug 2009 07:59:32 GMT\r\n" + "Server: Apache\r\n" + "X-Powered-By: Servlet/2.5 JSP/2.1\r\n" + "Content-Type: text/xml; charset=utf-8\r\n" + "Connection: close\r\n" + "\r\n" + "\n" + "\n" + " \n" + " \n" + " SOAP-ENV:Client\n" + " Client Error\n" + " \n" + " \n" + "" + ,.should_keep_alive= false + ,.message_complete_on_eof= true + ,.http_major= 1 + ,.http_minor= 1 + ,.status_code= 200 + ,.response_status= "OK" + ,.num_headers= 5 + ,.headers= + { { "Date", "Tue, 04 Aug 2009 07:59:32 GMT" } + , { "Server", "Apache" } + , { "X-Powered-By", "Servlet/2.5 JSP/2.1" } + , { "Content-Type", "text/xml; charset=utf-8" } + , { "Connection", "close" } + } + ,.body= "\n" + "\n" + " \n" + " \n" + " SOAP-ENV:Client\n" + " Client Error\n" + " \n" + " \n" + "" + } + +, {.name= "404 no headers no body" + ,.type= HTTP_RESPONSE + ,.raw= "HTTP/1.1 404 Not Found\r\n\r\n" + ,.should_keep_alive= false + ,.message_complete_on_eof= true + ,.http_major= 1 + ,.http_minor= 1 + ,.status_code= 404 + ,.response_status= "Not Found" + ,.num_headers= 0 + ,.headers= {} + ,.body_size= 0 + ,.body= "" + } + +, {.name= "301 no response phrase" + ,.type= HTTP_RESPONSE + ,.raw= "HTTP/1.1 301\r\n\r\n" + ,.should_keep_alive = false + ,.message_complete_on_eof= true + ,.http_major= 1 + ,.http_minor= 1 + ,.status_code= 301 + ,.response_status= "" + ,.num_headers= 0 + ,.headers= {} + ,.body= "" + } + +, {.name="200 trailing space on chunked body" + ,.type= HTTP_RESPONSE + ,.raw= "HTTP/1.1 200 OK\r\n" + "Content-Type: text/plain\r\n" + "Transfer-Encoding: chunked\r\n" + "\r\n" + "25 \r\n" + "This is the data in the first chunk\r\n" + "\r\n" + "1C\r\n" + "and this is the second one\r\n" + "\r\n" + "0 \r\n" + "\r\n" + ,.should_keep_alive= true + ,.message_complete_on_eof= false + ,.http_major= 1 + ,.http_minor= 1 + ,.status_code= 200 + ,.response_status= "OK" + ,.num_headers= 2 + ,.headers= + { {"Content-Type", "text/plain" } + , {"Transfer-Encoding", "chunked" } + } + ,.body_size = 37+28 + ,.body = + "This is the data in the first chunk\r\n" + "and this is the second one\r\n" + ,.num_chunks_complete= 3 + ,.chunk_lengths= { 0x25, 0x1c } + } + +, {.name="no carriage ret" + ,.type= HTTP_RESPONSE + ,.raw= "HTTP/1.1 200 OK\n" + "Content-Type: text/html; charset=utf-8\n" + "Connection: close\n" + "\n" + "these headers are from http://news.ycombinator.com/" + ,.should_keep_alive= false + ,.message_complete_on_eof= true + ,.http_major= 1 + ,.http_minor= 1 + ,.status_code= 200 + ,.response_status= "OK" + ,.num_headers= 2 + ,.headers= + { {"Content-Type", "text/html; charset=utf-8" } + , {"Connection", "close" } + } + ,.body= "these headers are from http://news.ycombinator.com/" + } + +, {.name="proxy connection" + ,.type= HTTP_RESPONSE + ,.raw= "HTTP/1.1 200 OK\r\n" + "Content-Type: text/html; charset=UTF-8\r\n" + "Content-Length: 11\r\n" + "Proxy-Connection: close\r\n" + "Date: Thu, 31 Dec 2009 20:55:48 +0000\r\n" + "\r\n" + "hello world" + ,.should_keep_alive= false + ,.message_complete_on_eof= false + ,.http_major= 1 + ,.http_minor= 1 + ,.status_code= 200 + ,.response_status= "OK" + ,.num_headers= 4 + ,.headers= + { {"Content-Type", "text/html; charset=UTF-8" } + , {"Content-Length", "11" } + , {"Proxy-Connection", "close" } + , {"Date", "Thu, 31 Dec 2009 20:55:48 +0000"} + } + ,.body= "hello world" + } + + /* shown by curl -o /dev/null -v "http://ad.doubleclick.net/pfadx/DARTSHELLCONFIGXML;dcmt=text/xml;" */ +, {.name="underscore header key" + ,.type= HTTP_RESPONSE + ,.raw= "HTTP/1.1 200 OK\r\n" + "Server: DCLK-AdSvr\r\n" + "Content-Type: text/xml\r\n" + "Content-Length: 0\r\n" + "DCLK_imp: v7;x;114750856;0-0;0;17820020;0/0;21603567/21621457/1;;~okv=;dcmt=text/xml;;~cs=o\r\n\r\n" + ,.should_keep_alive= true + ,.message_complete_on_eof= false + ,.http_major= 1 + ,.http_minor= 1 + ,.status_code= 200 + ,.response_status= "OK" + ,.num_headers= 4 + ,.headers= + { {"Server", "DCLK-AdSvr" } + , {"Content-Type", "text/xml" } + , {"Content-Length", "0" } + , {"DCLK_imp", "v7;x;114750856;0-0;0;17820020;0/0;21603567/21621457/1;;~okv=;dcmt=text/xml;;~cs=o" } + } + ,.body= "" + } + +/* The client should not merge two headers fields when the first one doesn't + * have a value. + */ +, {.name= "bonjourmadame.fr" + ,.type= HTTP_RESPONSE + ,.raw= "HTTP/1.0 301 Moved Permanently\r\n" + "Date: Thu, 03 Jun 2010 09:56:32 GMT\r\n" + "Server: Apache/2.2.3 (Red Hat)\r\n" + "Cache-Control: public\r\n" + "Pragma: \r\n" + "Location: http://www.bonjourmadame.fr/\r\n" + "Vary: Accept-Encoding\r\n" + "Content-Length: 0\r\n" + "Content-Type: text/html; charset=UTF-8\r\n" + "Connection: keep-alive\r\n" + "\r\n" + ,.should_keep_alive= true + ,.message_complete_on_eof= false + ,.http_major= 1 + ,.http_minor= 0 + ,.status_code= 301 + ,.response_status= "Moved Permanently" + ,.num_headers= 9 + ,.headers= + { { "Date", "Thu, 03 Jun 2010 09:56:32 GMT" } + , { "Server", "Apache/2.2.3 (Red Hat)" } + , { "Cache-Control", "public" } + , { "Pragma", "" } + , { "Location", "http://www.bonjourmadame.fr/" } + , { "Vary", "Accept-Encoding" } + , { "Content-Length", "0" } + , { "Content-Type", "text/html; charset=UTF-8" } + , { "Connection", "keep-alive" } + } + ,.body= "" + } + +/* Should handle spaces in header fields */ +, {.name= "field underscore" + ,.type= HTTP_RESPONSE + ,.raw= "HTTP/1.1 200 OK\r\n" + "Date: Tue, 28 Sep 2010 01:14:13 GMT\r\n" + "Server: Apache\r\n" + "Cache-Control: no-cache, must-revalidate\r\n" + "Expires: Mon, 26 Jul 1997 05:00:00 GMT\r\n" + ".et-Cookie: PlaxoCS=1274804622353690521; path=/; domain=.plaxo.com\r\n" + "Vary: Accept-Encoding\r\n" + "_eep-Alive: timeout=45\r\n" /* semantic value ignored */ + "_onnection: Keep-Alive\r\n" /* semantic value ignored */ + "Transfer-Encoding: chunked\r\n" + "Content-Type: text/html\r\n" + "Connection: close\r\n" + "\r\n" + "0\r\n\r\n" + ,.should_keep_alive= false + ,.message_complete_on_eof= false + ,.http_major= 1 + ,.http_minor= 1 + ,.status_code= 200 + ,.response_status= "OK" + ,.num_headers= 11 + ,.headers= + { { "Date", "Tue, 28 Sep 2010 01:14:13 GMT" } + , { "Server", "Apache" } + , { "Cache-Control", "no-cache, must-revalidate" } + , { "Expires", "Mon, 26 Jul 1997 05:00:00 GMT" } + , { ".et-Cookie", "PlaxoCS=1274804622353690521; path=/; domain=.plaxo.com" } + , { "Vary", "Accept-Encoding" } + , { "_eep-Alive", "timeout=45" } + , { "_onnection", "Keep-Alive" } + , { "Transfer-Encoding", "chunked" } + , { "Content-Type", "text/html" } + , { "Connection", "close" } + } + ,.body= "" + ,.num_chunks_complete= 1 + ,.chunk_lengths= {} + } + +/* Should handle non-ASCII in status line */ +, {.name= "non-ASCII in status line" + ,.type= HTTP_RESPONSE + ,.raw= "HTTP/1.1 500 Oriëntatieprobleem\r\n" + "Date: Fri, 5 Nov 2010 23:07:12 GMT+2\r\n" + "Content-Length: 0\r\n" + "Connection: close\r\n" + "\r\n" + ,.should_keep_alive= false + ,.message_complete_on_eof= false + ,.http_major= 1 + ,.http_minor= 1 + ,.status_code= 500 + ,.response_status= "Oriëntatieprobleem" + ,.num_headers= 3 + ,.headers= + { { "Date", "Fri, 5 Nov 2010 23:07:12 GMT+2" } + , { "Content-Length", "0" } + , { "Connection", "close" } + } + ,.body= "" + } + +/* Should handle HTTP/0.9 */ +, {.name= "http version 0.9" + ,.type= HTTP_RESPONSE + ,.raw= "HTTP/0.9 200 OK\r\n" + "\r\n" + ,.should_keep_alive= false + ,.message_complete_on_eof= true + ,.http_major= 0 + ,.http_minor= 9 + ,.status_code= 200 + ,.response_status= "OK" + ,.num_headers= 0 + ,.headers= + {} + ,.body= "" + } + +/* The client should wait for the server's EOF. That is, when neither + * content-length nor transfer-encoding is specified, the end of body + * is specified by the EOF. + */ +, {.name= "neither content-length nor transfer-encoding response" + ,.type= HTTP_RESPONSE + ,.raw= "HTTP/1.1 200 OK\r\n" + "Content-Type: text/plain\r\n" + "\r\n" + "hello world" + ,.should_keep_alive= false + ,.message_complete_on_eof= true + ,.http_major= 1 + ,.http_minor= 1 + ,.status_code= 200 + ,.response_status= "OK" + ,.num_headers= 1 + ,.headers= + { { "Content-Type", "text/plain" } + } + ,.body= "hello world" + } + +, {.name= "HTTP/1.0 with keep-alive and EOF-terminated 200 status" + ,.type= HTTP_RESPONSE + ,.raw= "HTTP/1.0 200 OK\r\n" + "Connection: keep-alive\r\n" + "\r\n" + ,.should_keep_alive= false + ,.message_complete_on_eof= true + ,.http_major= 1 + ,.http_minor= 0 + ,.status_code= 200 + ,.response_status= "OK" + ,.num_headers= 1 + ,.headers= + { { "Connection", "keep-alive" } + } + ,.body_size= 0 + ,.body= "" + } + +, {.name= "HTTP/1.0 with keep-alive and a 204 status" + ,.type= HTTP_RESPONSE + ,.raw= "HTTP/1.0 204 No content\r\n" + "Connection: keep-alive\r\n" + "\r\n" + ,.should_keep_alive= true + ,.message_complete_on_eof= false + ,.http_major= 1 + ,.http_minor= 0 + ,.status_code= 204 + ,.response_status= "No content" + ,.num_headers= 1 + ,.headers= + { { "Connection", "keep-alive" } + } + ,.body_size= 0 + ,.body= "" + } + +, {.name= "HTTP/1.1 with an EOF-terminated 200 status" + ,.type= HTTP_RESPONSE + ,.raw= "HTTP/1.1 200 OK\r\n" + "\r\n" + ,.should_keep_alive= false + ,.message_complete_on_eof= true + ,.http_major= 1 + ,.http_minor= 1 + ,.status_code= 200 + ,.response_status= "OK" + ,.num_headers= 0 + ,.headers={} + ,.body_size= 0 + ,.body= "" + } + +, {.name= "HTTP/1.1 with a 204 status" + ,.type= HTTP_RESPONSE + ,.raw= "HTTP/1.1 204 No content\r\n" + "\r\n" + ,.should_keep_alive= true + ,.message_complete_on_eof= false + ,.http_major= 1 + ,.http_minor= 1 + ,.status_code= 204 + ,.response_status= "No content" + ,.num_headers= 0 + ,.headers={} + ,.body_size= 0 + ,.body= "" + } + +, {.name= "HTTP/1.1 with a 204 status and keep-alive disabled" + ,.type= HTTP_RESPONSE + ,.raw= "HTTP/1.1 204 No content\r\n" + "Connection: close\r\n" + "\r\n" + ,.should_keep_alive= false + ,.message_complete_on_eof= false + ,.http_major= 1 + ,.http_minor= 1 + ,.status_code= 204 + ,.response_status= "No content" + ,.num_headers= 1 + ,.headers= + { { "Connection", "close" } + } + ,.body_size= 0 + ,.body= "" + } + +, {.name= "HTTP/1.1 with chunked endocing and a 200 response" + ,.type= HTTP_RESPONSE + ,.raw= "HTTP/1.1 200 OK\r\n" + "Transfer-Encoding: chunked\r\n" + "\r\n" + "0\r\n" + "\r\n" + ,.should_keep_alive= true + ,.message_complete_on_eof= false + ,.http_major= 1 + ,.http_minor= 1 + ,.status_code= 200 + ,.response_status= "OK" + ,.num_headers= 1 + ,.headers= + { { "Transfer-Encoding", "chunked" } + } + ,.body_size= 0 + ,.body= "" + ,.num_chunks_complete= 1 + } + +/* Should handle spaces in header fields */ +, {.name= "field space" + ,.type= HTTP_RESPONSE + ,.raw= "HTTP/1.1 200 OK\r\n" + "Server: Microsoft-IIS/6.0\r\n" + "X-Powered-By: ASP.NET\r\n" + "en-US Content-Type: text/xml\r\n" /* this is the problem */ + "Content-Type: text/xml\r\n" + "Content-Length: 16\r\n" + "Date: Fri, 23 Jul 2010 18:45:38 GMT\r\n" + "Connection: keep-alive\r\n" + "\r\n" + "hello" /* fake body */ + ,.should_keep_alive= true + ,.message_complete_on_eof= false + ,.http_major= 1 + ,.http_minor= 1 + ,.status_code= 200 + ,.response_status= "OK" + ,.num_headers= 7 + ,.headers= + { { "Server", "Microsoft-IIS/6.0" } + , { "X-Powered-By", "ASP.NET" } + , { "en-US Content-Type", "text/xml" } + , { "Content-Type", "text/xml" } + , { "Content-Length", "16" } + , { "Date", "Fri, 23 Jul 2010 18:45:38 GMT" } + , { "Connection", "keep-alive" } + } + ,.body= "hello" + } + +, {.name= "amazon.com" + ,.type= HTTP_RESPONSE + ,.raw= "HTTP/1.1 301 MovedPermanently\r\n" + "Date: Wed, 15 May 2013 17:06:33 GMT\r\n" + "Server: Server\r\n" + "x-amz-id-1: 0GPHKXSJQ826RK7GZEB2\r\n" + "p3p: policyref=\"http://www.amazon.com/w3c/p3p.xml\",CP=\"CAO DSP LAW CUR ADM IVAo IVDo CONo OTPo OUR DELi PUBi OTRi BUS PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA HEA PRE LOC GOV OTC \"\r\n" + "x-amz-id-2: STN69VZxIFSz9YJLbz1GDbxpbjG6Qjmmq5E3DxRhOUw+Et0p4hr7c/Q8qNcx4oAD\r\n" + "Location: http://www.amazon.com/Dan-Brown/e/B000AP9DSU/ref=s9_pop_gw_al1?_encoding=UTF8&refinementId=618073011&pf_rd_m=ATVPDKIKX0DER&pf_rd_s=center-2&pf_rd_r=0SHYY5BZXN3KR20BNFAY&pf_rd_t=101&pf_rd_p=1263340922&pf_rd_i=507846\r\n" + "Vary: Accept-Encoding,User-Agent\r\n" + "Content-Type: text/html; charset=ISO-8859-1\r\n" + "Transfer-Encoding: chunked\r\n" + "\r\n" + "1\r\n" + "\n\r\n" + "0\r\n" + "\r\n" + ,.should_keep_alive= true + ,.message_complete_on_eof= false + ,.http_major= 1 + ,.http_minor= 1 + ,.status_code= 301 + ,.response_status= "MovedPermanently" + ,.num_headers= 9 + ,.headers= { { "Date", "Wed, 15 May 2013 17:06:33 GMT" } + , { "Server", "Server" } + , { "x-amz-id-1", "0GPHKXSJQ826RK7GZEB2" } + , { "p3p", "policyref=\"http://www.amazon.com/w3c/p3p.xml\",CP=\"CAO DSP LAW CUR ADM IVAo IVDo CONo OTPo OUR DELi PUBi OTRi BUS PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA HEA PRE LOC GOV OTC \"" } + , { "x-amz-id-2", "STN69VZxIFSz9YJLbz1GDbxpbjG6Qjmmq5E3DxRhOUw+Et0p4hr7c/Q8qNcx4oAD" } + , { "Location", "http://www.amazon.com/Dan-Brown/e/B000AP9DSU/ref=s9_pop_gw_al1?_encoding=UTF8&refinementId=618073011&pf_rd_m=ATVPDKIKX0DER&pf_rd_s=center-2&pf_rd_r=0SHYY5BZXN3KR20BNFAY&pf_rd_t=101&pf_rd_p=1263340922&pf_rd_i=507846" } + , { "Vary", "Accept-Encoding,User-Agent" } + , { "Content-Type", "text/html; charset=ISO-8859-1" } + , { "Transfer-Encoding", "chunked" } + } + ,.body= "\n" + ,.num_chunks_complete= 2 + ,.chunk_lengths= { 1 } + } + +, {.name= "empty reason phrase after space" + ,.type= HTTP_RESPONSE + ,.raw= "HTTP/1.1 200 \r\n" + "\r\n" + ,.should_keep_alive= false + ,.message_complete_on_eof= true + ,.http_major= 1 + ,.http_minor= 1 + ,.status_code= 200 + ,.response_status= "" + ,.num_headers= 0 + ,.headers= {} + ,.body= "" + } + +, {.name= "Content-Length-X" + ,.type= HTTP_RESPONSE + ,.raw= "HTTP/1.1 200 OK\r\n" + "Content-Length-X: 0\r\n" + "Transfer-Encoding: chunked\r\n" + "\r\n" + "2\r\n" + "OK\r\n" + "0\r\n" + "\r\n" + ,.should_keep_alive= true + ,.message_complete_on_eof= false + ,.http_major= 1 + ,.http_minor= 1 + ,.status_code= 200 + ,.response_status= "OK" + ,.num_headers= 2 + ,.headers= { { "Content-Length-X", "0" } + , { "Transfer-Encoding", "chunked" } + } + ,.body= "OK" + ,.num_chunks_complete= 2 + ,.chunk_lengths= { 2 } + } + +, {.name= NULL } /* sentinel */ +}; + +char large_chunked_message[sizeof("HTTP/1.0 200 OK\r\nTransfer-Encoding: chunked\r\nContent-Type: text/plain\r\n\r\n")+(5+1024+2)*31337+5]; + +struct message large_chunked = + {.name= "large chunked" + ,.type= HTTP_RESPONSE + ,.raw= large_chunked_message + ,.should_keep_alive= false + ,.message_complete_on_eof= false + ,.http_major= 1 + ,.http_minor= 0 + ,.status_code= 200 + ,.response_status= "OK" + ,.num_headers= 2 + ,.headers= + { { "Transfer-Encoding", "chunked" } + , { "Content-Type", "text/plain" } + } + ,.body_size= 31337*1024 + ,.num_chunks_complete= 31338 +}; + +const struct url_test url_tests[] = +{ {.name="proxy request" + ,.url="http://hostname/" + ,.is_connect=0 + ,.u= + {.field_set=(1 << UF_SCHEMA) | (1 << UF_HOST) | (1 << UF_PATH) + ,.port=0 + ,.field_data= + {{ 0, 4 } /* UF_SCHEMA */ + ,{ 7, 8 } /* UF_HOST */ + ,{ 0, 0 } /* UF_PORT */ + ,{ 15, 1 } /* UF_PATH */ + ,{ 0, 0 } /* UF_QUERY */ + ,{ 0, 0 } /* UF_FRAGMENT */ + ,{ 0, 0 } /* UF_USERINFO */ + } + } + ,.rv=0 + } + +, {.name="proxy request with port" + ,.url="http://hostname:444/" + ,.is_connect=0 + ,.u= + {.field_set=(1 << UF_SCHEMA) | (1 << UF_HOST) | (1 << UF_PORT) | (1 << UF_PATH) + ,.port=444 + ,.field_data= + {{ 0, 4 } /* UF_SCHEMA */ + ,{ 7, 8 } /* UF_HOST */ + ,{ 16, 3 } /* UF_PORT */ + ,{ 19, 1 } /* UF_PATH */ + ,{ 0, 0 } /* UF_QUERY */ + ,{ 0, 0 } /* UF_FRAGMENT */ + ,{ 0, 0 } /* UF_USERINFO */ + } + } + ,.rv=0 + } + +, {.name="CONNECT request" + ,.url="hostname:443" + ,.is_connect=1 + ,.u= + {.field_set=(1 << UF_HOST) | (1 << UF_PORT) + ,.port=443 + ,.field_data= + {{ 0, 0 } /* UF_SCHEMA */ + ,{ 0, 8 } /* UF_HOST */ + ,{ 9, 3 } /* UF_PORT */ + ,{ 0, 0 } /* UF_PATH */ + ,{ 0, 0 } /* UF_QUERY */ + ,{ 0, 0 } /* UF_FRAGMENT */ + ,{ 0, 0 } /* UF_USERINFO */ + } + } + ,.rv=0 + } + +, {.name="CONNECT request but not connect" + ,.url="hostname:443" + ,.is_connect=0 + ,.rv=1 + } + +, {.name="proxy ipv6 request" + ,.url="http://[1:2::3:4]/" + ,.is_connect=0 + ,.u= + {.field_set=(1 << UF_SCHEMA) | (1 << UF_HOST) | (1 << UF_PATH) + ,.port=0 + ,.field_data= + {{ 0, 4 } /* UF_SCHEMA */ + ,{ 8, 8 } /* UF_HOST */ + ,{ 0, 0 } /* UF_PORT */ + ,{ 17, 1 } /* UF_PATH */ + ,{ 0, 0 } /* UF_QUERY */ + ,{ 0, 0 } /* UF_FRAGMENT */ + ,{ 0, 0 } /* UF_USERINFO */ + } + } + ,.rv=0 + } + +, {.name="proxy ipv6 request with port" + ,.url="http://[1:2::3:4]:67/" + ,.is_connect=0 + ,.u= + {.field_set=(1 << UF_SCHEMA) | (1 << UF_HOST) | (1 << UF_PORT) | (1 << UF_PATH) + ,.port=67 + ,.field_data= + {{ 0, 4 } /* UF_SCHEMA */ + ,{ 8, 8 } /* UF_HOST */ + ,{ 18, 2 } /* UF_PORT */ + ,{ 20, 1 } /* UF_PATH */ + ,{ 0, 0 } /* UF_QUERY */ + ,{ 0, 0 } /* UF_FRAGMENT */ + ,{ 0, 0 } /* UF_USERINFO */ + } + } + ,.rv=0 + } + +, {.name="CONNECT ipv6 address" + ,.url="[1:2::3:4]:443" + ,.is_connect=1 + ,.u= + {.field_set=(1 << UF_HOST) | (1 << UF_PORT) + ,.port=443 + ,.field_data= + {{ 0, 0 } /* UF_SCHEMA */ + ,{ 1, 8 } /* UF_HOST */ + ,{ 11, 3 } /* UF_PORT */ + ,{ 0, 0 } /* UF_PATH */ + ,{ 0, 0 } /* UF_QUERY */ + ,{ 0, 0 } /* UF_FRAGMENT */ + ,{ 0, 0 } /* UF_USERINFO */ + } + } + ,.rv=0 + } + +, {.name="ipv4 in ipv6 address" + ,.url="http://[2001:0000:0000:0000:0000:0000:1.9.1.1]/" + ,.is_connect=0 + ,.u= + {.field_set=(1 << UF_SCHEMA) | (1 << UF_HOST) | (1 << UF_PATH) + ,.port=0 + ,.field_data= + {{ 0, 4 } /* UF_SCHEMA */ + ,{ 8, 37 } /* UF_HOST */ + ,{ 0, 0 } /* UF_PORT */ + ,{ 46, 1 } /* UF_PATH */ + ,{ 0, 0 } /* UF_QUERY */ + ,{ 0, 0 } /* UF_FRAGMENT */ + ,{ 0, 0 } /* UF_USERINFO */ + } + } + ,.rv=0 + } + +, {.name="extra ? in query string" + ,.url="http://a.tbcdn.cn/p/fp/2010c/??fp-header-min.css,fp-base-min.css," + "fp-channel-min.css,fp-product-min.css,fp-mall-min.css,fp-category-min.css," + "fp-sub-min.css,fp-gdp4p-min.css,fp-css3-min.css,fp-misc-min.css?t=20101022.css" + ,.is_connect=0 + ,.u= + {.field_set=(1< +#include + +static int num_messages; +static struct message _messages[5]; + +/** + strnlen() is a POSIX.2008 addition. Can't rely on it being available so define it ourselves + +static size_t strnlen(const char* s, size_t maxlen) +{ + const char* p = (const char*) memchr(s, '\0', maxlen); + + if (p == U_NULLPTR) return maxlen; + + return p - s; +} + +static size_t strlncat(char* dst, size_t len, const char* src, size_t n) +{ + size_t rlen; + size_t ncpy; + size_t slen = strnlen(src, n); + size_t dlen = strnlen(dst, len); + + if (dlen < len) + { + rlen = len - dlen; + ncpy = slen < rlen ? slen : (rlen - 1); + + (void) memcpy(dst + dlen, src, ncpy); + + dst[dlen + ncpy] = '\0'; + } + +// assert(len > slen + dlen); + + return slen + dlen; +} +*/ + +static size_t strlncpy(char* dst, size_t len, const char* src, size_t n) +{ + size_t ncpy; + size_t slen = strnlen(src, n); + + if (len > 0) + { + ncpy = slen < len ? slen : (len - 1); + + (void) memcpy(dst, src, ncpy); + + dst[ncpy] = '\0'; + } + +/* assert(len > slen); */ + + return slen; +} + +/* +static size_t strlcat(char* dst, const char* src, size_t len) { return strlncat(dst, len, src, (size_t) -1); } +static size_t strlcpy(char* dst, const char* src, size_t len) { return strlncpy(dst, len, src, (size_t) -1); } +*/ + +static size_t parse(const char* buf, size_t len, int req = HTTP_REQUEST) +{ + U_TRACE(5, "::parse(%.*S,%u,%d)", len, buf, len, req) + + return UHTTP::parserExecute(buf, len, req == HTTP_RESPONSE); +} + +static inline int check_str_eq(const struct message* m, const char* prop, const char* expected, const char* found) +{ + U_TRACE(5, "::check_str_eq(%p,%p,%S,%S)", m, prop, expected, found) + + if ((expected == U_NULLPTR) != (found == U_NULLPTR)) + { + printf("\n*** Error: %s in '%s' ***\n\n", prop, m->name); + printf("expected %s\n", (expected == U_NULLPTR) ? "NULL" : expected); + printf(" found %s\n", (found == U_NULLPTR) ? "NULL" : found); + + return 0; + } + + if (expected != U_NULLPTR && 0 != strcmp(expected, found)) + { + printf("\n*** Error: %s in '%s' ***\n\n", prop, m->name); + printf("expected '%s'\n", expected); + printf(" found '%s'\n", found); + + return 0; + } + + return 1; +} + +static inline int check_num_eq(const struct message* m, const char* prop, int expected, int found) +{ + U_TRACE(5, "::check_num_eq(%p,%p,%u,%u)", m, prop, expected, found) + + if (expected != found) + { + printf("\n*** Error: %s in '%s' ***\n\n", prop, m->name); + printf("expected %d\n", expected); + printf(" found %d\n", found); + + return 0; + } + + return 1; +} + +#define MESSAGE_CHECK_STR_EQ(expected, found, prop) \ + if (!check_str_eq(expected, #prop, expected->prop, found->prop)) return 0 + +#define MESSAGE_CHECK_NUM_EQ(expected, found, prop) \ + if (!check_num_eq(expected, #prop, expected->prop, found->prop)) return 0 + +#define MESSAGE_CHECK_URL_EQ(u, expected, found, prop, fn) \ +do { \ + check_str_eq(expected, #prop, expected->prop, u.getFieldValue(fn).data()); \ +} while(0) + +static int message_eq(int index, int connect, const struct message* expected) +{ + U_TRACE(5, "::message_eq(%d,%d,%p)", index, connect, expected) + + int i; + struct message* m = _messages+index; + + MESSAGE_CHECK_NUM_EQ(expected, m, http_major); + MESSAGE_CHECK_NUM_EQ(expected, m, http_minor); + + if (expected->type == HTTP_REQUEST) + { + MESSAGE_CHECK_NUM_EQ(expected, m, method); + } + else + { + MESSAGE_CHECK_NUM_EQ(expected, m, status_code); + MESSAGE_CHECK_STR_EQ(expected, m, response_status); + } + + if (!connect) + { + MESSAGE_CHECK_NUM_EQ(expected, m, should_keep_alive); + MESSAGE_CHECK_NUM_EQ(expected, m, message_complete_on_eof); + } + + /* + assert(m->message_begin_cb_called); + assert(m->headers_complete_cb_called); + assert(m->message_complete_cb_called); + */ + + MESSAGE_CHECK_STR_EQ(expected, m, request_url); + + /* + * Check URL components; we can't do this w/ CONNECT since it doesn't send us a well-formed URL. + */ + + if (*m->request_url && m->method != HTTP_CONNECT) + { + Url u(m->request_url, strlen(m->request_url)); + + if (expected->host) + { + MESSAGE_CHECK_URL_EQ(u, expected, m, host, Url::U_HOST); + } + + if (expected->userinfo) + { + MESSAGE_CHECK_URL_EQ(u, expected, m, userinfo, Url::U_USERINFO); + } + + m->port = u.getPortNumber(); + + MESSAGE_CHECK_URL_EQ(u, expected, m, query_string, Url::U_QUERY); + MESSAGE_CHECK_URL_EQ(u, expected, m, fragment, Url::U_FRAGMENT); + MESSAGE_CHECK_URL_EQ(u, expected, m, request_path, Url::U_PATH); + MESSAGE_CHECK_NUM_EQ(expected, m, port); + } + + if (connect) + { + check_num_eq(m, "body_size", 0, m->body_size); + } + else if (expected->body_size) + { + MESSAGE_CHECK_NUM_EQ(expected, m, body_size); + } + else + { + MESSAGE_CHECK_STR_EQ(expected, m, body); + } + + if (connect) + { + check_num_eq(m, "num_chunks_complete", 0, m->num_chunks_complete); + } + else + { + /* assert(m->num_chunks == m->num_chunks_complete); */ + + MESSAGE_CHECK_NUM_EQ(expected, m, num_chunks_complete); + + for (i = 0; i < m->num_chunks && i < MAX_CHUNKS; i++) + { + MESSAGE_CHECK_NUM_EQ(expected, m, chunk_lengths[i]); + } + } + + MESSAGE_CHECK_NUM_EQ(expected, m, num_headers); + + int r; + for (i = 0; i < m->num_headers; i++) + { + r = check_str_eq(expected, "header field", expected->headers[i][0], m->headers[i][0]); + + if (!r) return 0; + + r = check_str_eq(expected, "header value", expected->headers[i][1], m->headers[i][1]); + + if (!r) return 0; + } + + MESSAGE_CHECK_STR_EQ(expected, m, upgrade); + + return 1; +} + +/** + * Given a sequence of varargs messages, return the number of them that the + * parser should successfully parse, taking into account that upgraded + * messages prevent all subsequent messages from being parsed. + */ + +static size_t count_parsed_messages(const size_t nmsgs, ...) +{ + U_TRACE(5, "::count_parsed_messages(%u)", nmsgs) + + size_t i; + va_list ap; + + va_start(ap, nmsgs); + + for (i = 0; i < nmsgs; i++) + { + struct message *m = va_arg(ap, struct message *); + + if (m->upgrade) + { + va_end(ap); + + return i + 1; + } + } + + va_end(ap); + + return nmsgs; +} + +/** + * Given a sequence of bytes and the number of these that we were able to + * parse, verify that upgrade bodies are correct. + +static void upgrade_message_fix(char* body, const size_t nread, const size_t nmsgs, ...) +{ + va_list ap; + size_t i; + size_t off = 0; + + va_start(ap, nmsgs); + + for (i = 0; i < nmsgs; i++) + { + struct message* m = va_arg(ap, struct message *); + + off += strlen(m->raw); + + if (m->upgrade) + { + off -= strlen(m->upgrade); + + // Check the portion of the response after its specified upgrade + + if (!check_str_eq(m, "upgrade", body + off, body + nread)) abort(); + + // Fix up the response so that message_eq() will verify the beginning of the upgrade + + *(body + nread + strlen(m->upgrade)) = '\0'; + + _messages[num_messages -1 ].upgrade = body + nread; + + va_end(ap); + + return; + } + } + + va_end(ap); + + printf("\n\n*** Error: expected a message with upgrade ***\n"); + + abort(); +} +*/ + +static void print_error(const char* raw, size_t error_location) +{ + U_TRACE(5, "::print_error(%S,%u)", raw, error_location) + + int this_line = 0, char_len = 0; + size_t i, j, len = strlen(raw), error_location_line = 0; + + for (i = 0; i < len; i++) + { + if (i == error_location) this_line = 1; + + switch (raw[i]) + { + case '\r': + char_len = 2; + fprintf(stderr, "\\r"); + break; + + case '\n': + fprintf(stderr, "\\n\n"); + + if (this_line) goto print; + + error_location_line = 0; + continue; + + default: + char_len = 1; + fputc(raw[i], stderr); + break; + } + + if (!this_line) error_location_line += char_len; + } + + fprintf(stderr, "[eof]\n"); + +print: + for (j = 0; j < error_location_line; j++) + { + fputc(' ', stderr); + } + + fprintf(stderr, "^\n\nerror location: %u\n", (unsigned int)error_location); +} + +static void test_message(const struct message* message) +{ + U_TRACE(5, "::test_message(%p)", message) + + size_t raw_len = strlen(message->raw); + size_t msg1len; + + for (msg1len = 0; msg1len < raw_len; msg1len++) + { + size_t read; + const char* msg1 = message->raw; + const char* msg2 = msg1 + msg1len; + size_t msg2len = raw_len - msg1len; + + if (msg1len) + { + read = parse(msg1, msg1len, message->type); + + if (message->upgrade && num_messages > 0) + { + _messages[num_messages - 1].upgrade = msg1 + read; + + goto test; + } + + if (read != msg1len) + { + print_error(msg1, read); + + abort(); + } + } + + read = parse(msg2, msg2len); + + if (message->upgrade) + { + _messages[num_messages - 1].upgrade = msg2 + read; + + goto test; + } + + if (read != msg2len) + { + print_error(msg2, read); + + abort(); + } + +test: if (num_messages != 1) + { + printf("\n*** num_messages != 1 after testing '%s' ***\n\n", message->name); + + abort(); + } + + if (!message_eq(0, 0, message)) abort(); + } +} + +static void test_simple(const char* buf, int err_expected) +{ + U_TRACE(5, "::test_simple(%S,%d)", buf, err_expected) + + int err = 0; + + parse(buf, strlen(buf)); + + if (err_expected != err) + { + fprintf(stderr, "\n*** test_simple expected %d, but saw %d ***\n\n%s\n", err_expected, err, buf); + + abort(); + } +} + +static void test_invalid_header_content(int req, const char* str) +{ + U_TRACE(5, "::test_invalid_header_content(%d,%S)", req, str) + + const char* buf = req ? "GET / HTTP/1.1\r\n" : "HTTP/1.1 200 OK\r\n"; + + parse(buf, strlen(buf)); + + buf = str; + size_t buflen = strlen(buf); + + if (parse(buf, buflen)) fprintf(stderr, "\n*** Error expected but none in invalid header content test ***\n"); +} + +static void test_invalid_header_field_content_error(int req) +{ + U_TRACE(5, "::test_invalid_header_field_content_error(%d)", req) + + test_invalid_header_content(req, "Foo: F\01ailure"); + test_invalid_header_content(req, "Foo: B\02ar"); +} + +static void test_invalid_header_field(int req, const char* str) +{ + U_TRACE(5, "::test_invalid_header_field(%d,%S)", req, str) + + const char* buf = req ? "GET / HTTP/1.1\r\n" : "HTTP/1.1 200 OK\r\n"; + + parse(buf, strlen(buf)); + + buf = str; + size_t buflen = strlen(buf); + + if (parse(buf, buflen)) fprintf(stderr, "\n*** Error expected but none in invalid header token test ***\n"); +} + +static void test_invalid_header_field_token_error(int req) +{ + U_TRACE(5, "::test_invalid_header_field_token_error(%d)", req) + + test_invalid_header_field(req, "Fo@: Failure"); + test_invalid_header_field(req, "Foo\01\test: Bar"); +} + +static void test_double_content_length_error(int req) +{ + U_TRACE(5, "::test_double_content_length_error(%d)", req) + + const char* buf = req ? "GET / HTTP/1.1\r\n" : "HTTP/1.1 200 OK\r\n"; + + parse(buf, strlen(buf)); + + buf = "Content-Length: 0\r\nContent-Length: 1\r\n\r\n"; + size_t buflen = strlen(buf); + + if (parse(buf, buflen)) fprintf(stderr, "\n*** Error expected but none in double content-length test ***\n"); +} + +static void test_chunked_content_length_error(int req) +{ + U_TRACE(5, "::test_chunked_content_length_error(%d)", req) + + const char* buf = req ? "GET / HTTP/1.1\r\n" : "HTTP/1.1 200 OK\r\n"; + + parse(buf, strlen(buf)); + + buf = "Transfer-Encoding: chunked\r\nContent-Length: 1\r\n\r\n"; + size_t buflen = strlen(buf); + + if (parse(buf, buflen)) fprintf(stderr, "\n*** Error expected but none in chunked content-length test ***\n"); +} + +static void test_header_cr_no_lf_error(int req) +{ + U_TRACE(5, "::test_header_cr_no_lf_error(%d)", req) + + const char* buf = req ? "GET / HTTP/1.1\r\n" : "HTTP/1.1 200 OK\r\n"; + + parse(buf, strlen(buf)); + + buf = "Foo: 1\rBar: 1\r\n\r\n"; + size_t buflen = strlen(buf); + + if (parse(buf, buflen)) fprintf(stderr, "\n*** Error expected but none in header whitespace test ***\n"); +} + +static void test_header_overflow_error(int req) +{ + U_TRACE(5+256, "::test_header_overflow_error(%d)", req) + + const char* buf = req ? "GET / HTTP/1.1\r\n" : "HTTP/1.0 200 OK\r\n"; + + parse(buf, strlen(buf), req); + + buf = "header-key: header-value\r\n"; + size_t buflen = strlen(buf); + + if (parse(buf, buflen)) fprintf(stderr, "\n*** Error expected but none in header overflow test ***\n"); +} + +static void test_header_nread_value() +{ + U_TRACE_NO_PARAM(5+256, "::test_header_nread_value()") + + bool result = parse(U_CONSTANT_TO_PARAM("GET / HTTP/1.1\r\nheader: value\nhdr: value\r\n")); + + U_INTERNAL_ASSERT_EQUALS(result, false) + U_INTERNAL_ASSERT(U_ClientImage_data_missing) +} + +static void test_content_length_overflow(const char* buf, size_t buflen, int req, int expect_ok) +{ + U_TRACE(5, "::test_content_length_overflow(%.*S,%u,%d,%d)", buflen, buf, buflen, req, expect_ok) + + bool result = (expect_ok == (parse(buf, buflen, req) != 0)); + + U_INTERNAL_ASSERT(result) +} + +static void test_header_content_length_overflow_error(void) +{ + U_TRACE_NO_PARAM(5, "::test_header_content_length_overflow_error()") + +#define X(size) \ + "HTTP/1.1 200 OK\r\n" \ + "Content-Length: " #size "\r\n" \ + "\r\n" + const char a[] = X(1844674407370955160); /* 2^64 / 10 - 1 */ + const char b[] = X(18446744073709551615); /* 2^64-1 */ + const char c[] = X(18446744073709551616); /* 2^64 */ +#undef X + test_content_length_overflow(a, sizeof(a)-1, HTTP_RESPONSE, 1); /* expect ok */ + test_content_length_overflow(b, sizeof(b)-1, HTTP_RESPONSE, 0); /* expect failure */ + test_content_length_overflow(c, sizeof(c)-1, HTTP_RESPONSE, 0); /* expect failure */ +} + +static void test_chunk_content_length_overflow_error(void) +{ + U_TRACE_NO_PARAM(5, "::test_chunk_content_length_overflow_error()") + +#define X(size) \ + "HTTP/1.1 200 OK\r\n" \ + "Transfer-Encoding: chunked\r\n" \ + "\r\n" \ + #size "\r\n" \ + "..." + const char a[] = X(FFFFFFFFFFFFFFE); /* 2^64 / 16 - 1 */ + const char b[] = X(FFFFFFFFFFFFFFFF); /* 2^64-1 */ + const char c[] = X(10000000000000000); /* 2^64 */ +#undef X + test_content_length_overflow(a, sizeof(a)-1, HTTP_RESPONSE, 1); /* expect ok */ + test_content_length_overflow(b, sizeof(b)-1, HTTP_RESPONSE, 0); /* expect failure */ + test_content_length_overflow(c, sizeof(c)-1, HTTP_RESPONSE, 0); /* expect failure */ +} + +static void test_no_overflow_long_body(int req, size_t length) +{ + U_TRACE(5+256, "::test_no_overflow_long_body(%d,%u)", req, length) + + size_t i; + char buf1[3000]; + size_t buf1len = sprintf(buf1, "%s\r\nConnection: Keep-Alive\r\nContent-Length: %lu\r\n\r\n", req == HTTP_REQUEST ? "POST / HTTP/1.0" : "HTTP/1.0 200 OK", (unsigned long)length); + + for (i = 0; i < length; i++) buf1[buf1len+i] = 'a'; + + buf1[buf1len+i] = '\0'; + + bool result = parse(buf1, buf1len+i, req); + + U_INTERNAL_ASSERT(result) +} + +static void test_multiple3(const struct message* r1, const struct message* r2, const struct message* r3) +{ + U_TRACE(5, "::test_multiple3(%p,%p,%p)", r1, r2, r3) + + int message_count = count_parsed_messages(3, r1, r2, r3); + + char total[ strlen(r1->raw) + + strlen(r2->raw) + + strlen(r3->raw) + + 1 + ]; + + total[0] = '\0'; + + strcat(total, r1->raw); + strcat(total, r2->raw); + strcat(total, r3->raw); + + parse(total, strlen(total)); + + if (!message_eq(0, 0, r1)) abort(); + if (message_count > 1 && !message_eq(1, 0, r2)) abort(); + if (message_count > 2 && !message_eq(2, 0, r3)) abort(); +} + +/* + * SCAN through every possible breaking to make sure the + * parser can handle getting the content in any chunks that + * might come from the socket + */ + +static void test_scan(const struct message* r1, const struct message* r2, const struct message* r3) +{ + U_TRACE(5, "::test_scan(%p,%p,%p)", r1, r2, r3) + + char total[80*1024] = "\0"; + char buf1[80*1024] = "\0"; + char buf2[80*1024] = "\0"; + char buf3[80*1024] = "\0"; + + strcat(total, r1->raw); + strcat(total, r2->raw); + strcat(total, r3->raw); + + int total_len = strlen(total); + + int total_ops = 2 * (total_len - 1) * (total_len - 2) / 2; + int ops = 0 ; + + size_t buf1_len, buf2_len, buf3_len; + int i, j, message_count = count_parsed_messages(3, r1, r2, r3); + + for (int type_both = 0; type_both < 2; type_both++) + { + for (j = 2; j < total_len; j++) + { + for (i = 1; i < j; i++) + { + if (ops % 1000 == 0) + { + printf("\b\b\b\b%3.0f%%", 100 * (float)ops /(float)total_ops); + + fflush(stdout); + } + + ops += 1; + + buf1_len = i; + strlncpy(buf1, sizeof(buf1), total, buf1_len); + buf1[buf1_len] = 0; + + buf2_len = j - i; + strlncpy(buf2, sizeof(buf1), total+i, buf2_len); + buf2[buf2_len] = 0; + + buf3_len = total_len - j; + strlncpy(buf3, sizeof(buf1), total+j, buf3_len); + buf3[buf3_len] = 0; + + parse(buf1, buf1_len); + + parse(buf2, buf2_len); + + parse(buf3, buf3_len); + + if (message_count != num_messages) + { + fprintf(stderr, "\n\nParser didn't see %d messages only %d\n", message_count, num_messages); + + goto error; + } + + if (!message_eq(0, 0, r1)) + { + fprintf(stderr, "\n\nError matching messages[0] in test_scan.\n"); + + goto error; + } + + if (message_count > 1 && !message_eq(1, 0, r2)) + { + fprintf(stderr, "\n\nError matching messages[1] in test_scan.\n"); + + goto error; + } + + if (message_count > 2 && !message_eq(2, 0, r3)) + { + fprintf(stderr, "\n\nError matching messages[2] in test_scan.\n"); + + goto error; + } + } + } + } + + puts("\b\b\b\b100%"); + + return; + +error: + fprintf(stderr, "i=%d j=%d\n", i, j); + fprintf(stderr, "buf1 (%u) %s\n\n", (unsigned int)buf1_len, buf1); + fprintf(stderr, "buf2 (%u) %s\n\n", (unsigned int)buf2_len , buf2); + fprintf(stderr, "buf3 (%u) %s\n", (unsigned int)buf3_len, buf3); + + abort(); +} + +// user required to free the result string terminated by \0 + +static void create_large_chunked_message(int body_size_in_kb, const char* headers) +{ + size_t wrote = 0; + size_t headers_len = strlen(headers); + + memcpy(large_chunked_message, headers, headers_len); + + wrote += headers_len; + + for (int i = 0; i < body_size_in_kb; i++) + { + // write 1kb chunk into the body. + memcpy(large_chunked_message + wrote, "400\r\n", 5); + wrote += 5; + memset(large_chunked_message + wrote, 'C', 1024); + wrote += 1024; + strcpy(large_chunked_message + wrote, "\r\n"); + wrote += 2; + } + + memcpy(large_chunked_message + wrote, "0\r\n\r\n", 6); +} + +/* Verify that body and next message won't be parsed in responses to CONNECT */ + +static void test_message_connect(const struct message* msg) +{ + U_TRACE(5, "::test_message_connect(%p)", msg) + + char* buf = (char*) msg->raw; + size_t buflen = strlen(msg->raw); + + parse(buf, buflen); + + if (num_messages != 1) + { + printf("\n*** num_messages != 1 after testing '%s' ***\n\n", msg->name); + + abort(); + } + + if (!message_eq(0, 1, msg)) abort(); +} + +static size_t parse_count_body(const char* buf, size_t len) +{ + size_t nparsed = parse(buf, len); + + return nparsed; +} + +static void test_message_count_body(const struct message* message) +{ + U_TRACE(5, "::test_message_count_body(%p)", message) + + size_t read; + size_t l = strlen(message->raw); + size_t i, toread; + size_t chunk = 4024; + + for (i = 0; i < l; i+= chunk) + { + toread = U_min(l-i, chunk); + + read = parse_count_body(message->raw + i, toread); + + if (read != toread) + { + print_error(message->raw, read); + + abort(); + } + } + + if (num_messages != 1) + { + printf("\n*** num_messages != 1 after testing '%s' ***\n\n", message->name); + + abort(); + } + + if (!message_eq(0, 0, message)) abort(); +} + +static int http_parser_parse_url(const struct url_test* test, struct http_parser_url* u) +{ + U_TRACE(5, "::http_parser_parse_url(%p,%p)", test, u) + + bool result = parse(test->url, strlen(test->url)); + + (void) memcpy(u, &test->u, sizeof(struct http_parser_url)); + + return (test->rv ? result == false : result); +} + +static void dump_url(const char* url, const struct http_parser_url* u) +{ + U_TRACE(5, "::dump_url(%S,%p)", url, u) + + unsigned int i; + + printf("\tfield_set: 0x%x, port: %u\n", u->field_set, u->port); + + for (i = 0; i < UF_MAX; i++) + { + if ((u->field_set & (1 << i)) == 0) + { + printf("\tfield_data[%u]: unset\n", i); + + continue; + } + + printf("\tfield_data[%u]: off: %u len: %u part: \"%.*s\n\"", i, u->field_data[i].off, u->field_data[i].len, u->field_data[i].len, url + u->field_data[i].off); + } +} + +static void test_parse_url(void) +{ + U_TRACE_NO_PARAM(5+256, "::test_parse_url()") + + unsigned int i, rv; + struct http_parser_url u; + const struct url_test* test; + + for (i = 0; i < getNumUrlTests(); i++) + { + test = url_tests+i; + + memset(&u, 0, sizeof(u)); + + rv = http_parser_parse_url(test, &u); + + if (test->rv == 0) + { + if (rv != 0) + { + printf("\n*** http_parser_parse_url(\"%s\") \"%s\" test failed, " "unexpected rv %d ***\n\n", test->url, test->name, rv); + + abort(); + } + + if (memcmp(&u, &test->u, sizeof(u)) != 0) + { + printf("\n*** http_parser_parse_url(\"%s\") \"%s\" failed ***\n", test->url, test->name); + + printf("target http_parser_url:\n"); + + dump_url(test->url, &test->u); + + printf("result http_parser_url:\n"); + + dump_url(test->url, &u); + + abort(); + } + } + else + { + /* test->rv != 0 */ + + if (rv == 0) + { + printf("\n*** http_parser_parse_url(\"%s\") \"%s\" test failed, unexpected rv %d ***\n\n", test->url, test->name, rv); + + abort(); + } + } + } +} + +int main(int argc, char** argv, char** env) +{ + U_ULIB_INIT(argv); + + U_TRACE(5, "main(%d)", argc) + + int i, j, k, request_count, response_count; + + u_init_ulib_hostname(); + + UClientImage_Base::init(); + + UString::str_allocate(STR_ALLOCATE_HTTP); + + for ( request_count = 0; requests[ request_count].name; request_count++); + for (response_count = 0; responses[response_count].name; response_count++); + + //// API + test_parse_url(); + + //// NREAD + test_header_nread_value(); + + //// OVERFLOW CONDITIONS + test_header_overflow_error(HTTP_REQUEST); + test_header_overflow_error(HTTP_RESPONSE); + + test_no_overflow_long_body(HTTP_REQUEST, 1000); + test_no_overflow_long_body(HTTP_RESPONSE, 1000); + + test_header_content_length_overflow_error(); + test_chunk_content_length_overflow_error(); + + //// HEADER FIELD CONDITIONS + test_double_content_length_error(HTTP_REQUEST); + test_chunked_content_length_error(HTTP_REQUEST); + test_header_cr_no_lf_error(HTTP_REQUEST); + test_invalid_header_field_token_error(HTTP_REQUEST); + test_invalid_header_field_content_error(HTTP_REQUEST); + test_double_content_length_error(HTTP_RESPONSE); + test_chunked_content_length_error(HTTP_RESPONSE); + test_header_cr_no_lf_error(HTTP_RESPONSE); + test_invalid_header_field_token_error(HTTP_RESPONSE); + test_invalid_header_field_content_error(HTTP_RESPONSE); + + //// RESPONSES + + for (i = 0; i < response_count; i++) test_message(&responses[i]); + for (i = 0; i < response_count; i++) test_message_connect(&responses[i]); + + for (i = 0; i < response_count; i++) + { + if (!responses[i].should_keep_alive) continue; + + for (j = 0; j < response_count; j++) + { + if (!responses[j].should_keep_alive) continue; + + for (k = 0; k < response_count; k++) test_multiple3(&responses[i], &responses[j], &responses[k]); + } + } + + test_message_count_body(&responses[NO_HEADERS_NO_BODY_404]); + test_message_count_body(&responses[TRAILING_SPACE_ON_CHUNKED_BODY]); + + // test very large chunked response + { + create_large_chunked_message(31337, + "HTTP/1.0 200 OK\r\n" + "Transfer-Encoding: chunked\r\n" + "Content-Type: text/plain\r\n" + "\r\n"); + + for (i = 0; i < MAX_CHUNKS; i++) large_chunked.chunk_lengths[i] = 1024; + + test_message_count_body(&large_chunked); + } + + printf("response scan 1/2 "); + test_scan( &responses[TRAILING_SPACE_ON_CHUNKED_BODY] + , &responses[NO_BODY_HTTP10_KA_204] + , &responses[NO_REASON_PHRASE] + ); + + printf("response scan 2/2 "); + test_scan( &responses[BONJOUR_MADAME_FR] + , &responses[UNDERSTORE_HEADER_KEY] + , &responses[NO_CARRIAGE_RET] + ); + + puts("responses okay"); + + + /// REQUESTS + + test_simple("GET / HTP/1.1\r\n\r\n", HPE_INVALID_VERSION); + + // Extended characters - see nodejs/test/parallel/test-http-headers-obstext.js + test_simple("GET / HTTP/1.1\r\n" "Test: Düsseldorf\r\n", HPE_OK); + + // Well-formed but incomplete + test_simple("GET / HTTP/1.1\r\n" + "Content-Type: text/plain\r\n" + "Content-Length: 6\r\n" + "\r\n" + "fooba", + HPE_OK); + + static const char* all_methods[] = { + "DELETE", + "GET", + "HEAD", + "POST", + "PUT", + //"CONNECT", //CONNECT can't be tested like other methods, it's a tunnel + "OPTIONS", + "TRACE", + "COPY", + "LOCK", + "MKCOL", + "MOVE", + "PROPFIND", + "PROPPATCH", + "SEARCH", + "UNLOCK", + "BIND", + "REBIND", + "UNBIND", + "ACL", + "REPORT", + "MKACTIVITY", + "CHECKOUT", + "MERGE", + "M-SEARCH", + "NOTIFY", + "SUBSCRIBE", + "UNSUBSCRIBE", + "PATCH", + "PURGE", + "MKCALENDAR", + "LINK", + "UNLINK", + U_NULLPTR }; + + const char** this_method; + + for (this_method = all_methods; *this_method; this_method++) + { + char buf[200]; + + sprintf(buf, "%s / HTTP/1.1\r\n\r\n", *this_method); + + test_simple(buf, HPE_OK); + } + + static const char* bad_methods[] = { + "ASDF", + "C******", + "COLA", + "GEM", + "GETA", + "M****", + "MKCOLA", + "PROPPATCHA", + "PUN", + "PX", + "SA", + "hello world", + U_NULLPTR }; + + for (this_method = bad_methods; *this_method; this_method++) + { + char buf[200]; + + sprintf(buf, "%s / HTTP/1.1\r\n\r\n", *this_method); + + test_simple(buf, HPE_INVALID_METHOD); + } + + // illegal header field name line folding + test_simple("GET / HTTP/1.1\r\n" "name\r\n" " : value\r\n" "\r\n", HPE_INVALID_HEADER_TOKEN); + + const char* dumbfuck2 = + "GET / HTTP/1.1\r\n" + "X-SSL-Bullshit: -----BEGIN CERTIFICATE-----\r\n" + "\tMIIFbTCCBFWgAwIBAgICH4cwDQYJKoZIhvcNAQEFBQAwcDELMAkGA1UEBhMCVUsx\r\n" + "\tETAPBgNVBAoTCGVTY2llbmNlMRIwEAYDVQQLEwlBdXRob3JpdHkxCzAJBgNVBAMT\r\n" + "\tAkNBMS0wKwYJKoZIhvcNAQkBFh5jYS1vcGVyYXRvckBncmlkLXN1cHBvcnQuYWMu\r\n" + "\tdWswHhcNMDYwNzI3MTQxMzI4WhcNMDcwNzI3MTQxMzI4WjBbMQswCQYDVQQGEwJV\r\n" + "\tSzERMA8GA1UEChMIZVNjaWVuY2UxEzARBgNVBAsTCk1hbmNoZXN0ZXIxCzAJBgNV\r\n" + "\tBAcTmrsogriqMWLAk1DMRcwFQYDVQQDEw5taWNoYWVsIHBhcmQYJKoZIhvcNAQEB\r\n" + "\tBQADggEPADCCAQoCggEBANPEQBgl1IaKdSS1TbhF3hEXSl72G9J+WC/1R64fAcEF\r\n" + "\tW51rEyFYiIeZGx/BVzwXbeBoNUK41OK65sxGuflMo5gLflbwJtHBRIEKAfVVp3YR\r\n" + "\tgW7cMA/s/XKgL1GEC7rQw8lIZT8RApukCGqOVHSi/F1SiFlPDxuDfmdiNzL31+sL\r\n" + "\t0iwHDdNkGjy5pyBSB8Y79dsSJtCW/iaLB0/n8Sj7HgvvZJ7x0fr+RQjYOUUfrePP\r\n" + "\tu2MSpFyf+9BbC/aXgaZuiCvSR+8Snv3xApQY+fULK/xY8h8Ua51iXoQ5jrgu2SqR\r\n" + "\twgA7BUi3G8LFzMBl8FRCDYGUDy7M6QaHXx1ZWIPWNKsCAwEAAaOCAiQwggIgMAwG\r\n" + "\tA1UdEwEB/wQCMAAwEQYJYIZIAYb4QgHTTPAQDAgWgMA4GA1UdDwEB/wQEAwID6DAs\r\n" + "\tBglghkgBhvhCAQ0EHxYdVUsgZS1TY2llbmNlIFVzZXIgQ2VydGlmaWNhdGUwHQYD\r\n" + "\tVR0OBBYEFDTt/sf9PeMaZDHkUIldrDYMNTBZMIGaBgNVHSMEgZIwgY+AFAI4qxGj\r\n" + "\tloCLDdMVKwiljjDastqooXSkcjBwMQswCQYDVQQGEwJVSzERMA8GA1UEChMIZVNj\r\n" + "\taWVuY2UxEjAQBgNVBAsTCUF1dGhvcml0eTELMAkGA1UEAxMCQ0ExLTArBgkqhkiG\r\n" + "\t9w0BCQEWHmNhLW9wZXJhdG9yQGdyaWQtc3VwcG9ydC5hYy51a4IBADApBgNVHRIE\r\n" + "\tIjAggR5jYS1vcGVyYXRvckBncmlkLXN1cHBvcnQuYWMudWswGQYDVR0gBBIwEDAO\r\n" + "\tBgwrBgEEAdkvAQEBAQYwPQYJYIZIAYb4QgEEBDAWLmh0dHA6Ly9jYS5ncmlkLXN1\r\n" + "\tcHBvcnQuYWMudmT4sopwqlBWsvcHViL2NybC9jYWNybC5jcmwwPQYJYIZIAYb4QgEDBDAWLmh0\r\n" + "\tdHA6Ly9jYS5ncmlkLXN1cHBvcnQuYWMudWsvcHViL2NybC9jYWNybC5jcmwwPwYD\r\n" + "\tVR0fBDgwNjA0oDKgMIYuaHR0cDovL2NhLmdyaWQt5hYy51ay9wdWIv\r\n" + "\tY3JsL2NhY3JsLmNybDANBgkqhkiG9w0BAQUFAAOCAQEAS/U4iiooBENGW/Hwmmd3\r\n" + "\tXCy6Zrt08YjKCzGNjorT98g8uGsqYjSxv/hmi0qlnlHs+k/3Iobc3LjS5AMYr5L8\r\n" + "\tUO7OSkgFFlLHQyC9JzPfmLCAugvzEbyv4Olnsr8hbxF1MbKZoQxUZtMVu29wjfXk\r\n" + "\thTeApBv7eaKCWpSp7MCbvgzm74izKhu3vlDk9w6qVrxePfGgpKPqfHiOoGhFnbTK\r\n" + "\twTC6o2xq5y0qZ03JonF7OJspEd3I5zKY3E+ov7/ZhW6DqT8UFvsAdjvQbXyhV8Eu\r\n" + "\tYhixw1aKEPzNjNowuIseVogKOLXxWI5vAi5HgXdS0/ES5gDGsABo4fqovUKlgop3\r\n" + "\tRA==\r\n" + "\t-----END CERTIFICATE-----\r\n" + "\r\n"; + + test_simple(dumbfuck2, HPE_OK); + + const char* corrupted_connection = + "GET / HTTP/1.1\r\n" + "Host: www.example.com\r\n" + "Connection\r\033\065\325eep-Alive\r\n" + "Accept-Encoding: gzip\r\n" + "\r\n"; + + test_simple(corrupted_connection, HPE_INVALID_HEADER_TOKEN); + + const char* corrupted_header_name = + "GET / HTTP/1.1\r\n" + "Host: www.example.com\r\n" + "X-Some-Header\r\033\065\325eep-Alive\r\n" + "Accept-Encoding: gzip\r\n" + "\r\n"; + + test_simple(corrupted_header_name, HPE_INVALID_HEADER_TOKEN); + +#if 0 + // NOTE(Wed Nov 18 11:57:27 CET 2009) this seems okay. we just read body until EOF. + // no content-length error if there is a body without content length + + const char* bad_get_no_headers_no_body = "GET /bad_get_no_headers_no_body/world HTTP/1.1\r\n" + "Accept: */*\r\n" + "\r\n" + "HELLO"; + + test_simple(bad_get_no_headers_no_body, 0); +#endif + /* TODO sending junk and large headers gets rejected */ + + /* check to make sure our predefined requests are okay */ + for (i = 0; requests[i].name; i++) test_message(&requests[i]); + + for (i = 0; i < request_count; i++) + { + if (!requests[i].should_keep_alive) continue; + + for (j = 0; j < request_count; j++) + { + if (!requests[j].should_keep_alive) continue; + + for (k = 0; k < request_count; k++) test_multiple3(&requests[i], &requests[j], &requests[k]); + } + } + + printf("request scan 1/4 "); + test_scan( &requests[GET_NO_HEADERS_NO_BODY] + , &requests[GET_ONE_HEADER_NO_BODY] + , &requests[GET_NO_HEADERS_NO_BODY] + ); + + printf("request scan 2/4 "); + test_scan( &requests[POST_CHUNKED_ALL_YOUR_BASE] + , &requests[POST_IDENTITY_BODY_WORLD] + , &requests[GET_FUNKY_CONTENT_LENGTH] + ); + + printf("request scan 3/4 "); + test_scan( &requests[TWO_CHUNKS_MULT_ZERO_END] + , &requests[CHUNKED_W_TRAILING_HEADERS] + , &requests[CHUNKED_W_BULLSHIT_AFTER_LENGTH] + ); + + printf("request scan 4/4 "); + test_scan( &requests[QUERY_URL_WITH_QUESTION_MARK_GET] + , &requests[PREFIX_NEWLINE_GET ] + , &requests[CONNECT_REQUEST] + ); + + puts("requests okay"); +} diff --git a/tests/examples/test_http_parser.h b/tests/examples/test_http_parser.h new file mode 100644 index 000000000..71a706e64 --- /dev/null +++ b/tests/examples/test_http_parser.h @@ -0,0 +1,163 @@ +/* test_http_parser.h */ + +#ifndef test_http_parser_h +#define test_http_parser_h 1 + +#include +#include + +#define MAX_HEADERS 13 +#define MAX_ELEMENT_SIZE 2048 +#define MAX_CHUNKS 16 + +#define HTTP_LINK -1 +#define HTTP_UNLINK -2 + +#define HPE_OK 0 +#define HPE_INVALID_METHOD 1 +#define HPE_INVALID_VERSION 2 +#define HPE_INVALID_HEADER_TOKEN 3 + +#define CURL_GET 0 +#define FIREFOX_GET 1 +#define DUMBFUCK 2 +#define FRAGMENT_IN_URI 3 +#define GET_NO_HEADERS_NO_BODY 4 +#define GET_ONE_HEADER_NO_BODY 5 +#define GET_FUNKY_CONTENT_LENGTH 6 +#define POST_IDENTITY_BODY_WORLD 7 +#define POST_CHUNKED_ALL_YOUR_BASE 8 +#define TWO_CHUNKS_MULT_ZERO_END 9 +#define CHUNKED_W_TRAILING_HEADERS 10 +#define CHUNKED_W_BULLSHIT_AFTER_LENGTH 11 +#define WITH_QUOTES 12 +#define APACHEBENCH_GET 13 +#define QUERY_URL_WITH_QUESTION_MARK_GET 14 +#define PREFIX_NEWLINE_GET 15 +#define UPGRADE_REQUEST 16 +#define CONNECT_REQUEST 17 +#define REPORT_REQ 18 +#define NO_HTTP_VERSION 19 +#define MSEARCH_REQ 20 +#define LINE_FOLDING_IN_HEADER 21 +#define QUERY_TERMINATED_HOST 22 +#define QUERY_TERMINATED_HOSTPORT 23 +#define SPACE_TERMINATED_HOSTPORT 24 +#define PATCH_REQ 25 +#define CONNECT_CAPS_REQUEST 26 +#define UTF8_PATH_REQ 27 +#define HOSTNAME_UNDERSCORE 28 +#define EAT_TRAILING_CRLF_NO_CONNECTION_CLOSE 29 +#define EAT_TRAILING_CRLF_WITH_CONNECTION_CLOSE 30 +#define PURGE_REQ 31 +#define SEARCH_REQ 32 +#define PROXY_WITH_BASIC_AUTH 33 +#define LINE_FOLDING_IN_HEADER_WITH_LF 34 +#define CONNECTION_MULTI 35 +#define CONNECTION_MULTI_LWS 36 +#define CONNECTION_MULTI_LWS_CRLF 37 +#define UPGRADE_POST_REQUEST 38 +#define CONNECT_WITH_BODY_REQUEST 39 +#define LINK_REQUEST 40 +#define UNLINK_REQUEST 41 +#define GOOGLE_301 0 +#define NO_CONTENT_LENGTH_RESPONSE 1 +#define NO_HEADERS_NO_BODY_404 2 +#define NO_REASON_PHRASE 3 +#define TRAILING_SPACE_ON_CHUNKED_BODY 4 +#define NO_CARRIAGE_RET 5 +#define PROXY_CONNECTION 6 +#define UNDERSTORE_HEADER_KEY 7 +#define BONJOUR_MADAME_FR 8 +#define RES_FIELD_UNDERSCORE 9 +#define NON_ASCII_IN_STATUS_LINE 10 +#define HTTP_VERSION_0_9 11 +#define NO_CONTENT_LENGTH_NO_TRANSFER_ENCODING_RESPONSE 12 +#define NO_BODY_HTTP10_KA_200 13 +#define NO_BODY_HTTP10_KA_204 14 +#define NO_BODY_HTTP11_KA_200 15 +#define NO_BODY_HTTP11_KA_204 16 +#define NO_BODY_HTTP11_NOKA_204 17 +#define NO_BODY_HTTP11_KA_CHUNKED_200 18 +#define SPACE_IN_FIELD_RES 19 +#define AMAZON_COM 20 +#define EMPTY_REASON_PHRASE_AFTER_SPACE 20 +#define CONTENT_LENGTH_X 21 + +#ifdef __cplusplus +extern "C" { +#endif + +enum http_parser_type { HTTP_REQUEST, HTTP_RESPONSE, HTTP_BOTH }; + +struct message { + const char* name; /* for debugging purposes */ + const char* raw; + int type; + int method; + int status_code; + char response_status[MAX_ELEMENT_SIZE]; + char request_path[MAX_ELEMENT_SIZE]; + char request_url[MAX_ELEMENT_SIZE]; + char fragment[MAX_ELEMENT_SIZE]; + char query_string[MAX_ELEMENT_SIZE]; + char body[MAX_ELEMENT_SIZE]; + size_t body_size; + const char* host; + const char* userinfo; + uint16_t port; + int num_headers; + enum { NONE=0, FIELD, VALUE } last_header_element; + char headers [MAX_HEADERS][2][MAX_ELEMENT_SIZE]; + int should_keep_alive; + + int num_chunks; + int num_chunks_complete; + int chunk_lengths[MAX_CHUNKS]; + + const char* upgrade; /* upgraded body */ + + unsigned short http_major; + unsigned short http_minor; + + int message_begin_cb_called; + int headers_complete_cb_called; + int message_complete_cb_called; + int message_complete_on_eof; + int body_is_final; +}; + +enum UrlFieldType { UF_SCHEMA, UF_HOST, UF_PORT, UF_PATH, UF_QUERY, UF_FRAGMENT, UF_USERINFO, UF_MAX }; + +struct http_parser_url { + uint16_t field_set; /* Bitmask of (1 << UF_*) values */ + uint16_t port; /* Converted UF_PORT string */ + + struct { + uint16_t off; /* Offset into buffer in which field starts */ + uint16_t len; /* Length of run in buffer */ + } field_data[7]; +}; + +struct url_test { + const char* name; + const char* url; + int is_connect; + struct http_parser_url u; + int rv; +}; + +extern U_EXPORT const struct message requests[]; /* * R E Q U E S T S * */ +extern U_EXPORT const struct message responses[]; /* * R E S P O N S E S * */ +extern U_EXPORT struct message large_chunked; + +extern U_EXPORT const struct url_test url_tests[]; + +extern U_EXPORT char large_chunked_message[sizeof("HTTP/1.0 200 OK\r\nTransfer-Encoding: chunked\r\nContent-Type: text/plain\r\n\r\n")+(5+1024+2)*31337+5]; + +U_EXPORT unsigned int getNumUrlTests(void); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/tests/examples/web_server.sh b/tests/examples/web_server.sh index 3a97d639d..4bec0d9a1 100755 --- a/tests/examples/web_server.sh +++ b/tests/examples/web_server.sh @@ -7,14 +7,14 @@ #DOC_ROOT=ruby/blog DOC_ROOT=benchmark/docroot -rm -f tmp/usp_compile.sh.err /tmp/*.hpack.* /var/log/httpd/access_log \ +rm -f tmp/usp_compile.sh.err /tmp/*.hpack.* \ $DOC_ROOT/web_server.log* \ out/userver_*.out err/userver_*.err \ trace.*userver_*.[0-9]* object.*userver_*.[0-9]* stack.*userver_*.[0-9]* mempool.*userver_*.[0-9]* \ $DOC_ROOT/trace.*userver_*.[0-9]* $DOC_ROOT/object.*userver_*.[0-9]* $DOC_ROOT/stack.*userver_*.[0-9]* $DOC_ROOT/mempool.*userver_*.[0-9]* - UTRACE="0 50M -1" - UTRACE_SIGNAL="0 50M -1" + UTRACE="0 50M 0" + UTRACE_SIGNAL="0 50M 0" #UOBJDUMP="0 10M 100" #USIMERR="error.sim" UMEMUSAGE=yes @@ -57,7 +57,7 @@ cat <inp/webserver.cfg userver { PORT 8080 RUN_AS_USER nobody -#MIN_SIZE_FOR_SENDFILE 2k + MIN_SIZE_FOR_SENDFILE 2k LOG_FILE web_server.log LOG_FILE_SZ 10M #LOG_FILE_SZ 20k @@ -76,8 +76,8 @@ userver { #PLUGIN "ssi http" #ORM_DRIVER "sqlite mysql" ORM_DRIVER sqlite -#DOCUMENT_ROOT JONATHAN/docroot - DOCUMENT_ROOT benchmark/docroot + DOCUMENT_ROOT JONATHAN/docroot +#DOCUMENT_ROOT benchmark/docroot PLUGIN_DIR ../../../../src/ulib/net/server/plugin/.libs ORM_DRIVER_DIR ../../../../src/ulib/orm/driver/.libs #DOCUMENT_ROOT . @@ -97,6 +97,7 @@ ALIAS "[ / /100.html ]" LIMIT_REQUEST_BODY 3M REQUEST_READ_TIMEOUT 30 APACHE_LIKE_LOG /var/log/httpd/access_log + LOG_FILE_SZ 10M #DIGEST_AUTHENTICATION yes #CACHE_FILE_STORE nocat/webif.gz #CACHE_FILE_MASK inp/http/data/file1|*.flv|*.svgz @@ -116,6 +117,7 @@ DIR_CMD="../../examples/userver" #STRACE=$TRUSS start_prg_background userver_tcp -c inp/webserver.cfg + # /srv/userver_orm.cfg # RA/RA.cfg # deployment.properties diff --git a/tests/ulib/ok/url.ok b/tests/ulib/ok/url.ok index b17c5295a..b2c9d1a29 100644 --- a/tests/ulib/ok/url.ok +++ b/tests/ulib/ok/url.ok @@ -1,22 +1,24 @@ -"http://www.cs.wustl.edu/" "http" "" "www.cs.wustl.edu" "80" "/" "" -"http://www.cs.wustl.edu/index.html" "http" "" "www.cs.wustl.edu" "80" "/index.html" "" -"http://www.cs.wustl.edu/form?var=foo" "http" "" "www.cs.wustl.edu" "80" "/form" "var=foo" -"http://www.notexist.com:8080/index.html" "http" "" "www.notexist.com" "8080" "/index.html" "" -"http://www.notexist.com:80/index.html" "http" "" "www.notexist.com" "80" "/index.html" "" -"http://www.notexist.com:80?var=foo" "http" "" "www.notexist.com" "80" "/" "var=foo" -"ftp://foo" "ftp" "" "foo" "21" "/" "" -"http://www/?kkk//" "http" "" "www" "80" "/" "kkk//" -"ftp://www.cs.wustl.edu/" "ftp" "" "www.cs.wustl.edu" "21" "/" "" -"ftp://user@www.cs.wustl.edu/" "ftp" "user" "www.cs.wustl.edu" "21" "/" "" -"ftp://user:pass@www.cs.wustl.edu/" "ftp" "user:pass" "www.cs.wustl.edu" "21" "/" "" -"ftp://user:pass@www.cs.wustl.edu/path" "ftp" "user:pass" "www.cs.wustl.edu" "21" "/path" "" -"ftp://www.cs.wustl.edu" "ftp" "" "www.cs.wustl.edu" "21" "/" "" -"http://www.cs.wustl.edu/index.html" "http" "" "www.cs.wustl.edu" "80" "/index.html" "" -"mailto:ace-users@cs.wustl.edu" "" "" "" "0" "/" "ailto:ace-users@cs.wustl.edu" -"mailto:majordomo@cs.wustl.edu?Subject: subscribe ace-users" "" "" "" "0" "/" "ailto:majordomo@cs.wustl.edu?Subject: subscribe ace-users" -"mailto:nobody" "" "" "" "0" "/" "ailto:nobody" -"http://www.cs.wustl.edu" "http" "" "www.cs.wustl.edu" "80" "/" "" -"file:/etc/passwd" "" "" "" "0" "/" "ile:/etc/passwd" -"http://www.cs.wustl.edu/form?var=foo&url=http%3a//www/%3fkkk//" "http" "" "www.cs.wustl.edu" "80" "/form" "var=foo&url=http://www/?kkk//" +"http://www.cs.wustl.edu/" "http" "" "www.cs.wustl.edu" "" "/" "" "" +"http://www.cs.wustl.edu/index.html" "http" "" "www.cs.wustl.edu" "" "/index.html" "" "" +"http://www.cs.wustl.edu/form?var=foo" "http" "" "www.cs.wustl.edu" "" "/form" "var=foo" "" +"http://www.notexist.com:8080/index.html" "http" "" "www.notexist.com" "8080" "/index.html" "" "" +"http://www.notexist.com:80/index.html" "http" "" "www.notexist.com" "80" "/index.html" "" "" +"http://www.notexist.com:80?var=foo" "http" "" "www.notexist.com" "80" "/" "var=foo" "" +"ftp://foo" "ftp" "" "foo" "" "/" "" "" +"http://www/?kkk//" "http" "" "www" "" "/" "kkk//" "" +"ftp://www.cs.wustl.edu/" "ftp" "" "www.cs.wustl.edu" "" "/" "" "" +"ftp://user@www.cs.wustl.edu/" "ftp" "user" "www.cs.wustl.edu" "" "/" "" "" +"ftp://user:pass@www.cs.wustl.edu/" "ftp" "user:pass" "www.cs.wustl.edu" "" "/" "" "" +"ftp://user:pass@www.cs.wustl.edu/path" "ftp" "user:pass" "www.cs.wustl.edu" "" "/path" "" "" +"ftp://www.cs.wustl.edu" "ftp" "" "www.cs.wustl.edu" "" "/" "" "" +"http://www.cs.wustl.edu/index.html" "http" "" "www.cs.wustl.edu" "" "/index.html" "" "" +"mailto:ace-users@cs.wustl.edu" "" "" "" "" "/" "" "" +"mailto:majordomo@cs.wustl.edu?Subject: subscribe ace-users" "" "" "" "" "/" "" "" +"mailto:nobody" "" "" "" "" "/" "" "" +"http://www.cs.wustl.edu" "http" "" "www.cs.wustl.edu" "" "/" "" "" +"file:/etc/passwd" "" "" "" "" "/" "" "" +"http://www.cs.wustl.edu/form?var=foo&url=http%3a//www/%3fkkk//" "http" "" "www.cs.wustl.edu" "" "/form" "var=foo&url=http://www/?kkk//" "" +"http://a:b@host.com:8080/p/a/t/h?query=string#hash" "http" "a:b" "host.com" "8080" "/p/a/t/h" "query=string" "hash" +"https://tools.ietf.org/id/draft-snell-link-method-01.html#rfc.section.5" "https" "" "tools.ietf.org" "" "/id/draft-snell-link-method-01.html" "" "rfc.section.5" "http://pippo@www.unirel.com:808/usr/src?var1=foo&var2=bar" "http" "pippo" "www.unirel.com" "808" "/usr/src" "var1=foo&var2=bar" "/info?var1=foo&var2=bar&ip=10.30.1.130&ap=ap@palazzoVecchio&ip=10.30.1.131&ap=ap@palazzoNuovo" diff --git a/tests/ulib/test_date.cpp b/tests/ulib/test_date.cpp index 6df2f9e7e..d91955d14 100644 --- a/tests/ulib/test_date.cpp +++ b/tests/ulib/test_date.cpp @@ -30,8 +30,7 @@ static void checkForDaylightSavingTime(const char* tz, const char* start, const U_INTERNAL_ASSERT_EQUALS(res2, -1) } -int -U_EXPORT main(int argc, char* argv[]) +int U_EXPORT main(int argc, char* argv[], char** env) { U_ULIB_INIT(argv); diff --git a/tests/ulib/test_http.cpp b/tests/ulib/test_http.cpp index 2afc26313..adb8ce61c 100644 --- a/tests/ulib/test_http.cpp +++ b/tests/ulib/test_http.cpp @@ -28,7 +28,7 @@ int U_EXPORT main(int argc, char* argv[], char* env[]) cout.write(content.data(), content.size()); } #else - (void) http.setHostPort(url.getHost(), url.getPort()); + (void) http.setHostPort(url.getHost(), url.getPortNumber()); # define AB_REQUEST(ver) "GET /usp/benchmarking.usp?name=stefano HTTP/1."#ver"\r\n" \ "Host: stefano\r\n" \ diff --git a/tests/ulib/test_log.cpp b/tests/ulib/test_log.cpp index c88936a7b..8d4246409 100644 --- a/tests/ulib/test_log.cpp +++ b/tests/ulib/test_log.cpp @@ -12,7 +12,11 @@ U_EXPORT main (int argc, char* argv[], char* env[]) u_init_ulib_hostname(); u_init_ulib_username(); - ULog y(U_STRING_FROM_CONSTANT("$PWD/test_log.log"), 1024, "tmp"); + ULog y(U_STRING_FROM_CONSTANT("$PWD/test_log.log"), 1024); + +#ifdef USE_LIBZ + y.setLogRotate("tmp"); +#endif y.setPrefix(U_CONSTANT_TO_PARAM(U_SERVER_LOG_PREFIX)); diff --git a/tests/ulib/test_url.cpp b/tests/ulib/test_url.cpp index e1a96d03a..2817c1140 100644 --- a/tests/ulib/test_url.cpp +++ b/tests/ulib/test_url.cpp @@ -47,7 +47,7 @@ int U_EXPORT main(int argc, char* argv[]) check(dati, filename); } - Url url[20] = { + Url url[22] = { Url(U_STRING_FROM_CONSTANT("http://www.cs.wustl.edu/")), Url(U_STRING_FROM_CONSTANT("http://www.cs.wustl.edu/index.html")), Url(U_STRING_FROM_CONSTANT("http://www.cs.wustl.edu/form?var=foo")), @@ -67,23 +67,26 @@ int U_EXPORT main(int argc, char* argv[]) Url(U_STRING_FROM_CONSTANT("mailto:nobody")), Url(U_STRING_FROM_CONSTANT("http://www.cs.wustl.edu")), Url(U_STRING_FROM_CONSTANT("file:/etc/passwd")), - Url(U_STRING_FROM_CONSTANT("http://www.cs.wustl.edu/form?var=foo&url=http%3a//www/%3fkkk//")) + Url(U_STRING_FROM_CONSTANT("http://www.cs.wustl.edu/form?var=foo&url=http%3a//www/%3fkkk//")), + Url(U_STRING_FROM_CONSTANT("http://a:b@host.com:8080/p/a/t/h?query=string#hash")), + Url(U_STRING_FROM_CONSTANT("https://tools.ietf.org/id/draft-snell-link-method-01.html#rfc.section.5")) }; uint32_t i; - for (i = 0; i < 20; ++i) + for (i = 0; i < 22; ++i) { - cout << '"' << url[i] << "\" " - << '"' << url[i].getService() << "\" " - << '"' << url[i].getUser() << "\" " - << '"' << url[i].getHost() << "\" " - << '"' << url[i].getPort() << "\" " - << '"' << url[i].getPath() << "\" " - << '"' << url[i].getQuery() << "\"\n"; + cout << '"' << url[i] << "\" " + << '"' << url[i].getService() << "\" " + << '"' << url[i].getUser() << "\" " + << '"' << url[i].getHost() << "\" " + << '"' << url[i].getPort() << "\" " + << '"' << url[i].getPath() << "\" " + << '"' << url[i].getQuery() << "\" " + << '"' << url[i].getFragment() << "\"\n"; } - for (i = 0; i < 20; ++i) + for (i = 0; i < 22; ++i) { url[i].eraseUser(); url[i].eraseQuery(); @@ -265,7 +268,7 @@ int U_EXPORT main(int argc, char* argv[]) U_ASSERT( u.getService() == UString( u.getService(buffer, sizeof(buffer)) ) ) U_ASSERT( u.getUser() == UString( u.getUser(buffer, sizeof(buffer)) ) ) U_ASSERT( u.getHost() == UString( u.getHost(buffer, sizeof(buffer)) ) ) - U_ASSERT( u.getPort() == 8080 ) + U_ASSERT( u.getPortNumber() == 8080 ) U_ASSERT( u.getPath() == UString( u.getPath(buffer, sizeof(buffer)) ) ) U_ASSERT( u.getQuery() == UString( u.getQuery(buffer, sizeof(buffer)) ) ) */