Needed for tempest.api.object_storage.test_object_slo.ObjectSloTest.test_delete_large_object.
Signed-off-by: Radoslaw Zarzynski <rzarzynski@mirantis.com>
virtual std::size_t send_header(const boost::string_ref& name,
const boost::string_ref& value) = 0;
+ /* Inform a client about a content length. Takes number of bytes supplied in
+ * @len XOR one of the alternative modes for dealing with it passed as @mode.
+ * On success returns number of bytes sent to the direct client of RadosGW.
+ * On failure throws int containing errno.
+ *
+ * CALL ORDER:
+ * - The method must be called EXACTLY ONE time.
+ * - The method must be preceeded with a call to send_status().
+ * - The method must not be called after complete_header(). */
virtual std::size_t send_content_length(uint64_t len) = 0;
+
+ virtual std::size_t send_chunked_transfer_encoding() {
+ /* This is a null implementation. We don't send anything here, even the HTTP
+ * header. The intended behaviour should be provided through a decorator or
+ * directly by a given front-end. */
+ return 0;
+ }
+
virtual std::size_t complete_header() = 0;
/* Receive body. On success Returns number of bytes sent to the direct
virtual std::size_t send_header(const boost::string_ref& name,
const boost::string_ref& value) noexcept = 0;
virtual int send_content_length(uint64_t len) = 0;
+ virtual int send_chunked_transfer_encoding() = 0;
virtual int complete_header() = 0;
virtual int recv_body(char* buf, std::size_t max) = 0;
EXCPT_TO_RC(get_decoratee().send_content_length(len));
}
+ int send_chunked_transfer_encoding() override {
+ EXCPT_TO_RC(get_decoratee().send_chunked_transfer_encoding());
+ }
+
int complete_header() override {
EXCPT_TO_RC(get_decoratee().complete_header());
}
return get_decoratee().send_content_length(len);
}
+ std::size_t send_chunked_transfer_encoding() override {
+ return get_decoratee().send_chunked_transfer_encoding();
+ }
+
std::size_t complete_header() override {
return get_decoratee().complete_header();
}
return sent;
}
+ std::size_t send_chunked_transfer_encoding() override {
+ const auto sent = RGWDecoratedStreamIO<T>::send_chunked_transfer_encoding();
+ if (enabled) {
+ total_sent += sent;
+ }
+ return sent;
+ }
+
std::size_t complete_header() override {
const auto sent = RGWDecoratedStreamIO<T>::complete_header();
if (enabled) {
}
std::size_t send_content_length(const uint64_t len) override;
+ std::size_t send_chunked_transfer_encoding() override;
std::size_t complete_header() override;
std::size_t send_body(const char* buf, std::size_t len) override;
int complete_request() override;
return RGWDecoratedStreamIO<T>::send_content_length(len);
}
+template <typename T>
+std::size_t RGWStreamIOBufferingEngine<T>::send_chunked_transfer_encoding()
+{
+ has_content_length = true;
+ return RGWDecoratedStreamIO<T>::send_chunked_transfer_encoding();
+}
+
template <typename T>
std::size_t RGWStreamIOBufferingEngine<T>::complete_header()
{
return RGWDecoratedStreamIO<T>::send_content_length(len);
}
- std::size_t complete_header() override {
- size_t sent = 0;
-
- if (! has_content_length) {
- sent += RGWDecoratedStreamIO<T>::send_header("Transfer-Enconding",
- "chunked");
- chunking_enabled = true;
- }
-
- return sent + RGWDecoratedStreamIO<T>::complete_header();
+ std::size_t send_chunked_transfer_encoding() override {
+ has_content_length = false;
+ chunking_enabled = true;
+ return RGWDecoratedStreamIO<T>::send_header("Transfer-Encoding", "chunked");
}
std::size_t send_body(const char* buf,
return sent;
}
}
+
+ int complete_request() override {
+ std::size_t sent = 0;
+
+ if (chunking_enabled) {
+ static constexpr char CHUNKED_RESP_END[] = "0\r\n\r\n";
+ sent += RGWDecoratedStreamIO<T>::send_body(CHUNKED_RESP_END,
+ sizeof(CHUNKED_RESP_END) - 1);
+ }
+
+ return sent + RGWDecoratedStreamIO<T>::complete_request();
+ }
};
template <typename T>
dump_header(s, "Accept-Ranges", "bytes");
}
+static void dump_chunked_encoding(struct req_state* const s)
+{
+ try {
+ STREAM_IO(s)->send_chunked_transfer_encoding();
+ } catch (RGWRestfulIOEngine::Exception& e) {
+ ldout(s->cct, 0) << "ERROR: STREAM_IO(s)->send_chunked_transfer_encoding()"
+ << " returned err=" << e.what() << dendl;
+ }
+}
+
void dump_etag(struct req_state* const s,
const boost::string_ref& etag,
const bool quoted)
s->formatter->output_footer();
dump_content_length(s, s->formatter->get_len());
} else {
- if (proposed_content_length != NO_CONTENT_LENGTH) {
+ if (proposed_content_length == CHUNKED_TRANSFER_ENCODING) {
+ dump_chunked_encoding(s);
+ } else if (proposed_content_length != NO_CONTENT_LENGTH) {
dump_content_length(s, proposed_content_length);
}
}
};
static constexpr int64_t NO_CONTENT_LENGTH = -1;
+static constexpr int64_t CHUNKED_TRANSFER_ENCODING = -2;
extern void set_req_state_err(struct rgw_err &err, int err_no, int prot_flags);
extern void set_req_state_err(struct req_state *s, int err_no);
if (multipart_delete) {
end_header(s, this /* RGWOp */, nullptr /* contype */,
- NO_CONTENT_LENGTH);
+ CHUNKED_TRANSFER_ENCODING);
if (deleter) {
bulkdelete_respond(deleter->get_num_deleted(),
{
set_req_state_err(s, op_ret);
dump_errno(s);
- end_header(s, NULL);
+ end_header(s, this /* RGWOp */, nullptr /* contype */,
+ CHUNKED_TRANSFER_ENCODING);
bulkdelete_respond(deleter->get_num_deleted(),
deleter->get_num_unfound(),