]>
git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/beast/test/beast/http/write.cpp
2 // Copyright (c) 2016-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
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)
7 // Official repository: https://github.com/boostorg/beast
10 // Test that header file is self-contained.
11 #include <boost/beast/http/write.hpp>
13 #include <boost/beast/http/buffer_body.hpp>
14 #include <boost/beast/http/empty_body.hpp>
15 #include <boost/beast/http/fields.hpp>
16 #include <boost/beast/http/message.hpp>
17 #include <boost/beast/http/read.hpp>
18 #include <boost/beast/http/string_body.hpp>
19 #include <boost/beast/core/error.hpp>
20 #include <boost/beast/core/multi_buffer.hpp>
21 #include <boost/beast/test/stream.hpp>
22 #include <boost/beast/test/yield_to.hpp>
23 #include <boost/beast/unit_test/suite.hpp>
24 #include <boost/asio/error.hpp>
33 : public beast::unit_test::suite
34 , public test::enable_yield_to
39 using value_type
= std::string
;
43 value_type
const& body_
;
46 using const_buffers_type
=
47 boost::asio::const_buffer
;
49 template<bool isRequest
, class Fields
>
51 writer(message
<isRequest
,
52 unsized_body
, Fields
> const& msg
)
60 ec
.assign(0, ec
.category());
63 boost::optional
<std::pair
<const_buffers_type
, bool>>
66 ec
.assign(0, ec
.category());
67 return {{const_buffers_type
{
68 body_
.data(), body_
.size()}, false}};
82 bool mutable read
= false;
88 value_type
const& body_
;
91 using const_buffers_type
=
92 boost::asio::const_buffer
;
94 template<bool isRequest
, class Fields
>
96 writer(message
<isRequest
,
97 test_body
, Fields
> const& msg
)
105 ec
.assign(0, ec
.category());
108 boost::optional
<std::pair
<const_buffers_type
, bool>>
111 ec
.assign(0, ec
.category());
114 std::integral_constant
<bool, isSplit
>{},
115 std::integral_constant
<bool, isFinalEmpty
>{});
119 boost::optional
<std::pair
<const_buffers_type
, bool>>
121 std::false_type
, // isSplit
122 std::false_type
) // isFinalEmpty
124 using boost::asio::buffer
;
127 return {{buffer(body_
.s
.data(), body_
.s
.size()), false}};
130 boost::optional
<std::pair
<const_buffers_type
, bool>>
132 std::false_type
, // isSplit
133 std::true_type
) // isFinalEmpty
135 using boost::asio::buffer
;
143 body_
.s
.data(), body_
.s
.size()), true}};
149 boost::optional
<std::pair
<const_buffers_type
, bool>>
151 std::true_type
, // isSplit
152 std::false_type
) // isFinalEmpty
154 using boost::asio::buffer
;
155 auto const n
= (body_
.s
.size() + 1) / 2;
162 return {{buffer(body_
.s
.data(), n
),
163 body_
.s
.size() > 1}};
165 return {{buffer(body_
.s
.data() + n
,
166 body_
.s
.size() - n
), false}};
170 boost::optional
<std::pair
<const_buffers_type
, bool>>
172 std::true_type
, // isSplit
173 std::true_type
) // isFinalEmpty
175 using boost::asio::buffer
;
176 auto const n
= (body_
.s
.size() + 1) / 2;
182 step_
= body_
.s
.size() > 1 ? 1 : 2;
183 return {{buffer(body_
.s
.data(), n
), true}};
185 BOOST_ASSERT(body_
.s
.size() > 1);
187 return {{buffer(body_
.s
.data() + n
,
188 body_
.s
.size() - n
), true}};
205 test::fail_counter
& fc_
;
209 value_type(test::fail_counter
& fc
)
215 operator=(std::string s
)
225 value_type
const& body_
;
228 using const_buffers_type
=
229 boost::asio::const_buffer
;
231 template<bool isRequest
, class Fields
>
233 writer(message
<isRequest
,
234 fail_body
, Fields
> const& msg
)
245 boost::optional
<std::pair
<const_buffers_type
, bool>>
248 if(body_
.fc_
.fail(ec
))
250 if(n_
>= body_
.s_
.size())
252 return {{const_buffers_type
{
253 body_
.s_
.data() + n_
++, 1}, true}};
258 template<bool isRequest
, class Body
, class Fields
>
261 to_string(message
<isRequest
, Body
, Fields
> const& m
)
263 std::stringstream ss
;
268 template<class ConstBufferSequence
>
271 to_string(ConstBufferSequence
const& bs
)
274 s
.reserve(buffer_size(bs
));
275 for(auto b
: beast::detail::buffers_range(bs
))
276 s
.append(reinterpret_cast<char const*>(b
),
281 template<bool isRequest
>
283 equal_body(string_view sv
, string_view body
)
285 test::stream ts
{ioc_
, sv
}, tr
{ioc_
};
287 message
<isRequest
, string_body
, fields
> m
;
293 return m
.body() == body
;
295 catch(std::exception
const& e
)
297 log
<< "equal_body: " << e
.what() << std::endl
;
302 template<bool isRequest
, class Body
, class Fields
>
304 str(message
<isRequest
, Body
, Fields
> const& m
)
306 test::stream ts
{ioc_
}, tr
{ioc_
};
310 if(ec
&& ec
!= error::end_of_stream
)
311 BOOST_THROW_EXCEPTION(system_error
{ec
});
312 return tr
.str().to_string();
316 testAsyncWrite(yield_context do_yield
)
319 response
<string_body
> m
;
321 m
.result(status::ok
);
322 m
.set(field::server
, "test");
323 m
.set(field::content_length
, "5");
326 test::stream ts
{ioc_
}, tr
{ioc_
};
328 async_write(ts
, m
, do_yield
[ec
]);
329 BEAST_EXPECT(! m
.keep_alive());
330 if(BEAST_EXPECTS(! ec
, ec
.message()))
331 BEAST_EXPECT(tr
.str() ==
332 "HTTP/1.0 200 OK\r\n"
334 "Content-Length: 5\r\n"
339 response
<string_body
> m
;
341 m
.result(status::ok
);
342 m
.set(field::server
, "test");
343 m
.set(field::transfer_encoding
, "chunked");
346 test::stream ts
{ioc_
}, tr
{ioc_
};
348 async_write(ts
, m
, do_yield
[ec
]);
349 if(BEAST_EXPECTS(! ec
, ec
.message()))
350 BEAST_EXPECT(tr
.str() ==
351 "HTTP/1.1 200 OK\r\n"
353 "Transfer-Encoding: chunked\r\n"
362 testFailures(yield_context do_yield
)
364 static std::size_t constexpr limit
= 100;
367 for(n
= 0; n
< limit
; ++n
)
369 test::fail_counter
fc(n
);
370 test::stream ts
{ioc_
, fc
}, tr
{ioc_
};
372 request
<fail_body
> m(verb::get
, "/", 10, fc
);
373 m
.set(field::user_agent
, "test");
374 m
.set(field::connection
, "keep-alive");
375 m
.set(field::content_length
, "5");
380 BEAST_EXPECT(tr
.str() ==
382 "User-Agent: test\r\n"
383 "Connection: keep-alive\r\n"
384 "Content-Length: 5\r\n"
391 catch(std::exception
const&)
395 BEAST_EXPECT(n
< limit
);
397 for(n
= 0; n
< limit
; ++n
)
399 test::fail_counter
fc(n
);
400 test::stream ts
{ioc_
, fc
}, tr
{ioc_
};
402 request
<fail_body
> m
{verb::get
, "/", 10, fc
};
403 m
.set(field::user_agent
, "test");
404 m
.set(field::transfer_encoding
, "chunked");
406 error_code ec
= test::error::fail_error
;
410 BEAST_EXPECT(! m
.keep_alive());
411 BEAST_EXPECT(tr
.str() ==
413 "User-Agent: test\r\n"
414 "Transfer-Encoding: chunked\r\n"
426 BEAST_EXPECT(n
< limit
);
428 for(n
= 0; n
< limit
; ++n
)
430 test::fail_counter
fc(n
);
431 test::stream ts
{ioc_
, fc
}, tr
{ioc_
};
433 request
<fail_body
> m
{verb::get
, "/", 10, fc
};
434 m
.set(field::user_agent
, "test");
435 m
.set(field::transfer_encoding
, "chunked");
437 error_code ec
= test::error::fail_error
;
438 async_write(ts
, m
, do_yield
[ec
]);
441 BEAST_EXPECT(! m
.keep_alive());
442 BEAST_EXPECT(tr
.str() ==
444 "User-Agent: test\r\n"
445 "Transfer-Encoding: chunked\r\n"
457 BEAST_EXPECT(n
< limit
);
459 for(n
= 0; n
< limit
; ++n
)
461 test::fail_counter
fc(n
);
462 test::stream ts
{ioc_
, fc
}, tr
{ioc_
};
464 request
<fail_body
> m
{verb::get
, "/", 10, fc
};
465 m
.set(field::user_agent
, "test");
466 m
.set(field::connection
, "keep-alive");
467 m
.set(field::content_length
, "5");
469 error_code ec
= test::error::fail_error
;
473 BEAST_EXPECT(tr
.str() ==
475 "User-Agent: test\r\n"
476 "Connection: keep-alive\r\n"
477 "Content-Length: 5\r\n"
484 BEAST_EXPECT(n
< limit
);
486 for(n
= 0; n
< limit
; ++n
)
488 test::fail_counter
fc(n
);
489 test::stream ts
{ioc_
, fc
}, tr
{ioc_
};
491 request
<fail_body
> m
{verb::get
, "/", 10, fc
};
492 m
.set(field::user_agent
, "test");
493 m
.set(field::connection
, "keep-alive");
494 m
.set(field::content_length
, "5");
496 error_code ec
= test::error::fail_error
;
497 async_write(ts
, m
, do_yield
[ec
]);
500 BEAST_EXPECT(tr
.str() ==
502 "User-Agent: test\r\n"
503 "Connection: keep-alive\r\n"
504 "Content-Length: 5\r\n"
511 BEAST_EXPECT(n
< limit
);
517 // auto content-length HTTP/1.0
519 request
<string_body
> m
;
523 m
.set(field::user_agent
, "test");
526 BEAST_EXPECT(str(m
) ==
528 "User-Agent: test\r\n"
529 "Content-Length: 1\r\n"
534 // no content-length HTTP/1.0
536 request
<unsized_body
> m
;
540 m
.set(field::user_agent
, "test");
543 test::stream ts
{ioc_
}, tr
{ioc_
};
547 BEAST_EXPECT(! m
.keep_alive());
548 BEAST_EXPECTS(! ec
, ec
.message());
549 BEAST_EXPECT(tr
.str() ==
551 "User-Agent: test\r\n"
556 // auto content-length HTTP/1.1
558 request
<string_body
> m
;
562 m
.set(field::user_agent
, "test");
565 BEAST_EXPECT(str(m
) ==
567 "User-Agent: test\r\n"
568 "Content-Length: 1\r\n"
573 // no content-length HTTP/1.1
575 request
<unsized_body
> m
;
579 m
.set(field::user_agent
, "test");
582 test::stream ts
{ioc_
}, tr
{ioc_
};
586 BEAST_EXPECT(tr
.str() ==
588 "User-Agent: test\r\n"
589 "Transfer-Encoding: chunked\r\n"
598 void test_std_ostream()
600 // Conversion to std::string via operator<<
602 request
<string_body
> m
;
606 m
.set(field::user_agent
, "test");
608 BEAST_EXPECT(to_string(m
) ==
609 "GET / HTTP/1.1\r\nUser-Agent: test\r\n\r\n*");
612 // Output to std::ostream
614 request
<string_body
> m
{verb::get
, "/", 11};
615 std::stringstream ss
;
617 BEAST_EXPECT(ss
.str() ==
622 // Output header to std::ostream
624 request
<string_body
> m
{verb::get
, "/", 11};
625 std::stringstream ss
;
627 BEAST_EXPECT(ss
.str() ==
633 // Ensure completion handlers are not leaked
636 static std::atomic
<std::size_t>&
637 count() { static std::atomic
<std::size_t> n
; return n
; }
638 handler() { ++count(); }
639 ~handler() { --count(); }
640 handler(handler
const&) { ++count(); }
641 void operator()(error_code
const&, std::size_t) const {}
648 // Make sure handlers are not destroyed
649 // after calling io_context::stop
650 boost::asio::io_context ioc
;
651 test::stream ts
{ioc
};
652 BEAST_EXPECT(handler::count() == 0);
653 request
<string_body
> m
;
657 m
.set("Content-Length", 5);
659 async_write(ts
, m
, handler
{});
660 BEAST_EXPECT(handler::count() > 0);
662 BEAST_EXPECT(handler::count() > 0);
664 BEAST_EXPECT(handler::count() > 0);
666 BEAST_EXPECT(handler::count() == 0);
669 // Make sure uninvoked handlers are
670 // destroyed when calling ~io_context
672 boost::asio::io_context ioc
;
673 test::stream ts
{ioc
}, tr
{ioc
};
675 BEAST_EXPECT(handler::count() == 0);
676 request
<string_body
> m
;
680 m
.set("Content-Length", 5);
682 async_write(ts
, m
, handler
{});
683 BEAST_EXPECT(handler::count() > 0);
685 BEAST_EXPECT(handler::count() == 0);
691 bool isRequest
, class Body
, class Fields
>
695 message
<isRequest
, Body
, Fields
> const& m
,
698 serializer
<isRequest
, Body
, Fields
> sr
{m
};
701 write_some(stream
, sr
, ec
);
711 bool isRequest
, class Body
, class Fields
>
715 message
<isRequest
, Body
, Fields
> const& m
,
719 serializer
<isRequest
, Body
, Fields
> sr
{m
};
722 async_write_some(stream
, sr
, yield
[ec
]);
732 testWriteStream(boost::asio::yield_context yield
)
734 test::stream ts
{ioc_
}, tr
{ioc_
};
740 m0
.result(status::ok
);
742 m0
.set(field::server
, "test");
743 m0
.body().s
= "Hello, world!\n";
746 std::string
const result
=
747 "HTTP/1.1 200 OK\r\n"
755 BEAST_EXPECT(tr
.str() == result
);
756 BEAST_EXPECT(equal_body
<false>(
757 tr
.str(), m
.body().s
));
763 do_async_write(ts
, m
, ec
, yield
);
764 BEAST_EXPECT(tr
.str() == result
);
765 BEAST_EXPECT(equal_body
<false>(
766 tr
.str(), m
.body().s
));
772 response_serializer
<Body
, fields
> sr
{m
};
777 if(sr
.is_header_done())
780 BEAST_EXPECT(! m
.body().read
);
786 response_serializer
<Body
, fields
> sr
{m
};
790 async_write_some(ts
, sr
, yield
);
791 if(sr
.is_header_done())
794 BEAST_EXPECT(! m
.body().read
);
799 m0
.set("Transfer-Encoding", "chunked");
804 BEAST_EXPECT(equal_body
<false>(
805 tr
.str(), m
.body().s
));
811 do_async_write(ts
, m
, ec
, yield
);
812 BEAST_EXPECT(equal_body
<false>(
813 tr
.str(), m
.body().s
));
819 response_serializer
<Body
, fields
> sr
{m
};
824 if(sr
.is_header_done())
827 BEAST_EXPECT(! m
.body().read
);
833 response_serializer
<Body
, fields
> sr
{m
};
837 async_write_some(ts
, sr
, yield
);
838 if(sr
.is_header_done())
841 BEAST_EXPECT(! m
.body().read
);
850 boost::asio::io_context ioc
;
851 test::stream ts
{ioc
}, tr
{ioc
};
853 response
<empty_body
> res
;
855 response_serializer
<empty_body
> sr
{res
};
856 async_write_header(ts
, sr
,
857 [&](error_code
const&, std::size_t)
868 [&](yield_context yield
)
870 testAsyncWrite(yield
);
877 [&](yield_context yield
)
879 testWriteStream
<test_body
<false, false>>(yield
);
880 testWriteStream
<test_body
<false, true>>(yield
);
881 testWriteStream
<test_body
< true, false>>(yield
);
882 testWriteStream
<test_body
< true, true>>(yield
);
887 BEAST_DEFINE_TESTSUITE(beast
,http
,write
);