From cf3ed744da619fdd5fc1f4322713f8d835229046 Mon Sep 17 00:00:00 2001 From: oberdorc Date: Sat, 2 Mar 2024 13:26:55 +0100 Subject: [PATCH 01/18] Added TLS-PSK authentication method via function callback. --- README.md | 94 +++++++++++++++++++++++------ configure.ac | 14 ++--- examples/Makefile.am | 3 +- examples/minimal_https_psk.cpp | 60 ++++++++++++++++++ src/httpserver/create_webserver.hpp | 8 +++ src/httpserver/webserver.hpp | 3 + src/webserver.cpp | 27 +++++++-- 7 files changed, 177 insertions(+), 32 deletions(-) create mode 100644 examples/minimal_https_psk.cpp diff --git a/README.md b/README.md index b0a4c0e8..eb7fea6c 100644 --- a/README.md +++ b/README.md @@ -153,15 +153,15 @@ You can also check this example on [github](https://github.com/etr/libhttpserver ## Structures and classes type definition * _webserver:_ Represents the daemon listening on a socket for HTTP traffic. - * _create_webserver:_ Builder class to support the creation of a webserver. + * _create_webserver:_ Builder class to support the creation of a webserver. * _http_resource:_ Represents the resource associated with a specific http endpoint. * _http_request:_ Represents the request received by the resource that process it. * _http_response:_ Represents the response sent by the server once the resource finished its work. - * _string_response:_ A simple string response. - * _file_response:_ A response getting content from a file. - * _basic_auth_fail_response:_ A failure in basic authentication. - * _digest_auth_fail_response:_ A failure in digest authentication. - * _deferred_response:_ A response getting content from a callback. + * _string_response:_ A simple string response. + * _file_response:_ A response getting content from a file. + * _basic_auth_fail_response:_ A failure in basic authentication. + * _digest_auth_fail_response:_ A failure in digest authentication. + * _deferred_response:_ A response getting content from a callback. [Back to TOC](#table-of-contents) @@ -193,9 +193,9 @@ For example, if your connection limit is “1”, a browser may open a first con * _.post_process() and .no_post_process():_ Enables/Disables the library to automatically parse the body of the http request as arguments if in querystring format. Read more [here](#parsing-requests). `on` by default. * _.put_processed_data_to_content() and .no_put_processed_data_to_content():_ Enables/Disables the library to copy parsed body data to the content or to only store it in the arguments map. `on` by default. * _.file_upload_target(**file_upload_target_T** file_upload_target):_ Controls, how the library stores uploaded files. Default value is `FILE_UPLOAD_MEMORY_ONLY`. - * `FILE_UPLOAD_MEMORY_ONLY`: The content of the file is only stored in memory. Depending on `put_processed_data_to_content` only as part of the arguments map or additionally in the content. - * `FILE_UPLOAD_DISK_ONLY`: The content of the file is stored only in the file system. The path is created from `file_upload_dir` and either a random name (if `generate_random_filename_on_upload` is true) or the actually uploaded file name. - * `FILE_UPLOAD_MEMORY_AND_DISK`: The content of the file is stored in memory and on the file system. + * `FILE_UPLOAD_MEMORY_ONLY`: The content of the file is only stored in memory. Depending on `put_processed_data_to_content` only as part of the arguments map or additionally in the content. + * `FILE_UPLOAD_DISK_ONLY`: The content of the file is stored only in the file system. The path is created from `file_upload_dir` and either a random name (if `generate_random_filename_on_upload` is true) or the actually uploaded file name. + * `FILE_UPLOAD_MEMORY_AND_DISK`: The content of the file is stored in memory and on the file system. * _.file_upload_dir(**const std::string&** file_upload_dir):_ Specifies the directory to store all uploaded files. Default value is `/tmp`. * _.generate_random_filename_on_upload() and .no_generate_random_filename_on_upload():_ Enables/Disables the library to generate a unique and unused filename to store the uploaded file to. Otherwise the actually uploaded file name is used. `off` by default. * _.deferred()_ and _.no_deferred():_ Enables/Disables the ability for the server to suspend and resume connections. Simply put, it enables/disables the ability to use `deferred_response`. Read more [here](#building-responses-to-requests). `on` by default. @@ -203,8 +203,8 @@ For example, if your connection limit is “1”, a browser may open a first con ### Threading Models * _.start_method(**const http::http_utils::start_method_T&** start_method):_ libhttpserver can operate with two different threading models that can be selected through this method. Default value is `INTERNAL_SELECT`. - * `http::http_utils::INTERNAL_SELECT`: In this mode, libhttpserver uses only a single thread to handle listening on the port and processing of requests. This mode is preferable if spawning a thread for each connection would be costly. If the HTTP server is able to quickly produce responses without much computational overhead for each connection, this mode can be a great choice. Note that libhttpserver will still start a single thread for itself -- this way, the main program can continue with its operations after calling the start method. Naturally, if the HTTP server needs to interact with shared state in the main application, synchronization will be required. If such synchronization in code providing a response results in blocking, all HTTP server operations on all connections will stall. This mode is a bad choice if response data cannot always be provided instantly. The reason is that the code generating responses should not block (since that would block all other connections) and on the other hand, if response data is not available immediately, libhttpserver will start to busy wait on it. If you need to scale along the number of concurrent connection and scale on multiple thread you can specify a value for `max_threads` (see below) thus enabling a thread pool - this is different from `THREAD_PER_CONNECTION` below where a new thread is spawned for each connection. - * `http::http_utils::THREAD_PER_CONNECTION`: In this mode, libhttpserver starts one thread to listen on the port for new connections and then spawns a new thread to handle each connection. This mode is great if the HTTP server has hardly any state that is shared between connections (no synchronization issues!) and may need to perform blocking operations (such as extensive IO or running of code) to handle an individual connection. + * `http::http_utils::INTERNAL_SELECT`: In this mode, libhttpserver uses only a single thread to handle listening on the port and processing of requests. This mode is preferable if spawning a thread for each connection would be costly. If the HTTP server is able to quickly produce responses without much computational overhead for each connection, this mode can be a great choice. Note that libhttpserver will still start a single thread for itself -- this way, the main program can continue with its operations after calling the start method. Naturally, if the HTTP server needs to interact with shared state in the main application, synchronization will be required. If such synchronization in code providing a response results in blocking, all HTTP server operations on all connections will stall. This mode is a bad choice if response data cannot always be provided instantly. The reason is that the code generating responses should not block (since that would block all other connections) and on the other hand, if response data is not available immediately, libhttpserver will start to busy wait on it. If you need to scale along the number of concurrent connection and scale on multiple thread you can specify a value for `max_threads` (see below) thus enabling a thread pool - this is different from `THREAD_PER_CONNECTION` below where a new thread is spawned for each connection. + * `http::http_utils::THREAD_PER_CONNECTION`: In this mode, libhttpserver starts one thread to listen on the port for new connections and then spawns a new thread to handle each connection. This mode is great if the HTTP server has hardly any state that is shared between connections (no synchronization issues!) and may need to perform blocking operations (such as extensive IO or running of code) to handle an individual connection. * _.max_threads(**int** max_threads):_ A thread pool can be combined with the `INTERNAL_SELECT` mode to benefit implementations that require scalability. As said before, by default this mode only uses a single thread. When combined with the thread pool option, it is possible to handle multiple connections with multiple threads. Any value greater than one for this option will activate the use of the thread pool. In contrast to the `THREAD_PER_CONNECTION` mode (where each thread handles one and only one connection), threads in the pool can handle a large number of concurrent connections. Using `INTERNAL_SELECT` in combination with a thread pool is typically the most scalable (but also hardest to debug) mode of operation for libhttpserver. Default value is `1`. This option is incompatible with `THREAD_PER_CONNECTION`. ### Custom defaulted error messages @@ -303,16 +303,17 @@ You can also check this example on [github](https://github.com/etr/libhttpserver ### TLS/HTTPS * _.use_ssl() and .no_ssl():_ Determines whether to run in HTTPS-mode or not. If you set this as on and libhttpserver was compiled without SSL support, the library will throw an exception at start of the server. `off` by default. * _.cred_type(**const http::http_utils::cred_type_T&** cred_type):_ Daemon credentials type. Either certificate or anonymous. Acceptable values are: - * `NONE`: No credentials. - * `CERTIFICATE`: Certificate credential. - * `ANON`: Anonymous credential. - * `SRP`: SRP credential. - * `PSK`: PSK credential. - * `IA`: IA credential. + * `NONE`: No credentials. + * `CERTIFICATE`: Certificate credential. + * `ANON`: Anonymous credential. + * `SRP`: SRP credential. + * `PSK`: PSK credential. + * `IA`: IA credential. * _.https_mem_key(**const std::string&** filename):_ String representing the path to a file containing the private key to be used by the HTTPS daemon. This must be used in conjunction with `https_mem_cert`. * _.https_mem_cert(**const std::string&** filename):_ String representing the path to a file containing the certificate to be used by the HTTPS daemon. This must be used in conjunction with `https_mem_key`. * _.https_mem_trust(**const std::string&** filename):_ String representing the path to a file containing the CA certificate to be used by the HTTPS daemon to authenticate and trust clients certificates. The presence of this option activates the request of certificate to the client. The request to the client is marked optional, and it is the responsibility of the server to check the presence of the certificate if needed. Note that most browsers will only present a client certificate only if they have one matching the specified CA, not sending any certificate otherwise. * _.https_priorities(**const std::string&** priority_string):_ SSL/TLS protocol version and ciphers. Must be followed by a string specifying the SSL/TLS protocol versions and ciphers that are acceptable for the application. The string is passed unchanged to gnutls_priority_init. If this option is not specified, `"NORMAL"` is used. +* _.psk_cred_handler(**std::function** callback): Assign callback function for handling TLS with pre-shared key (PSK) authentication. The function will be invoked with a identity name in the TLS handshake and returns the related pre-shared key as a hex-encoded string. This is the same as it is created, for example, by *psktool* from the GnuTLS suite. #### Minimal example using HTTPS ```cpp @@ -346,6 +347,59 @@ To test the above example, you can run the following command from a terminal: You can also check this example on [github](https://github.com/etr/libhttpserver/blob/master/examples/minimal_https.cpp). +#### Minimal example using HTTPS with PSK +```cpp + #include + + using namespace http_server; + + class hello_world_resource : public http_resource + { + public: + std::shared_ptr render(const http_request&) + { + return std::shared_ptr( + new string_response("Hello, World!")); + } + }; + + std::string psk_callback(const std::string& username) + { + // Known identity from the database. + auto identity = std::string {"oFWv9Cv3N9tUsm"}; + + // Pre-shared key in hex-encoded format. + auto key = std::string { + "467427f5a4696f8e0ac285f36840efcbf6fd8da88703d26ff68c1faac7f4e2ae"}; + + return (username == identity) ? key : std::string {}; + } + + int main() + { + webserver ws = + create_webserver(8080) + .use_ssl() + .https_priorities("NORMAL:+PSK:+ECDHE-PSK:+DHE-PSK") + .cred_type(http::http_utils::PSK) + .psk_cred_handler(psk_callback); + + hello_world_resource hwr; + ws.register_resource("/hello", &hwr); + ws.start(true); + + return 0; + } +``` + +To test the above example, you can run the following command from a terminal: + + openssl s_client -msg -brief -psk_identity oFWv9Cv3N9tUsm -psk 467427f5a4696f8e0ac285f36840efcbf6fd8da88703d26ff68c1faac7f4e2ae -connect localhost:8080 + +Once the connection is made, enter the HTTP request, i.e. "GET /hello HTTP/1.1" followed by an empty line and you will see the server response. + +You can also check this example on [github](https://github.com/etr/libhttpserver/blob/master/examples/minimal_https_psk.cpp). + ### IP Blacklisting/Whitelisting libhttpserver supports IP blacklisting and whitelisting as an internal feature. This section explains the startup options related with IP blacklisting/whitelisting. See the [specific section](#ip-blacklisting-and-whitelisting) to read more about the topic. * _.ban_system() and .no_ban_system:_ Can be used to enable/disable the ban system. `on` by default. @@ -643,9 +697,9 @@ There are 5 types of response that you can create - we will describe them here t * _basic_auth_fail_response(**const std::string&** content, **const std::string&** realm = `""`, **int** response_code = `200`, **const std::string&** content_type = `"text/plain"`):_ A response in return to a failure during basic authentication. It allows to specify a `content` string as a message to send back to the client. The `realm` parameter should contain your realm of authentication (if any). The other two optional parameters are the `response_code` and the `content_type`. You can find constant definition for the various response codes within the [http_utils](https://github.com/etr/libhttpserver/blob/master/src/httpserver/http_utils.hpp) library file. * _digest_auth_fail_response(**const std::string&** content, **const std::string&** realm = `""`, **const std::string&** opaque = `""`, **bool** reload_nonce = `false`, **int** response_code = `200`, **const std::string&** content_type = `"text/plain"`):_ A response in return to a failure during digest authentication. It allows to specify a `content` string as a message to send back to the client. The `realm` parameter should contain your realm of authentication (if any). The `opaque` represents a value that gets passed to the client and expected to be passed again to the server as-is. This value can be a hexadecimal or base64 string. The `reload_nonce` parameter tells the server to reload the nonce (you should use the value returned by the `check_digest_auth` method on the `http_request`. The other two optional parameters are the `response_code` and the `content_type`. You can find constant definition for the various response codes within the [http_utils](https://github.com/etr/libhttpserver/blob/master/src/httpserver/http_utils.hpp) library file. * _deferred_response(**ssize_t(*cycle_callback_ptr)(shared_ptr<T>, char*, size_t)** cycle_callback, **const std::string&** content = `""`, **int** response_code = `200`, **const std::string&** content_type = `"text/plain"`):_ A response that obtains additional content from a callback executed in a deferred way. It leaves the client in pending state (returning a `100 CONTINUE` message) and suspends the connection. Besides the callback, optionally, you can provide a `content` parameter that sets the initial message sent immediately to the client. The other two optional parameters are the `response_code` and the `content_type`. You can find constant definition for the various response codes within the [http_utils](https://github.com/etr/libhttpserver/blob/master/src/httpserver/http_utils.hpp) library file. To use `deferred_response` you need to have the `deferred` option active on your webserver (enabled by default). - * The `cycle_callback_ptr` has this shape: - _**ssize_t** cycle_callback(**shared_ptr<T> closure_data, char*** buf, **size_t** max_size)_. - You are supposed to implement a function in this shape and provide it to the `deferred_repsonse` method. The webserver will provide a `char*` to the function. It is responsibility of the function to allocate it and fill its content. The method is supposed to respect the `max_size` parameter passed in input. The function must return a `ssize_t` value representing the actual size you filled the `buf` with. Any value different from `-1` will keep the resume the connection, deliver the content and suspend it again (with a `100 CONTINUE`). If the method returns `-1`, the webserver will complete the communication with the client and close the connection. You can also pass a `shared_ptr` pointing to a data object of your choice (this will be templetized with a class of your choice). The server will guarantee that this object is passed at each invocation of the method allowing the client code to use it as a memory buffer during computation. + * The `cycle_callback_ptr` has this shape: + _**ssize_t** cycle_callback(**shared_ptr<T> closure_data, char*** buf, **size_t** max_size)_. + You are supposed to implement a function in this shape and provide it to the `deferred_repsonse` method. The webserver will provide a `char*` to the function. It is responsibility of the function to allocate it and fill its content. The method is supposed to respect the `max_size` parameter passed in input. The function must return a `ssize_t` value representing the actual size you filled the `buf` with. Any value different from `-1` will keep the resume the connection, deliver the content and suspend it again (with a `100 CONTINUE`). If the method returns `-1`, the webserver will complete the communication with the client and close the connection. You can also pass a `shared_ptr` pointing to a data object of your choice (this will be templetized with a class of your choice). The server will guarantee that this object is passed at each invocation of the method allowing the client code to use it as a memory buffer during computation. ### Setting additional properties of the response The `http_response` class offers an additional set of methods to "decorate" your responses. This set of methods is: diff --git a/configure.ac b/configure.ac index 9d5c63e2..b3ce5c89 100644 --- a/configure.ac +++ b/configure.ac @@ -25,7 +25,7 @@ m4_define([libhttpserver_MINOR_VERSION],[19])dnl m4_define([libhttpserver_REVISION],[0])dnl m4_define([libhttpserver_PKG_VERSION],[libhttpserver_MAJOR_VERSION.libhttpserver_MINOR_VERSION.libhttpserver_REVISION])dnl m4_define([libhttpserver_LDF_VERSION],[libhttpserver_MAJOR_VERSION:libhttpserver_MINOR_VERSION:libhttpserver_REVISION])dnl -AC_INIT([libhttpserver], libhttpserver_PKG_VERSION, [electrictwister2000@gmail.com]) +AC_INIT([libhttpserver], libhttpserver_PKG_VERSION, electrictwister2000@gmail.com) AM_INIT_AUTOMAKE([subdir-objects]) AC_CONFIG_HEADERS([config.h]) AC_CONFIG_MACRO_DIR([m4]) @@ -83,7 +83,6 @@ case "$host" in esac # Checks for header files. -AC_HEADER_STDC AC_CHECK_HEADER([stdint.h],[],[AC_MSG_ERROR("stdint.h not found")]) AC_CHECK_HEADER([inttypes.h],[],[AC_MSG_ERROR("inttypes.h not found")]) AC_CHECK_HEADER([errno.h],[],[AC_MSG_ERROR("errno.h not found")]) @@ -245,9 +244,10 @@ AM_CONDITIONAL([BUILD_EXAMPLES], [test "x$enable_examples" = "xyes"]) AM_CONDITIONAL([COND_GCOV],[test x"$cond_gcov" = x"yes"]) AC_SUBST(COND_GCOV) -if test x"have_gnutls" = x"yes"; then +if test "x$have_gnutls" = "xyes"; then + AC_DEFINE([HAVE_GNUTLS],[1],[Uses GNU TLS]) AM_CXXFLAGS="$AM_CXXFLAGS -DHAVE_GNUTLS" - AM_CFLAGS="$AM_CXXFLAGS -DHAVE_GNUTLS" + AM_CFLAGS="$AM_CFLAGS -DHAVE_GNUTLS" fi DX_HTML_FEATURE(ON) @@ -284,14 +284,14 @@ AC_CONFIG_FILES([examples/cert.pem:examples/cert.pem]) AC_CONFIG_FILES([examples/key.pem:examples/key.pem]) AC_CONFIG_FILES([examples/test_content:examples/test_content]) -AC_OUTPUT( - libhttpserver.pc +AC_CONFIG_FILES([libhttpserver.pc Makefile doc/Makefile src/Makefile test/Makefile examples/Makefile -) +]) +AC_OUTPUT AC_MSG_NOTICE([Configuration Summary: Operating System: ${host_os} diff --git a/examples/Makefile.am b/examples/Makefile.am index 0fe116af..f0e64626 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 benchmark_nodelay deferred_with_accumulator file_upload +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_https_psk minimal_file_response minimal_deferred url_registration minimal_ip_ban benchmark_select benchmark_threads benchmark_nodelay deferred_with_accumulator file_upload hello_world_SOURCES = hello_world.cpp service_SOURCES = service.cpp @@ -33,6 +33,7 @@ custom_access_log_SOURCES = custom_access_log.cpp basic_authentication_SOURCES = basic_authentication.cpp digest_authentication_SOURCES = digest_authentication.cpp minimal_https_SOURCES = minimal_https.cpp +minimal_https_psk_SOURCES = minimal_https_psk.cpp minimal_file_response_SOURCES = minimal_file_response.cpp minimal_deferred_SOURCES = minimal_deferred.cpp deferred_with_accumulator_SOURCES = deferred_with_accumulator.cpp diff --git a/examples/minimal_https_psk.cpp b/examples/minimal_https_psk.cpp new file mode 100644 index 00000000..bee12be4 --- /dev/null +++ b/examples/minimal_https_psk.cpp @@ -0,0 +1,60 @@ +/* + This file is part of libhttpserver + Copyright (C) 2011, 2012, 2013, 2014, 2015 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 + +using namespace httpserver; + +class hello_world_resource : public http_resource +{ + public: + std::shared_ptr render(const http_request&) + { + return std::shared_ptr( + new string_response("Hello, World!")); + } +}; + +std::string psk_callback(const std::string& username) +{ + // Known identity from the database. + auto identity = std::string {"oFWv9Cv3N9tUsm"}; + + // Pre-shared key in hex-encoded format. + auto key = std::string { + "467427f5a4696f8e0ac285f36840efcbf6fd8da88703d26ff68c1faac7f4e2ae"}; + + return (username == identity) ? key : std::string {}; +} + +int main() +{ + webserver ws = + create_webserver(8080) + .use_ssl() + .https_priorities("NORMAL:+PSK:+ECDHE-PSK:+DHE-PSK") + .cred_type(http::http_utils::PSK) + .psk_cred_handler(psk_callback); + + hello_world_resource hwr; + ws.register_resource("/hello", &hwr); + ws.start(true); + + return 0; +} diff --git a/src/httpserver/create_webserver.hpp b/src/httpserver/create_webserver.hpp index c6d61e4d..2134d4c4 100644 --- a/src/httpserver/create_webserver.hpp +++ b/src/httpserver/create_webserver.hpp @@ -42,6 +42,8 @@ namespace httpserver { class webserver; class http_request; +typedef std::function psk_cred_handler_callback; + typedef std::function(const http_request&)> render_ptr; typedef std::function validator_ptr; typedef std::function log_access_ptr; @@ -213,6 +215,11 @@ class create_webserver { return *this; } + create_webserver& psk_cred_handler(psk_cred_handler_callback handler) { + _psk_cred_handler = std::move(handler); + return *this; + } + create_webserver& https_priorities(const std::string& https_priorities) { _https_priorities = https_priorities; return *this; @@ -383,6 +390,7 @@ class create_webserver { std::string _https_mem_cert = ""; std::string _https_mem_trust = ""; std::string _https_priorities = ""; + psk_cred_handler_callback _psk_cred_handler; http::http_utils::cred_type_T _cred_type = http::http_utils::NONE; std::string _digest_auth_random = ""; int _nonce_nc_size = 0; diff --git a/src/httpserver/webserver.hpp b/src/httpserver/webserver.hpp index b2cbb1a6..b31c4f4f 100644 --- a/src/httpserver/webserver.hpp +++ b/src/httpserver/webserver.hpp @@ -152,6 +152,7 @@ class webserver { const std::string https_mem_cert; const std::string https_mem_trust; const std::string https_priorities; + const psk_cred_handler_callback psk_cred_handler; const http::http_utils::cred_type_T cred_type; const std::string digest_auth_random; const int nonce_nc_size; @@ -186,6 +187,8 @@ class webserver { std::shared_ptr internal_error_page(details::modded_request* mr, bool force_our = false) const; std::shared_ptr not_found_page(details::modded_request* mr) const; + static void psk_cred_handler_func(void* cls, const struct MHD_Connection* connection, const char* username, void** psk, size_t* psk_size); + static void request_completed(void *cls, struct MHD_Connection *connection, void **con_cls, enum MHD_RequestTerminationCode toe); diff --git a/src/webserver.cpp b/src/webserver.cpp index 86a34c75..cd4b8ca8 100644 --- a/src/webserver.cpp +++ b/src/webserver.cpp @@ -141,6 +141,7 @@ webserver::webserver(const create_webserver& params): https_mem_cert(params._https_mem_cert), https_mem_trust(params._https_mem_trust), https_priorities(params._https_priorities), + psk_cred_handler(params._psk_cred_handler), cred_type(params._cred_type), digest_auth_random(params._digest_auth_random), nonce_nc_size(params._nonce_nc_size), @@ -176,6 +177,18 @@ void webserver::sweet_kill() { stop(); } +void webserver::psk_cred_handler_func(void* cls, const struct MHD_Connection*, const char* username, void** psk, size_t* psk_size) { + std::string key = std::invoke(static_cast(cls)->psk_cred_handler,username); + +#ifdef HAVE_GNUTLS + *psk_size = key.length(); + *psk = malloc(*psk_size); + + if (gnutls_hex2bin(key.data(),key.length(),*psk,psk_size) != GNUTLS_E_SUCCESS) + *psk_size = 0; +#endif +} + void webserver::request_completed(void *cls, struct MHD_Connection *connection, void **con_cls, enum MHD_RequestTerminationCode toe) { // These parameters are passed to respect the MHD interface, but are not needed here. std::ignore = cls; @@ -210,9 +223,11 @@ bool webserver::start(bool blocking) { } gen; vector iov; + // Must be assigned first to options to ensure that all output is handled by external logger! + iov.push_back(gen(MHD_OPTION_EXTERNAL_LOGGER, (intptr_t) &error_log, this)); + iov.push_back(gen(MHD_OPTION_NOTIFY_COMPLETED, (intptr_t) &request_completed, nullptr)); iov.push_back(gen(MHD_OPTION_URI_LOG_CALLBACK, (intptr_t) &uri_log, this)); - iov.push_back(gen(MHD_OPTION_EXTERNAL_LOGGER, (intptr_t) &error_log, this)); iov.push_back(gen(MHD_OPTION_UNESCAPE_CALLBACK, (intptr_t) &unescaper_func, this)); iov.push_back(gen(MHD_OPTION_CONNECTION_TIMEOUT, connection_timeout)); if (bind_socket != 0) { @@ -247,12 +262,12 @@ bool webserver::start(bool blocking) { iov.push_back(gen(MHD_OPTION_NONCE_NC_SIZE, nonce_nc_size)); } - if (use_ssl) { + if (https_mem_key != "" && use_ssl) { // Need for const_cast to respect MHD interface that needs a void* iov.push_back(gen(MHD_OPTION_HTTPS_MEM_KEY, 0, reinterpret_cast(const_cast(https_mem_key.c_str())))); } - if (use_ssl) { + if (https_mem_cert != "" && use_ssl) { // Need for const_cast to respect MHD interface that needs a void* iov.push_back(gen(MHD_OPTION_HTTPS_MEM_CERT, 0, reinterpret_cast(const_cast(https_mem_cert.c_str())))); } @@ -273,9 +288,13 @@ bool webserver::start(bool blocking) { } #ifdef HAVE_GNUTLS - if (cred_type != http_utils::NONE) { + if (cred_type != http_utils::NONE && use_ssl) { iov.push_back(gen(MHD_OPTION_HTTPS_CRED_TYPE, cred_type)); } + + if (psk_cred_handler && use_ssl) { + iov.push_back(gen(MHD_OPTION_GNUTLS_PSK_CRED_HANDLER,(intptr_t) psk_cred_handler_func, this)); + } #endif // HAVE_GNUTLS iov.push_back(gen(MHD_OPTION_END, 0, nullptr)); From 9a27ce04757479ed262478a8b69dd5abcfd01c76 Mon Sep 17 00:00:00 2001 From: oberdorc <96446443+oberdorc@users.noreply.github.com> Date: Sat, 2 Mar 2024 13:44:10 +0100 Subject: [PATCH 02/18] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index eb7fea6c..514c6346 100644 --- a/README.md +++ b/README.md @@ -312,7 +312,7 @@ You can also check this example on [github](https://github.com/etr/libhttpserver * _.https_mem_key(**const std::string&** filename):_ String representing the path to a file containing the private key to be used by the HTTPS daemon. This must be used in conjunction with `https_mem_cert`. * _.https_mem_cert(**const std::string&** filename):_ String representing the path to a file containing the certificate to be used by the HTTPS daemon. This must be used in conjunction with `https_mem_key`. * _.https_mem_trust(**const std::string&** filename):_ String representing the path to a file containing the CA certificate to be used by the HTTPS daemon to authenticate and trust clients certificates. The presence of this option activates the request of certificate to the client. The request to the client is marked optional, and it is the responsibility of the server to check the presence of the certificate if needed. Note that most browsers will only present a client certificate only if they have one matching the specified CA, not sending any certificate otherwise. -* _.https_priorities(**const std::string&** priority_string):_ SSL/TLS protocol version and ciphers. Must be followed by a string specifying the SSL/TLS protocol versions and ciphers that are acceptable for the application. The string is passed unchanged to gnutls_priority_init. If this option is not specified, `"NORMAL"` is used. +* .https_priorities(**const std::string&** priority_string):_ SSL/TLS protocol version and ciphers. Must be followed by a string specifying the SSL/TLS protocol versions and ciphers that are acceptable for the application. The string is passed unchanged to gnutls_priority_init. If this option is not specified, `"NORMAL"` is used. * _.psk_cred_handler(**std::function** callback): Assign callback function for handling TLS with pre-shared key (PSK) authentication. The function will be invoked with a identity name in the TLS handshake and returns the related pre-shared key as a hex-encoded string. This is the same as it is created, for example, by *psktool* from the GnuTLS suite. #### Minimal example using HTTPS From cd3968b7accf31f6b6b874b9f73e7357524e7d07 Mon Sep 17 00:00:00 2001 From: oberdorc <96446443+oberdorc@users.noreply.github.com> Date: Sat, 2 Mar 2024 14:11:23 +0100 Subject: [PATCH 03/18] Update README.md --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 514c6346..c7de8056 100644 --- a/README.md +++ b/README.md @@ -312,8 +312,8 @@ You can also check this example on [github](https://github.com/etr/libhttpserver * _.https_mem_key(**const std::string&** filename):_ String representing the path to a file containing the private key to be used by the HTTPS daemon. This must be used in conjunction with `https_mem_cert`. * _.https_mem_cert(**const std::string&** filename):_ String representing the path to a file containing the certificate to be used by the HTTPS daemon. This must be used in conjunction with `https_mem_key`. * _.https_mem_trust(**const std::string&** filename):_ String representing the path to a file containing the CA certificate to be used by the HTTPS daemon to authenticate and trust clients certificates. The presence of this option activates the request of certificate to the client. The request to the client is marked optional, and it is the responsibility of the server to check the presence of the certificate if needed. Note that most browsers will only present a client certificate only if they have one matching the specified CA, not sending any certificate otherwise. -* .https_priorities(**const std::string&** priority_string):_ SSL/TLS protocol version and ciphers. Must be followed by a string specifying the SSL/TLS protocol versions and ciphers that are acceptable for the application. The string is passed unchanged to gnutls_priority_init. If this option is not specified, `"NORMAL"` is used. -* _.psk_cred_handler(**std::function** callback): Assign callback function for handling TLS with pre-shared key (PSK) authentication. The function will be invoked with a identity name in the TLS handshake and returns the related pre-shared key as a hex-encoded string. This is the same as it is created, for example, by *psktool* from the GnuTLS suite. +* _.https_priorities(**const std::string&** priority_string):_ SSL/TLS protocol version and ciphers. Must be followed by a string specifying the SSL/TLS protocol versions and ciphers that are acceptable for the application. The string is passed unchanged to gnutls_priority_init. If this option is not specified, `"NORMAL"` is used. +* _.psk_cred_handler(**std::function** callback):_ Assign a callback function for handling TLS with pre-shared key (PSK) authentication. The function is called in the TLS handshake with an identity name and returns the associated pre-shared key as a hexadecimal encoded string. This key is the same as it is created, for example, by *psktool* from the GnuTLS suite. #### Minimal example using HTTPS ```cpp @@ -345,7 +345,7 @@ To test the above example, you can run the following command from a terminal: curl -XGET -v -k 'https://localhost:8080/hello' -You can also check this example on [github](https://github.com/etr/libhttpserver/blob/master/examples/minimal_https.cpp). +You can also check this example on [github](https://github.com/oberdorc/libhttpserver/blob/master/examples/minimal_https.cpp). #### Minimal example using HTTPS with PSK ```cpp @@ -398,7 +398,7 @@ To test the above example, you can run the following command from a terminal: Once the connection is made, enter the HTTP request, i.e. "GET /hello HTTP/1.1" followed by an empty line and you will see the server response. -You can also check this example on [github](https://github.com/etr/libhttpserver/blob/master/examples/minimal_https_psk.cpp). +You can also check this example on [github](https://github.com/oberdorc/libhttpserver/blob/master/examples/minimal_https_psk.cpp). ### IP Blacklisting/Whitelisting libhttpserver supports IP blacklisting and whitelisting as an internal feature. This section explains the startup options related with IP blacklisting/whitelisting. See the [specific section](#ip-blacklisting-and-whitelisting) to read more about the topic. From e8cf5409bc3f68a5a0d0f8ea2fad92e3020673e2 Mon Sep 17 00:00:00 2001 From: oberdorc <96446443+oberdorc@users.noreply.github.com> Date: Sun, 3 Mar 2024 22:12:11 +0100 Subject: [PATCH 04/18] Update webserver.cpp Needs include of _gnutls.h_ if HAVE_GNUTLS is defined. --- src/webserver.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/webserver.cpp b/src/webserver.cpp index cd4b8ca8..f32b93b7 100644 --- a/src/webserver.cpp +++ b/src/webserver.cpp @@ -47,6 +47,10 @@ #include #include +#ifdef HAVE_GNUTLS +#include +#endif + #include "httpserver/create_webserver.hpp" #include "httpserver/details/http_endpoint.hpp" #include "httpserver/details/modded_request.hpp" From f336fecfefb5fc81fee374e5fb65746a43f80bb7 Mon Sep 17 00:00:00 2001 From: oberdorc <96446443+oberdorc@users.noreply.github.com> Date: Sun, 3 Mar 2024 22:29:07 +0100 Subject: [PATCH 05/18] Update webserver.cpp Address an error that _key_ in the static PSK handler function is assigned a value that is never used in the case if the Gnu TLS libary is not present, i.e. HAVE_GNUTLS has not been defined. The intended behavior is such that calling the static callback handler function of the webserver guarantees that the user registered callback function is invoked. --- src/webserver.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/webserver.cpp b/src/webserver.cpp index f32b93b7..5e795608 100644 --- a/src/webserver.cpp +++ b/src/webserver.cpp @@ -182,7 +182,7 @@ void webserver::sweet_kill() { } void webserver::psk_cred_handler_func(void* cls, const struct MHD_Connection*, const char* username, void** psk, size_t* psk_size) { - std::string key = std::invoke(static_cast(cls)->psk_cred_handler,username); + [[maybe_unused]] std::string key = std::invoke(static_cast(cls)->psk_cred_handler,username); #ifdef HAVE_GNUTLS *psk_size = key.length(); From 0e24af6e6e2eebbc9fda88113e691e551c6c5348 Mon Sep 17 00:00:00 2001 From: oberdorc <96446443+oberdorc@users.noreply.github.com> Date: Sun, 3 Mar 2024 23:42:40 +0100 Subject: [PATCH 06/18] Update webserver.cpp --- src/webserver.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/webserver.cpp b/src/webserver.cpp index 5e795608..f3eb444f 100644 --- a/src/webserver.cpp +++ b/src/webserver.cpp @@ -48,7 +48,7 @@ #include #ifdef HAVE_GNUTLS -#include +#include #endif #include "httpserver/create_webserver.hpp" From d6d0c478bfd1b56f25a35aa2f7e12f03bce175b6 Mon Sep 17 00:00:00 2001 From: oberdorc <96446443+oberdorc@users.noreply.github.com> Date: Sun, 3 Mar 2024 23:43:29 +0100 Subject: [PATCH 07/18] Update webserver.cpp --- src/webserver.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/webserver.cpp b/src/webserver.cpp index f3eb444f..123f45a8 100644 --- a/src/webserver.cpp +++ b/src/webserver.cpp @@ -48,7 +48,7 @@ #include #ifdef HAVE_GNUTLS -#include +#include #endif #include "httpserver/create_webserver.hpp" From 2c46df55b0c1138c8b057b430fcb7d3f8a01a166 Mon Sep 17 00:00:00 2001 From: oberdorc <96446443+oberdorc@users.noreply.github.com> Date: Tue, 5 Mar 2024 19:39:12 +0100 Subject: [PATCH 08/18] Update minimal_https_psk.cpp Obviously, the example fails to run if enumaration values in _enum htttp:http_utils:cred_type_T_ are not defined. I would think the condtional compilation here is not a good idea. Anyhow. Without HAVE_GNUTLS beeing defined, the example will now compile but always returns with an error. --- examples/minimal_https_psk.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/examples/minimal_https_psk.cpp b/examples/minimal_https_psk.cpp index bee12be4..6dfd3265 100644 --- a/examples/minimal_https_psk.cpp +++ b/examples/minimal_https_psk.cpp @@ -45,6 +45,7 @@ std::string psk_callback(const std::string& username) int main() { +#ifdef HAVE_GNUTLS webserver ws = create_webserver(8080) .use_ssl() @@ -57,4 +58,7 @@ int main() ws.start(true); return 0; + #else + return -1; + #endif } From c60071d0a52bcb5cc80be2938b3e56509aec4200 Mon Sep 17 00:00:00 2001 From: oberdorc <96446443+oberdorc@users.noreply.github.com> Date: Tue, 12 Mar 2024 17:51:19 +0100 Subject: [PATCH 09/18] Update Makefile.am Set library dependency for Gnu TLS if it is present. --- examples/Makefile.am | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/examples/Makefile.am b/examples/Makefile.am index f0e64626..681dac49 100644 --- a/examples/Makefile.am +++ b/examples/Makefile.am @@ -17,6 +17,11 @@ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA LDADD = $(top_builddir)/src/libhttpserver.la + +if HAVE_GNUTLS +LDADD += -lgnutls +endif + 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_https_psk minimal_file_response minimal_deferred url_registration minimal_ip_ban benchmark_select benchmark_threads benchmark_nodelay deferred_with_accumulator file_upload From 5eb1f03add6dff3330007e47456b5203d8b6efc4 Mon Sep 17 00:00:00 2001 From: oberdorc Date: Tue, 12 Mar 2024 18:19:37 +0100 Subject: [PATCH 10/18] Added conditional for Gnu TLS. --- configure.ac | 2 ++ 1 file changed, 2 insertions(+) diff --git a/configure.ac b/configure.ac index b3ce5c89..eb243a15 100644 --- a/configure.ac +++ b/configure.ac @@ -250,6 +250,8 @@ if test "x$have_gnutls" = "xyes"; then AM_CFLAGS="$AM_CFLAGS -DHAVE_GNUTLS" fi +AM_CONDITIONAL([HAVE_GNUTLS], [test "x$have_gnutls" = "xyes"]) + DX_HTML_FEATURE(ON) DX_CHM_FEATURE(OFF) DX_CHI_FEATURE(OFF) From beb773278f05007f2150f82feca0462c72dcc379 Mon Sep 17 00:00:00 2001 From: oberdorc <96446443+oberdorc@users.noreply.github.com> Date: Tue, 12 Mar 2024 18:44:07 +0100 Subject: [PATCH 11/18] Update Makefile.am Added conditional for Gnu TLS. --- test/Makefile.am | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/test/Makefile.am b/test/Makefile.am index 68ddb554..d8a780e2 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -17,6 +17,11 @@ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA LDADD = $(top_builddir)/src/libhttpserver.la + +if HAVE_GNUTLS +LDADD += -lgnutls +endif + AM_CPPFLAGS = -I$(top_srcdir)/src -I$(top_srcdir)/src/httpserver/ METASOURCES = AUTO check_PROGRAMS = basic file_upload http_utils threaded nodelay string_utilities http_endpoint ban_system ws_start_stop authentication deferred http_resource From 7f7920208d9a0accd60a5ad150eab946c2d844b3 Mon Sep 17 00:00:00 2001 From: oberdorc <96446443+oberdorc@users.noreply.github.com> Date: Wed, 13 Mar 2024 20:35:49 +0100 Subject: [PATCH 12/18] Update minimal_https_psk.cpp Correct for formatting issues highlighted by cpplint. --- examples/minimal_https_psk.cpp | 28 +++++++++++----------------- 1 file changed, 11 insertions(+), 17 deletions(-) diff --git a/examples/minimal_https_psk.cpp b/examples/minimal_https_psk.cpp index 6dfd3265..8f7c7e73 100644 --- a/examples/minimal_https_psk.cpp +++ b/examples/minimal_https_psk.cpp @@ -19,20 +19,15 @@ #include -using namespace httpserver; - -class hello_world_resource : public http_resource -{ - public: - std::shared_ptr render(const http_request&) - { - return std::shared_ptr( +class hello_world_resource : public httpserver::http_resource { + public: + std::shared_ptr render(const httpserver::http_request&) { + return std::shared_ptr( new string_response("Hello, World!")); } }; -std::string psk_callback(const std::string& username) -{ +std::string psk_callback(const std::string& username) { // Known identity from the database. auto identity = std::string {"oFWv9Cv3N9tUsm"}; @@ -43,14 +38,13 @@ std::string psk_callback(const std::string& username) return (username == identity) ? key : std::string {}; } -int main() -{ +int main() { #ifdef HAVE_GNUTLS - webserver ws = - create_webserver(8080) + httpserver::webserver ws = + httpserver::create_webserver(8080) .use_ssl() .https_priorities("NORMAL:+PSK:+ECDHE-PSK:+DHE-PSK") - .cred_type(http::http_utils::PSK) + .cred_type(httpserver::http::http_utils::PSK) .psk_cred_handler(psk_callback); hello_world_resource hwr; @@ -58,7 +52,7 @@ int main() ws.start(true); return 0; - #else +#else return -1; - #endif +#endif } From 454447f60b5f7a51fd1bd8570d63601b7122708e Mon Sep 17 00:00:00 2001 From: oberdorc <96446443+oberdorc@users.noreply.github.com> Date: Wed, 13 Mar 2024 20:39:16 +0100 Subject: [PATCH 13/18] Update create_webserver.hpp Correct for formatting issues highlighted by cpplint. --- src/httpserver/create_webserver.hpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/httpserver/create_webserver.hpp b/src/httpserver/create_webserver.hpp index 2134d4c4..12b6b2c7 100644 --- a/src/httpserver/create_webserver.hpp +++ b/src/httpserver/create_webserver.hpp @@ -30,6 +30,7 @@ #include #include #include +#include #include "httpserver/http_response.hpp" #include "httpserver/http_utils.hpp" @@ -216,10 +217,10 @@ class create_webserver { } create_webserver& psk_cred_handler(psk_cred_handler_callback handler) { - _psk_cred_handler = std::move(handler); + _psk_cred_handler = std::move(handler); return *this; } - + create_webserver& https_priorities(const std::string& https_priorities) { _https_priorities = https_priorities; return *this; From 6db40996fbf71ec2e4e1cd23b52f2a6ac6c1989b Mon Sep 17 00:00:00 2001 From: oberdorc <96446443+oberdorc@users.noreply.github.com> Date: Wed, 13 Mar 2024 20:41:58 +0100 Subject: [PATCH 14/18] Update webserver.cpp Correct for formatting issues highlighted by cpplint. --- src/webserver.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/webserver.cpp b/src/webserver.cpp index 123f45a8..d9c4ef3b 100644 --- a/src/webserver.cpp +++ b/src/webserver.cpp @@ -182,13 +182,13 @@ void webserver::sweet_kill() { } void webserver::psk_cred_handler_func(void* cls, const struct MHD_Connection*, const char* username, void** psk, size_t* psk_size) { - [[maybe_unused]] std::string key = std::invoke(static_cast(cls)->psk_cred_handler,username); + [[maybe_unused]] std::string key = std::invoke(static_cast(cls)->psk_cred_handler, username); #ifdef HAVE_GNUTLS *psk_size = key.length(); *psk = malloc(*psk_size); - if (gnutls_hex2bin(key.data(),key.length(),*psk,psk_size) != GNUTLS_E_SUCCESS) + if (gnutls_hex2bin(key.data(), key.length(), *psk,psk_size) != GNUTLS_E_SUCCESS) *psk_size = 0; #endif } @@ -227,7 +227,7 @@ bool webserver::start(bool blocking) { } gen; vector iov; - // Must be assigned first to options to ensure that all output is handled by external logger! + // Must be assigned first to options to ensure that all output is handled by external logger! iov.push_back(gen(MHD_OPTION_EXTERNAL_LOGGER, (intptr_t) &error_log, this)); iov.push_back(gen(MHD_OPTION_NOTIFY_COMPLETED, (intptr_t) &request_completed, nullptr)); @@ -295,9 +295,9 @@ bool webserver::start(bool blocking) { if (cred_type != http_utils::NONE && use_ssl) { iov.push_back(gen(MHD_OPTION_HTTPS_CRED_TYPE, cred_type)); } - + if (psk_cred_handler && use_ssl) { - iov.push_back(gen(MHD_OPTION_GNUTLS_PSK_CRED_HANDLER,(intptr_t) psk_cred_handler_func, this)); + iov.push_back(gen(MHD_OPTION_GNUTLS_PSK_CRED_HANDLER, (intptr_t) psk_cred_handler_func, this)); } #endif // HAVE_GNUTLS From e069f45f0e5340671dd6d23df721b166c584e142 Mon Sep 17 00:00:00 2001 From: oberdorc <96446443+oberdorc@users.noreply.github.com> Date: Wed, 13 Mar 2024 20:57:04 +0100 Subject: [PATCH 15/18] Update minimal_https_psk.cpp --- examples/minimal_https_psk.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/minimal_https_psk.cpp b/examples/minimal_https_psk.cpp index 8f7c7e73..f00270d9 100644 --- a/examples/minimal_https_psk.cpp +++ b/examples/minimal_https_psk.cpp @@ -23,7 +23,7 @@ class hello_world_resource : public httpserver::http_resource { public: std::shared_ptr render(const httpserver::http_request&) { return std::shared_ptr( - new string_response("Hello, World!")); + new httpserver::string_response("Hello, World!")); } }; From dfe3045f6558d2d03d72cc954e2975a24c575ab2 Mon Sep 17 00:00:00 2001 From: oberdorc <96446443+oberdorc@users.noreply.github.com> Date: Wed, 13 Mar 2024 23:35:18 +0100 Subject: [PATCH 16/18] Update create_webserver.hpp Corrected for formatting issues highlighted by cpplint. --- src/httpserver/create_webserver.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/httpserver/create_webserver.hpp b/src/httpserver/create_webserver.hpp index 12b6b2c7..0a06c9cf 100644 --- a/src/httpserver/create_webserver.hpp +++ b/src/httpserver/create_webserver.hpp @@ -218,9 +218,9 @@ class create_webserver { create_webserver& psk_cred_handler(psk_cred_handler_callback handler) { _psk_cred_handler = std::move(handler); - return *this; + return *this; } - + create_webserver& https_priorities(const std::string& https_priorities) { _https_priorities = https_priorities; return *this; From 5b989770ad77ec8026b146f58c4b82306fd54619 Mon Sep 17 00:00:00 2001 From: oberdorc <96446443+oberdorc@users.noreply.github.com> Date: Thu, 14 Mar 2024 17:06:31 +0100 Subject: [PATCH 17/18] Update minimal_https_psk.cpp Fixing formatting issue highlighted by cpplint. --- examples/minimal_https_psk.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/minimal_https_psk.cpp b/examples/minimal_https_psk.cpp index f00270d9..605081e4 100644 --- a/examples/minimal_https_psk.cpp +++ b/examples/minimal_https_psk.cpp @@ -20,7 +20,7 @@ #include class hello_world_resource : public httpserver::http_resource { - public: + public: std::shared_ptr render(const httpserver::http_request&) { return std::shared_ptr( new httpserver::string_response("Hello, World!")); From 140094616561ae7414b14a275e7b81876f3be154 Mon Sep 17 00:00:00 2001 From: oberdorc <96446443+oberdorc@users.noreply.github.com> Date: Thu, 14 Mar 2024 18:43:47 +0100 Subject: [PATCH 18/18] Update webserver.cpp Correct for error from cpplint: "Missing space after , [whitespace/comma] [3]"