1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab ft=cpp
8 #include <boost/optional.hpp>
10 #include "rgw_common.h"
11 #include "rgw_client_io.h"
17 class AccountingFilter
: public DecoratedRestfulClient
<T
>,
21 uint64_t total_received
;
26 AccountingFilter(CephContext
*cct
, U
&& decoratee
)
27 : DecoratedRestfulClient
<T
>(std::forward
<U
>(decoratee
)),
30 total_received(0), cct(cct
) {
33 size_t send_status(const int status
,
34 const char* const status_name
) override
{
35 const auto sent
= DecoratedRestfulClient
<T
>::send_status(status
,
37 lsubdout(cct
, rgw
, 30) << "AccountingFilter::send_status: e="
38 << (enabled
? "1" : "0") << ", sent=" << sent
<< ", total="
39 << total_sent
<< dendl
;
46 size_t send_100_continue() override
{
47 const auto sent
= DecoratedRestfulClient
<T
>::send_100_continue();
48 lsubdout(cct
, rgw
, 30) << "AccountingFilter::send_100_continue: e="
49 << (enabled
? "1" : "0") << ", sent=" << sent
<< ", total="
50 << total_sent
<< dendl
;
57 size_t send_header(const std::string_view
& name
,
58 const std::string_view
& value
) override
{
59 const auto sent
= DecoratedRestfulClient
<T
>::send_header(name
, value
);
60 lsubdout(cct
, rgw
, 30) << "AccountingFilter::send_header: e="
61 << (enabled
? "1" : "0") << ", sent=" << sent
<< ", total="
62 << total_sent
<< dendl
;
69 size_t send_content_length(const uint64_t len
) override
{
70 const auto sent
= DecoratedRestfulClient
<T
>::send_content_length(len
);
71 lsubdout(cct
, rgw
, 30) << "AccountingFilter::send_content_length: e="
72 << (enabled
? "1" : "0") << ", sent=" << sent
<< ", total="
73 << total_sent
<< dendl
;
80 size_t send_chunked_transfer_encoding() override
{
81 const auto sent
= DecoratedRestfulClient
<T
>::send_chunked_transfer_encoding();
82 lsubdout(cct
, rgw
, 30) << "AccountingFilter::send_chunked_transfer_encoding: e="
83 << (enabled
? "1" : "0") << ", sent=" << sent
<< ", total="
84 << total_sent
<< dendl
;
91 size_t complete_header() override
{
92 const auto sent
= DecoratedRestfulClient
<T
>::complete_header();
93 lsubdout(cct
, rgw
, 30) << "AccountingFilter::complete_header: e="
94 << (enabled
? "1" : "0") << ", sent=" << sent
<< ", total="
95 << total_sent
<< dendl
;
102 size_t recv_body(char* buf
, size_t max
) override
{
103 const auto received
= DecoratedRestfulClient
<T
>::recv_body(buf
, max
);
104 lsubdout(cct
, rgw
, 30) << "AccountingFilter::recv_body: e="
105 << (enabled
? "1" : "0") << ", received=" << received
<< dendl
;
107 total_received
+= received
;
112 size_t send_body(const char* const buf
,
113 const size_t len
) override
{
114 const auto sent
= DecoratedRestfulClient
<T
>::send_body(buf
, len
);
115 lsubdout(cct
, rgw
, 30) << "AccountingFilter::send_body: e="
116 << (enabled
? "1" : "0") << ", sent=" << sent
<< ", total="
117 << total_sent
<< dendl
;
124 size_t complete_request() override
{
125 const auto sent
= DecoratedRestfulClient
<T
>::complete_request();
126 lsubdout(cct
, rgw
, 30) << "AccountingFilter::complete_request: e="
127 << (enabled
? "1" : "0") << ", sent=" << sent
<< ", total="
128 << total_sent
<< dendl
;
135 uint64_t get_bytes_sent() const override
{
139 uint64_t get_bytes_received() const override
{
140 return total_received
;
143 void set_account(bool enabled
) override
{
144 this->enabled
= enabled
;
145 lsubdout(cct
, rgw
, 30) << "AccountingFilter::set_account: e="
146 << (enabled
? "1" : "0") << dendl
;
151 /* Filter for in-memory buffering incoming data and calculating the content
152 * length header if it isn't present. */
153 template <typename T
>
154 class BufferingFilter
: public DecoratedRestfulClient
<T
> {
155 template<typename Td
> friend class DecoratedRestfulClient
;
157 ceph::bufferlist data
;
159 bool has_content_length
;
164 template <typename U
>
165 BufferingFilter(CephContext
*cct
, U
&& decoratee
)
166 : DecoratedRestfulClient
<T
>(std::forward
<U
>(decoratee
)),
167 has_content_length(false),
168 buffer_data(false), cct(cct
) {
171 size_t send_content_length(const uint64_t len
) override
;
172 size_t send_chunked_transfer_encoding() override
;
173 size_t complete_header() override
;
174 size_t send_body(const char* buf
, size_t len
) override
;
175 size_t complete_request() override
;
178 template <typename T
>
179 size_t BufferingFilter
<T
>::send_body(const char* const buf
,
183 data
.append(buf
, len
);
185 lsubdout(cct
, rgw
, 30) << "BufferingFilter<T>::send_body: defer count = "
190 return DecoratedRestfulClient
<T
>::send_body(buf
, len
);
193 template <typename T
>
194 size_t BufferingFilter
<T
>::send_content_length(const uint64_t len
)
196 has_content_length
= true;
197 return DecoratedRestfulClient
<T
>::send_content_length(len
);
200 template <typename T
>
201 size_t BufferingFilter
<T
>::send_chunked_transfer_encoding()
203 has_content_length
= true;
204 return DecoratedRestfulClient
<T
>::send_chunked_transfer_encoding();
207 template <typename T
>
208 size_t BufferingFilter
<T
>::complete_header()
210 if (! has_content_length
) {
211 /* We will dump everything in complete_request(). */
213 lsubdout(cct
, rgw
, 30) << "BufferingFilter<T>::complete_header: has_content_length="
214 << (has_content_length
? "1" : "0") << dendl
;
218 return DecoratedRestfulClient
<T
>::complete_header();
221 template <typename T
>
222 size_t BufferingFilter
<T
>::complete_request()
226 if (! has_content_length
) {
227 /* It is not correct to count these bytes here,
228 * because they can only be part of the header.
229 * Therefore force count to 0.
231 sent
+= DecoratedRestfulClient
<T
>::send_content_length(data
.length());
232 sent
+= DecoratedRestfulClient
<T
>::complete_header();
233 lsubdout(cct
, rgw
, 30) <<
234 "BufferingFilter::complete_request: !has_content_length: IGNORE: sent="
240 /* We are sending each buffer separately to avoid extra memory shuffling
241 * that would occur on data.c_str() to provide a continuous memory area. */
242 for (const auto& ptr
: data
.buffers()) {
243 sent
+= DecoratedRestfulClient
<T
>::send_body(ptr
.c_str(),
248 lsubdout(cct
, rgw
, 30) << "BufferingFilter::complete_request: buffer_data: sent="
252 return sent
+ DecoratedRestfulClient
<T
>::complete_request();
255 template <typename T
> static inline
256 BufferingFilter
<T
> add_buffering(
259 return BufferingFilter
<T
>(cct
, std::forward
<T
>(t
));
263 template <typename T
>
264 class ChunkingFilter
: public DecoratedRestfulClient
<T
> {
265 template<typename Td
> friend class DecoratedRestfulClient
;
267 bool chunking_enabled
;
270 template <typename U
>
271 explicit ChunkingFilter(U
&& decoratee
)
272 : DecoratedRestfulClient
<T
>(std::forward
<U
>(decoratee
)),
273 chunking_enabled(false) {
276 size_t send_chunked_transfer_encoding() override
{
277 chunking_enabled
= true;
278 return DecoratedRestfulClient
<T
>::send_header("Transfer-Encoding",
282 size_t send_body(const char* buf
,
283 const size_t len
) override
{
284 if (! chunking_enabled
) {
285 return DecoratedRestfulClient
<T
>::send_body(buf
, len
);
287 static constexpr char HEADER_END
[] = "\r\n";
288 /* https://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.6.1 */
289 // TODO: we have no support for sending chunked-encoding
290 // extensions/trailing headers.
292 const auto chunk_size_len
= snprintf(chunk_size
, sizeof(chunk_size
),
296 sent
+= DecoratedRestfulClient
<T
>::send_body(chunk_size
, chunk_size_len
);
297 sent
+= DecoratedRestfulClient
<T
>::send_body(buf
, len
);
298 sent
+= DecoratedRestfulClient
<T
>::send_body(HEADER_END
,
299 sizeof(HEADER_END
) - 1);
304 size_t complete_request() override
{
307 if (chunking_enabled
) {
308 static constexpr char CHUNKED_RESP_END
[] = "0\r\n\r\n";
309 sent
+= DecoratedRestfulClient
<T
>::send_body(CHUNKED_RESP_END
,
310 sizeof(CHUNKED_RESP_END
) - 1);
313 return sent
+ DecoratedRestfulClient
<T
>::complete_request();
317 template <typename T
> static inline
318 ChunkingFilter
<T
> add_chunking(T
&& t
) {
319 return ChunkingFilter
<T
>(std::forward
<T
>(t
));
323 /* Class that controls and inhibits the process of sending Content-Length HTTP
324 * header where RFC 7230 requests so. The cases worth our attention are 204 No
325 * Content as well as 304 Not Modified. */
326 template <typename T
>
327 class ConLenControllingFilter
: public DecoratedRestfulClient
<T
> {
329 enum class ContentLengthAction
{
336 template <typename U
>
337 explicit ConLenControllingFilter(U
&& decoratee
)
338 : DecoratedRestfulClient
<T
>(std::forward
<U
>(decoratee
)),
339 action(ContentLengthAction::UNKNOWN
) {
342 size_t send_status(const int status
,
343 const char* const status_name
) override
{
344 if ((204 == status
|| 304 == status
) &&
345 ! g_conf()->rgw_print_prohibited_content_length
) {
346 action
= ContentLengthAction::INHIBIT
;
348 action
= ContentLengthAction::FORWARD
;
351 return DecoratedRestfulClient
<T
>::send_status(status
, status_name
);
354 size_t send_content_length(const uint64_t len
) override
{
356 case ContentLengthAction::FORWARD
:
357 return DecoratedRestfulClient
<T
>::send_content_length(len
);
358 case ContentLengthAction::INHIBIT
:
360 case ContentLengthAction::UNKNOWN
:
367 template <typename T
> static inline
368 ConLenControllingFilter
<T
> add_conlen_controlling(T
&& t
) {
369 return ConLenControllingFilter
<T
>(std::forward
<T
>(t
));
373 /* Filter that rectifies the wrong behaviour of some clients of the RGWRestfulIO
374 * interface. Should be removed after fixing those clients. */
375 template <typename T
>
376 class ReorderingFilter
: public DecoratedRestfulClient
<T
> {
378 enum class ReorderState
{
379 RGW_EARLY_HEADERS
, /* Got headers sent before calling send_status. */
380 RGW_STATUS_SEEN
, /* Status has been seen. */
381 RGW_DATA
/* Header has been completed. */
384 boost::optional
<uint64_t> content_length
;
386 std::vector
<std::pair
<std::string
, std::string
>> headers
;
388 size_t send_header(const std::string_view
& name
,
389 const std::string_view
& value
) override
{
391 case ReorderState::RGW_EARLY_HEADERS
:
392 case ReorderState::RGW_STATUS_SEEN
:
393 headers
.emplace_back(std::make_pair(std::string(name
.data(), name
.size()),
394 std::string(value
.data(), value
.size())));
396 case ReorderState::RGW_DATA
:
397 return DecoratedRestfulClient
<T
>::send_header(name
, value
);
404 template <typename U
>
405 explicit ReorderingFilter(U
&& decoratee
)
406 : DecoratedRestfulClient
<T
>(std::forward
<U
>(decoratee
)),
407 phase(ReorderState::RGW_EARLY_HEADERS
) {
410 size_t send_status(const int status
,
411 const char* const status_name
) override
{
412 phase
= ReorderState::RGW_STATUS_SEEN
;
414 return DecoratedRestfulClient
<T
>::send_status(status
, status_name
);
417 size_t send_content_length(const uint64_t len
) override
{
418 if (ReorderState::RGW_EARLY_HEADERS
== phase
) {
419 /* Oh great, someone tries to send content length before status. */
420 content_length
= len
;
423 return DecoratedRestfulClient
<T
>::send_content_length(len
);
427 size_t complete_header() override
{
430 /* Change state in order to immediately send everything we get. */
431 phase
= ReorderState::RGW_DATA
;
433 /* Sent content length if necessary. */
434 if (content_length
) {
435 sent
+= DecoratedRestfulClient
<T
>::send_content_length(*content_length
);
438 /* Header data in buffers are already counted. */
439 for (const auto& kv
: headers
) {
440 sent
+= DecoratedRestfulClient
<T
>::send_header(kv
.first
, kv
.second
);
444 return sent
+ DecoratedRestfulClient
<T
>::complete_header();
448 template <typename T
> static inline
449 ReorderingFilter
<T
> add_reordering(T
&& t
) {
450 return ReorderingFilter
<T
>(std::forward
<T
>(t
));
454 } /* namespace rgw */