From e6918187568dbd01842d8d1d2c808ce16a894239 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 21 Apr 2024 13:54:28 +0200 Subject: Adding upstream version 18.2.2. Signed-off-by: Daniel Baumann --- src/librbd/migration/HttpClient.h | 205 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 205 insertions(+) create mode 100644 src/librbd/migration/HttpClient.h (limited to 'src/librbd/migration/HttpClient.h') diff --git a/src/librbd/migration/HttpClient.h b/src/librbd/migration/HttpClient.h new file mode 100644 index 000000000..3997e6159 --- /dev/null +++ b/src/librbd/migration/HttpClient.h @@ -0,0 +1,205 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab + +#ifndef CEPH_LIBRBD_MIGRATION_HTTP_CLIENT_H +#define CEPH_LIBRBD_MIGRATION_HTTP_CLIENT_H + +#include "include/common_fwd.h" +#include "include/int_types.h" +#include "librbd/io/Types.h" +#include "librbd/migration/HttpProcessorInterface.h" +#include "librbd/migration/Types.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct Context; + +namespace librbd { + +struct AsioEngine; +struct ImageCtx; + +namespace migration { + +template +class HttpClient { +public: + using EmptyBody = boost::beast::http::empty_body; + using StringBody = boost::beast::http::string_body; + using Request = boost::beast::http::request; + using Response = boost::beast::http::response; + + using RequestPreprocessor = std::function; + + static HttpClient* create(ImageCtxT* image_ctx, const std::string& url) { + return new HttpClient(image_ctx, url); + } + + HttpClient(ImageCtxT* image_ctx, const std::string& url); + HttpClient(const HttpClient&) = delete; + HttpClient& operator=(const HttpClient&) = delete; + + void open(Context* on_finish); + void close(Context* on_finish); + + void get_size(uint64_t* size, Context* on_finish); + + void read(io::Extents&& byte_extents, bufferlist* data, + Context* on_finish); + + void set_ignore_self_signed_cert(bool ignore) { + m_ignore_self_signed_cert = ignore; + } + + void set_http_processor(HttpProcessorInterface* http_processor) { + m_http_processor = http_processor; + } + + template + void issue(boost::beast::http::request&& request, + Completion&& completion) { + struct WorkImpl : Work { + HttpClient* http_client; + boost::beast::http::request request; + Completion completion; + + WorkImpl(HttpClient* http_client, + boost::beast::http::request&& request, + Completion&& completion) + : http_client(http_client), request(std::move(request)), + completion(std::move(completion)) { + } + WorkImpl(const WorkImpl&) = delete; + WorkImpl& operator=(const WorkImpl&) = delete; + + bool need_eof() const override { + return request.need_eof(); + } + + bool header_only() const override { + return (request.method() == boost::beast::http::verb::head); + } + + void complete(int r, Response&& response) override { + completion(r, std::move(response)); + } + + void operator()(boost::beast::tcp_stream& stream) override { + preprocess_request(); + + boost::beast::http::async_write( + stream, request, + [http_session=http_client->m_http_session.get(), + work=this->shared_from_this()] + (boost::beast::error_code ec, std::size_t) mutable { + http_session->handle_issue(ec, std::move(work)); + }); + } + + void operator()( + boost::beast::ssl_stream& stream) override { + preprocess_request(); + + boost::beast::http::async_write( + stream, request, + [http_session=http_client->m_http_session.get(), + work=this->shared_from_this()] + (boost::beast::error_code ec, std::size_t) mutable { + http_session->handle_issue(ec, std::move(work)); + }); + } + + void preprocess_request() { + if (http_client->m_http_processor) { + http_client->m_http_processor->process_request(request); + } + } + }; + + initialize_default_fields(request); + issue(std::make_shared(this, std::move(request), + std::move(completion))); + } + +private: + struct Work; + struct HttpSessionInterface { + virtual ~HttpSessionInterface() {} + + virtual void init(Context* on_finish) = 0; + virtual void shut_down(Context* on_finish) = 0; + + virtual void issue(std::shared_ptr&& work) = 0; + virtual void handle_issue(boost::system::error_code ec, + std::shared_ptr&& work) = 0; + }; + + struct Work : public std::enable_shared_from_this { + virtual ~Work() {} + virtual bool need_eof() const = 0; + virtual bool header_only() const = 0; + virtual void complete(int r, Response&&) = 0; + virtual void operator()(boost::beast::tcp_stream& stream) = 0; + virtual void operator()( + boost::beast::ssl_stream& stream) = 0; + }; + + template struct HttpSession; + struct PlainHttpSession; + struct SslHttpSession; + + CephContext* m_cct; + ImageCtxT* m_image_ctx; + std::shared_ptr m_asio_engine; + std::string m_url; + + UrlSpec m_url_spec; + + bool m_ignore_self_signed_cert = false; + + HttpProcessorInterface* m_http_processor = nullptr; + + boost::asio::strand m_strand; + + boost::asio::ssl::context m_ssl_context; + std::unique_ptr m_http_session; + + template + void initialize_default_fields(Fields& fields) const { + fields.target(m_url_spec.path); + fields.set(boost::beast::http::field::host, m_url_spec.host); + fields.set(boost::beast::http::field::user_agent, + BOOST_BEAST_VERSION_STRING); + } + + void handle_get_size(int r, Response&& response, uint64_t* size, + Context* on_finish); + + void handle_read(int r, Response&& response, uint64_t byte_offset, + uint64_t byte_length, bufferlist* data, Context* on_finish); + + void issue(std::shared_ptr&& work); + + void create_http_session(Context* on_finish); + void shut_down_http_session(Context* on_finish); +}; + +} // namespace migration +} // namespace librbd + +extern template class librbd::migration::HttpClient; + +#endif // CEPH_LIBRBD_MIGRATION_HTTP_CLIENT_H -- cgit v1.2.3