Files
scylladb/utils/rest/client.hh
Avi Kivity 6df04c9e5b Update seastar submodule
Changed seastar::http::experimental to seastar::http to reflect
graduation of the seastar http API.

Changed call to seastar::rename_file() (in sstables/storage.cc,
sstables/sstable_directory.cc, sstable/sstables.cc and
db/hints/internal/hint_storage.cc) to reflect new default parameter.

Updated scylla_gdb test helper get_task() to work with updated
accept loop in Seatar. This is just test code (attempts to find
a task to operate on), not used in real scylla-gdb.py work, but
nevertheless the adjustment keeps backward compatibility.

Fixes https://scylladb.atlassian.net/browse/SCYLLADB-1798
Fixes https://scylladb.atlassian.net/browse/SCYLLADB-2043

* seastar 485a62b2...510f3148 (43):
  > reactor_backend: fix iocb double-free and shutdown hang during AIO teardown
  > file: fix default DMA alignment
  > http: add to_reply() to redirect_exception with extra-header support
  > core: propagate syscall errors via `coroutine::exception`
  > file: assert dma alignments are powers of two
  > doc: Document undocumented io_tester features and fix output example
  > backtrace: print the build_id along with the backtrace
  > reactor: default to oneline backtraces
  > Merge 'json: formatter: support types with user-defined conversion to sstring' from Benny Halevy
    tests: json_formatter: test formatter::write with string types
    json: formatter: support types with user-defined conversion to sstring
  > httpd_test: fix build failure with Seastar_SSTRING=OFF
  > net/tls: introduce ssl_call wrapper for SSL I/O
  > build: disable unused command line argument error for C++ module
  > coroutine/generator: fix setup of generator's waiting task
  > tests/tls: set 1000-day validity for self-signed CA cert
  > net: tls: openssl: disable certificate compression
  > reactor: reduce steady_clock::now() calls per scheduling quantum
  > fair_queue: remove notify_request_finished()
  > loop: use small_vector for parallel_for_each_state incomplete futures
  > dodge false sharing in spinlock
  > Merge 'Handle nowait support for reads and writes independently' from Pavel Emelyanov
    file: Change nowait_works mode detection
    file: Introduce read-only nowait_mode
    filesystem: Make nowait_works bit a enum class too
    file: Make nowait_works bit a enum class
  > Merge 'net/tls: improve OpenSSL error queue hygiene' from Gellért Peresztegi-Nagy
    net/tls: assert clean error queue before SSL operations
    net/tls: clear error queue after successful SSL operations
    net/tls: clear error queue after successful SSL_CTX_new
    net/tls: drain error queue on unexpected error codes
    net/tls: use make_openssl_error for BIO creation failure
  > vla.hh: add missing includes
  > Merge 'smp: make smp::count non-static' from Avi Kivity
    smp: convert all smp::count usages to instance-aware alternatives
    smp: add per-instance shard_count and this_smp() infrastructure
    disk_params: document pre-init smp::count access with explicit 0
    reactor_backend: document pre-init smp::count access with explicit 0
    tests: alien_test: pass shard count to alien thread explicitly
  > build: fix cmake missing ninja on Ubuntu 26.04
  > rpc: Fix uint64 wraparound of expired timeout in send_entry()
  > Merge 'Generalize some RPC tests' from Pavel Emelyanov
    tests: Generalize async connection-based scheduling RPC tests
    tests: Generalize sync connection-based scheduling RPC tests
    tests: Remove redundant variadic/nonvariadic RPC tuple tests
    tests: Generalize max timeout RPC tests
  > net: tls: openssl: Share BIO ptrs across shards
  > http: fix compilation on clang 22 with c++26
  > build: openssl tools needed for test cert generation
  > reactor: support rename2
  > future: fix forwarding of reference types
  > Merge 'Zero-copy http chunked data sink' from Pavel Emelyanov
    http: Make chunked data sink zero-copy
    tests/prometheus_http: Rewrite on top of http::client
    tests/httpd: Rewrite content_length_limit on top of http::client
  > tests: Replace ad-hoc http_consumer with production HTTP parser
  > Merge 'co_return to accept same expressions and types as return' from Alexey Bashtanov
    tests/unit/{coroutines,futures}: strict types on co_return and set_value
    api: introduce version 10:
    core/{coroutine,future}: make `co_return` more strict with types
    core/{coroutine,future}: preparations to fix `co_return` type semantics
  > Merge 'Perftune.py: add special handling for mlx5 rss queues number calculation' from Vladislav Zolotarov
    perftune.py: NetPerfTuner: enhance RSS (a.k.a. "Rx") queues accounting for mlx5 devices
    perftune.py: update docstring of NetPerfTuner.__get_rps_cpus() method
    perftune.py: add a method that parses and models the output of the 'ethtool -l' command for a given interface
  > httpd: rewrite do_accepts/do_accept_one as coroutines
  > file: add mmap support to file
  > http: Move client code out of experimental namespace
  > file: add hugetlbfs support to file system detection
  > tests: Replace test_source_impl with util::as_input_stream
  > tests: Replace buf_source_impl with util::as_input_stream
  > Merge 'rpc_tester: expose throuput for rpc tester' from Marcin Szopa
    rpc_tester: remove unused payload size variable from job_rpc_streaming class
    rpc_tester: add start time tracking for throughput calculation, print throughput and msg/s for job_rpc
    rpc_tester: refactor result emission to use dedicated functions for messages and throughput
  > iostream: cast first argument of `std::min` to `size_t`

Closes scylladb/scylladb#29952
2026-05-20 13:47:12 +03:00

214 lines
7.0 KiB
C++

/*
* Copyright (C) 2025 ScyllaDB
*
*/
/*
* SPDX-License-Identifier: LicenseRef-ScyllaDB-Source-Available-1.1
*/
#pragma once
#include <seastar/core/future.hh>
#include <seastar/http/url.hh>
#include <seastar/http/client.hh>
#include <seastar/http/request.hh>
#include <seastar/http/reply.hh>
#include <seastar/http/exception.hh>
#include "utils/rjson.hh"
namespace seastar {
class abort_source;
}
namespace rest {
/**
* Wrapper for http::request, making setting headers, body, etc
* more convenient for our purposes. Separated from the below client
* so the logic can be shared with non-single usage, i.e. the free-form
* simple_send method, possibly caching a http::client across calls.
*/
class request_wrapper {
public:
request_wrapper(std::string_view host);
request_wrapper(request_wrapper&&);
request_wrapper& add_header(std::string_view key, std::string_view value);
void clear_headers();
using reply_status = seastar::http::reply::status_type;
using request_type = seastar::http::request;
using reply_type = seastar::http::reply;
using method_type = seastar::httpd::operation_type;
using body_writer = decltype(std::declval<seastar::http::request>().body_writer);
void method(method_type);
void content(std::string_view content_type, std::string_view);
void content(std::string_view content_type, body_writer, size_t);
void target(std::string_view);
request_type& request() {
return _req;
}
const request_type& request() const {
return _req;
}
operator request_type&() {
return request();
}
operator const request_type&() const {
return request();
}
protected:
request_type _req;
};
/**
* HTTP client wrapper for making short, stateless REST calls, such as
* OAUTH, GCP/AWS/Azure queries, etc.
* No statefulness, no reuse, no sessions.
* Just a GET/POST and a result.
*/
class httpclient : public request_wrapper {
public:
httpclient();
httpclient(std::string host, uint16_t port, seastar::shared_ptr<seastar::tls::certificate_credentials> = {}, std::optional<seastar::tls::tls_options> = {});
struct result_type {
seastar::http::reply reply;
reply_status result() const {
return reply._status;
}
int result_int() const {
return int(result());
}
std::string_view body() const {
return reply._content;
}
};
using handler_func = std::function<void(const seastar::http::reply&, std::string_view)>;
seastar::future<result_type> send(seastar::abort_source* = nullptr);
seastar::future<> send(const handler_func&, seastar::abort_source* = nullptr);
const std::string& host() const {
return _host;
}
uint16_t port() const {
return _port;
}
static inline constexpr const char* CONTENT_TYPE_HEADER = "content-type";
private:
std::string _host;
uint16_t _port;
seastar::shared_ptr<seastar::tls::certificate_credentials> _creds;
seastar::tls::tls_options _tls_options;
};
using handler_func_ex = std::function<future<>(const seastar::http::reply&, seastar::input_stream<char>&)>;
seastar::future<> simple_send(seastar::http::client&, seastar::http::request&, const handler_func_ex&, seastar::abort_source* = nullptr);
seastar::future<> simple_send(seastar::http::client&, seastar::http::request&, const handler_func_ex&, const http::retry_strategy* strategy, seastar::abort_source* = nullptr);
// Interface for redacting sensitive data from HTTP requests and responses before logging.
class http_log_filter {
public:
static constexpr char REDACTED_VALUE[] = "[REDACTED]";
enum class body_type {
request,
response,
};
using string_opt = std::optional<std::string>;
// Filter a request/response header.
// Returns an optional containing the filtered value. If no filtering is required, the optional is not engaged.
virtual string_opt filter_header(std::string_view name, std::string_view value) const = 0;
// Filter the request/response body.
// Returns an optional containing the filtered value. If no filtering is required, the optional is not engaged.
virtual string_opt filter_body(body_type type, const std::string_view body) const = 0;
};
class nop_log_filter: public http_log_filter {
public:
string_opt filter_header(std::string_view name, std::string_view value) const override { return std::nullopt; }
string_opt filter_body(body_type type, std::string_view body) const override { return std::nullopt; }
};
template<typename T, http_log_filter::body_type type>
struct redacted {
const T& original;
const http_log_filter& filter;
std::optional<std::string> filter_header(std::string_view name, std::string_view value) const {
return filter.filter_header(name, value);
}
std::optional<std::string> filter_body(std::string_view value) const {
return filter.filter_body(type, value);
}
};
using redacted_request_type = redacted<httpclient::request_type, http_log_filter::body_type::request>;
using redacted_result_type = redacted<httpclient::result_type, http_log_filter::body_type::response>;
using key_value = std::pair<std::string_view, std::string_view>;
using key_values = std::span<const key_value>;
class unexpected_status_error : public seastar::httpd::unexpected_status_error {
std::vector<std::pair<std::string, std::string>> _headers;
public:
unexpected_status_error(seastar::http::reply::status_type, key_values);
const auto& headers() const {
return _headers;
}
};
future<rjson::value> send_request(std::string_view uri
, seastar::shared_ptr<seastar::tls::certificate_credentials>
, const rjson::value& body
, httpclient::method_type op
, key_values headers = {}
, seastar::abort_source* = nullptr
);
future<rjson::value> send_request(std::string_view uri
, seastar::shared_ptr<seastar::tls::certificate_credentials>
, std::string body
, std::string_view content_type
, httpclient::method_type op
, key_values headers = {}
, seastar::abort_source* = nullptr
);
future<> send_request(std::string_view uri
, seastar::shared_ptr<seastar::tls::certificate_credentials>
, std::string body
, std::string_view content_type
, const std::function<void(const httpclient::reply_type&, std::string_view)>& handler
, httpclient::method_type op
, key_values headers = {}
, seastar::abort_source* = nullptr
);
}
template <>
struct fmt::formatter<rest::httpclient::result_type> : fmt::formatter<std::string_view> {
auto format(const rest::httpclient::result_type&, fmt::format_context& ctx) const -> decltype(ctx.out());
};
template <>
struct fmt::formatter<rest::redacted_request_type> : fmt::formatter<std::string_view> {
auto format(const rest::redacted_request_type&, fmt::format_context& ctx) const -> decltype(ctx.out());
};
template <>
struct fmt::formatter<rest::redacted_result_type> : fmt::formatter<std::string_view> {
auto format(const rest::redacted_result_type&, fmt::format_context& ctx) const -> decltype(ctx.out());
};