Skip to content

Commit

Permalink
serializer supports stream chunking
Browse files Browse the repository at this point in the history
  • Loading branch information
cmazakas committed Apr 5, 2024
1 parent 4a36758 commit 3712fa1
Show file tree
Hide file tree
Showing 4 changed files with 317 additions and 9 deletions.
10 changes: 10 additions & 0 deletions include/boost/http_proto/message_view_base.hpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
//
// Copyright (c) 2021 Vinnie Falco (vinnie.falco@gmail.com)
// Copyright (c) 2024 Christian Mazakas
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
Expand Down Expand Up @@ -91,6 +92,15 @@ class BOOST_SYMBOL_VISIBLE
{
return ph_->md;
}

/** Return true if the message is using a chunked
transfer encoding.
*/
bool
chunked() const noexcept
{
return ph_->md.transfer_encoding.is_chunked;
}
};

} // http_proto
Expand Down
29 changes: 22 additions & 7 deletions include/boost/http_proto/serializer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ class BOOST_SYMBOL_VISIBLE
void
start(
message_view_base const& m,
ConstBufferSequence&& body);
ConstBufferSequence&& body);

/** Prepare the serializer for a new message
Expand Down Expand Up @@ -242,16 +242,31 @@ class BOOST_SYMBOL_VISIBLE
stream
};

// chunked-body = *chunk
// last-chunk
// trailer-section
// CRLF

// chunk = chunk-size [ chunk-ext ] CRLF
// chunk-data CRLF
static
constexpr
std::size_t
chunk_header_len_ = 16 + 2; // chunk-size + CRLF

// last-chunk = 1*("0") [ chunk-ext ] CRLF
static
constexpr
std::size_t
last_chunk_len_ = 1 + 2 + 2; // chunked-body termination requires an extra CRLF

static
constexpr
std::size_t
chunked_overhead_ =
16 + // size
2 + // CRLF
2 + // CRLF
1 + // "0"
2 + // CRLF
2; // CRLF
chunk_header_len_ +
2 + // CRLF
last_chunk_len_;

detail::workspace ws_;
detail::array_of_const_buffers buf_;
Expand Down
51 changes: 49 additions & 2 deletions src/serializer.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
//
// Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com)
// Copyright (c) 2024 Christian Mazakas
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
Expand Down Expand Up @@ -71,6 +72,26 @@ write_chunk_header(
buffers::buffer_size(dest0) == n);
}

template<class DynamicBuffer>
void
write_chunk_close(DynamicBuffer& db)
{
db.commit(
buffers::buffer_copy(
db.prepare(2),
buffers::const_buffer("\r\n", 2)));
}

template<class DynamicBuffer>
void
write_last_chunk(DynamicBuffer& db)
{
db.commit(
buffers::buffer_copy(
db.prepare(5),
buffers::const_buffer("0\r\n\r\n", 5)));
}

//------------------------------------------------

serializer::
Expand Down Expand Up @@ -521,7 +542,7 @@ serializer::
stream::
capacity() const
{
auto const n =
auto const n =
chunked_overhead_ +
2 + // CRLF
5; // final chunk
Expand All @@ -543,6 +564,11 @@ prepare(
std::size_t n) const ->
buffers_type
{
if( sr_->is_chunked_ )
return buffers::sans_prefix(
sr_->tmp0_.prepare(n + chunk_header_len_),
chunk_header_len_);

return sr_->tmp0_.prepare(n);
}

Expand All @@ -551,7 +577,24 @@ serializer::
stream::
commit(std::size_t n) const
{
sr_->tmp0_.commit(n);
if(! sr_->is_chunked_ )
{
sr_->tmp0_.commit(n);
}
else
{
// Zero sized chunks are not valid. Call close()
// if the intent is to signal the end of the body.
if( n == 0 )
detail::throw_logic_error();

auto m = n + chunk_header_len_;
auto dest = sr_->tmp0_.prepare(m);
write_chunk_header(
buffers::prefix(dest, chunk_header_len_), n);
sr_->tmp0_.commit(m);
write_chunk_close(sr_->tmp0_);
}
}

void
Expand All @@ -562,6 +605,10 @@ close() const
// Precondition violation
if(! sr_->more_)
detail::throw_logic_error();

if (sr_->is_chunked_)
write_last_chunk(sr_->tmp0_);

sr_->more_ = false;
}

Expand Down
Loading

0 comments on commit 3712fa1

Please sign in to comment.