#include #include #include #include #include #include #include "HTTPHandler.h" #include "NotFoundHandler.h" #include "StaticRequestHandler.h" #include "ReplicasStatusHandler.h" #include "InterserverIOHTTPHandler.h" #include "PrometheusRequestHandler.h" #include "WebUIRequestHandler.h" namespace DB { namespace ErrorCodes { extern const int LOGICAL_ERROR; extern const int UNKNOWN_ELEMENT_IN_CONFIG; extern const int INVALID_CONFIG_PARAMETER; } static void addCommonDefaultHandlersFactory(HTTPRequestHandlerFactoryMain & factory, IServer & server); static void addDefaultHandlersFactory( HTTPRequestHandlerFactoryMain & factory, IServer & server, const Poco::Util::AbstractConfiguration & config, AsynchronousMetrics & async_metrics); HTTPRequestHandlerFactoryMain::HTTPRequestHandlerFactoryMain(const std::string & name_) : log(&Poco::Logger::get(name_)), name(name_) { } std::unique_ptr HTTPRequestHandlerFactoryMain::createRequestHandler(const HTTPServerRequest & request) { LOG_TRACE(log, "HTTP Request for {}. Method: {}, Address: {}, User-Agent: {}{}, Content Type: {}, Transfer Encoding: {}, X-Forwarded-For: {}", name, request.getMethod(), request.clientAddress().toString(), request.get("User-Agent", "(none)"), (request.hasContentLength() ? (", Length: " + std::to_string(request.getContentLength())) : ("")), request.getContentType(), request.getTransferEncoding(), request.get("X-Forwarded-For", "(none)")); for (auto & handler_factory : child_factories) { auto handler = handler_factory->createRequestHandler(request); if (handler) return handler; } if (request.getMethod() == Poco::Net::HTTPRequest::HTTP_GET || request.getMethod() == Poco::Net::HTTPRequest::HTTP_HEAD || request.getMethod() == Poco::Net::HTTPRequest::HTTP_POST) { return std::unique_ptr(new NotFoundHandler); } return nullptr; } static inline auto createHandlersFactoryFromConfig( IServer & server, const Poco::Util::AbstractConfiguration & config, const std::string & name, const String & prefix, AsynchronousMetrics & async_metrics) { auto main_handler_factory = std::make_shared(name); Poco::Util::AbstractConfiguration::Keys keys; config.keys(prefix, keys); for (const auto & key : keys) { if (key == "defaults") { addDefaultHandlersFactory(*main_handler_factory, server, config, async_metrics); } else if (startsWith(key, "rule")) { const auto & handler_type = config.getString(prefix + "." + key + ".handler.type", ""); if (handler_type.empty()) throw Exception("Handler type in config is not specified here: " + prefix + "." + key + ".handler.type", ErrorCodes::INVALID_CONFIG_PARAMETER); if (handler_type == "static") main_handler_factory->addHandler(createStaticHandlerFactory(server, config, prefix + "." + key)); else if (handler_type == "dynamic_query_handler") main_handler_factory->addHandler(createDynamicHandlerFactory(server, config, prefix + "." + key)); else if (handler_type == "predefined_query_handler") main_handler_factory->addHandler(createPredefinedHandlerFactory(server, config, prefix + "." + key)); else if (handler_type == "prometheus") main_handler_factory->addHandler(createPrometheusHandlerFactory(server, config, async_metrics, prefix + "." + key)); else if (handler_type == "replicas_status") main_handler_factory->addHandler(createReplicasStatusHandlerFactory(server, config, prefix + "." + key)); else throw Exception("Unknown handler type '" + handler_type + "' in config here: " + prefix + "." + key + ".handler.type", ErrorCodes::INVALID_CONFIG_PARAMETER); } else throw Exception("Unknown element in config: " + prefix + "." + key + ", must be 'rule' or 'defaults'", ErrorCodes::UNKNOWN_ELEMENT_IN_CONFIG); } return main_handler_factory; } static inline HTTPRequestHandlerFactoryPtr createHTTPHandlerFactory(IServer & server, const Poco::Util::AbstractConfiguration & config, const std::string & name, AsynchronousMetrics & async_metrics) { if (config.has("http_handlers")) { return createHandlersFactoryFromConfig(server, config, name, "http_handlers", async_metrics); } else { auto factory = std::make_shared(name); addDefaultHandlersFactory(*factory, server, config, async_metrics); return factory; } } static inline HTTPRequestHandlerFactoryPtr createInterserverHTTPHandlerFactory(IServer & server, const std::string & name) { auto factory = std::make_shared(name); addCommonDefaultHandlersFactory(*factory, server); auto main_handler = std::make_shared>(server); main_handler->allowPostAndGetParamsAndOptionsRequest(); factory->addHandler(main_handler); return factory; } HTTPRequestHandlerFactoryPtr createHandlerFactory(IServer & server, const Poco::Util::AbstractConfiguration & config, AsynchronousMetrics & async_metrics, const std::string & name) { if (name == "HTTPHandler-factory" || name == "HTTPSHandler-factory") return createHTTPHandlerFactory(server, config, name, async_metrics); else if (name == "InterserverIOHTTPHandler-factory" || name == "InterserverIOHTTPSHandler-factory") return createInterserverHTTPHandlerFactory(server, name); else if (name == "PrometheusHandler-factory") { auto factory = std::make_shared(name); auto handler = std::make_shared>( server, PrometheusMetricsWriter(config, "prometheus", async_metrics)); handler->attachStrictPath(config.getString("prometheus.endpoint", "/metrics")); handler->allowGetAndHeadRequest(); factory->addHandler(handler); return factory; } throw Exception("LOGICAL ERROR: Unknown HTTP handler factory name.", ErrorCodes::LOGICAL_ERROR); } static const auto ping_response_expression = "Ok.\n"; static const auto root_response_expression = "config://http_server_default_response"; void addCommonDefaultHandlersFactory(HTTPRequestHandlerFactoryMain & factory, IServer & server) { auto root_handler = std::make_shared>(server, root_response_expression); root_handler->attachStrictPath("/"); root_handler->allowGetAndHeadRequest(); factory.addHandler(root_handler); auto ping_handler = std::make_shared>(server, ping_response_expression); ping_handler->attachStrictPath("/ping"); ping_handler->allowGetAndHeadRequest(); factory.addHandler(ping_handler); auto replicas_status_handler = std::make_shared>(server); replicas_status_handler->attachNonStrictPath("/replicas_status"); replicas_status_handler->allowGetAndHeadRequest(); factory.addHandler(replicas_status_handler); auto play_handler = std::make_shared>(server); play_handler->attachNonStrictPath("/play"); play_handler->allowGetAndHeadRequest(); factory.addHandler(play_handler); auto dashboard_handler = std::make_shared>(server); dashboard_handler->attachNonStrictPath("/dashboard"); dashboard_handler->allowGetAndHeadRequest(); factory.addHandler(dashboard_handler); auto js_handler = std::make_shared>(server); js_handler->attachNonStrictPath("/js/"); js_handler->allowGetAndHeadRequest(); factory.addHandler(js_handler); } void addDefaultHandlersFactory( HTTPRequestHandlerFactoryMain & factory, IServer & server, const Poco::Util::AbstractConfiguration & config, AsynchronousMetrics & async_metrics) { addCommonDefaultHandlersFactory(factory, server); auto query_handler = std::make_shared>(server, "query"); query_handler->allowPostAndGetParamsAndOptionsRequest(); factory.addHandler(query_handler); /// We check that prometheus handler will be served on current (default) port. /// Otherwise it will be created separately, see createHandlerFactory(...). if (config.has("prometheus") && config.getInt("prometheus.port", 0) == 0) { auto prometheus_handler = std::make_shared>( server, PrometheusMetricsWriter(config, "prometheus", async_metrics)); prometheus_handler->attachStrictPath(config.getString("prometheus.endpoint", "/metrics")); prometheus_handler->allowGetAndHeadRequest(); factory.addHandler(prometheus_handler); } } }