* Implemented simple daemon to receive requests and send responsesmaster
| @@ -0,0 +1,3 @@ | |||||
| [submodule "/home/bergmann/projects/dnpnode/projects/cppmicrohttpd/cmake/modules"] | |||||
| path = /home/bergmann/projects/dnpnode/projects/cppmicrohttpd/cmake/modules | |||||
| url = b3rgmann@git.bergmann89.de:cpp/CmakeModules.git | |||||
| @@ -0,0 +1,57 @@ | |||||
| # Initialize CMake ################################################################################ | |||||
| CMake_Minimum_Required ( VERSION 3.12.0 FATAL_ERROR ) | |||||
| # Set CMAKE_BUILD_TYPE | |||||
| If ( NOT CMAKE_BUILD_TYPE ) | |||||
| Set ( CMAKE_BUILD_TYPE "Release" CACHE STRING "Choose the type of build!" FORCE ) | |||||
| EndIf ( NOT CMAKE_BUILD_TYPE ) | |||||
| Set_Property ( CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS Debug Release RelWithDebInfo MinSizeRel ) | |||||
| # Set CMAKE_MODULE_PATH | |||||
| If ( EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/cmake/" ) | |||||
| Set ( CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} | |||||
| "${CMAKE_CURRENT_SOURCE_DIR}/cmake/" ) | |||||
| EndIf ( ) | |||||
| If ( EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/cmake/" ) | |||||
| Set ( CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} | |||||
| "${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules" ) | |||||
| EndIf ( ) | |||||
| # Project ######################################################################################### | |||||
| Include ( ${CMAKE_CURRENT_SOURCE_DIR}/cmake/cppmicrohttpd-var.cmake ) | |||||
| Include ( ${CMAKE_CURRENT_SOURCE_DIR}/cmake/cppmicrohttpd-options.cmake ) | |||||
| Project ( cppmicrohttpd | |||||
| DESCRIPTION "A simple library" | |||||
| VERSION "${CPPMICROHTTPD_VERSION}" ) | |||||
| Include ( CTest ) | |||||
| Include ( GNUInstallDirs ) | |||||
| # Subdirectories | |||||
| Add_SubDirectory ( ${CMAKE_CURRENT_SOURCE_DIR}/src ) | |||||
| Add_SubDirectory ( ${CMAKE_CURRENT_SOURCE_DIR}/test ) | |||||
| # Install | |||||
| Include ( CMakePackageConfigHelpers ) | |||||
| Write_Basic_Package_Version_File ( "${CMAKE_CURRENT_BINARY_DIR}/cmake/cppmicrohttpd-config-version.cmake" | |||||
| VERSION ${CPPMICROHTTPD_VERSION} | |||||
| COMPATIBILITY AnyNewerVersion ) | |||||
| Configure_File ( "${CMAKE_CURRENT_SOURCE_DIR}/cmake/cppmicrohttpd-config.cmake" | |||||
| "${CMAKE_CURRENT_BINARY_DIR}/cmake/cppmicrohttpd-config.cmake" | |||||
| @ONLY ) | |||||
| Set ( ConfigPackageLocation "${CPPMICROHTTPD_INSTALL_DIR_SHARE}/cmake" ) | |||||
| Install ( EXPORT | |||||
| cppmicrohttpd | |||||
| NAMESPACE | |||||
| cppmicrohttpd:: | |||||
| DESTINATION | |||||
| ${ConfigPackageLocation} ) | |||||
| Install ( FILES | |||||
| "${CMAKE_CURRENT_BINARY_DIR}/cmake/cppmicrohttpd-config.cmake" | |||||
| "${CMAKE_CURRENT_BINARY_DIR}/cmake/cppmicrohttpd-config-version.cmake" | |||||
| DESTINATION | |||||
| ${ConfigPackageLocation} | |||||
| COMPONENT | |||||
| Devel ) | |||||
| @@ -0,0 +1,10 @@ | |||||
| # cppmicrohttpd-config.cmake - package configuration file | |||||
| Message ( WARNING "Please configure the dependencies of this package!" ) | |||||
| # Include ( CMakeFindDependencyMacro ) | |||||
| # Find_Dependency ( <dependency> ) | |||||
| Include ( FindPackageHandleStandardArgs ) | |||||
| Set ( ${CMAKE_FIND_PACKAGE_NAME}_CONFIG ${CMAKE_CURRENT_LIST_FILE} ) | |||||
| Find_Package_Handle_Standard_Args ( cppmicrohttpd CONFIG_MODE ) | |||||
| Include ( "${CMAKE_CURRENT_LIST_DIR}/cppmicrohttpd.cmake") | |||||
| @@ -0,0 +1,15 @@ | |||||
| Option ( CPPMICROHTTPD_INSTALL_HEADER | |||||
| "Install headers of cppmicrohttpd." | |||||
| ON ) | |||||
| Option ( CPPMICROHTTPD_INSTALL_STATIC | |||||
| "Install static library of cppmicrohttpd." | |||||
| ON ) | |||||
| Option ( CPPMICROHTTPD_INSTALL_SHARED | |||||
| "Install shared library of cppmicrohttpd." | |||||
| ON ) | |||||
| Option ( CPPMICROHTTPD_INSTALL_DEBUG | |||||
| "Install the stripped debug informations of cppmicrohttpd." | |||||
| OFF ) | |||||
| Option ( CPPMICROHTTPD_NO_STRIP | |||||
| "Do not strip debug symbols from binary." | |||||
| OFF ) | |||||
| @@ -0,0 +1,31 @@ | |||||
| # Version | |||||
| Set ( CPPMICROHTTPD_VERSION_MAJOR 1 ) | |||||
| Set ( CPPMICROHTTPD_VERSION_MINOR 0 ) | |||||
| Set ( CPPMICROHTTPD_VERSION_PATCH 0 ) | |||||
| Set ( CPPMICROHTTPD_VERSION_BUILD 0 ) | |||||
| Set ( CPPMICROHTTPD_VERSION_SHORT "${CPPMICROHTTPD_VERSION_MAJOR}.${CPPMICROHTTPD_VERSION_MINOR}" ) | |||||
| Set ( CPPMICROHTTPD_VERSION "${CPPMICROHTTPD_VERSION_SHORT}.${CPPMICROHTTPD_VERSION_PATCH}.${CPPMICROHTTPD_VERSION_BUILD}" ) | |||||
| Set ( CPPMICROHTTPD_NAME "cppmicrohttpd-${CPPMICROHTTPD_VERSION_SHORT}" ) | |||||
| Set ( CPPMICROHTTPD_OUTPUTNAME "cppmicrohttpd" ) | |||||
| # Install directories | |||||
| Set ( CPPMICROHTTPD_INSTALL_DIR_INCLUDE "include/${CPPMICROHTTPD_NAME}" ) | |||||
| Set ( CPPMICROHTTPD_INSTALL_DIR_LIB "lib" ) | |||||
| Set ( CPPMICROHTTPD_INSTALL_DIR_SHARE "share/${CPPMICROHTTPD_NAME}" ) | |||||
| # C Standard | |||||
| Set ( CMAKE_C_STANDARD 11 ) | |||||
| Set ( CMAKE_CXX_STANDARD 17 ) | |||||
| Set ( CMAKE_C_STANDARD_REQUIRED ON ) | |||||
| Set ( CMAKE_CXX_STANDARD_REQUIRED ON ) | |||||
| # Git Version | |||||
| Include ( git_helper OPTIONAL RESULT_VARIABLE HAS_GIT_HELPER ) | |||||
| If ( HAS_GIT_HELPER ) | |||||
| GitGetVersion ( ${CMAKE_CURRENT_LIST_DIR}/.. | |||||
| CPPMICROHTTPD_VERSION_MAJOR | |||||
| CPPMICROHTTPD_VERSION_MINOR | |||||
| CPPMICROHTTPD_VERSION_PATCH | |||||
| CPPMICROHTTPD_VERSION_BUILD | |||||
| CPPMICROHTTPD_VERSION_HASH ) | |||||
| EndIf ( ) | |||||
| @@ -0,0 +1 @@ | |||||
| Subproject commit 1a32531aef2deeebd5637b1873bc4e976628801c | |||||
| @@ -0,0 +1,9 @@ | |||||
| #pragma once | |||||
| #include <cppmicrohttpd/daemon.h> | |||||
| #include <cppmicrohttpd/request.h> | |||||
| #include <cppmicrohttpd/response.h> | |||||
| #include <cppmicrohttpd/types.h> | |||||
| #include <cppmicrohttpd/daemon.inl> | |||||
| #include <cppmicrohttpd/types.inl> | |||||
| @@ -0,0 +1,134 @@ | |||||
| #pragma once | |||||
| #include <memory> | |||||
| #include <microhttpd.h> | |||||
| #include "types.h" | |||||
| #include "request/request.h" | |||||
| #include "response/response.h" | |||||
| namespace cppmicrohttpd | |||||
| { | |||||
| /** | |||||
| * @brief A simple HTTP daemon. | |||||
| */ | |||||
| struct daemon | |||||
| { | |||||
| public: | |||||
| using mhd_daemon_ptr_u = std::unique_ptr<MHD_Daemon, decltype(&MHD_stop_daemon)>; | |||||
| private: | |||||
| mhd_daemon_ptr_u _handle; //!< MHD handle | |||||
| public: | |||||
| /** | |||||
| * @brief Constructor. | |||||
| * | |||||
| * @param[in] port Port to open HTTP daemon on. | |||||
| * @param[in] flags Flags to create the daemon with. | |||||
| * @param[in] callbacks Flags that tell the daemon which callbacks should be registered. | |||||
| */ | |||||
| daemon( | |||||
| uint16_t port, | |||||
| const daemon_flags& flags, | |||||
| const callback_flags& callbacks = callback_flags::empty()); | |||||
| /** | |||||
| * @brief Destructor. | |||||
| */ | |||||
| virtual ~daemon() = default; | |||||
| /** | |||||
| * @brief Get the internal MHD handle. | |||||
| */ | |||||
| inline MHD_Daemon * handle() const; | |||||
| /** | |||||
| * @brief Run webserver operations (without blocking unless in client callbacks). | |||||
| */ | |||||
| inline void run(); | |||||
| /** | |||||
| * @brief Run webserver operations using the given sets of ready socket handles. | |||||
| * | |||||
| * @param[in] read File descriptor set with all file handles that are ready to read data from. | |||||
| * @param[in] write File descriptor set with all file handles that are ready to write data to. | |||||
| * @param[in] except File descriptor set with all file handles that are in a exceptional condition. | |||||
| */ | |||||
| inline void run(const fd_set& read, const fd_set& write, const fd_set& except); | |||||
| /** | |||||
| * @brief Write all file descriptors known by the daemon to the passed file descriptor sets. | |||||
| * | |||||
| * @param[in] read File descriptor set to listen for read operations. | |||||
| * @param[in] write File descriptor set to listen for write operations. | |||||
| * @param[in] except File descriptor set to listen for exceptional condition. | |||||
| * | |||||
| * @return Greatest file descriptor. | |||||
| */ | |||||
| inline int prepare_fd_sets(fd_set& read, fd_set& write, fd_set& except) const; | |||||
| /** | |||||
| * @brief Get the timeout in milliseconds to wait for the file descriptors. | |||||
| * | |||||
| * @return Timeout how many milliseconds select should at most block. | |||||
| */ | |||||
| inline unsigned long long get_timeout() const; | |||||
| protected: | |||||
| /** | |||||
| * @brief Create a new request for the passed arguments | |||||
| * | |||||
| * @param[in] p_connection Connection this request was reveiced at. | |||||
| * @param[in] p_url The URL requested by the client. | |||||
| * @param[in] p_method The HTTP method used by the client. | |||||
| * @param[in] p_version The HTTP version string. | |||||
| * | |||||
| * @return The created request. | |||||
| */ | |||||
| virtual request_ptr_u create_request( | |||||
| MHD_Connection * const p_connection, | |||||
| const char * const p_url, | |||||
| const char * const p_method, | |||||
| const char * const p_version); | |||||
| /** | |||||
| * @brief Create a response for the given request. | |||||
| * | |||||
| * @param[in] p_request Request to create response for. | |||||
| * | |||||
| * @return The created response. | |||||
| */ | |||||
| virtual response_ptr_u create_response( | |||||
| const request& p_request); | |||||
| public: | |||||
| /** | |||||
| * @brief Callback to handle requests. | |||||
| * | |||||
| * @param[in] cls User pointer passed to MHD. | |||||
| * @param[in] connection Connection the request was received at. | |||||
| * @param[in] url The URL requested by the client. | |||||
| * @param[in] method The HTTP method used by the client. | |||||
| * @param[in] version The HTTP version string. | |||||
| * @param[in] post_data The data being uploaded (excluding headers). | |||||
| * @param[in] data_size Number of bytes stored in post_data. | |||||
| * @param[in] con_cls User pointer to use for the connection. | |||||
| * | |||||
| * @return MHD_YES on success, MHD_NO on fatal error. | |||||
| */ | |||||
| static int mhd_access_handler_callback( | |||||
| void * cls, | |||||
| struct MHD_Connection * connection, | |||||
| const char * url, | |||||
| const char * method, | |||||
| const char * version, | |||||
| const char * post_data, | |||||
| size_t * data_size, | |||||
| void ** con_cls); | |||||
| }; | |||||
| } | |||||
| #include "daemon.inl" | |||||
| @@ -0,0 +1,41 @@ | |||||
| #pragma once | |||||
| #include "daemon.h" | |||||
| namespace cppmicrohttpd | |||||
| { | |||||
| /* daemon */ | |||||
| MHD_Daemon * daemon::handle() const | |||||
| { return _handle.get(); } | |||||
| void daemon::run() | |||||
| { | |||||
| if (MHD_run(_handle.get()) != MHD_YES) | |||||
| throw exception("Unable to execute MHD_run"); | |||||
| } | |||||
| void daemon::run(const fd_set& read, const fd_set& write, const fd_set& except) | |||||
| { | |||||
| if (MHD_run_from_select(_handle.get(), &read, &write, &except) != MHD_YES) | |||||
| throw exception("Unable to execute MHD_run_from_select"); | |||||
| } | |||||
| int daemon::prepare_fd_sets(fd_set& read, fd_set& write, fd_set& except) const | |||||
| { | |||||
| int ret = 0; | |||||
| if (MHD_get_fdset(_handle.get(), &read, &write, &except, &ret) != MHD_YES) | |||||
| throw exception("Unable to execute MHD_get_fdset"); | |||||
| return ret; | |||||
| } | |||||
| unsigned long long daemon::get_timeout() const | |||||
| { | |||||
| unsigned long long timeout = 0; | |||||
| if (MHD_get_timeout(_handle.get(), &timeout) != MHD_YES) | |||||
| throw exception("Unable to execute MHD_get_timeout"); | |||||
| return timeout; | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,8 @@ | |||||
| #pragma once | |||||
| #include "request/request.h" | |||||
| #include "request/post_data_request.h" | |||||
| #include "request/ignore_post_data_request.h" | |||||
| #include "request/request.inl" | |||||
| #include "request/post_data_request.inl" | |||||
| @@ -0,0 +1,30 @@ | |||||
| #pragma once | |||||
| #include "request.h" | |||||
| namespace cppmicrohttpd | |||||
| { | |||||
| /** | |||||
| * @brief Request class to completely ignore the uploaded data. | |||||
| */ | |||||
| struct ignore_post_data_request | |||||
| : public request | |||||
| { | |||||
| public: | |||||
| using request::request; | |||||
| /** | |||||
| * @brief Handle uploaded data. | |||||
| * | |||||
| * @param[in] p_data Received post data. | |||||
| * @param[in,out] p_size Number of bytes stored in postData. | |||||
| * | |||||
| * @retval true If the request is not yet finished. | |||||
| * @retval false If the request is finished. | |||||
| */ | |||||
| bool handle_post_pata( | |||||
| const void * p_data, | |||||
| size_t& p_size) override; | |||||
| }; | |||||
| } | |||||
| @@ -0,0 +1,107 @@ | |||||
| #pragma once | |||||
| #include "request.h" | |||||
| namespace cppmicrohttpd | |||||
| { | |||||
| /** | |||||
| * @brief Abstract request class to handle uploaded data. | |||||
| */ | |||||
| struct post_data_request | |||||
| : public request | |||||
| { | |||||
| private: | |||||
| using post_processor_ptr_u = std::unique_ptr<MHD_PostProcessor, decltype(&MHD_destroy_post_processor)>; | |||||
| private: | |||||
| post_processor_ptr_u _post_processor; //!< Post processor to handle uploaded data | |||||
| size_t _buffer_size; //!< Size of the internal post data buffer | |||||
| public: | |||||
| /** | |||||
| * @brief Constructor. | |||||
| * | |||||
| * @param[in] p_connection Connection this request was received at. | |||||
| * @param[in] p_url The URL requested by the client. | |||||
| * @param[in] p_method The HTTP method used by the client. | |||||
| * @param[in] p_version The HTTP version string. | |||||
| * @param[in] p_buffer_size Size of the internal post data buffer. | |||||
| * A tiny value e.g. 256 to 1024 should be sufficient, do NOT use a value smaller than 256. | |||||
| * For good performance, use 32k or 64k. | |||||
| */ | |||||
| inline post_data_request( | |||||
| MHD_Connection * const p_connection, | |||||
| const std::string& p_url, | |||||
| const std::string& p_method, | |||||
| const std::string& p_version, | |||||
| size_t p_buffer_size); | |||||
| /** | |||||
| * @brief Handle uploaded data. | |||||
| * | |||||
| * @param[in] p_data Received post data. | |||||
| * @param[in,out] p_size Number of bytes stored in postData. | |||||
| * | |||||
| * @retval true If the request is not yet finished. | |||||
| * @retval false If the request is finished. | |||||
| */ | |||||
| bool handle_post_pata( | |||||
| const void * p_data, | |||||
| size_t& p_size) override; | |||||
| private: | |||||
| /** | |||||
| * @brief Handle procesed post data from the post processor. | |||||
| * | |||||
| * @param[in] kind Type of the value. | |||||
| * @param[in] key Zero-terminated key for the value. | |||||
| * @param[in] filename Name of the uploaded file, NULL if not known. | |||||
| * @param[in] content_type Mime-type of the data, NULL if not known. | |||||
| * @param[in] transfer_encoding Encoding of the data, NULL if not known. | |||||
| * @param[in] data Pointer to size bytes of data at the specified offset. | |||||
| * @param[in] off Offset of data in the overall value. | |||||
| * @param[in] size Number of bytes in data available. | |||||
| * | |||||
| * @retval MHD_YES If the processing of the data was successful. | |||||
| * @retval MHD_NO If the processing of the data has failed. | |||||
| */ | |||||
| virtual int handle_processed_post_data( | |||||
| enum MHD_ValueKind kind, | |||||
| const char * key, | |||||
| const char * filename, | |||||
| const char * content_type, | |||||
| const char * transfer_encoding, | |||||
| const char * data, | |||||
| uint64_t off, | |||||
| size_t size) = 0; | |||||
| private: | |||||
| /** | |||||
| * @brief Callback to handle procesed post data. | |||||
| * | |||||
| * @param[in] cls Custom value selected at callback registration time. | |||||
| * @param[in] kind Type of the value. | |||||
| * @param[in] key Zero-terminated key for the value. | |||||
| * @param[in] filename Name of the uploaded file, NULL if not known. | |||||
| * @param[in] content_type Mime-type of the data, NULL if not known. | |||||
| * @param[in] transfer_encoding Encoding of the data, NULL if not known. | |||||
| * @param[in] data Pointer to size bytes of data at the specified offset. | |||||
| * @param[in] off Offset of data in the overall value. | |||||
| * @param[in] size Number of bytes in data available. | |||||
| * | |||||
| * @retval MHD_YES If the processing of the data was successful. | |||||
| * @retval MHD_NO If the processing of the data has failed. | |||||
| */ | |||||
| static int mhd_post_data_iterator_callback( | |||||
| void * cls, | |||||
| enum MHD_ValueKind kind, | |||||
| const char * key, | |||||
| const char * filename, | |||||
| const char * content_type, | |||||
| const char * transfer_encoding, | |||||
| const char * data, | |||||
| uint64_t off, | |||||
| size_t size); | |||||
| }; | |||||
| } | |||||
| @@ -0,0 +1,21 @@ | |||||
| #pragma once | |||||
| #include "post_data_request.h" | |||||
| namespace cppmicrohttpd | |||||
| { | |||||
| /* post_data_request */ | |||||
| post_data_request::post_data_request( | |||||
| MHD_Connection * const p_connection, | |||||
| const std::string& p_url, | |||||
| const std::string& p_method, | |||||
| const std::string& p_version, | |||||
| size_t p_buffer_size) | |||||
| : request (p_connection, p_url, p_method, p_version) | |||||
| , _post_processor (nullptr, &MHD_destroy_post_processor) | |||||
| , _buffer_size (p_buffer_size) | |||||
| { } | |||||
| } | |||||
| @@ -0,0 +1,76 @@ | |||||
| #pragma once | |||||
| #include <string> | |||||
| #include <memory> | |||||
| #include <microhttpd.h> | |||||
| #include "../types.h" | |||||
| #include "../response/response.h" | |||||
| namespace cppmicrohttpd | |||||
| { | |||||
| struct request; | |||||
| using request_ptr_u = std::unique_ptr<request>; | |||||
| /** | |||||
| * @brief Abstract request class. | |||||
| */ | |||||
| struct request | |||||
| { | |||||
| private: | |||||
| using exception_ptr_u = std::unique_ptr<std::exception>; | |||||
| public: | |||||
| MHD_Connection * const connection; //!< Connection this request was received at. | |||||
| const std::string url; //!< The URL requested by the client. | |||||
| const std::string method; //!< The HTTP method used by the client. | |||||
| const std::string version; //!< The HTTP version string. | |||||
| response_ptr_u response; //!< Response assigned to this request. | |||||
| exception_ptr_u error; //!< Error that occured during the request was handled. | |||||
| public: | |||||
| /** | |||||
| * @brief Constructor. | |||||
| * | |||||
| * @param[in] p_connection Connection this request was received at. | |||||
| * @param[in] p_url The URL requested by the client. | |||||
| * @param[in] p_method The HTTP method used by the client. | |||||
| * @param[in] p_version The HTTP version string. | |||||
| */ | |||||
| inline request( | |||||
| MHD_Connection * const p_connection, | |||||
| const std::string& p_url, | |||||
| const std::string& p_method, | |||||
| const std::string& p_version); | |||||
| /** | |||||
| * @brief Destructor. | |||||
| */ | |||||
| virtual ~request() = default; | |||||
| /** | |||||
| * @brief Set HTTP error, if an error is already set, the new error is ignored. | |||||
| * | |||||
| * @param[in] p_error Http error to set. | |||||
| */ | |||||
| template<typename T_exception> | |||||
| inline void set_error(const T_exception& p_error); | |||||
| /** | |||||
| * @brief Handle uploaded data. | |||||
| * | |||||
| * @param[in] p_data Received post data. | |||||
| * @param[in,out] p_size Number of bytes stored in postData. | |||||
| * | |||||
| * @retval true If the request is not yet finished. | |||||
| * @retval false If the request is finished. | |||||
| */ | |||||
| virtual bool handle_post_pata( | |||||
| const void * p_data, | |||||
| size_t& p_size); | |||||
| }; | |||||
| } | |||||
| @@ -0,0 +1,26 @@ | |||||
| #pragma once | |||||
| #include "request.h" | |||||
| namespace cppmicrohttpd | |||||
| { | |||||
| request::request( | |||||
| MHD_Connection * const p_connection, | |||||
| const std::string& p_url, | |||||
| const std::string& p_method, | |||||
| const std::string& p_version) | |||||
| : connection(p_connection) | |||||
| , url (p_url) | |||||
| , method (p_method) | |||||
| , version (p_version) | |||||
| { } | |||||
| template<typename T_exception> | |||||
| void request::set_error(const T_exception& p_error) | |||||
| { | |||||
| if (!error) | |||||
| error.reset(new T_exception(p_error)); | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,11 @@ | |||||
| #pragma once | |||||
| #include "response/response.h" | |||||
| #include "response/buffer_response.h" | |||||
| #include "response/callback_response.h" | |||||
| #include "response/no_content_response.h" | |||||
| #include "response/response.inl" | |||||
| #include "response/buffer_response.inl" | |||||
| #include "response/callback_response.inl" | |||||
| #include "response/no_content_response.inl" | |||||
| @@ -0,0 +1,26 @@ | |||||
| #pragma once | |||||
| #include "response.h" | |||||
| namespace cppmicrohttpd | |||||
| { | |||||
| struct buffer_response | |||||
| : public response | |||||
| { | |||||
| public: | |||||
| const std::string buffer; //!< Content of the response | |||||
| public: | |||||
| /** | |||||
| * @brief Constructor. | |||||
| * | |||||
| * @param[in] p_request Request this response belongs to. | |||||
| * @param[in] p_buffer Buffer to send in this response. | |||||
| */ | |||||
| inline buffer_response( | |||||
| const request_t& p_request, | |||||
| const std::string& p_buffer); | |||||
| }; | |||||
| } | |||||
| @@ -0,0 +1,24 @@ | |||||
| #pragma once | |||||
| #include "buffer_response.h" | |||||
| namespace cppmicrohttpd | |||||
| { | |||||
| /* buffer_response */ | |||||
| buffer_response::buffer_response( | |||||
| const request_t& p_request, | |||||
| const std::string& p_buffer) | |||||
| : response (p_request) | |||||
| , buffer (p_buffer) | |||||
| { | |||||
| handle.reset(MHD_create_response_from_buffer( | |||||
| buffer.size(), | |||||
| const_cast<char*>(buffer.data()), | |||||
| MHD_RESPMEM_PERSISTENT)); | |||||
| if (!handle) | |||||
| throw exception("Unable to create buffer response"); | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,63 @@ | |||||
| #pragma once | |||||
| #include "response.h" | |||||
| namespace cppmicrohttpd | |||||
| { | |||||
| struct callback_response | |||||
| : public response | |||||
| { | |||||
| public: | |||||
| /** | |||||
| * @brief Constructor. | |||||
| * | |||||
| * @param[in] p_request Request this response belongs to. | |||||
| * @param[in] p_chunk_size Size of the chunk to use for reading data from the callback. | |||||
| * @param[in] p_response_size Total size of the response (-1 for unknown) | |||||
| */ | |||||
| inline callback_response( | |||||
| const request_t& p_request, | |||||
| size_t p_chunk_size, | |||||
| ssize_t p_response_size = -1); | |||||
| private: | |||||
| /** | |||||
| * @brief Handle read requests from MHD. | |||||
| * | |||||
| * @param[in] p_pos Total position inside the response data stream. | |||||
| * @param[in] p_buf Buffer to write requested data to. | |||||
| * @param[in] p_max Max number of bytes to write to p_buf. | |||||
| * | |||||
| * @return Number of bytes stored in buf. | |||||
| * | |||||
| * @retval MHD_CONTENT_READER_END_OF_STREAM If the stream is finished. | |||||
| * @retval MHD_CONTENT_READER_END_WITH_ERROR If an error occured. | |||||
| */ | |||||
| virtual ssize_t read_content( | |||||
| uint64_t p_pos, | |||||
| char * p_buf, | |||||
| size_t p_max) = 0; | |||||
| private: | |||||
| /** | |||||
| * @brief Handle read requests from MHD. | |||||
| * | |||||
| * @param[in] cls User pointer that was passed to the MHD response. | |||||
| * @param[in] pos Total position inside the response data stream. | |||||
| * @param[in] buf Buffer to write requested data to. | |||||
| * @param[in] max Max number of bytes to write to buf. | |||||
| * | |||||
| * @return Number of bytes stored in buf. | |||||
| * | |||||
| * @retval MHD_CONTENT_READER_END_OF_STREAM If the stream is finished. | |||||
| * @retval MHD_CONTENT_READER_END_WITH_ERROR If an error occured. | |||||
| */ | |||||
| static ssize_t mhd_content_reader_callback( | |||||
| void * cls, | |||||
| uint64_t pos, | |||||
| char * buf, | |||||
| size_t max); | |||||
| }; | |||||
| } | |||||
| @@ -0,0 +1,28 @@ | |||||
| #pragma once | |||||
| #include "response.h" | |||||
| namespace cppmicrohttpd | |||||
| { | |||||
| /* callback_response */ | |||||
| callback_response::callback_response( | |||||
| const request_t& p_request, | |||||
| size_t p_chunk_size, | |||||
| ssize_t p_response_size) | |||||
| : response(p_request) | |||||
| { | |||||
| handle.reset(MHD_create_response_from_callback( | |||||
| p_response_size >= 0 | |||||
| ? static_cast<size_t>(p_response_size) | |||||
| : MHD_SIZE_UNKNOWN, | |||||
| p_chunk_size, | |||||
| &callback_response::mhd_content_reader_callback, | |||||
| this, | |||||
| nullptr)); | |||||
| if (!handle) | |||||
| throw exception("Unable to create callback response"); | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,21 @@ | |||||
| #pragma once | |||||
| #include "buffer_response.h" | |||||
| namespace cppmicrohttpd | |||||
| { | |||||
| struct no_content_response | |||||
| : public buffer_response | |||||
| { | |||||
| public: | |||||
| /** | |||||
| * @brief Constructor. | |||||
| * | |||||
| * @param[in] p_request Request this response belongs to. | |||||
| */ | |||||
| inline no_content_response( | |||||
| const request_t& p_request); | |||||
| }; | |||||
| } | |||||
| @@ -0,0 +1,15 @@ | |||||
| #pragma once | |||||
| #include "no_content_response.h" | |||||
| namespace cppmicrohttpd | |||||
| { | |||||
| /* no_content_response */ | |||||
| no_content_response::no_content_response( | |||||
| const request_t& p_request) | |||||
| : buffer_response(p_request, std::string()) | |||||
| { status = MHD_HTTP_NO_CONTENT; } | |||||
| } | |||||
| @@ -0,0 +1,66 @@ | |||||
| #pragma once | |||||
| #include <memory> | |||||
| #include <microhttpd.h> | |||||
| namespace cppmicrohttpd | |||||
| { | |||||
| struct request; | |||||
| struct response; | |||||
| using response_ptr_u = std::unique_ptr<response>; | |||||
| struct response | |||||
| { | |||||
| public: | |||||
| using handle_ptr_u = std::unique_ptr<MHD_Response, decltype(&MHD_destroy_response)>; | |||||
| using request_t = ::cppmicrohttpd::request; | |||||
| public: | |||||
| const request_t& request; //!< Request this response belongs to. | |||||
| handle_ptr_u handle; //!< MHD response handle | |||||
| unsigned int status { 0 }; //!< HTTP status code | |||||
| public: | |||||
| /** | |||||
| * @brief Constructor. | |||||
| * | |||||
| * @param[in] p_request Request this response belongs to. | |||||
| */ | |||||
| inline response(const request_t& p_request); | |||||
| /** | |||||
| * @brief Destructor. | |||||
| */ | |||||
| virtual ~response() = default; | |||||
| /** | |||||
| * @brief Add header entry to the response. | |||||
| * | |||||
| * @param[in] key Header key. | |||||
| * @param[in] value Header value. | |||||
| */ | |||||
| inline void add_header(const char * key, const char * value); | |||||
| public: | |||||
| /** | |||||
| * @brief Create a simple HTML response. | |||||
| * | |||||
| * @param[in] p_request Reference to request. | |||||
| * @param[in] p_status HTTP status of the response. | |||||
| * @param[in] p_title Title of the HTML document. | |||||
| * @param[in] p_head Headline of the HTML document. | |||||
| * @param[in] p_msg Content of the HTML document. | |||||
| * | |||||
| * @return Created response. | |||||
| */ | |||||
| static response_ptr_u build_simple_html_response( | |||||
| const cppmicrohttpd::request& p_request, | |||||
| unsigned int p_status, | |||||
| const std::string& p_title, | |||||
| const std::string& p_head, | |||||
| const std::string& p_msg); | |||||
| }; | |||||
| } | |||||
| @@ -0,0 +1,22 @@ | |||||
| #pragma once | |||||
| #include "response.h" | |||||
| #include "../types.h" | |||||
| namespace cppmicrohttpd | |||||
| { | |||||
| /* response */ | |||||
| response::response(const request_t& p_request) | |||||
| : request (p_request) | |||||
| , handle (nullptr, &MHD_destroy_response) | |||||
| { } | |||||
| void response::add_header(const char * key, const char * value) | |||||
| { | |||||
| if (MHD_add_response_header(handle.get(), key, value) != MHD_YES) | |||||
| throw exception(std::string("Unable to add header entry in response: ") + key + "=" + value); | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,149 @@ | |||||
| #pragma once | |||||
| #include <microhttpd.h> | |||||
| #include <cppcore/misc/flags.h> | |||||
| #include <cppcore/misc/exception.h> | |||||
| namespace cppmicrohttpd | |||||
| { | |||||
| /** | |||||
| * @brief Flags to create the daemon with. | |||||
| */ | |||||
| enum class daemon_flag | |||||
| : unsigned int | |||||
| { | |||||
| /** | |||||
| * Run in debug mode. If this flag is used, the library should print error messages and warnings to stderr. | |||||
| * Note that for this run-time option to have any effect, MHD needs to be compiled with messages enabled. | |||||
| * This is done by default except you ran configure with the --disable-messages flag set. | |||||
| */ | |||||
| use_debug = MHD_USE_DEBUG, | |||||
| /** | |||||
| * Run in HTTPS-mode. If you specify MHD_USE_SSL and MHD was compiled without SSL support, MHD_start_daemon | |||||
| * will return NULL. | |||||
| */ | |||||
| use_ssl = MHD_USE_SSL, | |||||
| /** | |||||
| * Run using one thread per connection. | |||||
| */ | |||||
| use_thread_per_connection = MHD_USE_THREAD_PER_CONNECTION, | |||||
| /** | |||||
| * Run using an internal thread doing SELECT. | |||||
| */ | |||||
| use_select_internally = MHD_USE_SELECT_INTERNALLY, | |||||
| /** | |||||
| * Run using the IPv6 protocol (otherwise, MHD will just support IPv4). If you specify MHD_USE_IPV6 and the | |||||
| * local platform does not support it, MHD_start_daemon will return NULL. | |||||
| * | |||||
| * If you want MHD to support IPv4 and IPv6 using a single socket, pass MHD_USE_DUAL_STACK, otherwise, | |||||
| * if you only pass this option, MHD will try to bind to IPv6-only (resulting in no IPv4 support). | |||||
| */ | |||||
| use_ipv6 = MHD_USE_IPv6, | |||||
| /** | |||||
| * Use a single socket for IPv4 and IPv6. Note that this will mean that IPv4 addresses are returned by MHD in | |||||
| * the IPv6-mapped format (the ’struct sockaddr_in6’ format will be used for IPv4 and IPv6). | |||||
| */ | |||||
| use_dual_stack = MHD_USE_DUAL_STACK, | |||||
| /** | |||||
| * Be pedantic about the protocol (as opposed to as tolerant as possible). Specifically, at the moment, | |||||
| * this flag causes MHD to reject HTTP 1.1 connections without a Host header. This is required by the standard, | |||||
| * but of course in violation of the “be as liberal as possible in what you accept” norm. It is recommended to | |||||
| * turn this ON if you are testing clients against MHD, and OFF in production. | |||||
| */ | |||||
| use_pedantic_checks = MHD_USE_PEDANTIC_CHECKS, | |||||
| /** | |||||
| * Use poll() instead of select(). This allows sockets with descriptors >= FD_SETSIZE. This option currently only | |||||
| * works in conjunction with MHD_USE_THREAD_PER_CONNECTION or MHD_USE_INTERNAL_SELECT (at this point). | |||||
| * If you specify MHD_USE_POLL and the local platform does not support it, MHD_start_daemon will return NULL. | |||||
| */ | |||||
| use_poll = MHD_USE_POLL, | |||||
| /** | |||||
| * Suppress (automatically) adding the ’Date:’ header to HTTP responses. This option should ONLY be used on | |||||
| * systems that do not have a clock and that DO provide other mechanisms for cache control. | |||||
| * See also RFC 2616, section 14.18 (exception 3). | |||||
| */ | |||||
| supress_date_no_clock = MHD_SUPPRESS_DATE_NO_CLOCK, | |||||
| /** | |||||
| * Run the HTTP server without any listen socket. This option only makes sense if MHD_add_connection is going | |||||
| * to be used exclusively to connect HTTP clients to the HTTP server. This option is incompatible with using | |||||
| * a thread pool; if it is used, MHD_OPTION_THREAD_POOL_SIZE is ignored. | |||||
| */ | |||||
| use_no_listen_socket = MHD_USE_NO_LISTEN_SOCKET, | |||||
| /** | |||||
| * Force MHD to use a signal pipe to notify the event loop (of threads) of our shutdown. This is required if | |||||
| * an appliction uses MHD_USE_INTERNAL_SELECT or MHD_USE_THREAD_PER_CONNECTION and then performs MHD_quiesce_daemon | |||||
| * (which eliminates our ability to signal termination via the listen socket). In these modes, MHD_quiesce_daemon | |||||
| * will fail if this option was not set. Also, use of this option is automatic (as in, you do not even have to | |||||
| * specify it), if MHD_USE_NO_LISTEN_SOCKET is specified. In "external" select mode, this option is always simply | |||||
| * ignored. | |||||
| * | |||||
| * Using this option also guarantees that MHD will not call shutdown() on the listen socket, which means a parent | |||||
| * process can continue to use the socket. | |||||
| */ | |||||
| use_pipe_for_shutdown = MHD_USE_PIPE_FOR_SHUTDOWN, | |||||
| /** | |||||
| * Enables using MHD_suspend_connection and MHD_resume_connection, as performing these calls requires some additional | |||||
| * pipes to be created, and code not using these calls should not pay the cost. | |||||
| */ | |||||
| use_suspend_resume = MHD_USE_SUSPEND_RESUME, | |||||
| /** | |||||
| * Enable TCP_FASTOPEN on the listen socket. TCP_FASTOPEN is currently supported on Linux >= 3.6. On other systems | |||||
| * using this option with cause MHD_start_daemon to fail. | |||||
| */ | |||||
| use_tcp_fastopen = MHD_USE_TCP_FASTOPEN, | |||||
| }; | |||||
| using daemon_flags = ::cppcore::simple_flags<daemon_flag>; | |||||
| /** | |||||
| * @brief Flag to indicate which callbacks should be registerd in MHC. | |||||
| */ | |||||
| enum class callback_flag | |||||
| { | |||||
| }; | |||||
| using callback_flags = ::cppcore::shifted_flags<callback_flag>; | |||||
| /** | |||||
| * @brief Exception with the error code and error string from the MHD library. | |||||
| */ | |||||
| struct exception | |||||
| : public ::cppcore::exception | |||||
| { | |||||
| public: | |||||
| using ::cppcore::exception::exception; | |||||
| }; | |||||
| struct http_exception | |||||
| : public ::cppcore::exception | |||||
| { | |||||
| uint status; //!< HTTP status code. | |||||
| /** | |||||
| * @brief Constructor. | |||||
| * | |||||
| * @param[in] p_status HTTP status code. | |||||
| * @param[in] p_message Actual error message. | |||||
| */ | |||||
| inline http_exception( | |||||
| uint p_status, | |||||
| const std::string& p_message); | |||||
| }; | |||||
| } | |||||
| #include "types.inl" | |||||
| @@ -0,0 +1,17 @@ | |||||
| #pragma once | |||||
| #include "types.h" | |||||
| namespace cppmicrohttpd | |||||
| { | |||||
| /* http_exception */ | |||||
| http_exception::http_exception( | |||||
| uint p_status, | |||||
| const std::string& p_message) | |||||
| : cppcore::exception(p_message) | |||||
| , status (p_status) | |||||
| { } | |||||
| } | |||||
| @@ -0,0 +1,107 @@ | |||||
| # Initialize ###################################################################################### | |||||
| Include ( cotire OPTIONAL RESULT_VARIABLE HAS_COTIRE ) | |||||
| Include ( pedantic OPTIONAL RESULT_VARIABLE HAS_PEDANTIC ) | |||||
| Include ( strip_symbols OPTIONAL RESULT_VARIABLE HAS_STRIP_SYMBOLS ) | |||||
| Find_Package ( cppcore REQUIRED ) | |||||
| # Object Library ################################################################################## | |||||
| Set ( CMAKE_POSITION_INDEPENDENT_CODE ON ) | |||||
| Set ( CPPMICROHTTPD_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../include ) | |||||
| File ( GLOB_RECURSE CPPMICROHTTPD_HEADER_FILES ${CPPMICROHTTPD_INCLUDE_DIR}/*.h ) | |||||
| File ( GLOB_RECURSE CPPMICROHTTPD_INLINE_FILES ${CPPMICROHTTPD_INCLUDE_DIR}/*.inl ) | |||||
| File ( GLOB_RECURSE CPPMICROHTTPD_SOURCE_FILES ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp ) | |||||
| Add_Library ( cppmicrohttpd-objects | |||||
| OBJECT | |||||
| ${CPPMICROHTTPD_HEADER_FILES} | |||||
| ${CPPMICROHTTPD_INLINE_FILES} | |||||
| ${CPPMICROHTTPD_SOURCE_FILES} ) | |||||
| Target_Include_Directories ( cppmicrohttpd-objects | |||||
| PUBLIC | |||||
| $<BUILD_INTERFACE:${CPPMICROHTTPD_INCLUDE_DIR}> | |||||
| $<INSTALL_INTERFACE:${CPPMICROHTTPD_INSTALL_DIR_INCLUDE}> ) | |||||
| Target_Link_Libraries ( cppmicrohttpd-objects | |||||
| PUBLIC | |||||
| cppcore::cppcore ) | |||||
| # Static Library ################################################################################## | |||||
| Add_Library ( cppmicrohttpd-static STATIC $<TARGET_OBJECTS:cppmicrohttpd-objects> ) | |||||
| Set_Target_Properties ( cppmicrohttpd-static | |||||
| PROPERTIES | |||||
| OUTPUT_NAME "${CPPMICROHTTPD_OUTPUTNAME}" | |||||
| VERSION ${CPPMICROHTTPD_VERSION} ) | |||||
| Target_Include_Directories ( cppmicrohttpd-static | |||||
| PUBLIC | |||||
| $<BUILD_INTERFACE:${CPPMICROHTTPD_INCLUDE_DIR}> | |||||
| $<INSTALL_INTERFACE:${CPPMICROHTTPD_INSTALL_DIR_INCLUDE}> ) | |||||
| Target_Link_Libraries ( cppmicrohttpd-static | |||||
| PUBLIC | |||||
| cppcore::cppcore ) | |||||
| # Shared Library ################################################################################## | |||||
| Add_Library ( cppmicrohttpd-shared SHARED $<TARGET_OBJECTS:cppmicrohttpd-objects> ) | |||||
| Set_Target_Properties ( cppmicrohttpd-shared | |||||
| PROPERTIES | |||||
| OUTPUT_NAME "${CPPMICROHTTPD_OUTPUTNAME}" | |||||
| VERSION ${CPPMICROHTTPD_VERSION} | |||||
| SOVERSION ${CPPMICROHTTPD_VERSION_SHORT} ) | |||||
| Target_Include_Directories ( cppmicrohttpd-shared | |||||
| PUBLIC | |||||
| $<BUILD_INTERFACE:${CPPMICROHTTPD_INCLUDE_DIR}> | |||||
| $<INSTALL_INTERFACE:${CPPMICROHTTPD_INSTALL_DIR_INCLUDE}> ) | |||||
| Target_Link_Libraries ( cppmicrohttpd-shared | |||||
| PUBLIC | |||||
| cppcore::cppcore ) | |||||
| # Optimization #################################################################################### | |||||
| # pedantic | |||||
| If ( HAS_PEDANTIC ) | |||||
| Pedantic_Apply_Flags_Target ( cppmicrohttpd-objects ALL ) | |||||
| Pedantic_Apply_Flags_Target ( cppmicrohttpd-static ALL ) | |||||
| Pedantic_Apply_Flags_Target ( cppmicrohttpd-shared ALL ) | |||||
| EndIf ( ) | |||||
| # cotire | |||||
| If ( HAS_COTIRE ) | |||||
| Cotire ( cppmicrohttpd-objects ) | |||||
| Cotire ( cppmicrohttpd-static ) | |||||
| Cotire ( cppmicrohttpd-shared ) | |||||
| EndIf ( ) | |||||
| # Install ######################################################################################### | |||||
| # Header | |||||
| If ( CPPMICROHTTPD_INSTALL_HEADER ) | |||||
| Install ( FILES ${CPPMICROHTTPD_INCLUDE_DIR}/cppmicrohttpd.h | |||||
| DESTINATION ${CPPMICROHTTPD_INSTALL_DIR_INCLUDE} ) | |||||
| Install ( DIRECTORY ${CPPMICROHTTPD_INCLUDE_DIR}/cppmicrohttpd | |||||
| DESTINATION ${CPPMICROHTTPD_INSTALL_DIR_INCLUDE} ) | |||||
| EndIf ( ) | |||||
| # Static | |||||
| If ( CPPMICROHTTPD_INSTALL_STATIC ) | |||||
| Install ( TARGETS cppmicrohttpd-static | |||||
| EXPORT cppmicrohttpd | |||||
| DESTINATION ${CPPMICROHTTPD_INSTALL_DIR_LIB} ) | |||||
| EndIf ( ) | |||||
| # Shared | |||||
| If ( CPPMICROHTTPD_INSTALL_SHARED ) | |||||
| Install ( TARGETS cppmicrohttpd-shared | |||||
| EXPORT cppmicrohttpd | |||||
| DESTINATION ${CPPMICROHTTPD_INSTALL_DIR_LIB} ) | |||||
| EndIf ( ) | |||||
| # Debug | |||||
| If ( HAS_STRIP_SYMBOLS AND NOT CPPMICROHTTPD_NO_STRIP ) | |||||
| Strip_Symbols ( cppmicrohttpd-shared CPPMICROHTTPD_DBG_FILE ) | |||||
| If ( CPPMICROHTTPD_INSTALL_DEBUG ) | |||||
| Install ( FILES ${CPPMICROHTTPD_DBG_FILE} | |||||
| DESTINATION ${CPPMICROHTTPD_INSTALL_DIR_LIB} ) | |||||
| EndIf ( ) | |||||
| EndIf ( ) | |||||
| @@ -0,0 +1,152 @@ | |||||
| #include <vector> | |||||
| #include <cppmicrohttpd/daemon.h> | |||||
| #include <cppmicrohttpd/request/request.inl> | |||||
| using namespace ::cppmicrohttpd; | |||||
| daemon::daemon( | |||||
| uint16_t port, | |||||
| const daemon_flags& flags, | |||||
| const callback_flags& callback) | |||||
| : _handle(nullptr, &MHD_stop_daemon) | |||||
| { | |||||
| std::vector<MHD_OptionItem> options; | |||||
| // TODO add more | |||||
| options.emplace_back(MHD_OptionItem { MHD_OPTION_END, 0, nullptr }); | |||||
| _handle.reset(MHD_start_daemon( | |||||
| static_cast<unsigned int>(flags), | |||||
| port, | |||||
| nullptr, | |||||
| nullptr, | |||||
| &daemon::mhd_access_handler_callback, | |||||
| this, | |||||
| MHD_OPTION_ARRAY, options.data(), | |||||
| MHD_OPTION_END)); | |||||
| if (!_handle) | |||||
| throw exception("Unable to create daemon"); | |||||
| } | |||||
| request_ptr_u daemon::create_request( | |||||
| MHD_Connection * const p_connection, | |||||
| const char * const p_url, | |||||
| const char * const p_method, | |||||
| const char * const p_version) | |||||
| { return std::make_unique<request>(p_connection, p_url, p_method, p_version); } | |||||
| response_ptr_u daemon::create_response( | |||||
| const request& p_request) | |||||
| { | |||||
| if (p_request.error) | |||||
| { | |||||
| /* TODO | |||||
| auto err = *request.httpError; | |||||
| return Response::buildSimpleHtmlResponse( | |||||
| request, | |||||
| err.status, | |||||
| err.title, | |||||
| err.head, | |||||
| err.message); | |||||
| */ | |||||
| } | |||||
| return nullptr; | |||||
| } | |||||
| int daemon::mhd_access_handler_callback( | |||||
| void * cls, | |||||
| struct MHD_Connection * connection, | |||||
| const char * url, | |||||
| const char * method, | |||||
| const char * version, | |||||
| const char * post_data, | |||||
| size_t * data_size, | |||||
| void ** con_cls) | |||||
| { | |||||
| if (!cls) | |||||
| return MHD_NO; | |||||
| if (!con_cls) | |||||
| return MHD_NO; | |||||
| auto& daemon = *static_cast<::cppmicrohttpd::daemon*>(cls); | |||||
| /* create request object */ | |||||
| try | |||||
| { | |||||
| if (!*con_cls) | |||||
| { | |||||
| auto tmp = daemon.create_request(connection, url, method, version); | |||||
| if (!tmp) | |||||
| throw exception("No request object was created"); | |||||
| *con_cls = tmp.release(); | |||||
| return MHD_YES; | |||||
| } | |||||
| } | |||||
| catch(...) | |||||
| { | |||||
| // TODO: log error | |||||
| return MHD_NO; | |||||
| } | |||||
| /* handle request data */ | |||||
| auto& req = *static_cast<request*>(*con_cls); | |||||
| try | |||||
| { | |||||
| if (req.handle_post_pata(post_data, *data_size)) | |||||
| return MHD_YES; | |||||
| } | |||||
| catch(const http_exception& ex) | |||||
| { | |||||
| req.set_error(ex); | |||||
| *data_size = 0; // Assume that all data has been progressed | |||||
| return MHD_YES; | |||||
| } | |||||
| catch(const exception& ex) | |||||
| { | |||||
| req.set_error(ex); | |||||
| *data_size = 0; // Assume that all data has been progressed | |||||
| return MHD_YES; | |||||
| } | |||||
| catch(std::exception& ex) | |||||
| { | |||||
| // TODO log error | |||||
| req.set_error(exception(ex.what())); | |||||
| *data_size = 0; // Assume that all data has been progressed | |||||
| return MHD_YES; | |||||
| } | |||||
| catch(...) | |||||
| { | |||||
| // TODO log error | |||||
| req.set_error(exception("Unknown error")); | |||||
| *data_size = 0; // Assume that all data has been progressed | |||||
| return MHD_YES; | |||||
| } | |||||
| /* create response object */ | |||||
| try | |||||
| { | |||||
| if (!req.response) | |||||
| { | |||||
| req.response = daemon.create_response(req); | |||||
| if (!req.response) | |||||
| throw exception("No response object was created"); | |||||
| auto& res = *req.response; | |||||
| if (MHD_queue_response(req.connection, res.status, res.handle.get()) != MHD_YES) | |||||
| throw exception("Unable to enqueue response"); | |||||
| } | |||||
| return MHD_YES; | |||||
| } | |||||
| catch(...) | |||||
| { | |||||
| // TODO log error | |||||
| return MHD_NO; | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,11 @@ | |||||
| #include <cppmicrohttpd/request/ignore_post_data_request.h> | |||||
| using namespace ::cppmicrohttpd; | |||||
| bool ignore_post_data_request::handle_post_pata( | |||||
| const void * p_data, | |||||
| size_t& p_size) | |||||
| { | |||||
| p_size = 0; | |||||
| return MHD_YES; | |||||
| } | |||||
| @@ -0,0 +1,79 @@ | |||||
| #include <cppmicrohttpd/request/post_data_request.h> | |||||
| #include <cppmicrohttpd/request/request.inl> | |||||
| using namespace ::cppmicrohttpd; | |||||
| bool post_data_request::handle_post_pata( | |||||
| const void * p_data, | |||||
| size_t& p_size) | |||||
| { | |||||
| /* check data size */ | |||||
| if (p_size <= 0) | |||||
| return false; | |||||
| /* lazy initialize the post processor */ | |||||
| if (!_post_processor) | |||||
| { | |||||
| _post_processor.reset(MHD_create_post_processor( | |||||
| connection, | |||||
| _buffer_size, | |||||
| &post_data_request::mhd_post_data_iterator_callback, | |||||
| this)); | |||||
| if (!_post_processor) | |||||
| throw exception("Unable to create post data processor!"); | |||||
| } | |||||
| /* execute post data processor */ | |||||
| auto ret = MHD_post_process(_post_processor.get(), static_cast<const char *>(p_data), p_size); | |||||
| p_size = 0; | |||||
| if (ret != MHD_YES) | |||||
| throw exception("Unable to handle post data!"); | |||||
| // libmicrohttpd requieres to process all post data before enqueue a response | |||||
| // so we always return "true" until all data has been processed | |||||
| // https://lists.gnu.org/archive/html/libmicrohttpd/2011-09/msg00028.html | |||||
| return true; | |||||
| } | |||||
| int post_data_request::mhd_post_data_iterator_callback( | |||||
| void * cls, | |||||
| enum MHD_ValueKind kind, | |||||
| const char * key, | |||||
| const char * filename, | |||||
| const char * content_type, | |||||
| const char * transfer_encoding, | |||||
| const char * data, | |||||
| uint64_t off, | |||||
| size_t size) | |||||
| { | |||||
| if (!cls) | |||||
| return MHD_NO; | |||||
| auto& req = *static_cast<post_data_request*>(cls); | |||||
| try | |||||
| { | |||||
| return req.handle_processed_post_data(kind, key, filename, content_type, transfer_encoding, data, off, size); | |||||
| } | |||||
| catch(const http_exception& ex) | |||||
| { | |||||
| // TODO log error | |||||
| req.set_error(ex); | |||||
| } | |||||
| catch(const exception& ex) | |||||
| { | |||||
| // TODO log error | |||||
| req.set_error(ex); | |||||
| } | |||||
| catch(const std::exception& ex) | |||||
| { | |||||
| // TODO log error | |||||
| req.set_error(exception(ex.what())); | |||||
| } | |||||
| catch(...) | |||||
| { | |||||
| // TODO log error | |||||
| req.set_error(exception("Unknown error")); | |||||
| } | |||||
| return MHD_YES; | |||||
| } | |||||
| @@ -0,0 +1,12 @@ | |||||
| #include <cppmicrohttpd/request/request.h> | |||||
| using namespace ::cppmicrohttpd; | |||||
| bool request::handle_post_pata( | |||||
| const void * p_data, | |||||
| size_t& p_size) | |||||
| { | |||||
| if (p_size > 0) | |||||
| throw exception("Normal request object is not expected to handle uplaoded data"); | |||||
| return false; | |||||
| } | |||||
| @@ -0,0 +1,32 @@ | |||||
| #include <cppmicrohttpd/response/callback_response.h> | |||||
| using namespace ::cppmicrohttpd; | |||||
| ssize_t callback_response::mhd_content_reader_callback( | |||||
| void * cls, | |||||
| uint64_t pos, | |||||
| char * buf, | |||||
| size_t max) | |||||
| { | |||||
| if (!cls) | |||||
| return static_cast<ssize_t>(MHD_CONTENT_READER_END_OF_STREAM); | |||||
| auto& res = *static_cast<callback_response*>(cls); | |||||
| try | |||||
| { | |||||
| return res.read_content(pos, buf, max); | |||||
| } | |||||
| catch(...) | |||||
| { | |||||
| // TODO log error | |||||
| } | |||||
| /** | |||||
| * HACK: Actually we should return MHD_CONTENT_READER_END_WITH_ERROR here, | |||||
| * but due to a bug in the microhttp library this will end in a deadlock :/ | |||||
| * Details: microhttpd recognizes the error and tries to close the connection | |||||
| * and free the response object. Deadlock occures when locking | |||||
| * the mutex of the response object, because it is already locked. | |||||
| */ | |||||
| return static_cast<ssize_t>(MHD_CONTENT_READER_END_OF_STREAM); | |||||
| } | |||||
| @@ -0,0 +1,27 @@ | |||||
| #include <sstream> | |||||
| #include <cppmicrohttpd/response/response.inl> | |||||
| #include <cppmicrohttpd/response/buffer_response.inl> | |||||
| using namespace ::cppmicrohttpd; | |||||
| response_ptr_u response::build_simple_html_response( | |||||
| const cppmicrohttpd::request& p_request, | |||||
| unsigned int p_status, | |||||
| const std::string& p_title, | |||||
| const std::string& p_head, | |||||
| const std::string& p_msg) | |||||
| { | |||||
| std::ostringstream os; | |||||
| os << "<html><head><title>" | |||||
| << p_title | |||||
| << "</title></head>" | |||||
| << "<body><h1>" | |||||
| << p_head | |||||
| << "</h1>" | |||||
| << p_msg | |||||
| << "</body></html>"; | |||||
| response_ptr_u ret = std::make_unique<buffer_response>(p_request, os.str()); | |||||
| ret->status = p_status; | |||||
| ret->add_header(MHD_HTTP_HEADER_CONTENT_TYPE, "text/html;charset=utf-8"); | |||||
| return ret; | |||||
| } | |||||
| @@ -0,0 +1,59 @@ | |||||
| # Initialize ###################################################################################### | |||||
| Include ( cotire OPTIONAL RESULT_VARIABLE HAS_COTIRE ) | |||||
| Include ( pedantic OPTIONAL RESULT_VARIABLE HAS_PEDANTIC ) | |||||
| Include ( cmake_tests OPTIONAL RESULT_VARIABLE HAS_CMAKE_TESTS ) | |||||
| Find_Package ( GTest ) | |||||
| If ( NOT "${GTest_FOUND}" ) | |||||
| Return ( ) | |||||
| EndIf ( ) | |||||
| # Test Helper ##################################################################################### | |||||
| File ( GLOB_RECURSE SOURCE_FILES ${CMAKE_CURRENT_SOURCE_DIR}/helper/*.cpp ) | |||||
| Add_Library ( cppmicrohttpd-test-helper STATIC ${SOURCE_FILES} ) | |||||
| Target_Include_Directories ( cppmicrohttpd-test-helper | |||||
| PUBLIC | |||||
| $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/helper> | |||||
| $<INSTALL_INTERFACE:${cppmicrohttpd_INSTALL_DIR_INCLUDE}> ) | |||||
| Target_Include_Directories ( cppmicrohttpd-test-helper | |||||
| SYSTEM PUBLIC | |||||
| ${MICROHTTPD_INCLUDE_DIRS} ) | |||||
| Target_Link_Libraries ( cppmicrohttpd-test-helper | |||||
| PUBLIC | |||||
| cppmicrohttpd-objects | |||||
| GMock::GMock ) | |||||
| # Test ############################################################################################ | |||||
| File ( GLOB_RECURSE CPPMICROHTTPD_TEST_HEADER_FILES ${CMAKE_CURRENT_SOURCE_DIR}/cppmicrohttpd/*.h ) | |||||
| File ( GLOB_RECURSE CPPMICROHTTPD_TEST_INLINE_FILES ${CMAKE_CURRENT_SOURCE_DIR}/cppmicrohttpd/*.inl ) | |||||
| File ( GLOB_RECURSE CPPMICROHTTPD_TEST_SOURCE_FILES ${CMAKE_CURRENT_SOURCE_DIR}/cppmicrohttpd/*.cpp ) | |||||
| Add_Executable ( cppmicrohttpd-test | |||||
| EXCLUDE_FROM_ALL | |||||
| ${CPPMICROHTTPD_TEST_HEADER_FILES} | |||||
| ${CPPMICROHTTPD_TEST_INLINE_FILES} | |||||
| ${CPPMICROHTTPD_TEST_SOURCE_FILES} ) | |||||
| Target_Link_Libraries ( cppmicrohttpd-test | |||||
| PUBLIC | |||||
| cppmicrohttpd-test-helper | |||||
| GTest::Main ) | |||||
| # pedantic | |||||
| If ( HAS_PEDANTIC ) | |||||
| Pedantic_Apply_Flags_Target ( cppmicrohttpd-test ALL ) | |||||
| EndIf ( ) | |||||
| # optimization | |||||
| If ( HAS_COTIRE ) | |||||
| Cotire ( cppmicrohttpd-test ) | |||||
| EndIf ( ) | |||||
| # test | |||||
| If ( HAS_CMAKE_TESTS ) | |||||
| Add_CMake_Test ( NAME cppmicrohttpd TARGET cppmicrohttpd-test ) | |||||
| Else ( ) | |||||
| Add_Test ( NAME cppmicrohttpd COMMAND cppmicrohttpd-test ) | |||||
| EndIf ( ) | |||||
| @@ -0,0 +1,121 @@ | |||||
| #include <gmock/gmock.h> | |||||
| #include <cppmicrohttpd.h> | |||||
| #include "../helper/libmicrohttpd_mock.h" | |||||
| using namespace ::testing; | |||||
| using namespace ::cppmicrohttpd; | |||||
| struct test_daemon | |||||
| : public daemon | |||||
| { | |||||
| inline test_daemon() | |||||
| : daemon(123, daemon_flags::empty()) | |||||
| { | |||||
| using namespace ::testing; | |||||
| ON_CALL(*this, create_request(_, _, _, _)) | |||||
| .WillByDefault(Invoke(this, &test_daemon::base_create_request)); | |||||
| ON_CALL(*this, create_response(_)) | |||||
| .WillByDefault(Invoke(this, &test_daemon::base_create_response)); | |||||
| } | |||||
| inline request_ptr_u base_create_request( | |||||
| MHD_Connection * const p_connection, | |||||
| const char * const p_url, | |||||
| const char * const p_method, | |||||
| const char * const p_version) | |||||
| { return daemon::create_request(p_connection, p_url, p_method, p_version); } | |||||
| inline response_ptr_u base_create_response( | |||||
| const ::cppmicrohttpd::request& p_request) | |||||
| { return daemon::create_response(p_request); } | |||||
| MOCK_METHOD4( | |||||
| create_request, | |||||
| request_ptr_u (struct MHD_Connection * const connection, | |||||
| const char * const url, | |||||
| const char * const method, | |||||
| const char * const version)); | |||||
| MOCK_METHOD1( | |||||
| create_response, | |||||
| response_ptr_u (const ::cppmicrohttpd::request& p_request)); | |||||
| }; | |||||
| TEST(cppmicrohttpd_tests, simpleRequest_get_success) | |||||
| { | |||||
| auto * daemonPtr = | |||||
| reinterpret_cast<MHD_Daemon *>(0xDEADBEEF); | |||||
| auto * connectionPtr = | |||||
| reinterpret_cast<MHD_Connection *>(0x12345678); | |||||
| auto * responsePtr = | |||||
| reinterpret_cast<MHD_Response *>(0x45128945); | |||||
| auto * response = | |||||
| "<html><head><title>" | |||||
| "200 - OK" | |||||
| "</title></head>" | |||||
| "<body><h1>" | |||||
| "200 - OK" | |||||
| "</h1>" | |||||
| "Request successfull" | |||||
| "</body></html>"; | |||||
| Sequence seq; | |||||
| StrictMock<libmicrohttpd_mock> microhttpd; | |||||
| EXPECT_CALL(microhttpd, MHD_start_daemon(0, 123, nullptr, nullptr, _, _)) | |||||
| .InSequence(seq) | |||||
| .WillOnce(Return(daemonPtr)); | |||||
| StrictMock<test_daemon> daemon; | |||||
| EXPECT_CALL(daemon, create_request(connectionPtr, StrEq("/test-url"), StrEq("GET"), StrEq("HTTP/1.1"))) | |||||
| .InSequence(seq); | |||||
| EXPECT_CALL(daemon, create_response(_)) | |||||
| .InSequence(seq) | |||||
| .WillOnce(Invoke([](auto& req){ | |||||
| return response::build_simple_html_response(req, 200, "200 - OK", "200 - OK", "Request successfull"); | |||||
| })); | |||||
| EXPECT_CALL(microhttpd, MHD_create_response_from_buffer(98, StrEq(response), MHD_RESPMEM_PERSISTENT)) | |||||
| .InSequence(seq) | |||||
| .WillOnce(Return(responsePtr)); | |||||
| EXPECT_CALL(microhttpd, MHD_add_response_header(responsePtr, StrEq("Content-Type"), StrEq("text/html;charset=utf-8"))) | |||||
| .InSequence(seq) | |||||
| .WillOnce(Return(MHD_YES)); | |||||
| EXPECT_CALL(microhttpd, MHD_queue_response(connectionPtr, 200, responsePtr)) | |||||
| .InSequence(seq) | |||||
| .WillOnce(Return(MHD_YES)); | |||||
| EXPECT_CALL(microhttpd, MHD_stop_daemon(daemonPtr)) | |||||
| .InSequence(seq); | |||||
| size_t size = 0; | |||||
| void * con_cls = nullptr; | |||||
| /* first call will initialize the request */ | |||||
| EXPECT_EQ( | |||||
| MHD_YES, | |||||
| daemon::mhd_access_handler_callback( | |||||
| &daemon, | |||||
| connectionPtr, | |||||
| "/test-url", | |||||
| "GET", | |||||
| "HTTP/1.1", | |||||
| nullptr, | |||||
| &size, | |||||
| &con_cls)); | |||||
| /* second call will render the response */ | |||||
| EXPECT_EQ( | |||||
| MHD_YES, | |||||
| daemon::mhd_access_handler_callback( | |||||
| &daemon, | |||||
| connectionPtr, | |||||
| "/test-url", | |||||
| "GET", | |||||
| "HTTP/1.1", | |||||
| nullptr, | |||||
| &size, | |||||
| &con_cls)); | |||||
| } | |||||
| @@ -0,0 +1,149 @@ | |||||
| #include "libmicrohttpd_mock.h" | |||||
| libmicrohttpd_mock * libmicrohttpd_mock::instance = nullptr; | |||||
| extern "C" | |||||
| { | |||||
| int MHD_get_fdset2( | |||||
| struct MHD_Daemon *daemon, | |||||
| fd_set * read_fd_set, | |||||
| fd_set * write_fd_set, | |||||
| fd_set * except_fd_set, | |||||
| int * max_fd, | |||||
| unsigned int fd_setsize) | |||||
| { | |||||
| return libmicrohttpd_mock::instance | |||||
| ? libmicrohttpd_mock::instance->MHD_get_fdset2(daemon, read_fd_set, write_fd_set, except_fd_set, max_fd, fd_setsize) | |||||
| : MHD_NO; | |||||
| } | |||||
| int MHD_get_timeout( | |||||
| struct MHD_Daemon * daemon, | |||||
| MHD_UNSIGNED_LONG_LONG * timeout) | |||||
| { | |||||
| return libmicrohttpd_mock::instance | |||||
| ? libmicrohttpd_mock::instance->MHD_get_timeout(daemon, timeout) | |||||
| : MHD_NO; | |||||
| } | |||||
| int MHD_run_from_select ( | |||||
| struct MHD_Daemon * daemon, | |||||
| const fd_set * read_fd_set, | |||||
| const fd_set * write_fd_set, | |||||
| const fd_set * except_fd_set) | |||||
| { | |||||
| return libmicrohttpd_mock::instance | |||||
| ? libmicrohttpd_mock::instance->MHD_run_from_select(daemon, read_fd_set, write_fd_set, except_fd_set) | |||||
| : MHD_NO; | |||||
| } | |||||
| struct MHD_Daemon * MHD_start_daemon ( | |||||
| unsigned int flags, | |||||
| uint16_t port, | |||||
| MHD_AcceptPolicyCallback apc, void * apc_cls, | |||||
| MHD_AccessHandlerCallback dh, void * dh_cls, | |||||
| ...) | |||||
| { | |||||
| return libmicrohttpd_mock::instance | |||||
| ? libmicrohttpd_mock::instance->MHD_start_daemon(flags, port, apc, apc_cls, dh, dh_cls) | |||||
| : nullptr; | |||||
| } | |||||
| void MHD_stop_daemon( | |||||
| struct MHD_Daemon * daemon) | |||||
| { | |||||
| if (libmicrohttpd_mock::instance) | |||||
| libmicrohttpd_mock::instance->MHD_stop_daemon(daemon); | |||||
| } | |||||
| int MHD_queue_response( | |||||
| struct MHD_Connection * connection, | |||||
| unsigned int status_code, | |||||
| struct MHD_Response * response) | |||||
| { | |||||
| return libmicrohttpd_mock::instance | |||||
| ? libmicrohttpd_mock::instance->MHD_queue_response(connection, status_code, response) | |||||
| : MHD_NO; | |||||
| } | |||||
| int MHD_add_response_header( | |||||
| struct MHD_Response * response, | |||||
| const char * header, | |||||
| const char * content) | |||||
| { | |||||
| return libmicrohttpd_mock::instance | |||||
| ? libmicrohttpd_mock::instance->MHD_add_response_header(response, header, content) | |||||
| : MHD_NO; | |||||
| } | |||||
| struct MHD_Response * MHD_create_response_from_buffer( | |||||
| size_t size, | |||||
| void * buffer, | |||||
| enum MHD_ResponseMemoryMode mode) | |||||
| { | |||||
| return libmicrohttpd_mock::instance | |||||
| ? libmicrohttpd_mock::instance->MHD_create_response_from_buffer(size, (const char *)buffer, mode) | |||||
| : nullptr; | |||||
| } | |||||
| struct MHD_Response * MHD_create_response_from_callback( | |||||
| uint64_t size, | |||||
| size_t block_size, | |||||
| MHD_ContentReaderCallback crc, | |||||
| void * crc_cls, | |||||
| MHD_ContentReaderFreeCallback crfc) | |||||
| { | |||||
| return libmicrohttpd_mock::instance | |||||
| ? libmicrohttpd_mock::instance->MHD_create_response_from_callback(size, block_size, crc, crc_cls, crfc) | |||||
| : nullptr; | |||||
| } | |||||
| int MHD_get_connection_values( | |||||
| struct MHD_Connection * connection, | |||||
| enum MHD_ValueKind kind, | |||||
| MHD_KeyValueIterator iterator, | |||||
| void * iterator_cls) | |||||
| { | |||||
| return libmicrohttpd_mock::instance | |||||
| ? libmicrohttpd_mock::instance->MHD_get_connection_values(connection, kind, iterator, iterator_cls) | |||||
| : MHD_NO; | |||||
| } | |||||
| void MHD_destroy_response( | |||||
| struct MHD_Response * response) | |||||
| { | |||||
| if (libmicrohttpd_mock::instance) | |||||
| libmicrohttpd_mock::instance->MHD_destroy_response(response); | |||||
| } | |||||
| struct MHD_PostProcessor * MHD_create_post_processor( | |||||
| struct MHD_Connection * connection, | |||||
| size_t buffer_size, | |||||
| MHD_PostDataIterator iter, | |||||
| void * iter_cls) | |||||
| { | |||||
| return libmicrohttpd_mock::instance | |||||
| ? libmicrohttpd_mock::instance->MHD_create_post_processor(connection, buffer_size, iter, iter_cls) | |||||
| : nullptr; | |||||
| } | |||||
| int MHD_destroy_post_processor( | |||||
| struct MHD_PostProcessor *pp) | |||||
| { | |||||
| return libmicrohttpd_mock::instance | |||||
| ? libmicrohttpd_mock::instance->MHD_destroy_post_processor(pp) | |||||
| : MHD_NO; | |||||
| } | |||||
| int MHD_post_process( | |||||
| struct MHD_PostProcessor * pp, | |||||
| const char * post_data, | |||||
| size_t post_data_len) | |||||
| { | |||||
| return libmicrohttpd_mock::instance | |||||
| ? libmicrohttpd_mock::instance->MHD_post_process(pp, post_data, post_data_len) | |||||
| : MHD_NO; | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,112 @@ | |||||
| #pragma once | |||||
| #include <microhttpd.h> | |||||
| #include <gmock/gmock.h> | |||||
| struct libmicrohttpd_mock | |||||
| { | |||||
| public: | |||||
| MOCK_METHOD6( | |||||
| MHD_get_fdset2, | |||||
| int (struct MHD_Daemon *daemon, | |||||
| fd_set * read_fd_set, | |||||
| fd_set * write_fd_set, | |||||
| fd_set * except_fd_set, | |||||
| int * max_fd, | |||||
| unsigned int fd_setsize)); | |||||
| MOCK_METHOD2( | |||||
| MHD_get_timeout, | |||||
| int (struct MHD_Daemon * daemon, | |||||
| MHD_UNSIGNED_LONG_LONG * timeout)); | |||||
| MOCK_METHOD4( | |||||
| MHD_run_from_select, | |||||
| int (struct MHD_Daemon * daemon, | |||||
| const fd_set * read_fd_set, | |||||
| const fd_set * write_fd_set, | |||||
| const fd_set * except_fd_set)); | |||||
| MOCK_METHOD6( | |||||
| MHD_start_daemon, | |||||
| struct MHD_Daemon * (unsigned int flags, | |||||
| uint16_t port, | |||||
| MHD_AcceptPolicyCallback apc, | |||||
| void * apc_cls, | |||||
| MHD_AccessHandlerCallback dh, | |||||
| void * dh_cls)); | |||||
| MOCK_METHOD1( | |||||
| MHD_stop_daemon, | |||||
| void (struct MHD_Daemon * daemon)); | |||||
| MOCK_METHOD3( | |||||
| MHD_queue_response, | |||||
| int (struct MHD_Connection * connection, | |||||
| unsigned int status_code, | |||||
| struct MHD_Response * response)); | |||||
| MOCK_METHOD3( | |||||
| MHD_add_response_header, | |||||
| int (struct MHD_Response * response, | |||||
| const char * header, | |||||
| const char * content)); | |||||
| MOCK_METHOD3( | |||||
| MHD_create_response_from_buffer, | |||||
| struct MHD_Response * (size_t size, | |||||
| const char * buffer, | |||||
| enum MHD_ResponseMemoryMode mode)); | |||||
| MOCK_METHOD5( | |||||
| MHD_create_response_from_callback, | |||||
| struct MHD_Response * (uint64_t size, | |||||
| size_t block_size, | |||||
| MHD_ContentReaderCallback crc, | |||||
| void * crc_cls, | |||||
| MHD_ContentReaderFreeCallback crfc)); | |||||
| MOCK_METHOD4( | |||||
| MHD_get_connection_values, | |||||
| int (struct MHD_Connection * connection, | |||||
| enum MHD_ValueKind kind, | |||||
| MHD_KeyValueIterator iterator, | |||||
| void * iterator_cls)); | |||||
| MOCK_METHOD1( | |||||
| MHD_destroy_response, | |||||
| void (struct MHD_Response * response)); | |||||
| MOCK_METHOD4( | |||||
| MHD_create_post_processor, | |||||
| struct MHD_PostProcessor * (struct MHD_Connection * connection, | |||||
| size_t buffer_size, | |||||
| MHD_PostDataIterator iter, | |||||
| void * iter_cls)); | |||||
| MOCK_METHOD1( | |||||
| MHD_destroy_post_processor, | |||||
| int (struct MHD_PostProcessor * pp)); | |||||
| MOCK_METHOD3( | |||||
| MHD_post_process, | |||||
| int (struct MHD_PostProcessor * pp, | |||||
| const char * post_data, | |||||
| size_t post_data_len)); | |||||
| public: | |||||
| inline libmicrohttpd_mock() | |||||
| { | |||||
| instance = this; | |||||
| } | |||||
| inline ~libmicrohttpd_mock() | |||||
| { | |||||
| if (instance == this) | |||||
| instance = nullptr; | |||||
| } | |||||
| public: | |||||
| static libmicrohttpd_mock * instance; | |||||
| }; | |||||