// -*- 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