]>
Commit | Line | Data |
---|---|---|
b32b8144 FG |
1 | // |
2 | // Copyright (c) 2016-2017 Vinnie Falco (vinnie dot falco at gmail dot com) | |
3 | // | |
4 | // Distributed under the Boost Software License, Version 1.0. (See accompanying | |
5 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) | |
6 | // | |
7 | // Official repository: https://github.com/boostorg/beast | |
8 | // | |
9 | ||
10 | #ifndef BOOST_BEAST_HTTP_IMPL_WRITE_IPP | |
11 | #define BOOST_BEAST_HTTP_IMPL_WRITE_IPP | |
12 | ||
13 | #include <boost/beast/http/type_traits.hpp> | |
14 | #include <boost/beast/core/bind_handler.hpp> | |
15 | #include <boost/beast/core/ostream.hpp> | |
16 | #include <boost/beast/core/handler_ptr.hpp> | |
17 | #include <boost/beast/core/type_traits.hpp> | |
18 | #include <boost/beast/core/detail/config.hpp> | |
19 | #include <boost/asio/associated_allocator.hpp> | |
20 | #include <boost/asio/associated_executor.hpp> | |
21 | #include <boost/asio/handler_continuation_hook.hpp> | |
11fdf7f2 | 22 | #include <boost/asio/handler_invoke_hook.hpp> |
b32b8144 FG |
23 | #include <boost/asio/post.hpp> |
24 | #include <boost/asio/write.hpp> | |
25 | #include <boost/optional.hpp> | |
26 | #include <boost/throw_exception.hpp> | |
27 | #include <ostream> | |
28 | #include <sstream> | |
29 | ||
30 | namespace boost { | |
31 | namespace beast { | |
32 | namespace http { | |
33 | namespace detail { | |
34 | ||
35 | template< | |
36 | class Stream, class Handler, | |
37 | bool isRequest, class Body, class Fields> | |
38 | class write_some_op | |
39 | { | |
40 | Stream& s_; | |
41 | serializer<isRequest,Body, Fields>& sr_; | |
42 | Handler h_; | |
43 | ||
44 | class lambda | |
45 | { | |
46 | write_some_op& op_; | |
47 | ||
48 | public: | |
49 | bool invoked = false; | |
50 | ||
51 | explicit | |
52 | lambda(write_some_op& op) | |
53 | : op_(op) | |
54 | { | |
55 | } | |
56 | ||
57 | template<class ConstBufferSequence> | |
58 | void | |
59 | operator()(error_code& ec, | |
60 | ConstBufferSequence const& buffers) | |
61 | { | |
62 | invoked = true; | |
63 | ec.assign(0, ec.category()); | |
64 | return op_.s_.async_write_some( | |
65 | buffers, std::move(op_)); | |
66 | } | |
67 | }; | |
68 | ||
69 | public: | |
70 | write_some_op(write_some_op&&) = default; | |
11fdf7f2 | 71 | write_some_op(write_some_op const&) = delete; |
b32b8144 FG |
72 | |
73 | template<class DeducedHandler> | |
74 | write_some_op(DeducedHandler&& h, Stream& s, | |
75 | serializer<isRequest, Body, Fields>& sr) | |
76 | : s_(s) | |
77 | , sr_(sr) | |
78 | , h_(std::forward<DeducedHandler>(h)) | |
79 | { | |
80 | } | |
81 | ||
82 | using allocator_type = | |
83 | boost::asio::associated_allocator_t<Handler>; | |
84 | ||
85 | allocator_type | |
86 | get_allocator() const noexcept | |
87 | { | |
11fdf7f2 | 88 | return (boost::asio::get_associated_allocator)(h_); |
b32b8144 FG |
89 | } |
90 | ||
91 | using executor_type = boost::asio::associated_executor_t< | |
92 | Handler, decltype(std::declval<Stream&>().get_executor())>; | |
93 | ||
94 | executor_type | |
95 | get_executor() const noexcept | |
96 | { | |
11fdf7f2 | 97 | return (boost::asio::get_associated_executor)( |
b32b8144 FG |
98 | h_, s_.get_executor()); |
99 | } | |
100 | ||
101 | void | |
102 | operator()(); | |
103 | ||
104 | void | |
105 | operator()( | |
106 | error_code ec, | |
107 | std::size_t bytes_transferred); | |
108 | ||
109 | friend | |
110 | bool asio_handler_is_continuation(write_some_op* op) | |
111 | { | |
112 | using boost::asio::asio_handler_is_continuation; | |
113 | return asio_handler_is_continuation( | |
114 | std::addressof(op->h_)); | |
115 | } | |
11fdf7f2 TL |
116 | |
117 | template<class Function> | |
118 | friend | |
119 | void asio_handler_invoke(Function&& f, write_some_op* op) | |
120 | { | |
121 | using boost::asio::asio_handler_invoke; | |
122 | asio_handler_invoke(f, std::addressof(op->h_)); | |
123 | } | |
b32b8144 FG |
124 | }; |
125 | ||
126 | template< | |
127 | class Stream, class Handler, | |
128 | bool isRequest, class Body, class Fields> | |
129 | void | |
130 | write_some_op< | |
131 | Stream, Handler, isRequest, Body, Fields>:: | |
132 | operator()() | |
133 | { | |
134 | error_code ec; | |
135 | if(! sr_.is_done()) | |
136 | { | |
137 | lambda f{*this}; | |
138 | sr_.next(ec, f); | |
139 | if(ec) | |
140 | { | |
141 | BOOST_ASSERT(! f.invoked); | |
142 | return boost::asio::post( | |
143 | s_.get_executor(), | |
144 | bind_handler(std::move(*this), ec, 0)); | |
145 | } | |
146 | if(f.invoked) | |
147 | { | |
148 | // *this has been moved from, | |
149 | // cannot access members here. | |
150 | return; | |
151 | } | |
152 | // What else could it be? | |
153 | BOOST_ASSERT(sr_.is_done()); | |
154 | } | |
155 | return boost::asio::post( | |
156 | s_.get_executor(), | |
157 | bind_handler(std::move(*this), ec, 0)); | |
158 | } | |
159 | ||
160 | template< | |
161 | class Stream, class Handler, | |
162 | bool isRequest, class Body, class Fields> | |
163 | void | |
164 | write_some_op< | |
165 | Stream, Handler, isRequest, Body, Fields>:: | |
166 | operator()( | |
167 | error_code ec, std::size_t bytes_transferred) | |
168 | { | |
169 | if(! ec) | |
170 | sr_.consume(bytes_transferred); | |
171 | h_(ec, bytes_transferred); | |
172 | } | |
173 | ||
174 | //------------------------------------------------------------------------------ | |
175 | ||
176 | struct serializer_is_header_done | |
177 | { | |
178 | template< | |
179 | bool isRequest, class Body, class Fields> | |
180 | bool | |
181 | operator()( | |
182 | serializer<isRequest, Body, Fields>& sr) const | |
183 | { | |
184 | return sr.is_header_done(); | |
185 | } | |
186 | }; | |
187 | ||
188 | struct serializer_is_done | |
189 | { | |
190 | template< | |
191 | bool isRequest, class Body, class Fields> | |
192 | bool | |
193 | operator()( | |
194 | serializer<isRequest, Body, Fields>& sr) const | |
195 | { | |
196 | return sr.is_done(); | |
197 | } | |
198 | }; | |
199 | ||
200 | //------------------------------------------------------------------------------ | |
201 | ||
202 | template< | |
203 | class Stream, class Handler, class Predicate, | |
204 | bool isRequest, class Body, class Fields> | |
205 | class write_op | |
206 | { | |
207 | int state_ = 0; | |
208 | Stream& s_; | |
209 | serializer<isRequest, Body, Fields>& sr_; | |
210 | std::size_t bytes_transferred_ = 0; | |
211 | Handler h_; | |
212 | ||
213 | public: | |
214 | write_op(write_op&&) = default; | |
11fdf7f2 | 215 | write_op(write_op const&) = delete; |
b32b8144 FG |
216 | |
217 | template<class DeducedHandler> | |
218 | write_op(DeducedHandler&& h, Stream& s, | |
219 | serializer<isRequest, Body, Fields>& sr) | |
220 | : s_(s) | |
221 | , sr_(sr) | |
222 | , h_(std::forward<DeducedHandler>(h)) | |
223 | { | |
224 | } | |
225 | ||
226 | using allocator_type = | |
227 | boost::asio::associated_allocator_t<Handler>; | |
228 | ||
229 | allocator_type | |
230 | get_allocator() const noexcept | |
231 | { | |
11fdf7f2 | 232 | return (boost::asio::get_associated_allocator)(h_); |
b32b8144 FG |
233 | } |
234 | ||
235 | using executor_type = boost::asio::associated_executor_t< | |
236 | Handler, decltype(std::declval<Stream&>().get_executor())>; | |
237 | ||
238 | executor_type | |
239 | get_executor() const noexcept | |
240 | { | |
11fdf7f2 | 241 | return (boost::asio::get_associated_executor)( |
b32b8144 FG |
242 | h_, s_.get_executor()); |
243 | } | |
244 | ||
245 | void | |
246 | operator()( | |
247 | error_code ec = {}, | |
248 | std::size_t bytes_transferred = 0); | |
249 | ||
250 | friend | |
251 | bool asio_handler_is_continuation(write_op* op) | |
252 | { | |
253 | using boost::asio::asio_handler_is_continuation; | |
254 | return op->state_ >= 3 || | |
255 | asio_handler_is_continuation( | |
256 | std::addressof(op->h_)); | |
257 | } | |
11fdf7f2 TL |
258 | |
259 | template<class Function> | |
260 | friend | |
261 | void asio_handler_invoke(Function&& f, write_op* op) | |
262 | { | |
263 | using boost::asio::asio_handler_invoke; | |
264 | asio_handler_invoke(f, std::addressof(op->h_)); | |
265 | } | |
b32b8144 FG |
266 | }; |
267 | ||
268 | template< | |
269 | class Stream, class Handler, class Predicate, | |
270 | bool isRequest, class Body, class Fields> | |
271 | void | |
272 | write_op<Stream, Handler, Predicate, | |
273 | isRequest, Body, Fields>:: | |
274 | operator()( | |
275 | error_code ec, std::size_t bytes_transferred) | |
276 | { | |
277 | if(ec) | |
278 | goto upcall; | |
279 | switch(state_) | |
280 | { | |
281 | case 0: | |
282 | { | |
283 | if(Predicate{}(sr_)) | |
284 | { | |
285 | state_ = 1; | |
286 | return boost::asio::post( | |
287 | s_.get_executor(), | |
288 | bind_handler(std::move(*this), ec, 0)); | |
289 | } | |
290 | state_ = 2; | |
291 | return beast::http::async_write_some( | |
292 | s_, sr_, std::move(*this)); | |
293 | } | |
294 | ||
295 | case 1: | |
296 | goto upcall; | |
297 | ||
298 | case 2: | |
299 | state_ = 3; | |
11fdf7f2 | 300 | BOOST_FALLTHROUGH; |
b32b8144 FG |
301 | |
302 | case 3: | |
303 | { | |
304 | bytes_transferred_ += bytes_transferred; | |
305 | if(Predicate{}(sr_)) | |
306 | goto upcall; | |
307 | return beast::http::async_write_some( | |
308 | s_, sr_, std::move(*this)); | |
309 | } | |
310 | } | |
311 | upcall: | |
312 | h_(ec, bytes_transferred_); | |
313 | } | |
314 | ||
315 | //------------------------------------------------------------------------------ | |
316 | ||
317 | template<class Stream, class Handler, | |
318 | bool isRequest, class Body, class Fields> | |
319 | class write_msg_op | |
320 | { | |
321 | struct data | |
322 | { | |
323 | Stream& s; | |
324 | serializer<isRequest, Body, Fields> sr; | |
325 | ||
11fdf7f2 | 326 | data(Handler const&, Stream& s_, message< |
b32b8144 FG |
327 | isRequest, Body, Fields>& m_) |
328 | : s(s_) | |
329 | , sr(m_) | |
330 | { | |
331 | } | |
332 | }; | |
333 | ||
334 | handler_ptr<data, Handler> d_; | |
335 | ||
336 | public: | |
337 | write_msg_op(write_msg_op&&) = default; | |
11fdf7f2 | 338 | write_msg_op(write_msg_op const&) = delete; |
b32b8144 FG |
339 | |
340 | template<class DeducedHandler, class... Args> | |
341 | write_msg_op(DeducedHandler&& h, Stream& s, Args&&... args) | |
342 | : d_(std::forward<DeducedHandler>(h), | |
343 | s, std::forward<Args>(args)...) | |
344 | { | |
345 | } | |
346 | ||
347 | using allocator_type = | |
348 | boost::asio::associated_allocator_t<Handler>; | |
349 | ||
350 | allocator_type | |
351 | get_allocator() const noexcept | |
352 | { | |
11fdf7f2 | 353 | return (boost::asio::get_associated_allocator)(d_.handler()); |
b32b8144 FG |
354 | } |
355 | ||
356 | using executor_type = boost::asio::associated_executor_t< | |
357 | Handler, decltype(std::declval<Stream&>().get_executor())>; | |
358 | ||
359 | executor_type | |
360 | get_executor() const noexcept | |
361 | { | |
11fdf7f2 | 362 | return (boost::asio::get_associated_executor)( |
b32b8144 FG |
363 | d_.handler(), d_->s.get_executor()); |
364 | } | |
365 | ||
366 | void | |
367 | operator()(); | |
368 | ||
369 | void | |
370 | operator()( | |
371 | error_code ec, std::size_t bytes_transferred); | |
372 | ||
373 | friend | |
374 | bool asio_handler_is_continuation(write_msg_op* op) | |
375 | { | |
376 | using boost::asio::asio_handler_is_continuation; | |
377 | return asio_handler_is_continuation( | |
378 | std::addressof(op->d_.handler())); | |
379 | } | |
11fdf7f2 TL |
380 | |
381 | template<class Function> | |
382 | friend | |
383 | void asio_handler_invoke(Function&& f, write_msg_op* op) | |
384 | { | |
385 | using boost::asio::asio_handler_invoke; | |
386 | asio_handler_invoke(f, std::addressof(op->d_.handler())); | |
387 | } | |
b32b8144 FG |
388 | }; |
389 | ||
390 | template<class Stream, class Handler, | |
391 | bool isRequest, class Body, class Fields> | |
392 | void | |
393 | write_msg_op< | |
394 | Stream, Handler, isRequest, Body, Fields>:: | |
395 | operator()() | |
396 | { | |
397 | auto& d = *d_; | |
398 | return async_write(d.s, d.sr, std::move(*this)); | |
399 | } | |
400 | ||
401 | template<class Stream, class Handler, | |
402 | bool isRequest, class Body, class Fields> | |
403 | void | |
404 | write_msg_op< | |
405 | Stream, Handler, isRequest, Body, Fields>:: | |
406 | operator()(error_code ec, std::size_t bytes_transferred) | |
407 | { | |
408 | d_.invoke(ec, bytes_transferred); | |
409 | } | |
410 | ||
411 | //------------------------------------------------------------------------------ | |
412 | ||
413 | template<class Stream> | |
414 | class write_some_lambda | |
415 | { | |
416 | Stream& stream_; | |
417 | ||
418 | public: | |
419 | bool invoked = false; | |
420 | std::size_t bytes_transferred = 0; | |
421 | ||
422 | explicit | |
423 | write_some_lambda(Stream& stream) | |
424 | : stream_(stream) | |
425 | { | |
426 | } | |
427 | ||
428 | template<class ConstBufferSequence> | |
429 | void | |
430 | operator()(error_code& ec, | |
431 | ConstBufferSequence const& buffers) | |
432 | { | |
433 | invoked = true; | |
434 | bytes_transferred = | |
435 | stream_.write_some(buffers, ec); | |
436 | } | |
437 | }; | |
438 | ||
439 | template<class Stream> | |
440 | class write_lambda | |
441 | { | |
442 | Stream& stream_; | |
443 | ||
444 | public: | |
445 | bool invoked = false; | |
446 | std::size_t bytes_transferred = 0; | |
447 | ||
448 | explicit | |
449 | write_lambda(Stream& stream) | |
450 | : stream_(stream) | |
451 | { | |
452 | } | |
453 | ||
454 | template<class ConstBufferSequence> | |
455 | void | |
456 | operator()(error_code& ec, | |
457 | ConstBufferSequence const& buffers) | |
458 | { | |
459 | invoked = true; | |
460 | bytes_transferred = boost::asio::write( | |
461 | stream_, buffers, ec); | |
462 | } | |
463 | }; | |
464 | ||
465 | template< | |
466 | class SyncWriteStream, | |
467 | bool isRequest, class Body, class Fields> | |
468 | std::size_t | |
11fdf7f2 | 469 | write_some_impl( |
b32b8144 FG |
470 | SyncWriteStream& stream, |
471 | serializer<isRequest, Body, Fields>& sr, | |
472 | error_code& ec) | |
473 | { | |
474 | if(! sr.is_done()) | |
475 | { | |
476 | write_some_lambda<SyncWriteStream> f{stream}; | |
477 | sr.next(ec, f); | |
478 | if(ec) | |
479 | return f.bytes_transferred; | |
480 | if(f.invoked) | |
481 | sr.consume(f.bytes_transferred); | |
482 | return f.bytes_transferred; | |
483 | } | |
484 | ec.assign(0, ec.category()); | |
485 | return 0; | |
486 | } | |
487 | ||
488 | template< | |
489 | class AsyncWriteStream, | |
490 | bool isRequest, class Body, class Fields, | |
491 | class WriteHandler> | |
492 | BOOST_ASIO_INITFN_RESULT_TYPE( | |
493 | WriteHandler, void(error_code, std::size_t)) | |
11fdf7f2 | 494 | async_write_some_impl( |
b32b8144 FG |
495 | AsyncWriteStream& stream, |
496 | serializer<isRequest, Body, Fields>& sr, | |
497 | WriteHandler&& handler) | |
498 | { | |
11fdf7f2 TL |
499 | BOOST_BEAST_HANDLER_INIT( |
500 | WriteHandler, void(error_code, std::size_t)); | |
b32b8144 FG |
501 | detail::write_some_op< |
502 | AsyncWriteStream, | |
503 | BOOST_ASIO_HANDLER_TYPE(WriteHandler, | |
504 | void(error_code, std::size_t)), | |
505 | isRequest, Body, Fields>{ | |
11fdf7f2 | 506 | std::move(init.completion_handler), stream, sr}(); |
b32b8144 FG |
507 | return init.result.get(); |
508 | } | |
509 | ||
510 | } // detail | |
511 | ||
512 | //------------------------------------------------------------------------------ | |
513 | ||
514 | template< | |
515 | class SyncWriteStream, | |
516 | bool isRequest, class Body, class Fields> | |
517 | std::size_t | |
518 | write_some( | |
519 | SyncWriteStream& stream, | |
520 | serializer<isRequest, Body, Fields>& sr) | |
521 | { | |
522 | static_assert(is_sync_write_stream<SyncWriteStream>::value, | |
523 | "SyncWriteStream requirements not met"); | |
524 | static_assert(is_body<Body>::value, | |
525 | "Body requirements not met"); | |
526 | static_assert(is_body_writer<Body>::value, | |
527 | "BodyWriter requirements not met"); | |
528 | error_code ec; | |
529 | auto const bytes_transferred = | |
530 | write_some(stream, sr, ec); | |
531 | if(ec) | |
532 | BOOST_THROW_EXCEPTION(system_error{ec}); | |
533 | return bytes_transferred; | |
534 | } | |
535 | ||
536 | template< | |
537 | class SyncWriteStream, | |
538 | bool isRequest, class Body, class Fields> | |
539 | std::size_t | |
540 | write_some( | |
541 | SyncWriteStream& stream, | |
542 | serializer<isRequest, Body, Fields>& sr, | |
543 | error_code& ec) | |
544 | { | |
545 | static_assert(is_sync_write_stream<SyncWriteStream>::value, | |
546 | "SyncWriteStream requirements not met"); | |
547 | static_assert(is_body<Body>::value, | |
548 | "Body requirements not met"); | |
549 | static_assert(is_body_writer<Body>::value, | |
550 | "BodyWriter requirements not met"); | |
11fdf7f2 | 551 | return detail::write_some_impl(stream, sr, ec); |
b32b8144 FG |
552 | } |
553 | ||
554 | template< | |
555 | class AsyncWriteStream, | |
556 | bool isRequest, class Body, class Fields, | |
557 | class WriteHandler> | |
558 | BOOST_ASIO_INITFN_RESULT_TYPE( | |
559 | WriteHandler, void(error_code, std::size_t)) | |
560 | async_write_some( | |
561 | AsyncWriteStream& stream, | |
562 | serializer<isRequest, Body, Fields>& sr, | |
563 | WriteHandler&& handler) | |
564 | { | |
565 | static_assert(is_async_write_stream< | |
566 | AsyncWriteStream>::value, | |
567 | "AsyncWriteStream requirements not met"); | |
568 | static_assert(is_body<Body>::value, | |
569 | "Body requirements not met"); | |
570 | static_assert(is_body_writer<Body>::value, | |
571 | "BodyWriter requirements not met"); | |
11fdf7f2 | 572 | return detail::async_write_some_impl(stream, sr, |
b32b8144 FG |
573 | std::forward<WriteHandler>(handler)); |
574 | } | |
575 | ||
576 | //------------------------------------------------------------------------------ | |
577 | ||
578 | template< | |
579 | class SyncWriteStream, | |
580 | bool isRequest, class Body, class Fields> | |
581 | std::size_t | |
582 | write_header(SyncWriteStream& stream, | |
583 | serializer<isRequest, Body, Fields>& sr) | |
584 | { | |
585 | static_assert(is_sync_write_stream<SyncWriteStream>::value, | |
586 | "SyncWriteStream requirements not met"); | |
587 | static_assert(is_body<Body>::value, | |
588 | "Body requirements not met"); | |
589 | static_assert(is_body_writer<Body>::value, | |
590 | "BodyWriter requirements not met"); | |
591 | error_code ec; | |
592 | auto const bytes_transferred = | |
593 | write_header(stream, sr, ec); | |
594 | if(ec) | |
595 | BOOST_THROW_EXCEPTION(system_error{ec}); | |
596 | return bytes_transferred; | |
597 | } | |
598 | ||
599 | template< | |
600 | class SyncWriteStream, | |
601 | bool isRequest, class Body, class Fields> | |
602 | std::size_t | |
603 | write_header( | |
604 | SyncWriteStream& stream, | |
605 | serializer<isRequest, Body, Fields>& sr, | |
606 | error_code& ec) | |
607 | { | |
608 | static_assert(is_sync_write_stream<SyncWriteStream>::value, | |
609 | "SyncWriteStream requirements not met"); | |
610 | static_assert(is_body<Body>::value, | |
611 | "Body requirements not met"); | |
612 | static_assert(is_body_writer<Body>::value, | |
613 | "BodyWriter requirements not met"); | |
614 | sr.split(true); | |
615 | std::size_t bytes_transferred = 0; | |
616 | if(! sr.is_header_done()) | |
617 | { | |
618 | detail::write_lambda<SyncWriteStream> f{stream}; | |
619 | do | |
620 | { | |
621 | sr.next(ec, f); | |
622 | bytes_transferred += f.bytes_transferred; | |
623 | if(ec) | |
624 | return bytes_transferred; | |
625 | BOOST_ASSERT(f.invoked); | |
626 | sr.consume(f.bytes_transferred); | |
627 | } | |
628 | while(! sr.is_header_done()); | |
629 | } | |
630 | else | |
631 | { | |
632 | ec.assign(0, ec.category()); | |
633 | } | |
634 | return bytes_transferred; | |
635 | } | |
636 | ||
637 | template< | |
638 | class AsyncWriteStream, | |
639 | bool isRequest, class Body, class Fields, | |
640 | class WriteHandler> | |
641 | BOOST_ASIO_INITFN_RESULT_TYPE( | |
642 | WriteHandler, void(error_code, std::size_t)) | |
643 | async_write_header( | |
644 | AsyncWriteStream& stream, | |
645 | serializer<isRequest, Body, Fields>& sr, | |
646 | WriteHandler&& handler) | |
647 | { | |
648 | static_assert(is_async_write_stream< | |
649 | AsyncWriteStream>::value, | |
650 | "AsyncWriteStream requirements not met"); | |
651 | static_assert(is_body<Body>::value, | |
652 | "Body requirements not met"); | |
653 | static_assert(is_body_writer<Body>::value, | |
654 | "BodyWriter requirements not met"); | |
655 | sr.split(true); | |
11fdf7f2 TL |
656 | BOOST_BEAST_HANDLER_INIT( |
657 | WriteHandler, void(error_code, std::size_t)); | |
b32b8144 FG |
658 | detail::write_op< |
659 | AsyncWriteStream, | |
660 | BOOST_ASIO_HANDLER_TYPE(WriteHandler, | |
661 | void(error_code, std::size_t)), | |
662 | detail::serializer_is_header_done, | |
663 | isRequest, Body, Fields>{ | |
11fdf7f2 | 664 | std::move(init.completion_handler), stream, sr}(); |
b32b8144 FG |
665 | return init.result.get(); |
666 | } | |
667 | ||
668 | //------------------------------------------------------------------------------ | |
669 | ||
670 | template< | |
671 | class SyncWriteStream, | |
672 | bool isRequest, class Body, class Fields> | |
673 | std::size_t | |
674 | write( | |
675 | SyncWriteStream& stream, | |
676 | serializer<isRequest, Body, Fields>& sr) | |
677 | { | |
678 | static_assert(is_sync_write_stream<SyncWriteStream>::value, | |
679 | "SyncWriteStream requirements not met"); | |
680 | error_code ec; | |
681 | auto const bytes_transferred = | |
682 | write(stream, sr, ec); | |
683 | if(ec) | |
684 | BOOST_THROW_EXCEPTION(system_error{ec}); | |
685 | return bytes_transferred; | |
686 | } | |
687 | ||
688 | template< | |
689 | class SyncWriteStream, | |
690 | bool isRequest, class Body, class Fields> | |
691 | std::size_t | |
692 | write( | |
693 | SyncWriteStream& stream, | |
694 | serializer<isRequest, Body, Fields>& sr, | |
695 | error_code& ec) | |
696 | { | |
697 | static_assert(is_sync_write_stream<SyncWriteStream>::value, | |
698 | "SyncWriteStream requirements not met"); | |
699 | std::size_t bytes_transferred = 0; | |
700 | sr.split(false); | |
701 | for(;;) | |
702 | { | |
703 | bytes_transferred += | |
704 | write_some(stream, sr, ec); | |
705 | if(ec) | |
706 | return bytes_transferred; | |
707 | if(sr.is_done()) | |
708 | break; | |
709 | } | |
710 | return bytes_transferred; | |
711 | } | |
712 | ||
713 | template< | |
714 | class AsyncWriteStream, | |
715 | bool isRequest, class Body, class Fields, | |
716 | class WriteHandler> | |
717 | BOOST_ASIO_INITFN_RESULT_TYPE( | |
718 | WriteHandler, void(error_code, std::size_t)) | |
719 | async_write( | |
720 | AsyncWriteStream& stream, | |
721 | serializer<isRequest, Body, Fields>& sr, | |
722 | WriteHandler&& handler) | |
723 | { | |
724 | static_assert(is_async_write_stream< | |
725 | AsyncWriteStream>::value, | |
726 | "AsyncWriteStream requirements not met"); | |
727 | static_assert(is_body<Body>::value, | |
728 | "Body requirements not met"); | |
729 | static_assert(is_body_writer<Body>::value, | |
730 | "BodyWriter requirements not met"); | |
731 | sr.split(false); | |
11fdf7f2 TL |
732 | BOOST_BEAST_HANDLER_INIT( |
733 | WriteHandler, void(error_code, std::size_t)); | |
b32b8144 FG |
734 | detail::write_op< |
735 | AsyncWriteStream, | |
736 | BOOST_ASIO_HANDLER_TYPE(WriteHandler, | |
737 | void(error_code, std::size_t)), | |
738 | detail::serializer_is_done, | |
739 | isRequest, Body, Fields>{ | |
11fdf7f2 | 740 | std::move(init.completion_handler), stream, sr}(); |
b32b8144 FG |
741 | return init.result.get(); |
742 | } | |
743 | ||
744 | //------------------------------------------------------------------------------ | |
745 | ||
746 | template< | |
747 | class SyncWriteStream, | |
748 | bool isRequest, class Body, class Fields> | |
749 | std::size_t | |
750 | write( | |
751 | SyncWriteStream& stream, | |
752 | message<isRequest, Body, Fields> const& msg) | |
753 | { | |
754 | static_assert(is_sync_write_stream<SyncWriteStream>::value, | |
755 | "SyncWriteStream requirements not met"); | |
756 | static_assert(is_body<Body>::value, | |
757 | "Body requirements not met"); | |
758 | static_assert(is_body_writer<Body>::value, | |
759 | "BodyWriter requirements not met"); | |
760 | error_code ec; | |
761 | auto const bytes_transferred = | |
762 | write(stream, msg, ec); | |
763 | if(ec) | |
764 | BOOST_THROW_EXCEPTION(system_error{ec}); | |
765 | return bytes_transferred; | |
766 | } | |
767 | ||
768 | template< | |
769 | class SyncWriteStream, | |
770 | bool isRequest, class Body, class Fields> | |
771 | std::size_t | |
772 | write( | |
773 | SyncWriteStream& stream, | |
774 | message<isRequest, Body, Fields> const& msg, | |
775 | error_code& ec) | |
776 | { | |
777 | static_assert(is_sync_write_stream<SyncWriteStream>::value, | |
778 | "SyncWriteStream requirements not met"); | |
779 | static_assert(is_body<Body>::value, | |
780 | "Body requirements not met"); | |
781 | static_assert(is_body_writer<Body>::value, | |
782 | "BodyWriter requirements not met"); | |
783 | serializer<isRequest, Body, Fields> sr{msg}; | |
784 | return write(stream, sr, ec); | |
785 | } | |
786 | ||
787 | template< | |
788 | class AsyncWriteStream, | |
789 | bool isRequest, class Body, class Fields, | |
790 | class WriteHandler> | |
791 | BOOST_ASIO_INITFN_RESULT_TYPE( | |
792 | WriteHandler, void(error_code, std::size_t)) | |
793 | async_write( | |
794 | AsyncWriteStream& stream, | |
795 | message<isRequest, Body, Fields>& msg, | |
796 | WriteHandler&& handler) | |
797 | { | |
798 | static_assert( | |
799 | is_async_write_stream<AsyncWriteStream>::value, | |
800 | "AsyncWriteStream requirements not met"); | |
801 | static_assert(is_body<Body>::value, | |
802 | "Body requirements not met"); | |
803 | static_assert(is_body_writer<Body>::value, | |
804 | "BodyWriter requirements not met"); | |
11fdf7f2 TL |
805 | BOOST_BEAST_HANDLER_INIT( |
806 | WriteHandler, void(error_code, std::size_t)); | |
b32b8144 FG |
807 | detail::write_msg_op< |
808 | AsyncWriteStream, | |
809 | BOOST_ASIO_HANDLER_TYPE(WriteHandler, | |
810 | void(error_code, std::size_t)), | |
811 | isRequest, Body, Fields>{ | |
11fdf7f2 | 812 | std::move(init.completion_handler), stream, msg}(); |
b32b8144 FG |
813 | return init.result.get(); |
814 | } | |
815 | ||
816 | //------------------------------------------------------------------------------ | |
817 | ||
818 | namespace detail { | |
819 | ||
820 | template<class Serializer> | |
821 | class write_ostream_lambda | |
822 | { | |
823 | std::ostream& os_; | |
824 | Serializer& sr_; | |
825 | ||
826 | public: | |
827 | write_ostream_lambda(std::ostream& os, | |
828 | Serializer& sr) | |
829 | : os_(os) | |
830 | , sr_(sr) | |
831 | { | |
832 | } | |
833 | ||
834 | template<class ConstBufferSequence> | |
835 | void | |
836 | operator()(error_code& ec, | |
837 | ConstBufferSequence const& buffers) const | |
838 | { | |
839 | ec.assign(0, ec.category()); | |
840 | if(os_.fail()) | |
841 | return; | |
842 | std::size_t bytes_transferred = 0; | |
843 | for(auto b : buffers_range(buffers)) | |
844 | { | |
845 | os_.write(reinterpret_cast<char const*>( | |
846 | b.data()), b.size()); | |
847 | if(os_.fail()) | |
848 | return; | |
849 | bytes_transferred += b.size(); | |
850 | } | |
851 | sr_.consume(bytes_transferred); | |
852 | } | |
853 | }; | |
854 | ||
855 | } // detail | |
856 | ||
857 | template<class Fields> | |
858 | std::ostream& | |
859 | operator<<(std::ostream& os, | |
860 | header<true, Fields> const& h) | |
861 | { | |
862 | typename Fields::writer fr{ | |
863 | h, h.version(), h.method()}; | |
864 | return os << buffers(fr.get()); | |
865 | } | |
866 | ||
867 | template<class Fields> | |
868 | std::ostream& | |
869 | operator<<(std::ostream& os, | |
870 | header<false, Fields> const& h) | |
871 | { | |
872 | typename Fields::writer fr{ | |
873 | h, h.version(), h.result_int()}; | |
874 | return os << buffers(fr.get()); | |
875 | } | |
876 | ||
877 | template<bool isRequest, class Body, class Fields> | |
878 | std::ostream& | |
879 | operator<<(std::ostream& os, | |
880 | message<isRequest, Body, Fields> const& msg) | |
881 | { | |
882 | static_assert(is_body<Body>::value, | |
883 | "Body requirements not met"); | |
884 | static_assert(is_body_writer<Body>::value, | |
885 | "BodyWriter requirements not met"); | |
886 | serializer<isRequest, Body, Fields> sr{msg}; | |
887 | error_code ec; | |
888 | detail::write_ostream_lambda<decltype(sr)> f{os, sr}; | |
889 | do | |
890 | { | |
891 | sr.next(ec, f); | |
892 | if(os.fail()) | |
893 | break; | |
894 | if(ec) | |
895 | { | |
896 | os.setstate(std::ios::failbit); | |
897 | break; | |
898 | } | |
899 | } | |
900 | while(! sr.is_done()); | |
901 | return os; | |
902 | } | |
903 | ||
904 | } // http | |
905 | } // beast | |
906 | } // boost | |
907 | ||
908 | #endif |