]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/boost/beast/http/impl/read.ipp
update sources to v12.2.3
[ceph.git] / ceph / src / boost / boost / beast / http / impl / read.ipp
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_READ_IPP_HPP
11 #define BOOST_BEAST_HTTP_IMPL_READ_IPP_HPP
12
13 #include <boost/beast/http/type_traits.hpp>
14 #include <boost/beast/http/error.hpp>
15 #include <boost/beast/http/parser.hpp>
16 #include <boost/beast/http/read.hpp>
17 #include <boost/beast/core/bind_handler.hpp>
18 #include <boost/beast/core/handler_ptr.hpp>
19 #include <boost/beast/core/read_size.hpp>
20 #include <boost/beast/core/type_traits.hpp>
21 #include <boost/asio/associated_allocator.hpp>
22 #include <boost/asio/associated_executor.hpp>
23 #include <boost/asio/handler_continuation_hook.hpp>
24 #include <boost/asio/post.hpp>
25 #include <boost/assert.hpp>
26 #include <boost/config.hpp>
27 #include <boost/optional.hpp>
28 #include <boost/throw_exception.hpp>
29
30 namespace boost {
31 namespace beast {
32 namespace http {
33
34 namespace detail {
35
36 //------------------------------------------------------------------------------
37
38 template<class Stream, class DynamicBuffer,
39 bool isRequest, class Derived, class Handler>
40 class read_some_op
41 {
42 int state_ = 0;
43 Stream& s_;
44 DynamicBuffer& b_;
45 basic_parser<isRequest, Derived>& p_;
46 boost::optional<typename
47 DynamicBuffer::mutable_buffers_type> mb_;
48 std::size_t bytes_transferred_ = 0;
49 Handler h_;
50
51 public:
52 read_some_op(read_some_op&&) = default;
53 read_some_op(read_some_op const&) = default;
54
55 template<class DeducedHandler>
56 read_some_op(DeducedHandler&& h, Stream& s,
57 DynamicBuffer& b, basic_parser<isRequest, Derived>& p)
58 : s_(s)
59 , b_(b)
60 , p_(p)
61 , h_(std::forward<DeducedHandler>(h))
62 {
63 }
64
65 using allocator_type =
66 boost::asio::associated_allocator_t<Handler>;
67
68 allocator_type
69 get_allocator() const noexcept
70 {
71 return boost::asio::get_associated_allocator(h_);
72 }
73
74 using executor_type = boost::asio::associated_executor_t<
75 Handler, decltype(std::declval<Stream&>().get_executor())>;
76
77 executor_type
78 get_executor() const noexcept
79 {
80 return boost::asio::get_associated_executor(
81 h_, s_.get_executor());
82 }
83
84 void
85 operator()(
86 error_code ec = {},
87 std::size_t bytes_transferred = 0);
88
89 friend
90 bool asio_handler_is_continuation(read_some_op* op)
91 {
92 using boost::asio::asio_handler_is_continuation;
93 return op->state_ >= 2 ? true :
94 asio_handler_is_continuation(
95 std::addressof(op->h_));
96 }
97 };
98
99 template<class Stream, class DynamicBuffer,
100 bool isRequest, class Derived, class Handler>
101 void
102 read_some_op<Stream, DynamicBuffer,
103 isRequest, Derived, Handler>::
104 operator()(
105 error_code ec,
106 std::size_t bytes_transferred)
107 {
108 switch(state_)
109 {
110 case 0:
111 state_ = 1;
112 if(b_.size() == 0)
113 goto do_read;
114 goto do_parse;
115
116 case 1:
117 state_ = 2;
118 case 2:
119 if(ec == boost::asio::error::eof)
120 {
121 BOOST_ASSERT(bytes_transferred == 0);
122 if(p_.got_some())
123 {
124 // caller sees EOF on next read
125 ec.assign(0, ec.category());
126 p_.put_eof(ec);
127 if(ec)
128 goto upcall;
129 BOOST_ASSERT(p_.is_done());
130 goto upcall;
131 }
132 ec = error::end_of_stream;
133 goto upcall;
134 }
135 if(ec)
136 goto upcall;
137 b_.commit(bytes_transferred);
138
139 do_parse:
140 {
141 auto const used = p_.put(b_.data(), ec);
142 bytes_transferred_ += used;
143 b_.consume(used);
144 if(! ec || ec != http::error::need_more)
145 goto do_upcall;
146 ec.assign(0, ec.category());
147 }
148
149 do_read:
150 try
151 {
152 mb_.emplace(b_.prepare(
153 read_size_or_throw(b_, 65536)));
154 }
155 catch(std::length_error const&)
156 {
157 ec = error::buffer_overflow;
158 goto do_upcall;
159 }
160 return s_.async_read_some(*mb_, std::move(*this));
161
162 do_upcall:
163 if(state_ >= 2)
164 goto upcall;
165 state_ = 3;
166 return boost::asio::post(
167 s_.get_executor(),
168 bind_handler(std::move(*this), ec, 0));
169
170 case 3:
171 break;
172 }
173 upcall:
174 h_(ec, bytes_transferred_);
175 }
176
177 //------------------------------------------------------------------------------
178
179 struct parser_is_done
180 {
181 template<bool isRequest, class Derived>
182 bool
183 operator()(basic_parser<
184 isRequest, Derived> const& p) const
185 {
186 return p.is_done();
187 }
188 };
189
190 struct parser_is_header_done
191 {
192 template<bool isRequest, class Derived>
193 bool
194 operator()(basic_parser<
195 isRequest, Derived> const& p) const
196 {
197 return p.is_header_done();
198 }
199 };
200
201 template<class Stream, class DynamicBuffer,
202 bool isRequest, class Derived, class Condition,
203 class Handler>
204 class read_op
205 {
206 int state_ = 0;
207 Stream& s_;
208 DynamicBuffer& b_;
209 basic_parser<isRequest, Derived>& p_;
210 std::size_t bytes_transferred_ = 0;
211 Handler h_;
212
213 public:
214 read_op(read_op&&) = default;
215 read_op(read_op const&) = default;
216
217 template<class DeducedHandler>
218 read_op(DeducedHandler&& h, Stream& s,
219 DynamicBuffer& b, basic_parser<isRequest,
220 Derived>& p)
221 : s_(s)
222 , b_(b)
223 , p_(p)
224 , h_(std::forward<DeducedHandler>(h))
225 {
226 }
227
228 using allocator_type =
229 boost::asio::associated_allocator_t<Handler>;
230
231 allocator_type
232 get_allocator() const noexcept
233 {
234 return boost::asio::get_associated_allocator(h_);
235 }
236
237 using executor_type = boost::asio::associated_executor_t<
238 Handler, decltype(std::declval<Stream&>().get_executor())>;
239
240 executor_type
241 get_executor() const noexcept
242 {
243 return boost::asio::get_associated_executor(
244 h_, s_.get_executor());
245 }
246
247 void
248 operator()(
249 error_code ec = {},
250 std::size_t bytes_transferred = 0);
251
252 friend
253 bool asio_handler_is_continuation(read_op* op)
254 {
255 using boost::asio::asio_handler_is_continuation;
256 return op->state_ >= 3 ? true :
257 asio_handler_is_continuation(
258 std::addressof(op->h_));
259 }
260 };
261
262 template<class Stream, class DynamicBuffer,
263 bool isRequest, class Derived, class Condition,
264 class Handler>
265 void
266 read_op<Stream, DynamicBuffer,
267 isRequest, Derived, Condition, Handler>::
268 operator()(
269 error_code ec,
270 std::size_t bytes_transferred)
271 {
272 switch(state_)
273 {
274 case 0:
275 if(Condition{}(p_))
276 {
277 state_ = 1;
278 return boost::asio::post(
279 s_.get_executor(),
280 bind_handler(std::move(*this), ec));
281 }
282 state_ = 2;
283
284 do_read:
285 return async_read_some(
286 s_, b_, p_, std::move(*this));
287
288 case 1:
289 goto upcall;
290
291 case 2:
292 case 3:
293 if(ec)
294 goto upcall;
295 bytes_transferred_ += bytes_transferred;
296 if(Condition{}(p_))
297 goto upcall;
298 state_ = 3;
299 goto do_read;
300 }
301 upcall:
302 h_(ec, bytes_transferred_);
303 }
304
305 //------------------------------------------------------------------------------
306
307 template<class Stream, class DynamicBuffer,
308 bool isRequest, class Body, class Allocator,
309 class Handler>
310 class read_msg_op
311 {
312 using parser_type =
313 parser<isRequest, Body, Allocator>;
314
315 using message_type =
316 typename parser_type::value_type;
317
318 struct data
319 {
320 int state = 0;
321 Stream& s;
322 DynamicBuffer& b;
323 message_type& m;
324 parser_type p;
325 std::size_t bytes_transferred = 0;
326
327 data(Handler&, Stream& s_,
328 DynamicBuffer& b_, message_type& m_)
329 : s(s_)
330 , b(b_)
331 , m(m_)
332 , p(std::move(m))
333 {
334 p.eager(true);
335 }
336 };
337
338 handler_ptr<data, Handler> d_;
339
340 public:
341 read_msg_op(read_msg_op&&) = default;
342 read_msg_op(read_msg_op const&) = default;
343
344 template<class DeducedHandler, class... Args>
345 read_msg_op(DeducedHandler&& h, Stream& s, Args&&... args)
346 : d_(std::forward<DeducedHandler>(h),
347 s, std::forward<Args>(args)...)
348 {
349 }
350
351 using allocator_type =
352 boost::asio::associated_allocator_t<Handler>;
353
354 allocator_type
355 get_allocator() const noexcept
356 {
357 return boost::asio::get_associated_allocator(d_.handler());
358 }
359
360 using executor_type = boost::asio::associated_executor_t<
361 Handler, decltype(std::declval<Stream&>().get_executor())>;
362
363 executor_type
364 get_executor() const noexcept
365 {
366 return boost::asio::get_associated_executor(
367 d_.handler(), d_->s.get_executor());
368 }
369
370 void
371 operator()(
372 error_code ec = {},
373 std::size_t bytes_transferred = 0);
374
375 friend
376 bool asio_handler_is_continuation(read_msg_op* op)
377 {
378 using boost::asio::asio_handler_is_continuation;
379 return op->d_->state >= 2 ? true :
380 asio_handler_is_continuation(
381 std::addressof(op->d_.handler()));
382 }
383 };
384
385 template<class Stream, class DynamicBuffer,
386 bool isRequest, class Body, class Allocator,
387 class Handler>
388 void
389 read_msg_op<Stream, DynamicBuffer,
390 isRequest, Body, Allocator, Handler>::
391 operator()(
392 error_code ec,
393 std::size_t bytes_transferred)
394 {
395 auto& d = *d_;
396 switch(d.state)
397 {
398 case 0:
399 d.state = 1;
400
401 do_read:
402 return async_read_some(
403 d.s, d.b, d.p, std::move(*this));
404
405 case 1:
406 case 2:
407 if(ec)
408 goto upcall;
409 d.bytes_transferred +=
410 bytes_transferred;
411 if(d.p.is_done())
412 {
413 d.m = d.p.release();
414 goto upcall;
415 }
416 d.state = 2;
417 goto do_read;
418 }
419 upcall:
420 bytes_transferred = d.bytes_transferred;
421 d_.invoke(ec, bytes_transferred);
422 }
423
424 } // detail
425
426 //------------------------------------------------------------------------------
427
428 template<
429 class SyncReadStream,
430 class DynamicBuffer,
431 bool isRequest, class Derived>
432 std::size_t
433 read_some(
434 SyncReadStream& stream,
435 DynamicBuffer& buffer,
436 basic_parser<isRequest, Derived>& parser)
437 {
438 static_assert(is_sync_read_stream<SyncReadStream>::value,
439 "SyncReadStream requirements not met");
440 static_assert(
441 boost::asio::is_dynamic_buffer<DynamicBuffer>::value,
442 "DynamicBuffer requirements not met");
443 BOOST_ASSERT(! parser.is_done());
444 error_code ec;
445 auto const bytes_transferred =
446 read_some(stream, buffer, parser, ec);
447 if(ec)
448 BOOST_THROW_EXCEPTION(system_error{ec});
449 return bytes_transferred;
450 }
451
452 template<
453 class SyncReadStream,
454 class DynamicBuffer,
455 bool isRequest, class Derived>
456 std::size_t
457 read_some(
458 SyncReadStream& stream,
459 DynamicBuffer& buffer,
460 basic_parser<isRequest, Derived>& parser,
461 error_code& ec)
462 {
463 static_assert(is_sync_read_stream<SyncReadStream>::value,
464 "SyncReadStream requirements not met");
465 static_assert(
466 boost::asio::is_dynamic_buffer<DynamicBuffer>::value,
467 "DynamicBuffer requirements not met");
468 BOOST_ASSERT(! parser.is_done());
469 std::size_t bytes_transferred = 0;
470 if(buffer.size() == 0)
471 goto do_read;
472 for(;;)
473 {
474 // invoke parser
475 {
476 auto const n = parser.put(buffer.data(), ec);
477 bytes_transferred += n;
478 buffer.consume(n);
479 if(! ec)
480 break;
481 if(ec != http::error::need_more)
482 break;
483 }
484 do_read:
485 boost::optional<typename
486 DynamicBuffer::mutable_buffers_type> b;
487 try
488 {
489 b.emplace(buffer.prepare(
490 read_size_or_throw(buffer, 65536)));
491 }
492 catch(std::length_error const&)
493 {
494 ec = error::buffer_overflow;
495 return bytes_transferred;
496 }
497 auto const n = stream.read_some(*b, ec);
498 if(ec == boost::asio::error::eof)
499 {
500 BOOST_ASSERT(n == 0);
501 if(parser.got_some())
502 {
503 // caller sees EOF on next read
504 parser.put_eof(ec);
505 if(ec)
506 break;
507 BOOST_ASSERT(parser.is_done());
508 break;
509 }
510 ec = error::end_of_stream;
511 break;
512 }
513 if(ec)
514 break;
515 buffer.commit(n);
516 }
517 return bytes_transferred;
518 }
519
520 template<
521 class AsyncReadStream,
522 class DynamicBuffer,
523 bool isRequest, class Derived,
524 class ReadHandler>
525 BOOST_ASIO_INITFN_RESULT_TYPE(
526 ReadHandler, void(error_code, std::size_t))
527 async_read_some(
528 AsyncReadStream& stream,
529 DynamicBuffer& buffer,
530 basic_parser<isRequest, Derived>& parser,
531 ReadHandler&& handler)
532 {
533 static_assert(is_async_read_stream<AsyncReadStream>::value,
534 "AsyncReadStream requirements not met");
535 static_assert(
536 boost::asio::is_dynamic_buffer<DynamicBuffer>::value,
537 "DynamicBuffer requirements not met");
538 BOOST_ASSERT(! parser.is_done());
539 boost::asio::async_completion<ReadHandler,
540 void(error_code, std::size_t)> init{handler};
541 detail::read_some_op<AsyncReadStream,
542 DynamicBuffer, isRequest, Derived, BOOST_ASIO_HANDLER_TYPE(
543 ReadHandler, void(error_code, std::size_t))>{
544 init.completion_handler, stream, buffer, parser}();
545 return init.result.get();
546 }
547
548 //------------------------------------------------------------------------------
549
550 template<
551 class SyncReadStream,
552 class DynamicBuffer,
553 bool isRequest, class Derived>
554 std::size_t
555 read_header(
556 SyncReadStream& stream,
557 DynamicBuffer& buffer,
558 basic_parser<isRequest, Derived>& parser)
559 {
560 static_assert(is_sync_read_stream<SyncReadStream>::value,
561 "SyncReadStream requirements not met");
562 static_assert(
563 boost::asio::is_dynamic_buffer<DynamicBuffer>::value,
564 "DynamicBuffer requirements not met");
565 error_code ec;
566 auto const bytes_transferred =
567 read_header(stream, buffer, parser, ec);
568 if(ec)
569 BOOST_THROW_EXCEPTION(system_error{ec});
570 return bytes_transferred;
571 }
572
573 template<
574 class SyncReadStream,
575 class DynamicBuffer,
576 bool isRequest, class Derived>
577 std::size_t
578 read_header(
579 SyncReadStream& stream,
580 DynamicBuffer& buffer,
581 basic_parser<isRequest, Derived>& parser,
582 error_code& ec)
583 {
584 static_assert(is_sync_read_stream<SyncReadStream>::value,
585 "SyncReadStream requirements not met");
586 static_assert(
587 boost::asio::is_dynamic_buffer<DynamicBuffer>::value,
588 "DynamicBuffer requirements not met");
589 parser.eager(false);
590 if(parser.is_header_done())
591 {
592 ec.assign(0, ec.category());
593 return 0;
594 }
595 std::size_t bytes_transferred = 0;
596 do
597 {
598 bytes_transferred += read_some(
599 stream, buffer, parser, ec);
600 if(ec)
601 return bytes_transferred;
602 }
603 while(! parser.is_header_done());
604 return bytes_transferred;
605 }
606
607 template<
608 class AsyncReadStream,
609 class DynamicBuffer,
610 bool isRequest, class Derived,
611 class ReadHandler>
612 BOOST_ASIO_INITFN_RESULT_TYPE(
613 ReadHandler, void(error_code, std::size_t))
614 async_read_header(
615 AsyncReadStream& stream,
616 DynamicBuffer& buffer,
617 basic_parser<isRequest, Derived>& parser,
618 ReadHandler&& handler)
619 {
620 static_assert(is_async_read_stream<AsyncReadStream>::value,
621 "AsyncReadStream requirements not met");
622 static_assert(
623 boost::asio::is_dynamic_buffer<DynamicBuffer>::value,
624 "DynamicBuffer requirements not met");
625 parser.eager(false);
626 boost::asio::async_completion<ReadHandler,
627 void(error_code, std::size_t)> init{handler};
628 detail::read_op<AsyncReadStream, DynamicBuffer,
629 isRequest, Derived, detail::parser_is_header_done,
630 BOOST_ASIO_HANDLER_TYPE(ReadHandler, void(error_code, std::size_t))>{
631 init.completion_handler, stream, buffer, parser}();
632 return init.result.get();
633 }
634
635 //------------------------------------------------------------------------------
636
637 template<
638 class SyncReadStream,
639 class DynamicBuffer,
640 bool isRequest, class Derived>
641 std::size_t
642 read(
643 SyncReadStream& stream,
644 DynamicBuffer& buffer,
645 basic_parser<isRequest, Derived>& parser)
646 {
647 static_assert(is_sync_read_stream<SyncReadStream>::value,
648 "SyncReadStream requirements not met");
649 static_assert(
650 boost::asio::is_dynamic_buffer<DynamicBuffer>::value,
651 "DynamicBuffer requirements not met");
652 error_code ec;
653 auto const bytes_transferred =
654 read(stream, buffer, parser, ec);
655 if(ec)
656 BOOST_THROW_EXCEPTION(system_error{ec});
657 return bytes_transferred;
658 }
659
660 template<
661 class SyncReadStream,
662 class DynamicBuffer,
663 bool isRequest, class Derived>
664 std::size_t
665 read(
666 SyncReadStream& stream,
667 DynamicBuffer& buffer,
668 basic_parser<isRequest, Derived>& parser,
669 error_code& ec)
670 {
671 static_assert(is_sync_read_stream<SyncReadStream>::value,
672 "SyncReadStream requirements not met");
673 static_assert(
674 boost::asio::is_dynamic_buffer<DynamicBuffer>::value,
675 "DynamicBuffer requirements not met");
676 parser.eager(true);
677 if(parser.is_done())
678 {
679 ec.assign(0, ec.category());
680 return 0;
681 }
682 std::size_t bytes_transferred = 0;
683 do
684 {
685 bytes_transferred += read_some(
686 stream, buffer, parser, ec);
687 if(ec)
688 return bytes_transferred;
689 }
690 while(! parser.is_done());
691 return bytes_transferred;
692 }
693
694 template<
695 class AsyncReadStream,
696 class DynamicBuffer,
697 bool isRequest, class Derived,
698 class ReadHandler>
699 BOOST_ASIO_INITFN_RESULT_TYPE(
700 ReadHandler, void(error_code, std::size_t))
701 async_read(
702 AsyncReadStream& stream,
703 DynamicBuffer& buffer,
704 basic_parser<isRequest, Derived>& parser,
705 ReadHandler&& handler)
706 {
707 static_assert(is_async_read_stream<AsyncReadStream>::value,
708 "AsyncReadStream requirements not met");
709 static_assert(
710 boost::asio::is_dynamic_buffer<DynamicBuffer>::value,
711 "DynamicBuffer requirements not met");
712 parser.eager(true);
713 boost::asio::async_completion<
714 ReadHandler,
715 void(error_code, std::size_t)> init{handler};
716 detail::read_op<AsyncReadStream, DynamicBuffer,
717 isRequest, Derived, detail::parser_is_done,
718 BOOST_ASIO_HANDLER_TYPE(ReadHandler, void(error_code, std::size_t))>{
719 init.completion_handler, stream, buffer, parser}();
720 return init.result.get();
721 }
722
723 //------------------------------------------------------------------------------
724
725 template<
726 class SyncReadStream,
727 class DynamicBuffer,
728 bool isRequest, class Body, class Allocator>
729 std::size_t
730 read(
731 SyncReadStream& stream,
732 DynamicBuffer& buffer,
733 message<isRequest, Body, basic_fields<Allocator>>& msg)
734 {
735 static_assert(is_sync_read_stream<SyncReadStream>::value,
736 "SyncReadStream requirements not met");
737 static_assert(
738 boost::asio::is_dynamic_buffer<DynamicBuffer>::value,
739 "DynamicBuffer requirements not met");
740 static_assert(is_body<Body>::value,
741 "Body requirements not met");
742 static_assert(is_body_reader<Body>::value,
743 "BodyReader requirements not met");
744 error_code ec;
745 auto const bytes_transferred =
746 read(stream, buffer, msg, ec);
747 if(ec)
748 BOOST_THROW_EXCEPTION(system_error{ec});
749 return bytes_transferred;
750 }
751
752 template<
753 class SyncReadStream,
754 class DynamicBuffer,
755 bool isRequest, class Body, class Allocator>
756 std::size_t
757 read(
758 SyncReadStream& stream,
759 DynamicBuffer& buffer,
760 message<isRequest, Body, basic_fields<Allocator>>& msg,
761 error_code& ec)
762 {
763 static_assert(is_sync_read_stream<SyncReadStream>::value,
764 "SyncReadStream requirements not met");
765 static_assert(
766 boost::asio::is_dynamic_buffer<DynamicBuffer>::value,
767 "DynamicBuffer requirements not met");
768 static_assert(is_body<Body>::value,
769 "Body requirements not met");
770 static_assert(is_body_reader<Body>::value,
771 "BodyReader requirements not met");
772 parser<isRequest, Body, Allocator> p{std::move(msg)};
773 p.eager(true);
774 auto const bytes_transferred =
775 read(stream, buffer, p.base(), ec);
776 if(ec)
777 return bytes_transferred;
778 msg = p.release();
779 return bytes_transferred;
780 }
781
782 template<
783 class AsyncReadStream,
784 class DynamicBuffer,
785 bool isRequest, class Body, class Allocator,
786 class ReadHandler>
787 BOOST_ASIO_INITFN_RESULT_TYPE(
788 ReadHandler, void(error_code, std::size_t))
789 async_read(
790 AsyncReadStream& stream,
791 DynamicBuffer& buffer,
792 message<isRequest, Body, basic_fields<Allocator>>& msg,
793 ReadHandler&& handler)
794 {
795 static_assert(is_async_read_stream<AsyncReadStream>::value,
796 "AsyncReadStream requirements not met");
797 static_assert(
798 boost::asio::is_dynamic_buffer<DynamicBuffer>::value,
799 "DynamicBuffer requirements not met");
800 static_assert(is_body<Body>::value,
801 "Body requirements not met");
802 static_assert(is_body_reader<Body>::value,
803 "BodyReader requirements not met");
804 boost::asio::async_completion<
805 ReadHandler,
806 void(error_code, std::size_t)> init{handler};
807 detail::read_msg_op<
808 AsyncReadStream,
809 DynamicBuffer,
810 isRequest, Body, Allocator,
811 BOOST_ASIO_HANDLER_TYPE(
812 ReadHandler, void(error_code, std::size_t))>{
813 init.completion_handler, stream, buffer, msg}();
814 return init.result.get();
815 }
816
817 } // http
818 } // beast
819 } // boost
820
821 #endif