Fix some bugs when testing opensds ansible
[stor4nfv.git] / src / ceph / src / rgw / rgw_client_io_filters.h
1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
3
4 #ifndef CEPH_RGW_CLIENT_IO_DECOIMPL_H
5 #define CEPH_RGW_CLIENT_IO_DECOIMPL_H
6
7 #include <type_traits>
8
9 #include <boost/optional.hpp>
10
11 #include "rgw_common.h"
12 #include "rgw_client_io.h"
13
14 namespace rgw {
15 namespace io {
16
17 template <typename T>
18 class AccountingFilter : public DecoratedRestfulClient<T>,
19                          public Accounter {
20   bool enabled;
21   uint64_t total_sent;
22   uint64_t total_received;
23   CephContext *cct;
24
25 public:
26   template <typename U>
27   AccountingFilter(CephContext *cct, U&& decoratee)
28     : DecoratedRestfulClient<T>(std::forward<U>(decoratee)),
29       enabled(false),
30       total_sent(0),
31       total_received(0), cct(cct) {
32   }
33
34   size_t send_status(const int status,
35                      const char* const status_name) override {
36     const auto sent = DecoratedRestfulClient<T>::send_status(status,
37                                                              status_name);
38     lsubdout(cct, rgw, 30) << "AccountingFilter::send_status: e="
39         << (enabled ? "1" : "0") << ", sent=" << sent << ", total="
40         << total_sent << dendl;
41     if (enabled) {
42       total_sent += sent;
43     }
44     return sent;
45   }
46
47   size_t send_100_continue() override {
48     const auto sent = DecoratedRestfulClient<T>::send_100_continue();
49     lsubdout(cct, rgw, 30) << "AccountingFilter::send_100_continue: e="
50         << (enabled ? "1" : "0") << ", sent=" << sent << ", total="
51         << total_sent << dendl;
52     if (enabled) {
53       total_sent += sent;
54     }
55     return sent;
56   }
57
58   size_t send_header(const boost::string_ref& name,
59                      const boost::string_ref& value) override {
60     const auto sent = DecoratedRestfulClient<T>::send_header(name, value);
61     lsubdout(cct, rgw, 30) << "AccountingFilter::send_header: e="
62         << (enabled ? "1" : "0") << ", sent=" << sent << ", total="
63         << total_sent << dendl;
64     if (enabled) {
65       total_sent += sent;
66     }
67     return sent;
68   }
69
70   size_t send_content_length(const uint64_t len) override {
71     const auto sent = DecoratedRestfulClient<T>::send_content_length(len);
72     lsubdout(cct, rgw, 30) << "AccountingFilter::send_content_length: e="
73         << (enabled ? "1" : "0") << ", sent=" << sent << ", total="
74         << total_sent << dendl;
75     if (enabled) {
76       total_sent += sent;
77     }
78     return sent;
79   }
80
81   size_t send_chunked_transfer_encoding() override {
82     const auto sent = DecoratedRestfulClient<T>::send_chunked_transfer_encoding();
83     lsubdout(cct, rgw, 30) << "AccountingFilter::send_chunked_transfer_encoding: e="
84         << (enabled ? "1" : "0") << ", sent=" << sent << ", total="
85         << total_sent << dendl;
86     if (enabled) {
87       total_sent += sent;
88     }
89     return sent;
90   }
91
92   size_t complete_header() override {
93     const auto sent = DecoratedRestfulClient<T>::complete_header();
94     lsubdout(cct, rgw, 30) << "AccountingFilter::complete_header: e="
95         << (enabled ? "1" : "0") << ", sent=" << sent << ", total="
96         << total_sent << dendl;
97     if (enabled) {
98       total_sent += sent;
99     }
100     return sent;
101   }
102
103   size_t recv_body(char* buf, size_t max) override {
104     const auto received = DecoratedRestfulClient<T>::recv_body(buf, max);
105     lsubdout(cct, rgw, 30) << "AccountingFilter::recv_body: e="
106         << (enabled ? "1" : "0") << ", received=" << received << dendl;
107     if (enabled) {
108       total_received += received;
109     }
110     return received;
111   }
112
113   size_t send_body(const char* const buf,
114                    const size_t len) override {
115     const auto sent = DecoratedRestfulClient<T>::send_body(buf, len);
116     lsubdout(cct, rgw, 30) << "AccountingFilter::send_body: e="
117         << (enabled ? "1" : "0") << ", sent=" << sent << ", total="
118         << total_sent << dendl;
119     if (enabled) {
120       total_sent += sent;
121     }
122     return sent;
123   }
124
125   size_t complete_request() override {
126     const auto sent = DecoratedRestfulClient<T>::complete_request();
127     lsubdout(cct, rgw, 30) << "AccountingFilter::complete_request: e="
128         << (enabled ? "1" : "0") << ", sent=" << sent << ", total="
129         << total_sent << dendl;
130     if (enabled) {
131       total_sent += sent;
132     }
133     return sent;
134   }
135
136   uint64_t get_bytes_sent() const override {
137     return total_sent;
138   }
139
140   uint64_t get_bytes_received() const override {
141     return total_received;
142   }
143
144   void set_account(bool enabled) override {
145     this->enabled = enabled;
146     lsubdout(cct, rgw, 30) << "AccountingFilter::set_account: e="
147         << (enabled ? "1" : "0") << dendl;
148   }
149 };
150
151
152 /* Filter for in-memory buffering incoming data and calculating the content
153  * length header if it isn't present. */
154 template <typename T>
155 class BufferingFilter : public DecoratedRestfulClient<T> {
156   template<typename Td> friend class DecoratedRestfulClient;
157 protected:
158   ceph::bufferlist data;
159
160   bool has_content_length;
161   bool buffer_data;
162   CephContext *cct;
163
164 public:
165   template <typename U>
166   BufferingFilter(CephContext *cct, U&& decoratee)
167     : DecoratedRestfulClient<T>(std::forward<U>(decoratee)),
168       has_content_length(false),
169       buffer_data(false), cct(cct) {
170   }
171
172   size_t send_content_length(const uint64_t len) override;
173   size_t send_chunked_transfer_encoding() override;
174   size_t complete_header() override;
175   size_t send_body(const char* buf, size_t len) override;
176   size_t complete_request() override;
177 };
178
179 template <typename T>
180 size_t BufferingFilter<T>::send_body(const char* const buf,
181                                      const size_t len)
182 {
183   if (buffer_data) {
184     data.append(buf, len);
185
186     lsubdout(cct, rgw, 30) << "BufferingFilter<T>::send_body: defer count = "
187         << len << dendl;
188     return 0;
189   }
190
191   return DecoratedRestfulClient<T>::send_body(buf, len);
192 }
193
194 template <typename T>
195 size_t BufferingFilter<T>::send_content_length(const uint64_t len)
196 {
197   has_content_length = true;
198   return DecoratedRestfulClient<T>::send_content_length(len);
199 }
200
201 template <typename T>
202 size_t BufferingFilter<T>::send_chunked_transfer_encoding()
203 {
204   has_content_length = true;
205   return DecoratedRestfulClient<T>::send_chunked_transfer_encoding();
206 }
207
208 template <typename T>
209 size_t BufferingFilter<T>::complete_header()
210 {
211   if (! has_content_length) {
212     /* We will dump everything in complete_request(). */
213     buffer_data = true;
214     lsubdout(cct, rgw, 30) << "BufferingFilter<T>::complete_header: has_content_length="
215         << (has_content_length ? "1" : "0") << dendl;
216     return 0;
217   }
218
219   return DecoratedRestfulClient<T>::complete_header();
220 }
221
222 template <typename T>
223 size_t BufferingFilter<T>::complete_request()
224 {
225   size_t sent = 0;
226
227   if (! has_content_length) {
228     /* It is not correct to count these bytes here,
229      * because they can only be part of the header.
230      * Therefore force count to 0.
231      */
232     sent += DecoratedRestfulClient<T>::send_content_length(data.length());
233     sent += DecoratedRestfulClient<T>::complete_header();
234     lsubdout(cct, rgw, 30) <<
235         "BufferingFilter::complete_request: !has_content_length: IGNORE: sent="
236         << sent << dendl;
237     sent = 0;
238   }
239
240   if (buffer_data) {
241     /* We are sending each buffer separately to avoid extra memory shuffling
242      * that would occur on data.c_str() to provide a continuous memory area. */
243     for (const auto& ptr : data.buffers()) {
244       sent += DecoratedRestfulClient<T>::send_body(ptr.c_str(),
245                                                    ptr.length());
246     }
247     data.clear();
248     buffer_data = false;
249     lsubdout(cct, rgw, 30) << "BufferingFilter::complete_request: buffer_data: sent="
250         << sent << dendl;
251   }
252
253   return sent + DecoratedRestfulClient<T>::complete_request();
254 }
255
256 template <typename T> static inline
257 BufferingFilter<T> add_buffering(
258 CephContext *cct,
259 T&& t) {
260   return BufferingFilter<T>(cct, std::forward<T>(t));
261 }
262
263
264 template <typename T>
265 class ChunkingFilter : public DecoratedRestfulClient<T> {
266   template<typename Td> friend class DecoratedRestfulClient;
267 protected:
268   bool chunking_enabled;
269
270 public:
271   template <typename U>
272   ChunkingFilter(U&& decoratee)
273     : DecoratedRestfulClient<T>(std::forward<U>(decoratee)),
274       chunking_enabled(false) {
275   }
276
277   size_t send_chunked_transfer_encoding() override {
278     chunking_enabled = true;
279     return DecoratedRestfulClient<T>::send_header("Transfer-Encoding",
280                                                   "chunked");
281   }
282
283   size_t send_body(const char* buf,
284                    const size_t len) override {
285     if (! chunking_enabled) {
286       return DecoratedRestfulClient<T>::send_body(buf, len);
287     } else {
288       static constexpr char HEADER_END[] = "\r\n";
289       char sizebuf[32];
290       const auto slen = snprintf(sizebuf, sizeof(buf), "%" PRIx64 "\r\n", len);
291       size_t sent = 0;
292
293       sent += DecoratedRestfulClient<T>::send_body(sizebuf, slen);
294       sent += DecoratedRestfulClient<T>::send_body(buf, len);
295       sent += DecoratedRestfulClient<T>::send_body(HEADER_END,
296                                                    sizeof(HEADER_END) - 1);
297       return sent;
298     }
299   }
300
301   size_t complete_request() override {
302     size_t sent = 0;
303
304     if (chunking_enabled) {
305       static constexpr char CHUNKED_RESP_END[] = "0\r\n\r\n";
306       sent += DecoratedRestfulClient<T>::send_body(CHUNKED_RESP_END,
307                                                    sizeof(CHUNKED_RESP_END) - 1);
308     }
309
310     return sent + DecoratedRestfulClient<T>::complete_request();
311   }
312 };
313
314 template <typename T> static inline
315 ChunkingFilter<T> add_chunking(T&& t) {
316   return ChunkingFilter<T>(std::forward<T>(t));
317 }
318
319
320 /* Class that controls and inhibits the process of sending Content-Length HTTP
321  * header where RFC 7230 requests so. The cases worth our attention are 204 No
322  * Content as well as 304 Not Modified. */
323 template <typename T>
324 class ConLenControllingFilter : public DecoratedRestfulClient<T> {
325 protected:
326   enum class ContentLengthAction {
327     FORWARD,
328     INHIBIT,
329     UNKNOWN
330   } action;
331
332 public:
333   template <typename U>
334   ConLenControllingFilter(U&& decoratee)
335     : DecoratedRestfulClient<T>(std::forward<U>(decoratee)),
336       action(ContentLengthAction::UNKNOWN) {
337   }
338
339   size_t send_status(const int status,
340                      const char* const status_name) override {
341     if ((204 == status || 304 == status) &&
342         ! g_conf->rgw_print_prohibited_content_length) {
343       action = ContentLengthAction::INHIBIT;
344     } else {
345       action = ContentLengthAction::FORWARD;
346     }
347
348     return DecoratedRestfulClient<T>::send_status(status, status_name);
349   }
350
351   size_t send_content_length(const uint64_t len) override {
352     switch(action) {
353     case ContentLengthAction::FORWARD:
354       return DecoratedRestfulClient<T>::send_content_length(len);
355     case ContentLengthAction::INHIBIT:
356       return 0;
357     case ContentLengthAction::UNKNOWN:
358     default:
359       return -EINVAL;
360     }
361   }
362 };
363
364 template <typename T> static inline
365 ConLenControllingFilter<T> add_conlen_controlling(T&& t) {
366   return ConLenControllingFilter<T>(std::forward<T>(t));
367 }
368
369
370 /* Filter that rectifies the wrong behaviour of some clients of the RGWRestfulIO
371  * interface. Should be removed after fixing those clients. */
372 template <typename T>
373 class ReorderingFilter : public DecoratedRestfulClient<T> {
374 protected:
375   enum class ReorderState {
376     RGW_EARLY_HEADERS,  /* Got headers sent before calling send_status. */
377     RGW_STATUS_SEEN,    /* Status has been seen. */
378     RGW_DATA            /* Header has been completed. */
379   } phase;
380
381   boost::optional<uint64_t> content_length;
382
383   std::vector<std::pair<std::string, std::string>> headers;
384
385   size_t send_header(const boost::string_ref& name,
386                      const boost::string_ref& value) override {
387     switch (phase) {
388     case ReorderState::RGW_EARLY_HEADERS:
389     case ReorderState::RGW_STATUS_SEEN:
390       headers.emplace_back(std::make_pair(std::string(name.data(), name.size()),
391                                           std::string(value.data(), value.size())));
392       return 0;
393     case ReorderState::RGW_DATA:
394       return DecoratedRestfulClient<T>::send_header(name, value);
395     }
396
397     return -EIO;
398   }
399
400 public:
401   template <typename U>
402   ReorderingFilter(U&& decoratee)
403     : DecoratedRestfulClient<T>(std::forward<U>(decoratee)),
404       phase(ReorderState::RGW_EARLY_HEADERS) {
405   }
406
407   size_t send_status(const int status,
408                      const char* const status_name) override {
409     phase = ReorderState::RGW_STATUS_SEEN;
410
411     return DecoratedRestfulClient<T>::send_status(status, status_name);
412   }
413
414   size_t send_content_length(const uint64_t len) override {
415     if (ReorderState::RGW_EARLY_HEADERS == phase) {
416       /* Oh great, someone tries to send content length before status. */
417       content_length = len;
418       return 0;
419     } else {
420       return DecoratedRestfulClient<T>::send_content_length(len);
421     }
422   }
423
424   size_t complete_header() override {
425     size_t sent = 0;
426
427     /* Change state in order to immediately send everything we get. */
428     phase = ReorderState::RGW_DATA;
429
430     /* Sent content length if necessary. */
431     if (content_length) {
432       sent += DecoratedRestfulClient<T>::send_content_length(*content_length);
433     }
434
435     /* Header data in buffers are already counted. */
436     for (const auto& kv : headers) {
437       sent += DecoratedRestfulClient<T>::send_header(kv.first, kv.second);
438     }
439     headers.clear();
440
441     return sent + DecoratedRestfulClient<T>::complete_header();
442   }
443 };
444
445 template <typename T> static inline
446 ReorderingFilter<T> add_reordering(T&& t) {
447   return ReorderingFilter<T>(std::forward<T>(t));
448 }
449
450 } /* namespace io */
451 } /* namespace rgw */
452 #endif /* CEPH_RGW_CLIENT_IO_DECOIMPL_H */