Skip to content

Commit 4da2936

Browse files
committed
serializer handles head responses
1 parent 04b6699 commit 4da2936

3 files changed

Lines changed: 427 additions & 90 deletions

File tree

src/detail/serializer.cpp

Lines changed: 59 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -29,11 +29,11 @@ serializer(config const& cfg, capy::any_write_stream* stream)
2929
, min_prepare_(cfg.min_prepare)
3030
, direct_thr_(cfg.direct_thr)
3131
, enc_thr_(cfg.enc_thr)
32-
, in_(new unsigned char[
32+
, out_(new unsigned char[
3333
cfg.out_buffer + cfg.enc_buffer + margin] + margin)
34-
, in_cap_(cfg.out_buffer)
35-
, out_(in_)
3634
, out_cap_(cfg.enc_buffer)
35+
, in_(out_)
36+
, in_cap_(cfg.out_buffer)
3737
{
3838
}
3939

@@ -74,24 +74,24 @@ serializer::
7474
~serializer()
7575
{
7676
if(out_)
77-
delete[]((out_ > in_ ? in_ : out_) - margin);
77+
delete[](out_ - margin);
7878
}
7979

8080
void
8181
serializer::
8282
reset(
8383
capy::any_write_stream* stream,
8484
http::message_base* msg,
85-
encoder_base* enc,
85+
encoder* enc,
8686
bool head) noexcept
8787
{
88-
if(out_ > in_)
89-
out_ = in_;
88+
if(head)
89+
enc = nullptr;
9090

91-
if(!enc_ && enc)
91+
if(!enc == (in_ != out_))
9292
{
93-
std::swap(out_cap_, in_cap_);
94-
in_ += out_cap_;
93+
std::swap(in_cap_, out_cap_);
94+
in_ = enc ? out_ + out_cap_ : out_;
9595
}
9696

9797
stream_ = stream;
@@ -169,7 +169,7 @@ do_commit(std::size_t n) noexcept
169169

170170
bool
171171
serializer::
172-
can_coalesce(std::size_t avail) const noexcept
172+
should_coalesce(std::size_t avail) const noexcept
173173
{
174174
if(avail > capacity())
175175
return false;
@@ -182,6 +182,9 @@ void
182182
serializer::
183183
finalize(std::size_t remaining) noexcept
184184
{
185+
if(head_)
186+
return;
187+
185188
if(enc_)
186189
{
187190
if(enc_started_)
@@ -192,8 +195,6 @@ finalize(std::size_t remaining) noexcept
192195

193196
msg_->erase(http::field::content_encoding);
194197
enc_ = nullptr;
195-
std::swap(out_, in_);
196-
std::swap(out_cap_, in_cap_);
197198
}
198199
decide_framing(remaining);
199200
}
@@ -246,11 +247,11 @@ encode(
246247
co_return { ec, consumed };
247248
}
248249

249-
capy::mutable_buffer out =
250-
{ out_ + out_len_, out_cap_ - out_len_ };
251-
252250
auto r = enc_->process(
253-
out, in, eof && n == tail.size());
251+
{ out_ + out_len_, out_cap_ - out_len_ },
252+
in,
253+
eof && n == tail.size());
254+
254255
enc_started_ = true;
255256
out_len_ += r.produced;
256257
in += r.consumed;
@@ -284,12 +285,11 @@ flush(
284285
std::span<capy::const_buffer const> tail,
285286
bool eof)
286287
{
287-
if(!enc_)
288-
out_len_ = in_len_;
289-
290-
auto const tail_size = capy::buffer_size(tail);
291-
auto const chunked = msg_->chunked();
292-
BOOST_ASSERT(eof || out_len_ + tail_size != 0);
288+
auto const buf = enc_ ? out_ : in_;
289+
auto& len = enc_ ? out_len_ : in_len_;
290+
auto const tail_len = capy::buffer_size(tail);
291+
auto const chunked = msg_->chunked() && !head_;
292+
BOOST_ASSERT(eof || len + tail_len != 0);
293293
BOOST_ASSERT(tail.size() <= capy::detail::max_iovec_);
294294

295295
capy::const_buffer vec[capy::detail::max_iovec_ + 3];
@@ -306,20 +306,43 @@ flush(
306306

307307
if(chunked)
308308
{
309-
append(chunk_frame(tail_size));
309+
static constexpr char hex[] = "0123456789abcdef";
310+
auto s = len + tail_len;
311+
auto p = buf;
312+
313+
*--p = '\n';
314+
*--p = '\r';
315+
316+
do
317+
{
318+
*--p = hex[s & 0xF];
319+
s >>= 4;
320+
} while(s != 0);
321+
322+
// prev chunk's CRLF
323+
if(total_body_)
324+
{
325+
*--p = '\n';
326+
*--p = '\r';
327+
}
328+
329+
append({ p, static_cast<std::size_t>(buf - p) + len });
310330
}
311331
else
312332
{
313-
auto const declared =
314-
msg_->payload() == http::payload::size
315-
? msg_->payload_size() : 0;
316-
auto const produced = total_body_ + out_len_ + tail_size;
333+
auto const decl = [&]()-> std::uint64_t
334+
{
335+
if(head_ || msg_->payload() != http::payload::size)
336+
return 0;
337+
return msg_->payload_size();
338+
}();
339+
auto const prod = total_body_ + len + tail_len;
317340

318-
if(produced > declared || (eof && produced != declared))
341+
if(prod > decl || (eof && prod != decl))
319342
co_return { error::body_size_mismatch, 0 };
320343

321-
if(out_len_ != 0)
322-
append({ out_, out_len_ });
344+
if(len != 0)
345+
append({ buf, len });
323346
}
324347

325348
auto const owned = sum;
@@ -328,18 +351,16 @@ flush(
328351
append(b);
329352

330353
if(chunked && eof)
331-
append({ "\r\n0\r\n\r\n", out_len_ || tail_size ? 7u : 2u });
354+
append({ "\r\n0\r\n\r\n", len || tail_len ? 7u : 2u });
332355

333-
auto const need = chunked || eof ? sum : owned + (tail_size != 0);
356+
auto const need = chunked || eof ? sum : owned + !!tail_len;
334357
auto [ec, written] = co_await write_at_least({ vec, n }, need);
335358
if(ec)
336359
co_return { ec, 0 };
337360

338-
auto const consumed = (std::min)(written - owned, tail_size);
339-
total_body_ += out_len_ + consumed;
340-
out_len_ = 0;
341-
if(!enc_)
342-
in_len_ = 0;
361+
auto const consumed = (std::min)(written - owned, tail_len);
362+
total_body_ += len + consumed;
363+
len = 0;
343364
hdr_sent_ = true;
344365
done_ = eof;
345366
co_return { {}, consumed };
@@ -366,34 +387,6 @@ write_at_least(
366387
co_return { {}, written };
367388
}
368389

369-
capy::const_buffer
370-
serializer::
371-
chunk_frame(std::size_t tail_size) noexcept
372-
{
373-
static constexpr char hex[] = "0123456789abcdef";
374-
auto s = out_len_ + tail_size;
375-
auto p = out_;
376-
377-
*--p = '\n';
378-
*--p = '\r';
379-
380-
do
381-
{
382-
*--p = hex[s & 0xF];
383-
s >>= 4;
384-
} while(s != 0);
385-
386-
// prev chunk's CRLF
387-
if(total_body_ != 0)
388-
{
389-
*--p = '\n';
390-
*--p = '\r';
391-
}
392-
393-
return { p, static_cast<std::size_t>(
394-
out_ - p) + out_len_ };
395-
}
396-
397390
} // namespace detail
398391
} // namespace burl
399392
} // namespace boost

src/detail/serializer.hpp

Lines changed: 10 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ namespace detail
2929
class serializer
3030
{
3131
public:
32-
struct encoder_base
32+
struct encoder
3333
{
3434
struct result
3535
{
@@ -38,7 +38,7 @@ class serializer
3838
std::error_code ec;
3939
};
4040

41-
virtual ~encoder_base() = default;
41+
virtual ~encoder() = default;
4242

4343
virtual result
4444
process(
@@ -90,23 +90,17 @@ class serializer
9090
return msg_;
9191
}
9292

93-
encoder_base*
94-
encoder() const noexcept
95-
{
96-
return enc_;
97-
}
98-
9993
void
10094
reset(
10195
capy::any_write_stream* stream,
10296
http::message_base* msg,
103-
encoder_base* enc = nullptr,
97+
encoder* enc = nullptr,
10498
bool head = false) noexcept;
10599

106100
void
107101
reset(
108102
http::message_base* msg,
109-
encoder_base* enc = nullptr,
103+
encoder* enc = nullptr,
110104
bool head = false) noexcept
111105
{
112106
BOOST_ASSERT(stream_);
@@ -148,7 +142,7 @@ class serializer
148142
do_commit(std::size_t n) noexcept;
149143

150144
bool
151-
can_coalesce(std::size_t avail) const noexcept;
145+
should_coalesce(std::size_t avail) const noexcept;
152146

153147
void
154148
finalize(std::size_t remaining) noexcept;
@@ -177,23 +171,20 @@ class serializer
177171
std::span<capy::const_buffer const> buffers,
178172
std::size_t bytes);
179173

180-
capy::const_buffer
181-
chunk_frame(std::size_t tail_size) noexcept;
182-
183174
static constexpr std::size_t margin = 24;
184175

185176
capy::any_write_stream* stream_;
186177
http::message_base* msg_ = nullptr;
187-
encoder_base* enc_ = nullptr;
178+
encoder* enc_ = nullptr;
188179
std::size_t min_prepare_;
189180
std::size_t direct_thr_;
190181
std::size_t enc_thr_;
191-
unsigned char* in_;
192-
std::size_t in_cap_;
193-
std::size_t in_len_ = 0;
194182
unsigned char* out_;
195183
std::size_t out_cap_;
196184
std::size_t out_len_ = 0;
185+
unsigned char* in_;
186+
std::size_t in_cap_;
187+
std::size_t in_len_ = 0;
197188
std::uint64_t total_body_ = 0;
198189
bool head_ = false;
199190
bool enc_started_ = false;
@@ -207,7 +198,7 @@ serializer::
207198
write_some(Buffers buffers)
208199
{
209200
auto const avail = capy::buffer_size(buffers);
210-
if(can_coalesce(avail))
201+
if(should_coalesce(avail))
211202
{
212203
do_commit(capy::buffer_copy(do_prepare(), buffers));
213204
co_return { {}, avail };

0 commit comments

Comments
 (0)