#pragma once #include #include #include #include #include #include #include namespace CurrentMetrics { extern const Metric HTTPConnection; } namespace Poco { class Logger; } namespace DB { class Session; class Credentials; class IServer; struct Settings; class WriteBufferFromHTTPServerResponse; using CompiledRegexPtr = std::shared_ptr; class HTTPHandler : public HTTPRequestHandler { public: HTTPHandler(IServer & server_, const std::string & name); virtual ~HTTPHandler() override; void handleRequest(HTTPServerRequest & request, HTTPServerResponse & response) override; /// This method is called right before the query execution. virtual void customizeContext(HTTPServerRequest & /* request */, ContextMutablePtr /* context */) {} virtual bool customizeQueryParam(ContextMutablePtr context, const std::string & key, const std::string & value) = 0; virtual std::string getQuery(HTTPServerRequest & request, HTMLForm & params, ContextMutablePtr context) = 0; private: struct Output { /* Raw data * ↓ * CascadeWriteBuffer out_maybe_delayed_and_compressed (optional) * ↓ (forwards data if an overflow is occur or explicitly via pushDelayedResults) * CompressedWriteBuffer out_maybe_compressed (optional) * ↓ * WriteBufferFromHTTPServerResponse out */ std::shared_ptr out; /// Points to 'out' or to CompressedWriteBuffer(*out), depending on settings. std::shared_ptr out_maybe_compressed; /// Points to 'out' or to CompressedWriteBuffer(*out) or to CascadeWriteBuffer. std::shared_ptr out_maybe_delayed_and_compressed; bool finalized = false; inline bool hasDelayed() const { return out_maybe_delayed_and_compressed != out_maybe_compressed; } inline void finalize() { if (finalized) return; finalized = true; if (out_maybe_delayed_and_compressed) out_maybe_delayed_and_compressed->finalize(); if (out_maybe_compressed) out_maybe_compressed->finalize(); if (out) out->finalize(); } inline bool isFinalized() const { return finalized; } }; IServer & server; Poco::Logger * log; /// It is the name of the server that will be sent in an http-header X-ClickHouse-Server-Display-Name. String server_display_name; CurrentMetrics::Increment metric_increment{CurrentMetrics::HTTPConnection}; /// Reference to the immutable settings in the global context. /// Those settings are used only to extract a http request's parameters. /// See settings http_max_fields, http_max_field_name_size, http_max_field_value_size in HTMLForm. const Settings & default_settings; // session is reset at the end of each request/response. std::unique_ptr session; // The request_credential instance may outlive a single request/response loop. // This happens only when the authentication mechanism requires more than a single request/response exchange (e.g., SPNEGO). std::unique_ptr request_credentials; // Returns true when the user successfully authenticated, // the session instance will be configured accordingly, and the request_credentials instance will be dropped. // Returns false when the user is not authenticated yet, and the 'Negotiate' response is sent, // the session and request_credentials instances are preserved. // Throws an exception if authentication failed. bool authenticateUser( HTTPServerRequest & request, HTMLForm & params, HTTPServerResponse & response); /// Also initializes 'used_output'. void processQuery( HTTPServerRequest & request, HTMLForm & params, HTTPServerResponse & response, Output & used_output, std::optional & query_scope); void trySendExceptionToClient( const std::string & s, int exception_code, HTTPServerRequest & request, HTTPServerResponse & response, Output & used_output); static void pushDelayedResults(Output & used_output); }; class DynamicQueryHandler : public HTTPHandler { private: std::string param_name; public: explicit DynamicQueryHandler(IServer & server_, const std::string & param_name_ = "query"); std::string getQuery(HTTPServerRequest & request, HTMLForm & params, ContextMutablePtr context) override; bool customizeQueryParam(ContextMutablePtr context, const std::string &key, const std::string &value) override; }; class PredefinedQueryHandler : public HTTPHandler { private: NameSet receive_params; std::string predefined_query; CompiledRegexPtr url_regex; std::unordered_map header_name_with_capture_regex; public: PredefinedQueryHandler( IServer & server_, const NameSet & receive_params_, const std::string & predefined_query_ , const CompiledRegexPtr & url_regex_, const std::unordered_map & header_name_with_regex_); virtual void customizeContext(HTTPServerRequest & request, ContextMutablePtr context) override; std::string getQuery(HTTPServerRequest & request, HTMLForm & params, ContextMutablePtr context) override; bool customizeQueryParam(ContextMutablePtr context, const std::string & key, const std::string & value) override; }; }