]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
rgw: ONLY move rgw_client_io_decoimpl.h to rgw_client_io_filters.h.
authorRadoslaw Zarzynski <rzarzynski@mirantis.com>
Tue, 11 Oct 2016 19:46:20 +0000 (21:46 +0200)
committerRadoslaw Zarzynski <rzarzynski@mirantis.com>
Fri, 21 Oct 2016 20:57:22 +0000 (22:57 +0200)
Signed-off-by: Radoslaw Zarzynski <rzarzynski@mirantis.com>
src/rgw/rgw_civetweb_frontend.cc
src/rgw/rgw_client_io.h
src/rgw/rgw_client_io_decoimpl.h [deleted file]
src/rgw/rgw_client_io_filters.h [new file with mode: 0644]
src/rgw/rgw_fcgi_process.cc

index e0adeb8040f69ac6b8d17cb1a43156d2c9339928..27f1518a591ea31462a0663fe415cde49b018176 100644 (file)
@@ -7,7 +7,7 @@
 #include <boost/utility/string_ref.hpp>
 
 #include "rgw_frontend.h"
-#include "rgw_client_io_decoimpl.h"
+#include "rgw_client_io_filters.h"
 
 #define dout_subsys ceph_subsys_rgw
 
index 82460d0d1021be416e23811a35e67976897915e9..6bc6c939970e5064181c28fc8b07b6659ce90cb5 100644 (file)
@@ -184,7 +184,7 @@ public:
  * mixing interfaces with implementation. Additionally, those classes derive
  * from RGWRestfulIO defined here. I believe that including in the middle of
  * file is still better than polluting it directly. */
-#include "rgw_client_io_decoimpl.h"
+#include "rgw_client_io_filters.h"
 
 
 /* RGWRestfulIO: high level interface to interact with RESTful clients. What
diff --git a/src/rgw/rgw_client_io_decoimpl.h b/src/rgw/rgw_client_io_decoimpl.h
deleted file mode 100644 (file)
index f573af8..0000000
+++ /dev/null
@@ -1,404 +0,0 @@
-// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
-// vim: ts=8 sw=2 smarttab
-
-#ifndef CEPH_RGW_CLIENT_IO_DECOIMPL_H
-#define CEPH_RGW_CLIENT_IO_DECOIMPL_H
-
-#include <type_traits>
-
-#include <boost/optional.hpp>
-
-#include "rgw_common.h"
-#include "rgw_client_io.h"
-
-namespace rgw {
-namespace io {
-
-template <typename T>
-class AccountingFilter : public DecoratedRestfulClient<T>,
-                         public Accounter {
-  bool enabled;
-  uint64_t total_sent;
-  uint64_t total_received;
-
-public:
-  template <typename U>
-  AccountingFilter(U&& decoratee)
-    : DecoratedRestfulClient<T>(std::forward<U>(decoratee)),
-      enabled(false),
-      total_sent(0),
-      total_received(0) {
-  }
-
-  size_t send_status(const int status,
-                     const char* const status_name) override {
-    const auto sent = DecoratedRestfulClient<T>::send_status(status,
-                                                             status_name);
-    if (enabled) {
-      total_sent += sent;
-    }
-    return sent;
-  }
-
-  size_t send_100_continue() override {
-    const auto sent = DecoratedRestfulClient<T>::send_100_continue();
-    if (enabled) {
-      total_sent += sent;
-    }
-    return sent;
-  }
-
-  size_t send_header(const boost::string_ref& name,
-                     const boost::string_ref& value) override {
-    const auto sent = DecoratedRestfulClient<T>::send_header(name, value);
-    if (enabled) {
-      total_sent += sent;
-    }
-    return sent;
-  }
-
-  size_t send_content_length(const uint64_t len) override {
-    const auto sent = DecoratedRestfulClient<T>::send_content_length(len);
-    if (enabled) {
-      total_sent += sent;
-    }
-    return sent;
-  }
-
-  size_t send_chunked_transfer_encoding() override {
-    const auto sent = DecoratedRestfulClient<T>::send_chunked_transfer_encoding();
-    if (enabled) {
-      total_sent += sent;
-    }
-    return sent;
-  }
-
-  size_t complete_header() override {
-    const auto sent = DecoratedRestfulClient<T>::complete_header();
-    if (enabled) {
-      total_sent += sent;
-    }
-    return sent;
-  }
-
-  size_t recv_body(char* buf, size_t max) override {
-    const auto received = DecoratedRestfulClient<T>::recv_body(buf, max);
-    if (enabled) {
-      total_received += received;
-    }
-    return received;
-  }
-
-  size_t send_body(const char* const buf,
-                   const size_t len) override {
-    const auto sent = DecoratedRestfulClient<T>::send_body(buf, len);
-    if (enabled) {
-      total_sent += sent;
-    }
-    return sent;
-  }
-
-  uint64_t get_bytes_sent() const override {
-    return total_sent;
-  }
-
-  uint64_t get_bytes_received() const override {
-    return total_received;
-  }
-
-  void set_account(bool enabled) override {
-    this->enabled = enabled;
-  }
-};
-
-
-/* Filter for in-memory buffering incoming data and calculating the content
- * length header if it isn't present. */
-template <typename T>
-class BufferingFilter : public DecoratedRestfulClient<T> {
-  template<typename Td> friend class DecoratedRestfulClient;
-protected:
-  ceph::bufferlist data;
-
-  bool has_content_length;
-  bool buffer_data;
-
-public:
-  template <typename U>
-  BufferingFilter(U&& decoratee)
-    : DecoratedRestfulClient<T>(std::forward<U>(decoratee)),
-      has_content_length(false),
-      buffer_data(false) {
-  }
-
-  size_t send_content_length(const uint64_t len) override;
-  size_t send_chunked_transfer_encoding() override;
-  size_t complete_header() override;
-  size_t send_body(const char* buf, size_t len) override;
-  size_t complete_request() override;
-};
-
-template <typename T>
-size_t BufferingFilter<T>::send_body(const char* const buf,
-                                     const size_t len)
-{
-  if (buffer_data) {
-    data.append(buf, len);
-    return 0;
-  }
-
-  return DecoratedRestfulClient<T>::send_body(buf, len);
-}
-
-template <typename T>
-size_t BufferingFilter<T>::send_content_length(const uint64_t len)
-{
-  has_content_length = true;
-  return DecoratedRestfulClient<T>::send_content_length(len);
-}
-
-template <typename T>
-size_t BufferingFilter<T>::send_chunked_transfer_encoding()
-{
-  has_content_length = true;
-  return DecoratedRestfulClient<T>::send_chunked_transfer_encoding();
-}
-
-template <typename T>
-size_t BufferingFilter<T>::complete_header()
-{
-  if (! has_content_length) {
-    /* We will dump everything in complete_request(). */
-    buffer_data = true;
-    return 0;
-  }
-
-  return DecoratedRestfulClient<T>::complete_header();
-}
-
-template <typename T>
-size_t BufferingFilter<T>::complete_request()
-{
-  size_t sent = 0;
-
-  if (! has_content_length) {
-    sent += DecoratedRestfulClient<T>::send_content_length(data.length());
-    sent += DecoratedRestfulClient<T>::complete_header();
-  }
-
-  if (buffer_data) {
-    /* We are sending each buffer separately to avoid extra memory shuffling
-     * that would occur on data.c_str() to provide a continuous memory area. */
-    for (const auto& ptr : data.buffers()) {
-      sent += DecoratedRestfulClient<T>::send_body(ptr.c_str(),
-                                                   ptr.length());
-    }
-    data.clear();
-    buffer_data = false;
-  }
-
-  return sent + DecoratedRestfulClient<T>::complete_request();
-}
-
-template <typename T> static inline
-BufferingFilter<T> add_buffering(T&& t) {
-  return BufferingFilter<T>(std::forward<T>(t));
-}
-
-
-template <typename T>
-class ChunkingFilter : public DecoratedRestfulClient<T> {
-  template<typename Td> friend class DecoratedRestfulClient;
-protected:
-  bool has_content_length;
-  bool chunking_enabled;
-
-public:
-  template <typename U>
-  ChunkingFilter(U&& decoratee)
-    : DecoratedRestfulClient<T>(std::forward<U>(decoratee)),
-      has_content_length(false),
-      chunking_enabled(false) {
-  }
-
-  size_t send_content_length(const uint64_t len) override {
-    has_content_length = true;
-    return DecoratedRestfulClient<T>::send_content_length(len);
-  }
-
-  size_t send_chunked_transfer_encoding() override {
-    has_content_length = false;
-    chunking_enabled = true;
-    return DecoratedRestfulClient<T>::send_header("Transfer-Encoding",
-                                                  "chunked");
-  }
-
-  size_t send_body(const char* buf,
-                   const size_t len) override {
-    if (! chunking_enabled) {
-      return DecoratedRestfulClient<T>::send_body(buf, len);
-    } else {
-      static constexpr char HEADER_END[] = "\r\n";
-      char sizebuf[32];
-      const auto slen = snprintf(sizebuf, sizeof(buf), "%" PRIx64 "\r\n", len);
-      size_t sent = 0;
-
-      sent += DecoratedRestfulClient<T>::send_body(sizebuf, slen);
-      sent += DecoratedRestfulClient<T>::send_body(buf, len);
-      sent += DecoratedRestfulClient<T>::send_body(HEADER_END,
-                                                   sizeof(HEADER_END) - 1);
-      return sent;
-    }
-  }
-
-  size_t complete_request() override {
-    size_t sent = 0;
-
-    if (chunking_enabled) {
-      static constexpr char CHUNKED_RESP_END[] = "0\r\n\r\n";
-      sent += DecoratedRestfulClient<T>::send_body(CHUNKED_RESP_END,
-                                                   sizeof(CHUNKED_RESP_END) - 1);
-    }
-
-    return sent + DecoratedRestfulClient<T>::complete_request();
-  }
-};
-
-template <typename T> static inline
-ChunkingFilter<T> add_chunking(T&& t) {
-  return ChunkingFilter<T>(std::forward<T>(t));
-}
-
-
-/* Class that controls and inhibits the process of sending Content-Length HTTP
- * header where RFC 7230 requests so. The cases worth our attention are 204 No
- * Content as well as 304 Not Modified. */
-template <typename T>
-class ConLenControllingFilter : public DecoratedRestfulClient<T> {
-protected:
-  enum class ContentLengthAction {
-    FORWARD,
-    INHIBIT,
-    UNKNOWN
-  } action;
-
-public:
-  template <typename U>
-  ConLenControllingFilter(U&& decoratee)
-    : DecoratedRestfulClient<T>(std::forward<U>(decoratee)),
-      action(ContentLengthAction::UNKNOWN) {
-  }
-
-  size_t send_status(const int status,
-                     const char* const status_name) override {
-    if (204 == status || 304 == status) {
-      action = ContentLengthAction::INHIBIT;
-    } else {
-      action = ContentLengthAction::FORWARD;
-    }
-
-    return DecoratedRestfulClient<T>::send_status(status, status_name);
-  }
-
-  size_t send_content_length(const uint64_t len) override {
-    switch(action) {
-    case ContentLengthAction::FORWARD:
-      return DecoratedRestfulClient<T>::send_content_length(len);
-    case ContentLengthAction::INHIBIT:
-      return 0;
-    case ContentLengthAction::UNKNOWN:
-    default:
-      return -EINVAL;
-    }
-  }
-};
-
-template <typename T> static inline
-ConLenControllingFilter<T> add_conlen_controlling(T&& t) {
-  return ConLenControllingFilter<T>(std::forward<T>(t));
-}
-
-
-/* Filter that rectifies the wrong behaviour of some clients of the RGWRestfulIO
- * interface. Should be removed after fixing those clients. */
-template <typename T>
-class ReorderingFilter : public DecoratedRestfulClient<T> {
-protected:
-  enum class ReorderState {
-    RGW_EARLY_HEADERS,  /* Got headers sent before calling send_status. */
-    RGW_STATUS_SEEN,    /* Status has been seen. */
-    RGW_DATA            /* Header has been completed. */
-  } phase;
-
-  boost::optional<uint64_t> content_length;
-
-  std::vector<std::pair<std::string, std::string>> headers;
-
-  size_t send_header(const boost::string_ref& name,
-                     const boost::string_ref& value) override {
-    switch (phase) {
-    case ReorderState::RGW_EARLY_HEADERS:
-    case ReorderState::RGW_STATUS_SEEN:
-      headers.emplace_back(std::make_pair(name.to_string(),
-                                          value.to_string()));
-      return 0;
-    case ReorderState::RGW_DATA:
-      return DecoratedRestfulClient<T>::send_header(name, value);
-    }
-
-    return -EIO;
-  }
-
-public:
-  template <typename U>
-  ReorderingFilter(U&& decoratee)
-    : DecoratedRestfulClient<T>(std::forward<U>(decoratee)),
-      phase(ReorderState::RGW_EARLY_HEADERS) {
-  }
-
-  size_t send_status(const int status,
-                     const char* const status_name) override {
-    phase = ReorderState::RGW_STATUS_SEEN;
-
-    return DecoratedRestfulClient<T>::send_status(status, status_name);
-  }
-
-  size_t send_content_length(const uint64_t len) override {
-    if (ReorderState::RGW_EARLY_HEADERS == phase) {
-      /* Oh great, someone tries to send content length before status. */
-      content_length = len;
-      return 0;
-    } else {
-      return DecoratedRestfulClient<T>::send_content_length(len);
-    }
-  }
-
-  size_t complete_header() override {
-    size_t sent = 0;
-
-    /* Change state in order to immediately send everything we get. */
-    phase = ReorderState::RGW_DATA;
-
-    /* Sent content length if necessary. */
-    if (content_length) {
-      sent += DecoratedRestfulClient<T>::send_content_length(*content_length);
-    }
-
-    /* Header data in buffers are already counted. */
-    for (const auto& kv : headers) {
-      sent += DecoratedRestfulClient<T>::send_header(kv.first, kv.second);
-    }
-    headers.clear();
-
-    return sent + DecoratedRestfulClient<T>::complete_header();
-  }
-};
-
-template <typename T> static inline
-ReorderingFilter<T> add_reordering(T&& t) {
-  return ReorderingFilter<T>(std::forward<T>(t));
-}
-
-} /* namespace io */
-} /* namespace rgw */
-#endif /* CEPH_RGW_CLIENT_IO_DECOIMPL_H */
diff --git a/src/rgw/rgw_client_io_filters.h b/src/rgw/rgw_client_io_filters.h
new file mode 100644 (file)
index 0000000..f573af8
--- /dev/null
@@ -0,0 +1,404 @@
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+
+#ifndef CEPH_RGW_CLIENT_IO_DECOIMPL_H
+#define CEPH_RGW_CLIENT_IO_DECOIMPL_H
+
+#include <type_traits>
+
+#include <boost/optional.hpp>
+
+#include "rgw_common.h"
+#include "rgw_client_io.h"
+
+namespace rgw {
+namespace io {
+
+template <typename T>
+class AccountingFilter : public DecoratedRestfulClient<T>,
+                         public Accounter {
+  bool enabled;
+  uint64_t total_sent;
+  uint64_t total_received;
+
+public:
+  template <typename U>
+  AccountingFilter(U&& decoratee)
+    : DecoratedRestfulClient<T>(std::forward<U>(decoratee)),
+      enabled(false),
+      total_sent(0),
+      total_received(0) {
+  }
+
+  size_t send_status(const int status,
+                     const char* const status_name) override {
+    const auto sent = DecoratedRestfulClient<T>::send_status(status,
+                                                             status_name);
+    if (enabled) {
+      total_sent += sent;
+    }
+    return sent;
+  }
+
+  size_t send_100_continue() override {
+    const auto sent = DecoratedRestfulClient<T>::send_100_continue();
+    if (enabled) {
+      total_sent += sent;
+    }
+    return sent;
+  }
+
+  size_t send_header(const boost::string_ref& name,
+                     const boost::string_ref& value) override {
+    const auto sent = DecoratedRestfulClient<T>::send_header(name, value);
+    if (enabled) {
+      total_sent += sent;
+    }
+    return sent;
+  }
+
+  size_t send_content_length(const uint64_t len) override {
+    const auto sent = DecoratedRestfulClient<T>::send_content_length(len);
+    if (enabled) {
+      total_sent += sent;
+    }
+    return sent;
+  }
+
+  size_t send_chunked_transfer_encoding() override {
+    const auto sent = DecoratedRestfulClient<T>::send_chunked_transfer_encoding();
+    if (enabled) {
+      total_sent += sent;
+    }
+    return sent;
+  }
+
+  size_t complete_header() override {
+    const auto sent = DecoratedRestfulClient<T>::complete_header();
+    if (enabled) {
+      total_sent += sent;
+    }
+    return sent;
+  }
+
+  size_t recv_body(char* buf, size_t max) override {
+    const auto received = DecoratedRestfulClient<T>::recv_body(buf, max);
+    if (enabled) {
+      total_received += received;
+    }
+    return received;
+  }
+
+  size_t send_body(const char* const buf,
+                   const size_t len) override {
+    const auto sent = DecoratedRestfulClient<T>::send_body(buf, len);
+    if (enabled) {
+      total_sent += sent;
+    }
+    return sent;
+  }
+
+  uint64_t get_bytes_sent() const override {
+    return total_sent;
+  }
+
+  uint64_t get_bytes_received() const override {
+    return total_received;
+  }
+
+  void set_account(bool enabled) override {
+    this->enabled = enabled;
+  }
+};
+
+
+/* Filter for in-memory buffering incoming data and calculating the content
+ * length header if it isn't present. */
+template <typename T>
+class BufferingFilter : public DecoratedRestfulClient<T> {
+  template<typename Td> friend class DecoratedRestfulClient;
+protected:
+  ceph::bufferlist data;
+
+  bool has_content_length;
+  bool buffer_data;
+
+public:
+  template <typename U>
+  BufferingFilter(U&& decoratee)
+    : DecoratedRestfulClient<T>(std::forward<U>(decoratee)),
+      has_content_length(false),
+      buffer_data(false) {
+  }
+
+  size_t send_content_length(const uint64_t len) override;
+  size_t send_chunked_transfer_encoding() override;
+  size_t complete_header() override;
+  size_t send_body(const char* buf, size_t len) override;
+  size_t complete_request() override;
+};
+
+template <typename T>
+size_t BufferingFilter<T>::send_body(const char* const buf,
+                                     const size_t len)
+{
+  if (buffer_data) {
+    data.append(buf, len);
+    return 0;
+  }
+
+  return DecoratedRestfulClient<T>::send_body(buf, len);
+}
+
+template <typename T>
+size_t BufferingFilter<T>::send_content_length(const uint64_t len)
+{
+  has_content_length = true;
+  return DecoratedRestfulClient<T>::send_content_length(len);
+}
+
+template <typename T>
+size_t BufferingFilter<T>::send_chunked_transfer_encoding()
+{
+  has_content_length = true;
+  return DecoratedRestfulClient<T>::send_chunked_transfer_encoding();
+}
+
+template <typename T>
+size_t BufferingFilter<T>::complete_header()
+{
+  if (! has_content_length) {
+    /* We will dump everything in complete_request(). */
+    buffer_data = true;
+    return 0;
+  }
+
+  return DecoratedRestfulClient<T>::complete_header();
+}
+
+template <typename T>
+size_t BufferingFilter<T>::complete_request()
+{
+  size_t sent = 0;
+
+  if (! has_content_length) {
+    sent += DecoratedRestfulClient<T>::send_content_length(data.length());
+    sent += DecoratedRestfulClient<T>::complete_header();
+  }
+
+  if (buffer_data) {
+    /* We are sending each buffer separately to avoid extra memory shuffling
+     * that would occur on data.c_str() to provide a continuous memory area. */
+    for (const auto& ptr : data.buffers()) {
+      sent += DecoratedRestfulClient<T>::send_body(ptr.c_str(),
+                                                   ptr.length());
+    }
+    data.clear();
+    buffer_data = false;
+  }
+
+  return sent + DecoratedRestfulClient<T>::complete_request();
+}
+
+template <typename T> static inline
+BufferingFilter<T> add_buffering(T&& t) {
+  return BufferingFilter<T>(std::forward<T>(t));
+}
+
+
+template <typename T>
+class ChunkingFilter : public DecoratedRestfulClient<T> {
+  template<typename Td> friend class DecoratedRestfulClient;
+protected:
+  bool has_content_length;
+  bool chunking_enabled;
+
+public:
+  template <typename U>
+  ChunkingFilter(U&& decoratee)
+    : DecoratedRestfulClient<T>(std::forward<U>(decoratee)),
+      has_content_length(false),
+      chunking_enabled(false) {
+  }
+
+  size_t send_content_length(const uint64_t len) override {
+    has_content_length = true;
+    return DecoratedRestfulClient<T>::send_content_length(len);
+  }
+
+  size_t send_chunked_transfer_encoding() override {
+    has_content_length = false;
+    chunking_enabled = true;
+    return DecoratedRestfulClient<T>::send_header("Transfer-Encoding",
+                                                  "chunked");
+  }
+
+  size_t send_body(const char* buf,
+                   const size_t len) override {
+    if (! chunking_enabled) {
+      return DecoratedRestfulClient<T>::send_body(buf, len);
+    } else {
+      static constexpr char HEADER_END[] = "\r\n";
+      char sizebuf[32];
+      const auto slen = snprintf(sizebuf, sizeof(buf), "%" PRIx64 "\r\n", len);
+      size_t sent = 0;
+
+      sent += DecoratedRestfulClient<T>::send_body(sizebuf, slen);
+      sent += DecoratedRestfulClient<T>::send_body(buf, len);
+      sent += DecoratedRestfulClient<T>::send_body(HEADER_END,
+                                                   sizeof(HEADER_END) - 1);
+      return sent;
+    }
+  }
+
+  size_t complete_request() override {
+    size_t sent = 0;
+
+    if (chunking_enabled) {
+      static constexpr char CHUNKED_RESP_END[] = "0\r\n\r\n";
+      sent += DecoratedRestfulClient<T>::send_body(CHUNKED_RESP_END,
+                                                   sizeof(CHUNKED_RESP_END) - 1);
+    }
+
+    return sent + DecoratedRestfulClient<T>::complete_request();
+  }
+};
+
+template <typename T> static inline
+ChunkingFilter<T> add_chunking(T&& t) {
+  return ChunkingFilter<T>(std::forward<T>(t));
+}
+
+
+/* Class that controls and inhibits the process of sending Content-Length HTTP
+ * header where RFC 7230 requests so. The cases worth our attention are 204 No
+ * Content as well as 304 Not Modified. */
+template <typename T>
+class ConLenControllingFilter : public DecoratedRestfulClient<T> {
+protected:
+  enum class ContentLengthAction {
+    FORWARD,
+    INHIBIT,
+    UNKNOWN
+  } action;
+
+public:
+  template <typename U>
+  ConLenControllingFilter(U&& decoratee)
+    : DecoratedRestfulClient<T>(std::forward<U>(decoratee)),
+      action(ContentLengthAction::UNKNOWN) {
+  }
+
+  size_t send_status(const int status,
+                     const char* const status_name) override {
+    if (204 == status || 304 == status) {
+      action = ContentLengthAction::INHIBIT;
+    } else {
+      action = ContentLengthAction::FORWARD;
+    }
+
+    return DecoratedRestfulClient<T>::send_status(status, status_name);
+  }
+
+  size_t send_content_length(const uint64_t len) override {
+    switch(action) {
+    case ContentLengthAction::FORWARD:
+      return DecoratedRestfulClient<T>::send_content_length(len);
+    case ContentLengthAction::INHIBIT:
+      return 0;
+    case ContentLengthAction::UNKNOWN:
+    default:
+      return -EINVAL;
+    }
+  }
+};
+
+template <typename T> static inline
+ConLenControllingFilter<T> add_conlen_controlling(T&& t) {
+  return ConLenControllingFilter<T>(std::forward<T>(t));
+}
+
+
+/* Filter that rectifies the wrong behaviour of some clients of the RGWRestfulIO
+ * interface. Should be removed after fixing those clients. */
+template <typename T>
+class ReorderingFilter : public DecoratedRestfulClient<T> {
+protected:
+  enum class ReorderState {
+    RGW_EARLY_HEADERS,  /* Got headers sent before calling send_status. */
+    RGW_STATUS_SEEN,    /* Status has been seen. */
+    RGW_DATA            /* Header has been completed. */
+  } phase;
+
+  boost::optional<uint64_t> content_length;
+
+  std::vector<std::pair<std::string, std::string>> headers;
+
+  size_t send_header(const boost::string_ref& name,
+                     const boost::string_ref& value) override {
+    switch (phase) {
+    case ReorderState::RGW_EARLY_HEADERS:
+    case ReorderState::RGW_STATUS_SEEN:
+      headers.emplace_back(std::make_pair(name.to_string(),
+                                          value.to_string()));
+      return 0;
+    case ReorderState::RGW_DATA:
+      return DecoratedRestfulClient<T>::send_header(name, value);
+    }
+
+    return -EIO;
+  }
+
+public:
+  template <typename U>
+  ReorderingFilter(U&& decoratee)
+    : DecoratedRestfulClient<T>(std::forward<U>(decoratee)),
+      phase(ReorderState::RGW_EARLY_HEADERS) {
+  }
+
+  size_t send_status(const int status,
+                     const char* const status_name) override {
+    phase = ReorderState::RGW_STATUS_SEEN;
+
+    return DecoratedRestfulClient<T>::send_status(status, status_name);
+  }
+
+  size_t send_content_length(const uint64_t len) override {
+    if (ReorderState::RGW_EARLY_HEADERS == phase) {
+      /* Oh great, someone tries to send content length before status. */
+      content_length = len;
+      return 0;
+    } else {
+      return DecoratedRestfulClient<T>::send_content_length(len);
+    }
+  }
+
+  size_t complete_header() override {
+    size_t sent = 0;
+
+    /* Change state in order to immediately send everything we get. */
+    phase = ReorderState::RGW_DATA;
+
+    /* Sent content length if necessary. */
+    if (content_length) {
+      sent += DecoratedRestfulClient<T>::send_content_length(*content_length);
+    }
+
+    /* Header data in buffers are already counted. */
+    for (const auto& kv : headers) {
+      sent += DecoratedRestfulClient<T>::send_header(kv.first, kv.second);
+    }
+    headers.clear();
+
+    return sent + DecoratedRestfulClient<T>::complete_header();
+  }
+};
+
+template <typename T> static inline
+ReorderingFilter<T> add_reordering(T&& t) {
+  return ReorderingFilter<T>(std::forward<T>(t));
+}
+
+} /* namespace io */
+} /* namespace rgw */
+#endif /* CEPH_RGW_CLIENT_IO_DECOIMPL_H */
index 5dffbfb0f8c2f376d69bdc70a74630f8fe892b3b..b585db2272c6b0a59b47f1235d651dc55e5fad61 100644 (file)
@@ -12,7 +12,7 @@
 #include "rgw_process.h"
 #include "rgw_loadgen.h"
 #include "rgw_client_io.h"
-#include "rgw_client_io_decoimpl.h"
+#include "rgw_client_io_filters.h"
 
 #define dout_subsys ceph_subsys_rgw