/* * Copyright 2019-present ScyllaDB */ /* * SPDX-License-Identifier: LicenseRef-ScyllaDB-Source-Available-1.0 */ #pragma once #include "alternator/executor.hh" #include "utils/scoped_item_list.hh" #include #include #include #include #include #include "alternator/auth.hh" #include "service/qos/service_level_controller.hh" #include "utils/small_vector.hh" #include "utils/updateable_value.hh" #include struct client_data; namespace alternator { using chunked_content = rjson::chunked_content; class server : public peering_sharded_service { // The maximum size of a request body that Alternator will accept, // in bytes. This is a safety measure to prevent Alternator from // running out of memory when a client sends a very large request. // DynamoDB also has the same limit set to 16 MB. static constexpr size_t request_content_length_limit = 16*MB; using alternator_callback = std::function(executor&, executor::client_state&, tracing::trace_state_ptr, service_permit, rjson::value, std::unique_ptr)>; using alternator_callbacks_map = std::unordered_map; httpd::http_server _http_server; httpd::http_server _https_server; executor& _executor; service::storage_proxy& _proxy; gms::gossiper& _gossiper; auth::service& _auth_service; qos::service_level_controller& _sl_controller; key_cache _key_cache; utils::updateable_value _enforce_authorization; utils::updateable_value _warn_authorization; utils::updateable_value _max_users_query_size_in_trace_output; utils::small_vector, 2> _enabled_servers; named_gate _pending_requests; // In some places we will need a CQL updateable_timeout_config object even // though it isn't really relevant for Alternator which defines its own // timeouts separately. We can create this object only once. updateable_timeout_config _timeout_config; alternator_callbacks_map _callbacks; semaphore* _memory_limiter; utils::updateable_value _max_concurrent_requests; ::shared_ptr _credentials; class json_parser { static constexpr size_t yieldable_parsing_threshold = 16*KB; chunked_content _raw_document; rjson::value _parsed_document; std::exception_ptr _current_exception; semaphore _parsing_sem{1}; condition_variable _document_waiting; condition_variable _document_parsed; abort_source _as; future<> _run_parse_json_thread; public: json_parser(); // Moving a chunked_content into parse() allows parse() to free each // chunk as soon as it is parsed, so when chunks are relatively small, // we don't need to store the sum of unparsed and parsed sizes. future parse(chunked_content&& content); future<> stop(); }; json_parser _json_parser; // The server maintains a list of ongoing requests, that are being handled // by handle_api_request(). It uses this list in get_client_data(), which // is called when reading the "system.clients" virtual table. struct ongoing_request { socket_address _client_address; sstring _user_agent; sstring _username; scheduling_group _scheduling_group; bool _is_https; client_data make_client_data() const; }; utils::scoped_item_list _ongoing_requests; public: server(executor& executor, service::storage_proxy& proxy, gms::gossiper& gossiper, auth::service& service, qos::service_level_controller& sl_controller); future<> init(net::inet_address addr, std::optional port, std::optional https_port, std::optional creds, utils::updateable_value enforce_authorization, utils::updateable_value warn_authorization, utils::updateable_value max_users_query_size_in_trace_output, semaphore* memory_limiter, utils::updateable_value max_concurrent_requests); future<> stop(); // get_client_data() is called (on each shard separately) when the virtual // table "system.clients" is read. It is expected to generate a list of // clients connected to this server (on this shard). This function is // called by alternator::controller::get_client_data(). future> get_client_data(); private: void set_routes(seastar::httpd::routes& r); // If verification succeeds, returns the authenticated user's username future verify_signature(const seastar::http::request&, const chunked_content&); future handle_api_request(std::unique_ptr req); }; }