/** * * @file HttpAppFramework.h * @author An Tao * * Copyright 2018, An Tao. All rights reserved. * https://github.com/an-tao/drogon * Use of this source code is governed by a MIT license * that can be found in the License file. * * Drogon * */ #pragma once #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace drogon { // the drogon banner const char banner[] = " _ \n" " __| |_ __ ___ __ _ ___ _ __ \n" " / _` | '__/ _ \\ / _` |/ _ \\| '_ \\ \n" "| (_| | | | (_) | (_| | (_) | | | |\n" " \\__,_|_| \\___/ \\__, |\\___/|_| |_|\n" " |___/ \n"; DROGON_EXPORT std::string getVersion(); DROGON_EXPORT std::string getGitCommit(); class HttpControllerBase; class HttpSimpleControllerBase; class WebSocketControllerBase; using ExceptionHandler = std::function &&)>; using DefaultHandler = std::function &&)>; class DROGON_EXPORT HttpAppFramework : public trantor::NonCopyable { public: virtual ~HttpAppFramework() = default; /// Get the instance of HttpAppFramework /** * HttpAppFramework works at singleton mode, so any calling of this * method gets the same instance; * Calling drogon::HttpAppFramework::instance() * can be replaced by a simple interface -- drogon::app() */ static HttpAppFramework &instance(); /// Run the event loop /** * Calling this method starts the IO event loops and the main loop of the * application; * This method can be called in the main thread or any other thread. * This method blocks the current thread until the main event loop exits. */ virtual void run() = 0; /// Return true if the framework is running virtual bool isRunning() = 0; /// Quit the event loop /** * Calling this method results in stopping all network IO in the * framework and interrupting the blocking of the run() method. Usually, * after calling this method, the application exits (when the run() method * is called in the main thread). * * @note * This method can be called in any thread and anywhere. * This method should not be called before calling run(). */ virtual void quit() = 0; /// Get the main event loop of the framework; /** * @note * The event loop is not the network IO loop, but the main event loop * of the framework in which only some timer tasks are running; * User can run some timer tasks or other tasks in this loop; * This method can be call in any thread. */ virtual trantor::EventLoop *getLoop() const = 0; /// Get an IO loop with id. E.g. 0 <= id < #Total thread-loops /** * @note * The event loop is one of the network IO loops. Use the loop * for events/actions rather then the main thread. * REMARKS : Function assumed the number of threads will not exceed 2^32. * Change to long long for alien computers. */ virtual trantor::EventLoop *getIOLoop(size_t id) const = 0; /// Set custom 404 page /** * @param resp is the object set to 404 response * After calling this method, the resp object is returned * by the HttpResponse::newNotFoundResponse() method. * @param set404 if true, the status code of the resp will * be set to 404 automatically */ virtual HttpAppFramework &setCustom404Page(const HttpResponsePtr &resp, bool set404 = true) = 0; /// Set custom error handler /** * @param resp_generator is invoked when an error in the framework needs to * be sent to the client to provide a custom layout. */ virtual HttpAppFramework &setCustomErrorHandler( std::function &&resp_generator) = 0; /// Get custom error handler /** * @return A const-reference to the error handler set using * setCustomErrorHandler. If none was provided, the default error handler is * returned. */ virtual const std::function &getCustomErrorHandler() const = 0; /// Get the plugin object registered in the framework /** * @note * This method is usually called after the framework runs. * Calling this method in the initAndStart() method of plugins is also * valid. */ template T *getPlugin() { static_assert(IsPlugin::value, "The Template parameter must be a subclass of " "PluginBase"); assert(isRunning()); static auto pluginPtr = dynamic_cast(getPlugin(T::classTypeName())); return pluginPtr; } /// Get the plugin object registered in the framework /** * @param name is the class name of the plugin. * * @note * This method is usually called after the framework runs. * Calling this method in the initAndStart() method of plugins is also * valid. */ virtual PluginBase *getPlugin(const std::string &name) = 0; /* The following is a series of methods of AOP */ /// Register a beginning advice /** * @param advice is called immediately after the main event loop runs. */ virtual HttpAppFramework ®isterBeginningAdvice( const std::function &advice) = 0; /// Register an advice for new connections /** * @param advice is called immediately when a new connection is * established. the first parameter of it is the remote address of the new * connection, the second one is the local address of it. * If the advice returns a false value, drogon closes the connection. * Users can use this advice to implement some security policies. */ virtual HttpAppFramework ®isterNewConnectionAdvice( const std::function &advice) = 0; /** * @brief Register an advice for new HTTP responses. * * @param advice is called immediately when a new HTTP response is created. * Users can use the callback to modify the response if they want. * @note This advice is called before any subsequent operation on the * response is performed by drogon or applications, so some modification * (e.g. modification on the status code) in this callback may be override * by subsequent operations. * @return HttpAppFramework& */ virtual HttpAppFramework ®isterHttpResponseCreationAdvice( const std::function &advice) = 0; /// Register a synchronous advice /** * @param advice is called immediately after the request is created. If a * no-empty response is returned by the advice, it is sent to the client and * no handler is invoked. * * @note The following diagram shows the location of the * AOP join points during http request processing. * * @code +-----------+ +----------+ | Request | | Response | +-----------+ +----------+ | ^ v | sync join point o----------->[HttpResponsePtr]----------->+ | | v | Pre-routing join point o----------->[Advice callback]----------->+ | | v Invalid path | [Find Handler]---------------->[404]----------->+ | | v | Post-routing join point o----------->[Advice callback]----------->+ | | v Invalid method | [Check Method]---------------->[405]----------->+ | | v | [Filters]------->[Filter callback]----------->+ | | v Y | [Is OPTIONS method?]------------->[200]----------->+ | | v | Pre-handling join point o----------->[Advice callback]----------->+ | | v | [Handler] | | | v | Post-handling join point o---------------------------------------->+ @endcode * */ virtual HttpAppFramework ®isterSyncAdvice( const std::function &advice) = 0; /// Register an advice called before routing /** * @param advice is called after all the synchronous advices return * nullptr and before the request is routed to any handler. The parameters * of the advice are same as those of the doFilter method of the Filter * class. */ virtual HttpAppFramework ®isterPreRoutingAdvice( const std::function &advice) = 0; /// Register an observer called before routing /** * @param advice is called at the same time as the above advice. It can be * thought of as an observer who cannot respond to http requests. * @note This advice has less overhead than the above one. If one does not * intend to intercept the http request, please use this interface. */ virtual HttpAppFramework ®isterPreRoutingAdvice( const std::function &advice) = 0; /// Register an advice called after routing /** * @param advice is called immediately after the request matches a handler * path and before any 'doFilter' method of filters applies. The parameters * of the advice are same as those of the doFilter method of the Filter * class. */ virtual HttpAppFramework ®isterPostRoutingAdvice( const std::function &advice) = 0; /// Register an observer called after routing /** * @param advice is called at the same time as the above advice. It can be * thought of as an observer who cannot respond to http requests. * @note This advice has less overhead than the above one. If one does not * intend to intercept the http request, please use this interface. */ virtual HttpAppFramework ®isterPostRoutingAdvice( const std::function &advice) = 0; /// Register an advice called before the request is handled /** * @param advice is called immediately after the request is approved by all * filters and before it is handled. The parameters of the advice are * same as those of the doFilter method of the Filter class. */ virtual HttpAppFramework ®isterPreHandlingAdvice( const std::function &advice) = 0; /// Register an observer called before the request is handled /** * @param advice is called at the same time as the above advice. It can be * thought of as an observer who cannot respond to http requests. This * advice has less overhead than the above one. If one does not intend to * intercept the http request, please use this interface. */ virtual HttpAppFramework ®isterPreHandlingAdvice( const std::function &advice) = 0; /// Register an advice called after the request is handled /** * @param advice is called immediately after the request is handled and * a response object is created by handlers. */ virtual HttpAppFramework ®isterPostHandlingAdvice( const std::function &advice) = 0; /// Register an advice called before a response is sent to the client. /** * @note This advice is different from the PostHandlingAdvice, responses to * static resources are also handled here. */ virtual HttpAppFramework ®isterPreSendingAdvice( const std::function &advice) = 0; /// Setup output of logs to files /** * @note * Logs are output to the standard output by default. * Logging is setuped only if output path of logs is defined. * This method is called in run() function, hence use this method only if * you want to setup logging earlier. * @return HttpAppFramework& */ virtual HttpAppFramework &setupFileLogger() = 0; /* End of AOP methods */ /// Load the configuration file with json format. /** * @param filename the configuration file */ virtual HttpAppFramework &loadConfigFile( const std::string &fileName) noexcept(false) = 0; /// Load the configuration from a Json::Value Object. /** * @param Json::Value Object containing the configuration. * @note Please refer to the configuration file for the content of the json * object. */ virtual HttpAppFramework &loadConfigJson(const Json::Value &data) noexcept( false) = 0; /// Load the configuration from a Json::Value Object. /** * @param rvalue reference to a Json::Value object containing the * configuration. * @note Please refer to the configuration file for the content of the json * object. */ virtual HttpAppFramework &loadConfigJson(Json::Value &&data) noexcept( false) = 0; /// Register a HttpSimpleController object into the framework. /** * @param pathName When the path of a http request is equal to the * pathName, the asyncHandleHttpRequest() method of the controller is * called. * @param ctrlName is the name of the controller. It includes the namespace * to which the controller belongs. * @param filtersAndMethods is a vector containing Http methods or filter * name constraints. * * Example: * @code app.registerHttpSimpleController("/userinfo","UserInfoCtrl",{Get,"LoginFilter"}); @endcode * * @note * Users can perform the same operation through the configuration file or a * macro in the header file. */ virtual HttpAppFramework ®isterHttpSimpleController( const std::string &pathName, const std::string &ctrlName, const std::vector &filtersAndMethods = std::vector{}) = 0; /// Register a handler into the framework. /** * @param pathPattern When the path of a http request matches the * pathPattern, the handler indicated by the function parameter is called. * @param function indicates any type of callable object with a valid * processing interface. * @param filtersAndMethods is the same as the third parameter in the above * method. * * Example: * @code app().registerHandler("/hello?username={1}", [](const HttpRequestPtr& req, std::function &&callback, const std::string &name) { Json::Value json; json["result"]="ok"; json["message"]=std::string("hello,")+name; auto resp=HttpResponse::newHttpJsonResponse(json); callback(resp); }, {Get,"LoginFilter"}); @endcode * @note * As you can see in the above example, this method supports parameters * mapping. */ template HttpAppFramework ®isterHandler( const std::string &pathPattern, FUNCTION &&function, const std::vector &filtersAndMethods = std::vector{}, const std::string &handlerName = "") { LOG_TRACE << "pathPattern:" << pathPattern; auto binder = std::make_shared>( std::forward(function)); getLoop()->queueInLoop([binder]() { binder->createHandlerInstance(); }); std::vector validMethods; std::vector filters; for (auto const &filterOrMethod : filtersAndMethods) { if (filterOrMethod.type() == internal::ConstraintType::HttpFilter) { filters.push_back(filterOrMethod.getFilterName()); } else if (filterOrMethod.type() == internal::ConstraintType::HttpMethod) { validMethods.push_back(filterOrMethod.getHttpMethod()); } else { LOG_ERROR << "Invalid controller constraint type"; exit(1); } } registerHttpController( pathPattern, binder, validMethods, filters, handlerName); return *this; } /** * @brief Register a handler into the framework via a regular expression. * * @param regExp A regular expression string, when the path of a http * request matches the regular expression, the handler indicated by the * function parameter is called. * @note When the match is successful, Each string that matches a * subexpression is sequentially mapped to a handler parameter. * @param function indicates any type of callable object with a valid * processing interface. * @param filtersAndMethods is the same as the third parameter in the above * method. * @param handlerName a name for the handler. * @return HttpAppFramework& */ template HttpAppFramework ®isterHandlerViaRegex( const std::string ®Exp, FUNCTION &&function, const std::vector &filtersAndMethods = std::vector{}, const std::string &handlerName = "") { LOG_TRACE << "regex:" << regExp; internal::HttpBinderBasePtr binder; binder = std::make_shared>( std::forward(function)); std::vector validMethods; std::vector filters; for (auto const &filterOrMethod : filtersAndMethods) { if (filterOrMethod.type() == internal::ConstraintType::HttpFilter) { filters.push_back(filterOrMethod.getFilterName()); } else if (filterOrMethod.type() == internal::ConstraintType::HttpMethod) { validMethods.push_back(filterOrMethod.getHttpMethod()); } else { LOG_ERROR << "Invalid controller constraint type"; exit(1); } } registerHttpControllerViaRegex( regExp, binder, validMethods, filters, handlerName); return *this; } /// Register a WebSocketController into the framework. /** * The parameters of this method are the same as those in the * registerHttpSimpleController() method. */ virtual HttpAppFramework ®isterWebSocketController( const std::string &pathName, const std::string &ctrlName, const std::vector &filtersAndMethods = std::vector{}) = 0; /// Register controller objects created and initialized by the user /** * @details Drogon can only automatically create controllers using the * default constructor. Sometimes users want to be able to create * controllers using constructors with parameters. Controllers created by * user in this way should be registered to the framework via this method. * The macro or configuration file is still valid for the path routing * configuration of the controller created by users. * * @note * The declaration of the controller class must be as follows: * @code class ApiTest : public drogon::HttpController { public: ApiTest(const std::string &str); ... }; @endcode * The second template parameter must be explicitly set to false to disable * automatic creation. * And then user can create and register it somewhere as follows: * @code auto ctrlPtr=std::make_shared("hello world"); drogon::app().registerController(ctrlPtr); @endcode * This method should be called before calling the app().run() method. */ template HttpAppFramework ®isterController(const std::shared_ptr &ctrlPtr) { static_assert((std::is_base_of::value || std::is_base_of::value || std::is_base_of::value), "Error! Only controller objects can be registered here"); static_assert(!T::isAutoCreation, "Controllers created and initialized " "automatically by drogon cannot be " "registered here"); DrClassMap::setSingleInstance(ctrlPtr); T::initPathRouting(); return *this; } /// Register filter objects created and initialized by the user /** * This method is similar to the above method. */ template HttpAppFramework ®isterFilter(const std::shared_ptr &filterPtr) { static_assert(std::is_base_of::value, "Error! Only filter objects can be registered here"); static_assert(!T::isAutoCreation, "Filters created and initialized " "automatically by drogon cannot be " "registered here"); DrClassMap::setSingleInstance(filterPtr); return *this; } /// Register a default handler into the framework when no handler matches /// the request. If set, it is executed if the static file router does /// not find any file corresponding to the request. Thus it replaces /// the default 404 not found response. /** * @param function indicates any type of callable object with a valid * processing interface. */ virtual HttpAppFramework &setDefaultHandler(DefaultHandler handler) = 0; /// Forward the http request /** * @param req the HTTP request to be forwarded; * @param hostString is the address where the request is forwarded. The * following strings are valid for the parameter: * * @code https://www.baidu.com http://www.baidu.com https://127.0.0.1:8080/ http://127.0.0.1 http://[::1]:8080/ @endcode * * @param timeout See the timeout parameter of the sendRequest method of the * HttpClient class. this parameter is only valid when the hostString is not * empty. * @param callback is called when the response is created. * * @note * If the hostString parameter is empty, the request is handled by the same * application, so in this condition * one should modify the path of the req parameter before forwarding to * avoid infinite loop processing. * * This method can be used to implement reverse proxy or redirection on the * server side. */ virtual void forward( const HttpRequestPtr &req, std::function &&callback, const std::string &hostString = "", double timeout = 0) = 0; /// Get information about the handlers registered to drogon /** * @return * The first item of std::tuple in the return value represents the path * pattern of the handler; * The last item in std::tuple is the description of the handler. */ virtual std::vector> getHandlersInfo() const = 0; /// Get the custom configuration defined by users in the configuration file. virtual const Json::Value &getCustomConfig() const = 0; /// Set the number of threads for IO event loops /** * @param threadNum the number of threads * The default value is 1, if the parameter is 0, the number is equal to * the number of CPU cores. * * @note * This number is usually less than or equal to the number of CPU cores. * This number can be configured in the configuration file. */ virtual HttpAppFramework &setThreadNum(size_t threadNum) = 0; /// Get the number of threads for IO event loops virtual size_t getThreadNum() const = 0; /// Set the global cert file and private key file for https /// These options can be configured in the configuration file. virtual HttpAppFramework &setSSLFiles(const std::string &certPath, const std::string &keyPath) = 0; /// Supplies file style SSL options to `SSL_CONF_cmd`. Valid options are /// available at /// https://www.openssl.org/docs/manmaster/man3/SSL_CONF_cmd.html virtual HttpAppFramework &setSSLConfigCommands( const std::vector> &sslConfCmds) = 0; /// Add a listener for http or https service /** * @param ip is the ip that the listener listens on. * @param port is the port that the listener listens on. * @param useSSL if the parameter is true, the listener is used for the * https service. * @param certFile * @param keyFile specify the cert file and the private key file for this * listener. If they are empty, the global configuration set by the above * method is used. * @param useOldTLS If true, the TLS1.0/1.1 are enabled for HTTPS * connections. * * @note * This operation can be performed by an option in the configuration file. */ virtual HttpAppFramework &addListener( const std::string &ip, uint16_t port, bool useSSL = false, const std::string &certFile = "", const std::string &keyFile = "", bool useOldTLS = false, const std::vector> &sslConfCmds = {}) = 0; /// Enable sessions supporting. /** * @param timeout The number of seconds which is the timeout of a session * @param sameSite The default value of SameSite attribute * * @note * Session support is disabled by default. * If there isn't any request from a client for timeout(>0) seconds, * the session of the client is destroyed. * If the timeout parameter is equal to 0, sessions will remain permanently * This operation can be performed by an option in the configuration file. */ virtual HttpAppFramework &enableSession( const size_t timeout = 0, Cookie::SameSite sameSite = Cookie::SameSite::kNull) = 0; /// A wrapper of the above method. /** * Example: Users can set the timeout value as follows: * @code app().enableSession(0.2h); app().enableSession(12min); @endcode */ inline HttpAppFramework &enableSession( const std::chrono::duration &timeout, Cookie::SameSite sameSite = Cookie::SameSite::kNull) { return enableSession((size_t)timeout.count(), sameSite); } /// Register an advice called when starting a new session. /** * @param advice is called with the session id. */ virtual HttpAppFramework ®isterSessionStartAdvice( const AdviceStartSessionCallback &advice) = 0; /// Register an advice called when destroying a session. /** * @param advice is called with the session id. */ virtual HttpAppFramework ®isterSessionDestroyAdvice( const AdviceDestroySessionCallback &advice) = 0; /// Disable sessions supporting. /** * @note * This operation can be performed by an option in the configuration file. */ virtual HttpAppFramework &disableSession() = 0; /// Set the root path of HTTP document, default path is ./ /** * @note * This operation can be performed by an option in the configuration file. */ virtual HttpAppFramework &setDocumentRoot(const std::string &rootPath) = 0; /// Get the document root directory. virtual const std::string &getDocumentRoot() const = 0; /** * @brief Set the Static File Headers * * @param headers Each pair object in the vector presents the field name and * field value of a header in an static file response. */ virtual HttpAppFramework &setStaticFileHeaders( const std::vector> &headers) = 0; /** * @brief Add a location of static files for GET requests. * * @param uriPrefix The URI prefix of the location prefixed with "/" * @param defaultContentType The default content type of the static files * without an extension. * @param alias The location in file system, if it is prefixed with "/", it * presents an absolute path, otherwise it presents a relative path to the * document_root path. * @param isCaseSensitive * @param allowAll If it is set to false, only static files with a valid * extension can be accessed. * @param isRecursive If it is set to false, files in sub directories can't * be accessed. * @param filters The list of filters which acting on the location. * @return HttpAppFramework& */ virtual HttpAppFramework &addALocation( const std::string &uriPrefix, const std::string &defaultContentType = "", const std::string &alias = "", bool isCaseSensitive = false, bool allowAll = true, bool isRecursive = true, const std::vector &filters = {}) = 0; /// Set the path to store uploaded files. /** * @param uploadPath is the directory where the uploaded files are * stored. if it isn't prefixed with /, ./ or ../, it is relative path * of document_root path, The default value is 'uploads'. * * @note * This operation can be performed by an option in the configuration * file. */ virtual HttpAppFramework &setUploadPath(const std::string &uploadPath) = 0; /// Get the path to store uploaded files. virtual const std::string &getUploadPath() const = 0; /// Set types of files that can be downloaded. /** * Example: * @code app.setFileTypes({"html","txt","png","jpg"}); @endcode * * @note * This operation can be performed by an option in the configuration file. */ virtual HttpAppFramework &setFileTypes( const std::vector &types) = 0; /// Enable supporting for dynamic views loading. /** * * @param libPaths is a vector that contains paths to view files. * * @param outputPath is the directory where the output source files locate. if * it is set to an empty string, drogon use libPaths as output paths. If the * path isn't prefixed with /, it is relative path of the current working * directory. * * @note * It is disabled by default. * This operation can be performed by an option in the configuration file. */ #ifndef _WIN32 virtual HttpAppFramework &enableDynamicViewsLoading( const std::vector &libPaths, const std::string &outputPath = "") = 0; #endif /// Set the maximum number of all connections. /** * The default value is 100000. * * @note * This operation can be performed by an option in the configuration file. */ virtual HttpAppFramework &setMaxConnectionNum(size_t maxConnections) = 0; /// Set the maximum number of connections per remote IP. /** * The default value is 0 which means no limit. * * @note * This operation can be performed by an option in the configuration file. */ virtual HttpAppFramework &setMaxConnectionNumPerIP( size_t maxConnectionsPerIP) = 0; /// Make the application run as a daemon. /** * Disabled by default. * * @note * This operation can be performed by an option in the configuration file. */ virtual HttpAppFramework &enableRunAsDaemon() = 0; /// Disable the handling of SIGTERM signal. /** * Enabled by default. * * @note * This operation can be performed by an option in the configuration file. * When disabled setTermSignalHandler() is useless */ virtual HttpAppFramework &disableSigtermHandling() = 0; /// Make the application restart after crashing. /** * Disabled by default. * * @note * This operation can be performed by an option in the configuration file. */ virtual HttpAppFramework &enableRelaunchOnError() = 0; /// Set the output path of logs. /** * @param logPath The path to logs. * @param logfileBaseName The base name of log files. * @param logSize indicates the maximum size of a log file. * * @note * This operation can be performed by an option in the configuration file. */ virtual HttpAppFramework &setLogPath( const std::string &logPath, const std::string &logfileBaseName = "", size_t logSize = 100000000) = 0; /// Set the log level /** * @param level is one of TRACE, DEBUG, INFO, WARN. The Default value is * DEBUG. * * @note * This operation can be performed by an option in the configuration file. */ virtual HttpAppFramework &setLogLevel(trantor::Logger::LogLevel level) = 0; /// Set the log time display /** * @param on is true to display local time, false to display UTC time. The * Default value is false. * * @note * This operation can be performed by an option in the configuration file. */ virtual HttpAppFramework &setLogLocalTime(bool on) = 0; /// Enable the sendfile system call in linux. /** * @param sendFile if the parameter is true, sendfile() system-call is used * to send static files to clients; The default value is true. * * @note * This operation can be performed by an option in the configuration file. * Even though sendfile() is enabled, only files larger than 200k are sent * this way, * because the advantages of sendfile() can only be reflected in sending * large files. */ virtual HttpAppFramework &enableSendfile(bool sendFile) = 0; /// Enable gzip compression. /** * @param useGzip if the parameter is true, use gzip to compress the * response body's content; * The default value is true. * * @note * This operation can be performed by an option in the configuration file. * After gzip is enabled, gzip is used under the following conditions: * 1. The content type of response is not a binary type. * 2. The content length is bigger than 1024 bytes. */ virtual HttpAppFramework &enableGzip(bool useGzip) = 0; /// Return true if gzip is enabled. virtual bool isGzipEnabled() const = 0; /// Enable brotli compression. /** * @param useBrotli if the parameter is true, use brotli to compress the * response body's content; * The default value is true. * * @note * This operation can be performed by an option in the configuration file. * After brotli is enabled, brotli is used under the following conditions: * 1. The content type of response is not a binary type. * 2. The content length is bigger than 1024 bytes. */ virtual HttpAppFramework &enableBrotli(bool useBrotli) = 0; /// Return true if brotli is enabled. virtual bool isBrotliEnabled() const = 0; /// Set the time in which the static file response is cached in memory. /** * @param cacheTime in seconds. 0 means always cached, negative means no * cache * * @note * This operation can be performed by an option in the configuration file. */ virtual HttpAppFramework &setStaticFilesCacheTime(int cacheTime) = 0; /// Get the time set by the above method. virtual int staticFilesCacheTime() const = 0; /// Set the lifetime of the connection without read or write /** * @param timeout in seconds. 60 by default. Setting the timeout to 0 means * that drogon does not close idle connections. * * @note * This operation can be performed by an option in the configuration file. */ virtual HttpAppFramework &setIdleConnectionTimeout(size_t timeout) = 0; /// A wrapper of the above method. /** * Example: * Users can set the timeout value as follows: * @code app().setIdleConnectionTimeout(0.5h); app().setIdleConnectionTimeout(30min); @endcode */ inline HttpAppFramework &setIdleConnectionTimeout( const std::chrono::duration &timeout) { return setIdleConnectionTimeout((size_t)timeout.count()); } /// Set the 'server' header field in each response sent by drogon. /** * @param server empty string by default with which the 'server' header * field is set to "Server: drogon/version string\r\n" * * @note * This operation can be performed by an option in the configuration file. */ virtual HttpAppFramework &setServerHeaderField( const std::string &server) = 0; /// Control if the 'Server' header is added to each HTTP response. /** * @note * These operations can be performed by options in the configuration file. * The headers are sent to clients by default. */ virtual HttpAppFramework &enableServerHeader(bool flag) = 0; /// Control if the 'Date' header is added to each HTTP response. /** * @note * These operations can be performed by options in the configuration file. * The headers are sent to clients by default. */ virtual HttpAppFramework &enableDateHeader(bool flag) = 0; /// Set the maximum number of requests that can be served through one /// keep-alive connection. /** * After the maximum number of requests are made, the connection is closed. * The default value is 0 which means no limit. * * @note * This operation can be performed by an option in the configuration file. */ virtual HttpAppFramework &setKeepaliveRequestsNumber( const size_t number) = 0; /// Set the maximum number of unhandled requests that can be cached in /// pipelining buffer. /** * The default value of 0 means no limit. * After the maximum number of requests cached in pipelining buffer are * made, the connection is closed. * * @note * This operation can be performed by an option in the configuration file. */ virtual HttpAppFramework &setPipeliningRequestsNumber( const size_t number) = 0; /// Set the gzip_static option. /** * If it is set to true, when the client requests a static file, drogon * first finds the compressed file with the extension ".gz" in the same path * and send the compressed file to the client. The default value is true. * * @note * This operation can be performed by an option in the configuration file. */ virtual HttpAppFramework &setGzipStatic(bool useGzipStatic) = 0; /// Set the br_static option. /** * If it is set to true, when the client requests a static file, drogon * first finds the compressed file with the extension ".br" in the same path * and send the compressed file to the client. The default value is true. * * @note * This operation can be performed by an option in the configuration file. */ virtual HttpAppFramework &setBrStatic(bool useGzipStatic) = 0; /// Set the max body size of the requests received by drogon. /** * The default value is 1M. * @note * This operation can be performed by an option in the configuration file. */ virtual HttpAppFramework &setClientMaxBodySize(size_t maxSize) = 0; /// Set the maximum body size in memory of HTTP requests received by drogon. /** * The default value is "64K" bytes. If the body size of a HTTP request * exceeds this limit, the body is stored to a temporary file for * processing. * * @note * This operation can be performed by an option in the configuration file. */ virtual HttpAppFramework &setClientMaxMemoryBodySize(size_t maxSize) = 0; /// Set the max size of messages sent by WebSocket client. /** * The default value is 128K. * @note * This operation can be performed by an option in the configuration file. */ virtual HttpAppFramework &setClientMaxWebSocketMessageSize( size_t maxSize) = 0; // Set the HTML file of the home page, the default value is "index.html" /** * If there isn't any handler registered to the path "/", the home page file * in the "document_root" * is send to clients as a response to the request for "/". * @note * This operation can be performed by an option in the configuration file. */ virtual HttpAppFramework &setHomePage(const std::string &homePageFile) = 0; /** * @brief Set the TERM Signal Handler. This method provides a way to users * for exiting program gracefully. When the TERM signal is received after * app().run() is called, the handler is invoked. Drogon uses a default * signal handler for the TERM signal, which calls the 'app().quit()' method * when the TERM signal is received. * * @param handler * @return HttpAppFramework& */ virtual HttpAppFramework &setTermSignalHandler( const std::function &handler) = 0; /** * @brief Set the INT Signal Handler. This method provides a way to users * for exiting program gracefully. When the INT signal is received after * app().run() is called, the handler is invoked. Drogon uses a default * signal handler for the INT signal, which calls the 'app().quit()' method * when the INT signal is received. * * @param handler * @return HttpAppFramework& */ virtual HttpAppFramework &setIntSignalHandler( const std::function &handler) = 0; /// Get homepage, default is "index.html" /** * @note * This method must be called after the framework has been run. */ virtual const std::string &getHomePage() const = 0; /// Set to enable implicit pages, enabled by default /** * @brief Implicit pages are used when the server detects if the user * requested a directory. By default, it will try to append index.html to * the path, see setImplicitPage() if you want to customize this * (http://localhost/a-directory resolves to * http://localhost/a-directory/index.html by default). * * @note * This operation can be performed by an option in the configuration file. */ virtual HttpAppFramework &setImplicitPageEnable(bool useImplicitPage) = 0; /// Return true if implicit pages are enabled /** * @note * This method must be called after the framework has been run. */ virtual bool isImplicitPageEnabled() const = 0; /// Set the HTML file that a directory would resolve to by default, default /// is "index.html" /** * @brief Set the page which would the server load in if it detects that * the user requested a directory * * @note * This operation can be performed by an option in the configuration file. */ virtual HttpAppFramework &setImplicitPage( const std::string &implicitPageFile) = 0; /// Get the implicit HTML page /** * @note * This method must be called after the framework has been run. */ virtual const std::string &getImplicitPage() const = 0; /// Get a database client by name /** * @note * This method must be called after the framework has been run. */ virtual orm::DbClientPtr getDbClient( const std::string &name = "default") = 0; /// Get a 'fast' database client by name /** * @note * This method must be called after the framework has been run. */ virtual orm::DbClientPtr getFastDbClient( const std::string &name = "default") = 0; /** * @brief Check if all database clients in the framework are available * (connect to the database successfully). */ virtual bool areAllDbClientsAvailable() const noexcept = 0; /// Get a redis client by name /** * @note * This method must be called after the framework has been run. */ virtual nosql::RedisClientPtr getRedisClient( const std::string &name = "default") = 0; /// Get a 'fast' redis client by name /** * @note * This method must be called after the framework has been run. */ virtual nosql::RedisClientPtr getFastRedisClient( const std::string &name = "default") = 0; /** * @brief Set the maximum stack depth of the json parser when reading a json * string, the default value is 1000. * * @note * This operation can be performed by an option in the configuration file. */ virtual HttpAppFramework &setJsonParserStackLimit( size_t limit) noexcept = 0; /** * @brief Get the maximum stack depth of the json parser when reading a json * string. */ virtual size_t getJsonParserStackLimit() const noexcept = 0; /** * @brief This method is to enable or disable the unicode escaping (\u) in * the json string of HTTP responses or requests. it works (disable * successfully) when the version of JsonCpp >= 1.9.3, the unicode escaping * is enabled by default. */ virtual HttpAppFramework &setUnicodeEscapingInJson( bool enable) noexcept = 0; /** * @brief Check if the unicode escaping is used in the json string of HTTP * requests and responses. */ virtual bool isUnicodeEscapingUsedInJson() const noexcept = 0; /** * @brief Set the float precision in Json string of HTTP requests or * responses with json content. * * @param precision The maximum digits length. * @param precisionType Must be "significant" or "decimal", defaults to * "significant" that means setting max number of significant digits in * string, "decimal" means setting max number of digits after "." in string * @return HttpAppFramework& */ virtual HttpAppFramework &setFloatPrecisionInJson( unsigned int precision, const std::string &precisionType = "significant") noexcept = 0; /** * @brief Get the float precision set by the above method. * * @return std::pair */ virtual const std::pair &getFloatPrecisionInJson() const noexcept = 0; /// Create a database client /** * @param dbType The database type is one of * "postgresql","mysql","sqlite3". * @param host IP or host name. * @param port The port on which the database server is listening. * @databaseName Database name * @param userName User name * @param password Password for the database server * @param connectionNum The number of connections to the database server. * It's valid only if @param isFast is false. * @param filename The file name of sqlite3 database file. * @param name The client name. * @param isFast Indicates if the client is a fast database client. * @param characterSet The character set of the database server. * @param timeout The timeout in seconds for executing SQL queries. zero or * negative value means no timeout. * * @note * This operation can be performed by an option in the configuration file. */ virtual HttpAppFramework &createDbClient( const std::string &dbType, const std::string &host, const unsigned short port, const std::string &databaseName, const std::string &userName, const std::string &password, const size_t connectionNum = 1, const std::string &filename = "", const std::string &name = "default", const bool isFast = false, const std::string &characterSet = "", double timeout = -1.0, const bool autoBatch = false) = 0; /// Create a redis client /** * @param ip IP of redis server. * @param port The port on which the redis server is listening. * @param name The client name. * @param username Username for redis server * @param password Password for the redis server * @param connectionNum The number of connections to the redis server. * @param isFast Indicates if the client is a fast database client. * * @note * This operation can be performed by an option in the configuration file. */ virtual HttpAppFramework &createRedisClient( const std::string &ip, unsigned short port, const std::string &name = "default", const std::string &password = "", size_t connectionNum = 1, bool isFast = false, double timeout = -1.0, unsigned int db = 0, const std::string &username = "") = 0; /// Get the DNS resolver /** * @note * When the c-ares library is installed in the system, it runs with the best * performance. */ virtual const std::shared_ptr &getResolver() const = 0; /// Return true is drogon supports SSL(https) virtual bool supportSSL() const = 0; /** * @brief Get the Current Thread Index whose range is [0, the total number * of IO threads] * * @return size_t If the current thread is the main EventLoop thread (in * which the app().run() is called), the number of the IO threads is * returned. If the current thread is a network IO thread, the index of it * in the range [0, the number of IO threads) is returned. otherwise the * maximum value of type size_t is returned. * * @note Basically this method is used for storing thread-related various in * an array and users can use indexes returned by this method to access * them. This is much faster than using a map. If the array is properly * initialized at the beginning, users can access it without locks. */ virtual size_t getCurrentThreadIndex() const = 0; /** * @brief Get the addresses of listeners. * * @return std::vector * @note This method should be called after calling the app().run(). One * could run this method in an AOP join point (such as the BeginningAdvice). */ virtual std::vector getListeners() const = 0; /** * @brief Enable ReusePort mode or not. If the mode is enabled, one can run * multiple processes listening to the same port at the same time. If this * method is not called, the feature is disabled. * * @note * This operation can be performed by an option in the configuration file. */ virtual void enableReusePort(bool enable = true) = 0; /** * @brief Return if the ReusePort mode is enabled. */ virtual bool reusePort() const = 0; /** * @brief handler will be called upon an exception escapes a request handler */ virtual void setExceptionHandler(ExceptionHandler handler) = 0; /** * @brief returns the excaption handler */ virtual const ExceptionHandler &getExceptionHandler() const = 0; /** * @brief Adds a new custom extension to MIME type mapping */ virtual HttpAppFramework ®isterCustomExtensionMime( const std::string &ext, const std::string &mime) = 0; virtual HttpAppFramework &enableCompressedRequest(bool enable = true) = 0; virtual bool isCompressedRequestEnabled() const = 0; private: virtual void registerHttpController( const std::string &pathPattern, const internal::HttpBinderBasePtr &binder, const std::vector &validMethods = std::vector(), const std::vector &filters = std::vector(), const std::string &handlerName = "") = 0; virtual void registerHttpControllerViaRegex( const std::string ®Exp, const internal::HttpBinderBasePtr &binder, const std::vector &validMethods, const std::vector &filters, const std::string &handlerName) = 0; }; /// A wrapper of the instance() method inline HttpAppFramework &app() { return HttpAppFramework::instance(); } } // namespace drogon