Skip to content

Commit 3712fa1

Browse files
committed
serializer supports stream chunking
1 parent 4a36758 commit 3712fa1

File tree

4 files changed

+317
-9
lines changed

4 files changed

+317
-9
lines changed

include/boost/http_proto/message_view_base.hpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
//
22
// Copyright (c) 2021 Vinnie Falco ([email protected])
3+
// Copyright (c) 2024 Christian Mazakas
34
//
45
// Distributed under the Boost Software License, Version 1.0. (See accompanying
56
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -91,6 +92,15 @@ class BOOST_SYMBOL_VISIBLE
9192
{
9293
return ph_->md;
9394
}
95+
96+
/** Return true if the message is using a chunked
97+
transfer encoding.
98+
*/
99+
bool
100+
chunked() const noexcept
101+
{
102+
return ph_->md.transfer_encoding.is_chunked;
103+
}
94104
};
95105

96106
} // http_proto

include/boost/http_proto/serializer.hpp

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ class BOOST_SYMBOL_VISIBLE
123123
void
124124
start(
125125
message_view_base const& m,
126-
ConstBufferSequence&& body);
126+
ConstBufferSequence&& body);
127127

128128
/** Prepare the serializer for a new message
129129
@@ -242,16 +242,31 @@ class BOOST_SYMBOL_VISIBLE
242242
stream
243243
};
244244

245+
// chunked-body = *chunk
246+
// last-chunk
247+
// trailer-section
248+
// CRLF
249+
250+
// chunk = chunk-size [ chunk-ext ] CRLF
251+
// chunk-data CRLF
252+
static
253+
constexpr
254+
std::size_t
255+
chunk_header_len_ = 16 + 2; // chunk-size + CRLF
256+
257+
// last-chunk = 1*("0") [ chunk-ext ] CRLF
258+
static
259+
constexpr
260+
std::size_t
261+
last_chunk_len_ = 1 + 2 + 2; // chunked-body termination requires an extra CRLF
262+
245263
static
246264
constexpr
247265
std::size_t
248266
chunked_overhead_ =
249-
16 + // size
250-
2 + // CRLF
251-
2 + // CRLF
252-
1 + // "0"
253-
2 + // CRLF
254-
2; // CRLF
267+
chunk_header_len_ +
268+
2 + // CRLF
269+
last_chunk_len_;
255270

256271
detail::workspace ws_;
257272
detail::array_of_const_buffers buf_;

src/serializer.cpp

Lines changed: 49 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
//
22
// Copyright (c) 2019 Vinnie Falco ([email protected])
3+
// Copyright (c) 2024 Christian Mazakas
34
//
45
// Distributed under the Boost Software License, Version 1.0. (See accompanying
56
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -71,6 +72,26 @@ write_chunk_header(
7172
buffers::buffer_size(dest0) == n);
7273
}
7374

75+
template<class DynamicBuffer>
76+
void
77+
write_chunk_close(DynamicBuffer& db)
78+
{
79+
db.commit(
80+
buffers::buffer_copy(
81+
db.prepare(2),
82+
buffers::const_buffer("\r\n", 2)));
83+
}
84+
85+
template<class DynamicBuffer>
86+
void
87+
write_last_chunk(DynamicBuffer& db)
88+
{
89+
db.commit(
90+
buffers::buffer_copy(
91+
db.prepare(5),
92+
buffers::const_buffer("0\r\n\r\n", 5)));
93+
}
94+
7495
//------------------------------------------------
7596

7697
serializer::
@@ -521,7 +542,7 @@ serializer::
521542
stream::
522543
capacity() const
523544
{
524-
auto const n =
545+
auto const n =
525546
chunked_overhead_ +
526547
2 + // CRLF
527548
5; // final chunk
@@ -543,6 +564,11 @@ prepare(
543564
std::size_t n) const ->
544565
buffers_type
545566
{
567+
if( sr_->is_chunked_ )
568+
return buffers::sans_prefix(
569+
sr_->tmp0_.prepare(n + chunk_header_len_),
570+
chunk_header_len_);
571+
546572
return sr_->tmp0_.prepare(n);
547573
}
548574

@@ -551,7 +577,24 @@ serializer::
551577
stream::
552578
commit(std::size_t n) const
553579
{
554-
sr_->tmp0_.commit(n);
580+
if(! sr_->is_chunked_ )
581+
{
582+
sr_->tmp0_.commit(n);
583+
}
584+
else
585+
{
586+
// Zero sized chunks are not valid. Call close()
587+
// if the intent is to signal the end of the body.
588+
if( n == 0 )
589+
detail::throw_logic_error();
590+
591+
auto m = n + chunk_header_len_;
592+
auto dest = sr_->tmp0_.prepare(m);
593+
write_chunk_header(
594+
buffers::prefix(dest, chunk_header_len_), n);
595+
sr_->tmp0_.commit(m);
596+
write_chunk_close(sr_->tmp0_);
597+
}
555598
}
556599

557600
void
@@ -562,6 +605,10 @@ close() const
562605
// Precondition violation
563606
if(! sr_->more_)
564607
detail::throw_logic_error();
608+
609+
if (sr_->is_chunked_)
610+
write_last_chunk(sr_->tmp0_);
611+
565612
sr_->more_ = false;
566613
}
567614

0 commit comments

Comments
 (0)