]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
librbd/migration: implement a callback hook for processing http requests
authorJason Dillaman <dillaman@redhat.com>
Fri, 13 Nov 2020 02:17:43 +0000 (21:17 -0500)
committerJason Dillaman <dillaman@redhat.com>
Mon, 23 Nov 2020 13:45:50 +0000 (08:45 -0500)
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 <dillaman@redhat.com>
src/librbd/migration/HttpClient.cc
src/librbd/migration/HttpClient.h
src/librbd/migration/HttpProcessorInterface.h [new file with mode: 0644]
src/test/librbd/migration/test_mock_HttpClient.cc

index 8ae55ba94ccc9849fd0b243a773418d6c95690a3..b077e93359561353df1b8cd6255c9291aad45f72 100644 (file)
@@ -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 <typename I>
 void HttpClient<I>::get_size(uint64_t* size, Context* on_finish) {
   ldout(m_cct, 10) << dendl;
 
-  boost::beast::http::request<EmptyBody> req;
+  Request req;
   req.method(boost::beast::http::verb::head);
 
   issue(
index 79ff2c3eeb97d5c741b86285c486762266f3ca2d..0dfca9d48e17ac7dc9a50ab1fc4fe0d994ef932a 100644 (file)
@@ -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 <boost/asio/io_context_strand.hpp>
 #include <boost/asio/ip/tcp.hpp>
@@ -18,6 +19,7 @@
 #include <boost/beast/http/string_body.hpp>
 #include <boost/beast/http/write.hpp>
 #include <boost/beast/ssl/ssl_stream.hpp>
+#include <functional>
 #include <memory>
 #include <string>
 #include <utility>
@@ -39,6 +41,8 @@ public:
   using Request = boost::beast::http::request<EmptyBody>;
   using Response = boost::beast::http::response<StringBody>;
 
+  using RequestPreprocessor = std::function<void(Request&)>;
+
   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 <class Body, typename Completion>
   void issue(boost::beast::http::request<Body>&& request,
              Completion&& completion) {
     struct WorkImpl : Work {
+      HttpClient* http_client;
       boost::beast::http::request<Body> request;
       Completion completion;
 
-      WorkImpl(boost::beast::http::request<Body>&& request,
+      WorkImpl(HttpClient* http_client,
+               boost::beast::http::request<Body>&& 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<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 preprocess_request() {
+        if (http_client->m_http_processor) {
+          http_client->m_http_processor->process_request(request);
+        }
+      }
     };
 
     initialize_default_fields(request);
-    issue(std::make_shared<WorkImpl>(std::move(request),
+    issue(std::make_shared<WorkImpl>(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<boost::beast::tcp_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 (file)
index 0000000..3d9af88
--- /dev/null
@@ -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 <boost/beast/http/empty_body.hpp>
+#include <boost/beast/http/message.hpp>
+
+namespace librbd {
+namespace migration {
+
+struct HttpProcessorInterface {
+  using EmptyBody = boost::beast::http::empty_body;
+  using EmptyRequest = boost::beast::http::request<EmptyBody>;
+
+  virtual ~HttpProcessorInterface() {
+  }
+
+  virtual void process_request(EmptyRequest& request) = 0;
+
+};
+
+} // namespace migration
+} // namespace librbd
+
+#endif // CEPH_LIBRBD_MIGRATION_HTTP_PROCESSOR_INTERFACE_H
index 0a52d71a4e4100cf493114c417182049840ccea4..57718edf1277803cde35f4bcb60e4ec241750d50 100644 (file)
@@ -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);