From cb491fa5ca24dc76cd53ec699a11868a22ee79a5 Mon Sep 17 00:00:00 2001 From: Sebastiano Merlino Date: Fri, 9 Aug 2019 16:17:55 +0000 Subject: [PATCH 1/3] Removed unused parameters from webserver class --- src/httpserver/webserver.hpp | 1 - src/webserver.cpp | 3 +-- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/src/httpserver/webserver.hpp b/src/httpserver/webserver.hpp index 5745fe69..31ad5f34 100644 --- a/src/httpserver/webserver.hpp +++ b/src/httpserver/webserver.hpp @@ -183,7 +183,6 @@ class webserver std::map registered_resources; std::map registered_resources_str; - int next_to_choose; std::set bans; std::set allowances; diff --git a/src/webserver.cpp b/src/webserver.cpp index 64d92c25..cac34adb 100644 --- a/src/webserver.cpp +++ b/src/webserver.cpp @@ -151,8 +151,7 @@ webserver::webserver(const create_webserver& params): single_resource(params._single_resource), not_found_resource(params._not_found_resource), method_not_allowed_resource(params._method_not_allowed_resource), - internal_error_resource(params._internal_error_resource), - next_to_choose(0) + internal_error_resource(params._internal_error_resource) { ignore_sigpipe(); pthread_mutex_init(&mutexwait, NULL); From 5c64e1a3885527ee00fda7a3fd04c11a6d8b54b6 Mon Sep 17 00:00:00 2001 From: Sebastiano Merlino Date: Fri, 9 Aug 2019 17:42:01 +0000 Subject: [PATCH 2/3] Added support for TCP-NODELAY --- .travis.yml | 16 +++++++ examples/benchmark_nodelay.cpp | 41 ++++++++++++++++ src/httpserver/create_webserver.hpp | 11 +++++ src/httpserver/webserver.hpp | 1 + src/webserver.cpp | 14 ++++++ test/Makefile.am | 3 +- test/integ/nodelay.cpp | 74 +++++++++++++++++++++++++++++ 7 files changed, 159 insertions(+), 1 deletion(-) create mode 100755 examples/benchmark_nodelay.cpp create mode 100644 test/integ/nodelay.cpp diff --git a/.travis.yml b/.travis.yml index 49180545..9a47d329 100644 --- a/.travis.yml +++ b/.travis.yml @@ -98,6 +98,12 @@ script: ./benchmark_select 8080 $(nproc) & sleep 5 && ab -n 10000000 -c 100 localhost:8080/plaintext fi + - | + if [ "$PERFORMANCE" = "nodelay" ]; then + cd examples + ./benchmark_nodelay 8080 $(nproc) & + sleep 5 && ab -n 10000000 -c 100 localhost:8080/plaintext + fi - | if [ "$PERFORMANCE" = "threads" ]; then cd examples @@ -215,6 +221,16 @@ matrix: - apache2-utils env: - MATRIX_EVAL="CC=gcc-7 && CXX=g++-7 && PERFORMANCE=select" + - os: linux + addons: + apt: + sources: + - ubuntu-toolchain-r-test + packages: + - g++-7 + - apache2-utils + env: + - MATRIX_EVAL="CC=gcc-7 && CXX=g++-7 && PERFORMANCE=nodelay" - os: linux addons: apt: diff --git a/examples/benchmark_nodelay.cpp b/examples/benchmark_nodelay.cpp new file mode 100755 index 00000000..a67e95bf --- /dev/null +++ b/examples/benchmark_nodelay.cpp @@ -0,0 +1,41 @@ +#include +#include +#include + +#define PATH "/plaintext" +#define BODY "Hello, World!" + +using namespace httpserver; + +class hello_world_resource : public http_resource { + public: + hello_world_resource(const std::shared_ptr& resp): + resp(resp) + { + } + + const std::shared_ptr render(const http_request&) { + return resp; + } + + private: + std::shared_ptr resp; +}; + +int main(int argc, char** argv) +{ + webserver ws = create_webserver(atoi(argv[1])) + .start_method(http::http_utils::INTERNAL_SELECT) + .tcp_nodelay() + .max_threads(atoi(argv[2])); + + std::shared_ptr hello = std::shared_ptr(new string_response(BODY, 200)); + hello->with_header("Server", "libhttpserver"); + + hello_world_resource hwr(hello); + ws.register_resource(PATH, &hwr, false); + + ws.start(true); + + return 0; +} diff --git a/src/httpserver/create_webserver.hpp b/src/httpserver/create_webserver.hpp index 6fc5d3c5..596d7b33 100644 --- a/src/httpserver/create_webserver.hpp +++ b/src/httpserver/create_webserver.hpp @@ -80,6 +80,7 @@ class create_webserver _post_process_enabled(true), _deferred_enabled(false), _single_resource(false), + _tcp_nodelay(false), _not_found_resource(0x0), _method_not_allowed_resource(0x0), _internal_error_resource(0x0) @@ -121,6 +122,7 @@ class create_webserver _post_process_enabled(b._post_process_enabled), _deferred_enabled(b._deferred_enabled), _single_resource(b._single_resource), + _tcp_nodelay(b._tcp_nodelay), _not_found_resource(b._not_found_resource), _method_not_allowed_resource(b._method_not_allowed_resource), _internal_error_resource(b._internal_error_resource) @@ -162,6 +164,7 @@ class create_webserver _post_process_enabled(b._post_process_enabled), _deferred_enabled(b._deferred_enabled), _single_resource(b._single_resource), + _tcp_nodelay(b._tcp_nodelay), _not_found_resource(std::move(b._not_found_resource)), _method_not_allowed_resource(std::move(b._method_not_allowed_resource)), _internal_error_resource(std::move(b._internal_error_resource)) @@ -206,6 +209,7 @@ class create_webserver this->_post_process_enabled = b._post_process_enabled; this->_deferred_enabled = b._deferred_enabled; this->_single_resource = b._single_resource; + this->_tcp_nodelay = b._tcp_nodelay; this->_not_found_resource = b._not_found_resource; this->_method_not_allowed_resource = b._method_not_allowed_resource; this->_internal_error_resource = b._internal_error_resource; @@ -251,6 +255,7 @@ class create_webserver this->_post_process_enabled = b._post_process_enabled; this->_deferred_enabled = b._deferred_enabled; this->_single_resource = b._single_resource; + this->_tcp_nodelay = b._tcp_nodelay; this->_not_found_resource = std::move(b._not_found_resource); this->_method_not_allowed_resource = std::move(b._method_not_allowed_resource); this->_internal_error_resource = std::move(b._internal_error_resource); @@ -293,6 +298,7 @@ class create_webserver _post_process_enabled(true), _deferred_enabled(false), _single_resource(false), + _tcp_nodelay(false), _not_found_resource(0x0), _method_not_allowed_resource(0x0), _internal_error_resource(0x0) @@ -471,6 +477,10 @@ class create_webserver { _single_resource = true; return *this; } + create_webserver& tcp_nodelay() + { + _tcp_nodelay = true; return *this; + } create_webserver& not_found_resource(render_ptr not_found_resource) { _not_found_resource = not_found_resource; return *this; @@ -524,6 +534,7 @@ class create_webserver bool _post_process_enabled; bool _deferred_enabled; bool _single_resource; + bool _tcp_nodelay; render_ptr _not_found_resource; render_ptr _method_not_allowed_resource; render_ptr _internal_error_resource; diff --git a/src/httpserver/webserver.hpp b/src/httpserver/webserver.hpp index 31ad5f34..71433965 100644 --- a/src/httpserver/webserver.hpp +++ b/src/httpserver/webserver.hpp @@ -174,6 +174,7 @@ class webserver const bool post_process_enabled; const bool deferred_enabled; bool single_resource; + bool tcp_nodelay; pthread_mutex_t mutexwait; pthread_rwlock_t runguard; pthread_cond_t mutexcond; diff --git a/src/webserver.cpp b/src/webserver.cpp index cac34adb..a0608f95 100644 --- a/src/webserver.cpp +++ b/src/webserver.cpp @@ -32,9 +32,11 @@ #if defined(__MINGW32__) || defined(__CYGWIN32__) #include +#include #define _WINDOWS #else #include +#include #endif #include @@ -149,6 +151,7 @@ webserver::webserver(const create_webserver& params): post_process_enabled(params._post_process_enabled), deferred_enabled(params._deferred_enabled), single_resource(params._single_resource), + tcp_nodelay(params._tcp_nodelay), not_found_resource(params._not_found_resource), method_not_allowed_resource(params._method_not_allowed_resource), internal_error_resource(params._internal_error_resource) @@ -757,6 +760,17 @@ int webserver::answer_to_connection(void* cls, MHD_Connection* connection, ); } + const MHD_ConnectionInfo * conninfo = MHD_get_connection_info( + connection, + MHD_CONNECTION_INFO_CONNECTION_FD + ); + + if (static_cast(cls)->tcp_nodelay) + { + int yes = 1; + setsockopt(conninfo->connect_fd, IPPROTO_TCP, TCP_NODELAY, (char *) &yes, sizeof(int)); + } + std::string t_url = url; base_unescaper(t_url, static_cast(cls)->unescaper); diff --git a/test/Makefile.am b/test/Makefile.am index a4ff3fce..e6c91b02 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -19,7 +19,7 @@ LDADD = $(top_builddir)/src/libhttpserver.la AM_CPPFLAGS = -I$(top_srcdir)/src -I$(top_srcdir)/src/httpserver/ METASOURCES = AUTO -check_PROGRAMS = basic http_utils threaded string_utilities http_endpoint ban_system ws_start_stop authentication deferred +check_PROGRAMS = basic http_utils threaded nodelay string_utilities http_endpoint ban_system ws_start_stop authentication deferred MOSTLYCLEANFILES = *.gcda *.gcno *.gcov @@ -32,6 +32,7 @@ deferred_SOURCES = integ/deferred.cpp http_utils_SOURCES = unit/http_utils_test.cpp string_utilities_SOURCES = unit/string_utilities_test.cpp http_endpoint_SOURCES = unit/http_endpoint_test.cpp +nodelay_SOURCES = integ/nodelay.cpp noinst_HEADERS = littletest.hpp AM_CXXFLAGS += -lcurl -Wall -fPIC diff --git a/test/integ/nodelay.cpp b/test/integ/nodelay.cpp new file mode 100644 index 00000000..aad199f7 --- /dev/null +++ b/test/integ/nodelay.cpp @@ -0,0 +1,74 @@ +/* + This file is part of libhttpserver + Copyright (C) 2011-2019 Sebastiano Merlino + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 + USA +*/ + +#include "littletest.hpp" +#include +#include +#include +#include "httpserver.hpp" + +using namespace httpserver; +using namespace std; + +class ok_resource : public http_resource +{ + public: + const shared_ptr render_GET(const http_request& req) + { + return shared_ptr(new string_response("OK", 200, "text/plain")); + } +}; + +LT_BEGIN_SUITE(threaded_suite) + + webserver* ws; + + void set_up() + { + ws = new webserver(create_webserver(8080).tcp_nodelay()); + ws->start(false); + } + + void tear_down() + { + ws->stop(); + delete ws; + } +LT_END_SUITE(threaded_suite) + +LT_BEGIN_AUTO_TEST(threaded_suite, base) + ok_resource resource; + ws->register_resource("base", &resource); + curl_global_init(CURL_GLOBAL_ALL); + std::string s; + CURL* curl; + CURLcode res; + + curl = curl_easy_init(); + curl_easy_setopt(curl, CURLOPT_URL, "localhost:8080/base"); + curl_easy_setopt(curl, CURLOPT_HTTPGET, 1L); + res = curl_easy_perform(curl); + LT_ASSERT_EQ(res, 0); + curl_easy_cleanup(curl); +LT_END_AUTO_TEST(base) + +LT_BEGIN_AUTO_TEST_ENV() + AUTORUN_TESTS() +LT_END_AUTO_TEST_ENV() From f578654619181debe330ea162bbdd1e7104fcd17 Mon Sep 17 00:00:00 2001 From: Sebastiano Merlino Date: Fri, 9 Aug 2019 11:14:10 -0700 Subject: [PATCH 3/3] Add Target to compile nodelay benchmark --- examples/Makefile.am | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/Makefile.am b/examples/Makefile.am index 137c071c..318a7a8d 100644 --- a/examples/Makefile.am +++ b/examples/Makefile.am @@ -19,7 +19,7 @@ LDADD = $(top_builddir)/src/libhttpserver.la AM_CPPFLAGS = -I$(top_srcdir)/src -I$(top_srcdir)/src/httpserver/ METASOURCES = AUTO -noinst_PROGRAMS = hello_world service minimal_hello_world custom_error allowing_disallowing_methods handlers hello_with_get_arg setting_headers custom_access_log basic_authentication digest_authentication minimal_https minimal_file_response minimal_deferred url_registration minimal_ip_ban benchmark_select benchmark_threads deferred_with_accumulator +noinst_PROGRAMS = hello_world service minimal_hello_world custom_error allowing_disallowing_methods handlers hello_with_get_arg setting_headers custom_access_log basic_authentication digest_authentication minimal_https minimal_file_response minimal_deferred url_registration minimal_ip_ban benchmark_select benchmark_threads benchmark_nodelay deferred_with_accumulator hello_world_SOURCES = hello_world.cpp service_SOURCES = service.cpp @@ -40,3 +40,4 @@ url_registration_SOURCES = url_registration.cpp minimal_ip_ban_SOURCES = minimal_ip_ban.cpp benchmark_select_SOURCES = benchmark_select.cpp benchmark_threads_SOURCES = benchmark_threads.cpp +benchmark_nodelay_SOURCES = benchmark_nodelay.cpp