From: Jason Dillaman Date: Fri, 13 Nov 2020 02:17:43 +0000 (-0500) Subject: librbd/migration: implement a callback hook for processing http requests X-Git-Tag: v16.1.0~479^2~3 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=7e3fa13ab3e6e568a11bee0e9e60e58f3a1726de;p=ceph.git librbd/migration: implement a callback hook for processing http requests The S3 authentication scheme requires adding additional headers to the outbound request as well as computing a secure signature for the request using the secret key. Signed-off-by: Jason Dillaman --- diff --git a/src/librbd/migration/HttpClient.cc b/src/librbd/migration/HttpClient.cc index 8ae55ba94ccc9..b077e93359561 100644 --- a/src/librbd/migration/HttpClient.cc +++ b/src/librbd/migration/HttpClient.cc @@ -110,7 +110,7 @@ public: ldout(cct, 20) << "work=" << work.get() << dendl; ++m_in_flight_requests; - (*work)(this, derived().stream()); + (*work)(derived().stream()); } void handle_issue(boost::system::error_code ec, @@ -776,7 +776,7 @@ template void HttpClient::get_size(uint64_t* size, Context* on_finish) { ldout(m_cct, 10) << dendl; - boost::beast::http::request req; + Request req; req.method(boost::beast::http::verb::head); issue( diff --git a/src/librbd/migration/HttpClient.h b/src/librbd/migration/HttpClient.h index 79ff2c3eeb97d..0dfca9d48e17a 100644 --- a/src/librbd/migration/HttpClient.h +++ b/src/librbd/migration/HttpClient.h @@ -7,6 +7,7 @@ #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 @@ -18,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -39,6 +41,8 @@ public: 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); } @@ -59,16 +63,23 @@ public: 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(boost::beast::http::request&& request, + WorkImpl(HttpClient* http_client, + boost::beast::http::request&& request, Completion&& completion) - : request(std::move(request)), completion(std::move(completion)) { + : http_client(http_client), request(std::move(request)), + completion(std::move(completion)) { } WorkImpl(const WorkImpl&) = delete; WorkImpl& operator=(const WorkImpl&) = delete; @@ -85,31 +96,40 @@ public: completion(r, std::move(response)); } - void operator()( - HttpSessionInterface* http_session, - boost::beast::tcp_stream& stream) override { + void operator()(boost::beast::tcp_stream& stream) override { + preprocess_request(); + boost::beast::http::async_write( stream, request, - [http_session, work=this->shared_from_this()] + [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()( - HttpSessionInterface* http_session, boost::beast::ssl_stream& stream) override { + preprocess_request(); + boost::beast::http::async_write( stream, request, - [http_session, work=this->shared_from_this()] + [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(std::move(request), + issue(std::make_shared(this, std::move(request), std::move(completion))); } @@ -131,11 +151,8 @@ private: 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()( - HttpSessionInterface* http_session, - boost::beast::tcp_stream& stream) = 0; - virtual void operator()( - HttpSessionInterface* http_session, boost::beast::ssl_stream& stream) = 0; }; @@ -153,6 +170,8 @@ private: bool m_ignore_self_signed_cert = false; + HttpProcessorInterface* m_http_processor = nullptr; + boost::asio::io_context::strand m_strand; boost::asio::ssl::context m_ssl_context; diff --git a/src/librbd/migration/HttpProcessorInterface.h b/src/librbd/migration/HttpProcessorInterface.h new file mode 100644 index 0000000000000..3d9af88bd168a --- /dev/null +++ b/src/librbd/migration/HttpProcessorInterface.h @@ -0,0 +1,27 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab + +#ifndef CEPH_LIBRBD_MIGRATION_HTTP_PROCESSOR_INTERFACE_H +#define CEPH_LIBRBD_MIGRATION_HTTP_PROCESSOR_INTERFACE_H + +#include +#include + +namespace librbd { +namespace migration { + +struct HttpProcessorInterface { + using EmptyBody = boost::beast::http::empty_body; + using EmptyRequest = boost::beast::http::request; + + virtual ~HttpProcessorInterface() { + } + + virtual void process_request(EmptyRequest& request) = 0; + +}; + +} // namespace migration +} // namespace librbd + +#endif // CEPH_LIBRBD_MIGRATION_HTTP_PROCESSOR_INTERFACE_H diff --git a/src/test/librbd/migration/test_mock_HttpClient.cc b/src/test/librbd/migration/test_mock_HttpClient.cc index 0a52d71a4e410..57718edf12778 100644 --- a/src/test/librbd/migration/test_mock_HttpClient.cc +++ b/src/test/librbd/migration/test_mock_HttpClient.cc @@ -35,8 +35,6 @@ inline ImageCtx *get_image_ctx(MockTestImageCtx *image_ctx) { using EmptyHttpRequest = boost::beast::http::request< boost::beast::http::empty_body>; -using HttpRequest = boost::beast::http::request< - boost::beast::http::string_body>; using HttpResponse = boost::beast::http::response< boost::beast::http::string_body>; @@ -457,11 +455,11 @@ TEST_F(TestMockMigrationHttpClient, IssueSendFailed) { client_accept(&socket, false, &on_connect_ctx2); // send request via closed connection - HttpRequest req; + EmptyHttpRequest req; req.method(boost::beast::http::verb::get); C_SaferCond ctx2; - http_client.issue(HttpRequest{req}, + http_client.issue(EmptyHttpRequest{req}, [&ctx2](int r, HttpResponse&&) mutable { ctx2.complete(r); }); @@ -494,11 +492,11 @@ TEST_F(TestMockMigrationHttpClient, IssueReceiveFailed) { ASSERT_EQ(0, ctx1.wait()); // send request via closed connection - HttpRequest req; + EmptyHttpRequest req; req.method(boost::beast::http::verb::get); C_SaferCond ctx2; - http_client.issue(HttpRequest{req}, + http_client.issue(EmptyHttpRequest{req}, [&ctx2](int r, HttpResponse&&) mutable { ctx2.complete(r); }); @@ -544,17 +542,17 @@ TEST_F(TestMockMigrationHttpClient, IssueResetFailed) { ASSERT_EQ(0, ctx1.wait()); // send requests then close connection - HttpRequest req; + EmptyHttpRequest req; req.method(boost::beast::http::verb::get); C_SaferCond ctx2; - http_client.issue(HttpRequest{req}, + http_client.issue(EmptyHttpRequest{req}, [&ctx2](int r, HttpResponse&&) mutable { ctx2.complete(r); }); C_SaferCond ctx3; - http_client.issue(HttpRequest{req}, + http_client.issue(EmptyHttpRequest{req}, [&ctx3](int r, HttpResponse&&) mutable { ctx3.complete(r); }); @@ -577,7 +575,7 @@ TEST_F(TestMockMigrationHttpClient, IssueResetFailed) { client_accept(&socket, false, &on_connect_ctx2); C_SaferCond ctx4; - http_client.issue(HttpRequest{req}, + http_client.issue(EmptyHttpRequest{req}, [&ctx4](int r, HttpResponse&&) mutable { ctx4.complete(r); }); @@ -610,23 +608,23 @@ TEST_F(TestMockMigrationHttpClient, IssuePipelined) { ASSERT_EQ(0, ctx1.wait()); // issue two pipelined (concurrent) get requests - HttpRequest req1; + EmptyHttpRequest req1; req1.method(boost::beast::http::verb::get); C_SaferCond ctx2; HttpResponse res1; - http_client.issue(HttpRequest{req1}, + http_client.issue(EmptyHttpRequest{req1}, [&ctx2, &res1](int r, HttpResponse&& response) mutable { res1 = std::move(response); ctx2.complete(r); }); - HttpRequest req2; + EmptyHttpRequest req2; req2.method(boost::beast::http::verb::get); C_SaferCond ctx3; HttpResponse res2; - http_client.issue(HttpRequest{req2}, + http_client.issue(EmptyHttpRequest{req2}, [&ctx3, &res2](int r, HttpResponse&& response) mutable { res2 = std::move(response); ctx3.complete(r); @@ -668,7 +666,7 @@ TEST_F(TestMockMigrationHttpClient, IssuePipelinedRestart) { ASSERT_EQ(0, ctx1.wait()); // issue two pipelined (concurrent) get requests - HttpRequest req1; + EmptyHttpRequest req1; req1.keep_alive(false); req1.method(boost::beast::http::verb::get); @@ -677,18 +675,18 @@ TEST_F(TestMockMigrationHttpClient, IssuePipelinedRestart) { C_SaferCond ctx2; HttpResponse res1; - http_client.issue(HttpRequest{req1}, + http_client.issue(EmptyHttpRequest{req1}, [&ctx2, &res1](int r, HttpResponse&& response) mutable { res1 = std::move(response); ctx2.complete(r); }); - HttpRequest req2; + EmptyHttpRequest req2; req2.method(boost::beast::http::verb::get); C_SaferCond ctx3; HttpResponse res2; - http_client.issue(HttpRequest{req2}, + http_client.issue(EmptyHttpRequest{req2}, [&ctx3, &res2](int r, HttpResponse&& response) mutable { res2 = std::move(response); ctx3.complete(r); @@ -734,11 +732,11 @@ TEST_F(TestMockMigrationHttpClient, ShutdownInFlight) { ASSERT_EQ(0, on_connect_ctx.wait()); ASSERT_EQ(0, ctx1.wait()); - HttpRequest req; + EmptyHttpRequest req; req.method(boost::beast::http::verb::get); C_SaferCond ctx2; - http_client.issue(HttpRequest{req}, + http_client.issue(EmptyHttpRequest{req}, [&ctx2](int r, HttpResponse&&) mutable { ctx2.complete(r); }); @@ -769,7 +767,7 @@ TEST_F(TestMockMigrationHttpClient, GetSize) { C_SaferCond ctx2; http_client.get_size(&size, &ctx2); - HttpRequest expected_req; + EmptyHttpRequest expected_req; expected_req.method(boost::beast::http::verb::head); client_read_request(socket, expected_req); @@ -803,7 +801,7 @@ TEST_F(TestMockMigrationHttpClient, GetSizeError) { C_SaferCond ctx2; http_client.get_size(&size, &ctx2); - HttpRequest expected_req; + EmptyHttpRequest expected_req; expected_req.method(boost::beast::http::verb::head); client_read_request(socket, expected_req); @@ -836,12 +834,12 @@ TEST_F(TestMockMigrationHttpClient, Read) { C_SaferCond ctx2; http_client.read({{0, 128}, {256, 64}}, &bl, &ctx2); - HttpRequest expected_req1; + EmptyHttpRequest expected_req1; expected_req1.method(boost::beast::http::verb::get); expected_req1.set(boost::beast::http::field::range, "bytes=0-127"); client_read_request(socket, expected_req1); - HttpRequest expected_req2; + EmptyHttpRequest expected_req2; expected_req2.method(boost::beast::http::verb::get); expected_req2.set(boost::beast::http::field::range, "bytes=256-319"); client_read_request(socket, expected_req2);