Skip to content

Commit d502b88

Browse files
committed
stream prepare has nullary overload
1 parent b5cbccc commit d502b88

File tree

3 files changed

+146
-70
lines changed

3 files changed

+146
-70
lines changed

include/boost/http_proto/serializer.hpp

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -247,25 +247,35 @@ class BOOST_SYMBOL_VISIBLE
247247
// trailer-section
248248
// CRLF
249249

250+
static
251+
constexpr
252+
std::size_t
253+
crlf_len_ = 2;
254+
250255
// chunk = chunk-size [ chunk-ext ] CRLF
251256
// chunk-data CRLF
252257
static
253258
constexpr
254259
std::size_t
255-
chunk_header_len_ = 16 + 2; // chunk-size + CRLF
260+
chunk_header_len_ =
261+
16 + // 16 hex digits => 64 bit number
262+
crlf_len_;
256263

257264
// last-chunk = 1*("0") [ chunk-ext ] CRLF
258265
static
259266
constexpr
260267
std::size_t
261-
last_chunk_len_ = 1 + 2 + 2; // chunked-body termination requires an extra CRLF
268+
last_chunk_len_ =
269+
1 + // "0"
270+
crlf_len_ +
271+
crlf_len_; // chunked-body termination requires an extra CRLF
262272

263273
static
264274
constexpr
265275
std::size_t
266276
chunked_overhead_ =
267277
chunk_header_len_ +
268-
2 + // CRLF
278+
crlf_len_ + // closing chunk data
269279
last_chunk_len_;
270280

271281
detail::workspace ws_;
@@ -315,7 +325,7 @@ struct serializer::stream
315325

316326
BOOST_HTTP_PROTO_DECL
317327
buffers_type
318-
prepare(std::size_t n) const;
328+
prepare() const;
319329

320330
BOOST_HTTP_PROTO_DECL
321331
void

src/serializer.cpp

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -560,14 +560,29 @@ size() const
560560
auto
561561
serializer::
562562
stream::
563-
prepare(
564-
std::size_t n) const ->
565-
buffers_type
563+
prepare() const ->
564+
buffers_type
566565
{
566+
auto n = sr_->tmp0_.capacity();
567567
if( sr_->is_chunked_ )
568+
{
569+
// for chunked encoding, we want to unconditionally
570+
// reserve space for the complete chunk and the
571+
// last-chunk
572+
// this enables users to call:
573+
//
574+
// stream.commit(n); stream.close();
575+
//
576+
// without needing to worry about draining the
577+
// serializer via `consume()` calls
578+
if( n < chunked_overhead_ + 1 )
579+
detail::throw_length_error();
580+
581+
n -= chunked_overhead_;
568582
return buffers::sans_prefix(
569-
sr_->tmp0_.prepare(n + chunk_header_len_),
583+
sr_->tmp0_.prepare(chunk_header_len_ + n),
570584
chunk_header_len_);
585+
}
571586

572587
return sr_->tmp0_.prepare(n);
573588
}
@@ -603,10 +618,10 @@ stream::
603618
close() const
604619
{
605620
// Precondition violation
606-
if(! sr_->more_)
621+
if(! sr_->more_ )
607622
detail::throw_logic_error();
608623

609-
if (sr_->is_chunked_)
624+
if( sr_->is_chunked_ )
610625
write_last_chunk(sr_->tmp0_);
611626

612627
sr_->more_ = false;

test/unit/serializer.cpp

Lines changed: 111 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -255,26 +255,34 @@ struct serializer_test
255255
f(s);
256256
};
257257

258+
struct check_stream_opts
259+
{
260+
std::size_t sr_capacity = 1024;
261+
};
262+
258263
template <class F>
259264
void
260265
check_stream(
261266
core::string_view headers,
262267
core::string_view body,
268+
check_stream_opts const& opts,
263269
F f)
264270
{
271+
auto sr_capacity = opts.sr_capacity;
272+
265273
response res(headers);
266274

267-
serializer sr(1024);
275+
serializer sr(sr_capacity);
268276
auto stream = sr.start_stream(res);
269277

270278
std::vector<char> s; // stores complete output
271-
std::size_t const chunk_data_size = 100;
272279

273280
auto prepare_chunk = [&]
274281
{
275-
auto mbs = stream.prepare(chunk_data_size);
282+
auto mbs = stream.prepare();
283+
276284
auto bs = buffers::buffer_size(mbs);
277-
BOOST_TEST_EQ(bs, chunk_data_size);
285+
BOOST_TEST_GT(bs, 0);
278286

279287
if( bs > body.size() )
280288
bs = body.size();
@@ -300,8 +308,7 @@ struct serializer_test
300308
while( buf.size() > 0 )
301309
{
302310
auto num_copied =
303-
buffers::buffer_copy(
304-
out_buf, buf);
311+
buffers::buffer_copy(out_buf, buf);
305312

306313
buf += num_copied;
307314

@@ -454,55 +461,100 @@ struct serializer_test
454461
check_chunked_body(s, "");
455462
});
456463

457-
check_stream(
458-
"HTTP/1.1 200 OK\r\n"
459-
"Server: test\r\n"
460-
"\r\n",
461-
std::string(0, '*'),
462-
[](core::string_view s){
463-
core::string_view expected_header =
464-
"HTTP/1.1 200 OK\r\n"
465-
"Server: test\r\n"
466-
"\r\n";
467-
BOOST_TEST(s.starts_with(expected_header));
468-
s.remove_prefix(expected_header.size());
469-
BOOST_TEST_EQ(s, std::string(0, '*'));
470-
});
464+
// empty stream
465+
{
466+
check_stream_opts opts;
467+
check_stream(
468+
"HTTP/1.1 200 OK\r\n"
469+
"Server: test\r\n"
470+
"\r\n",
471+
std::string(0, '*'),
472+
opts,
473+
[](core::string_view s)
474+
{
475+
core::string_view expected_header =
476+
"HTTP/1.1 200 OK\r\n"
477+
"Server: test\r\n"
478+
"\r\n";
479+
BOOST_TEST(s.starts_with(expected_header));
480+
s.remove_prefix(expected_header.size());
481+
BOOST_TEST(s.empty());
482+
});
483+
}
471484

472-
check_stream(
473-
"HTTP/1.1 200 OK\r\n"
474-
"Server: test\r\n"
475-
"Content-Length: 2048\r\n"
476-
"\r\n",
477-
std::string(2048, '*'),
478-
[](core::string_view s){
479-
core::string_view expected_header =
480-
"HTTP/1.1 200 OK\r\n"
481-
"Server: test\r\n"
482-
"Content-Length: 2048\r\n"
483-
"\r\n";
484-
BOOST_TEST(s.starts_with(expected_header));
485-
s.remove_prefix(expected_header.size());
486-
BOOST_TEST_EQ(s, std::string(2048, '*'));
487-
});
485+
// empty stream, chunked
486+
{
487+
check_stream_opts opts;
488+
check_stream(
489+
"HTTP/1.1 200 OK\r\n"
490+
"Server: test\r\n"
491+
"Transfer-Encoding: chunked\r\n"
492+
"\r\n",
493+
std::string(0, '*'),
494+
opts,
495+
[](core::string_view s)
496+
{
497+
core::string_view expected_header =
498+
"HTTP/1.1 200 OK\r\n"
499+
"Server: test\r\n"
500+
"Transfer-Encoding: chunked\r\n"
501+
"\r\n";
502+
BOOST_TEST(s.starts_with(expected_header));
503+
s.remove_prefix(expected_header.size());
504+
check_chunked_body(s, "");
505+
});
506+
}
488507

489-
check_stream(
490-
"HTTP/1.1 200 OK\r\n"
491-
"Server: test\r\n"
492-
"Transfer-Encoding: chunked\r\n"
493-
"\r\n",
494-
std::string(2048, '*'),
495-
[](core::string_view s){
496-
core::string_view expected_header =
497-
"HTTP/1.1 200 OK\r\n"
498-
"Server: test\r\n"
499-
"Transfer-Encoding: chunked\r\n"
500-
"\r\n";
501-
BOOST_TEST(s.starts_with(expected_header));
502-
s.remove_prefix(expected_header.size());
503-
check_chunked_body(
504-
s, std::string(2048, '*'));
505-
});
508+
// stream
509+
{
510+
check_stream_opts opts;
511+
check_stream(
512+
"HTTP/1.1 200 OK\r\n"
513+
"Server: test\r\n"
514+
"Content-Length: 13370\r\n"
515+
"\r\n",
516+
std::string(13370, '*'),
517+
opts,
518+
[](core::string_view s){
519+
core::string_view expected_header =
520+
"HTTP/1.1 200 OK\r\n"
521+
"Server: test\r\n"
522+
"Content-Length: 13370\r\n"
523+
"\r\n";
524+
525+
BOOST_TEST(
526+
s.starts_with(expected_header));
527+
528+
s.remove_prefix(expected_header.size());
529+
BOOST_TEST_EQ(
530+
s, std::string(13370, '*'));
531+
});
532+
}
533+
534+
// stream, chunked
535+
{
536+
check_stream_opts opts;
537+
check_stream(
538+
"HTTP/1.1 200 OK\r\n"
539+
"Server: test\r\n"
540+
"Transfer-Encoding: chunked\r\n"
541+
"\r\n",
542+
std::string(13370, '*'),
543+
opts,
544+
[](core::string_view s)
545+
{
546+
core::string_view expected_header =
547+
"HTTP/1.1 200 OK\r\n"
548+
"Server: test\r\n"
549+
"Transfer-Encoding: chunked\r\n"
550+
"\r\n";
551+
BOOST_TEST(s.starts_with(
552+
expected_header));
553+
s.remove_prefix(expected_header.size());
554+
check_chunked_body(
555+
s, std::string(13370, '*'));
556+
});
557+
}
506558
}
507559

508560
void
@@ -631,8 +683,8 @@ struct serializer_test
631683

632684
serializer sr;
633685
auto stream = sr.start_stream(res);
634-
auto mbs = stream.prepare(0);
635-
BOOST_TEST_EQ(
686+
auto mbs = stream.prepare();
687+
BOOST_TEST_GT(
636688
buffers::buffer_size(mbs), 0);
637689
BOOST_TEST_THROWS(
638690
stream.commit(0), std::logic_error);
@@ -686,14 +738,13 @@ struct serializer_test
686738
std::string chunk(chunk_size, 'a');
687739
while( num_written < 2048 )
688740
{
689-
auto mbs =
690-
stream.prepare(chunk_size);
691-
692741
auto n = buffers::buffer_copy(
693-
mbs,
742+
stream.prepare(),
694743
buffers::const_buffer(
695-
chunk.data(), chunk.size()));
744+
chunk.data(),
745+
chunk.size()));
696746

747+
BOOST_TEST_GT(n, 0);
697748
stream.commit(n);
698749
num_written += n;
699750
}

0 commit comments

Comments
 (0)