http_examples.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407
  1. //
  2. // Copyright (c) 2016-2019 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. #include "example/doc/http_examples.hpp"
  10. #include <boost/beast/core/flat_buffer.hpp>
  11. #include <boost/beast/core/read_size.hpp>
  12. #include <boost/beast/core/ostream.hpp>
  13. #include <boost/beast/core/detail/clamp.hpp>
  14. #include <boost/beast/core/detail/type_traits.hpp>
  15. #include <boost/beast/http/chunk_encode.hpp>
  16. #include <boost/beast/http/parser.hpp>
  17. #include <boost/beast/http/read.hpp>
  18. #include <boost/beast/http/write.hpp>
  19. #include <boost/beast/_experimental/test/stream.hpp>
  20. #include <boost/beast/test/yield_to.hpp>
  21. #include <boost/beast/_experimental/unit_test/suite.hpp>
  22. #include <sstream>
  23. #include <array>
  24. #include <limits>
  25. #include <list>
  26. #include <sstream>
  27. #include <vector>
  28. namespace boost {
  29. namespace beast {
  30. namespace http {
  31. class examples_test
  32. : public beast::unit_test::suite
  33. , public beast::test::enable_yield_to
  34. {
  35. public:
  36. // two threads, for some examples
  37. examples_test()
  38. : enable_yield_to(2)
  39. {
  40. }
  41. template<bool isRequest, class Body, class Fields>
  42. static
  43. std::string
  44. to_string(message<isRequest, Body, Fields> const& m)
  45. {
  46. std::stringstream ss;
  47. ss << m;
  48. return ss.str();
  49. }
  50. template<bool isRequest>
  51. bool
  52. equal_body(string_view sv, string_view body)
  53. {
  54. test::stream ts{ioc_, sv};
  55. message<isRequest, string_body, fields> m;
  56. multi_buffer b;
  57. ts.close_remote();
  58. try
  59. {
  60. read(ts, b, m);
  61. return m.body() == body;
  62. }
  63. catch(std::exception const& e)
  64. {
  65. log << "equal_body: " << e.what() << std::endl;
  66. return false;
  67. }
  68. }
  69. void
  70. doExpect100Continue()
  71. {
  72. test::stream ts{ioc_}, tr{ioc_};
  73. ts.connect(tr);
  74. yield_to(
  75. [&](yield_context)
  76. {
  77. error_code ec;
  78. flat_buffer buffer;
  79. receive_expect_100_continue(
  80. tr, buffer, ec);
  81. BEAST_EXPECTS(! ec, ec.message());
  82. },
  83. [&](yield_context)
  84. {
  85. flat_buffer buffer;
  86. request<string_body> req;
  87. req.version(11);
  88. req.method_string("POST");
  89. req.target("/");
  90. req.insert(field::user_agent, "test");
  91. req.body() = "Hello, world!";
  92. req.prepare_payload();
  93. error_code ec;
  94. send_expect_100_continue(
  95. ts, buffer, req, ec);
  96. BEAST_EXPECTS(! ec, ec.message());
  97. });
  98. }
  99. void
  100. doCgiResponse()
  101. {
  102. std::string const s = "Hello, world!";
  103. test::stream t0{ioc_, s};
  104. t0.read_size(3);
  105. t0.close_remote();
  106. test::stream t1{ioc_}, t1r{ioc_};
  107. t1.connect(t1r);
  108. error_code ec;
  109. send_cgi_response(t0, t1, ec);
  110. BEAST_EXPECTS(! ec, ec.message());
  111. BEAST_EXPECT(equal_body<false>(t1r.str(), s));
  112. }
  113. void
  114. doRelay()
  115. {
  116. request<string_body> req;
  117. req.version(11);
  118. req.method_string("POST");
  119. req.target("/");
  120. req.insert(field::user_agent, "test");
  121. req.body() = "Hello, world!";
  122. req.prepare_payload();
  123. test::stream ds{ioc_}, dsr{ioc_};
  124. ds.connect(dsr);
  125. dsr.read_size(3);
  126. test::stream us{ioc_}, usr{ioc_};
  127. us.connect(usr);
  128. us.write_size(3);
  129. error_code ec;
  130. write(ds, req);
  131. BEAST_EXPECTS(! ec, ec.message());
  132. ds.close();
  133. flat_buffer buffer;
  134. relay<true>(us, dsr, buffer, ec,
  135. [&](header<true, fields>& h, error_code& ev)
  136. {
  137. ev = {};
  138. h.erase("Content-Length");
  139. h.set("Transfer-Encoding", "chunked");
  140. });
  141. BEAST_EXPECTS(! ec, ec.message());
  142. BEAST_EXPECT(equal_body<true>(
  143. usr.str(), req.body()));
  144. }
  145. void
  146. doReadStdStream()
  147. {
  148. std::string const s =
  149. "HTTP/1.0 200 OK\r\n"
  150. "User-Agent: test\r\n"
  151. "\r\n"
  152. "Hello, world!";
  153. std::istringstream is(s);
  154. error_code ec;
  155. flat_buffer buffer;
  156. response<string_body> res;
  157. read_istream(is, buffer, res, ec);
  158. BEAST_EXPECTS(! ec, ec.message());
  159. BEAST_EXPECT(to_string(res) == s);
  160. }
  161. void
  162. doWriteStdStream()
  163. {
  164. std::ostringstream os;
  165. request<string_body> req;
  166. req.version(11);
  167. req.method(verb::get);
  168. req.target("/");
  169. req.insert(field::user_agent, "test");
  170. error_code ec;
  171. write_ostream(os, req, ec);
  172. BEAST_EXPECTS(! ec, ec.message());
  173. BEAST_EXPECT(to_string(req) == os.str());
  174. }
  175. void
  176. doHEAD()
  177. {
  178. test::stream ts{ioc_}, tr{ioc_};
  179. ts.connect(tr);
  180. yield_to(
  181. [&](yield_context)
  182. {
  183. error_code ec;
  184. flat_buffer buffer;
  185. do_server_head(tr, buffer, ec);
  186. BEAST_EXPECTS(! ec, ec.message());
  187. },
  188. [&](yield_context)
  189. {
  190. error_code ec;
  191. flat_buffer buffer;
  192. auto res = do_head_request(ts, buffer, "/", ec);
  193. BEAST_EXPECTS(! ec, ec.message());
  194. });
  195. }
  196. struct handler
  197. {
  198. std::string body;
  199. template<class Body>
  200. void
  201. operator()(request<Body>&&)
  202. {
  203. }
  204. void
  205. operator()(request<string_body>&& req)
  206. {
  207. body = req.body();
  208. }
  209. };
  210. void
  211. doDeferredBody()
  212. {
  213. test::stream ts(ioc_,
  214. "POST / HTTP/1.1\r\n"
  215. "User-Agent: test\r\n"
  216. "Content-Type: multipart/form-data\r\n"
  217. "Content-Length: 13\r\n"
  218. "\r\n"
  219. "Hello, world!");
  220. handler h;
  221. flat_buffer buffer;
  222. do_form_request(ts, buffer, h);
  223. BEAST_EXPECT(h.body == "Hello, world!");
  224. }
  225. //--------------------------------------------------------------------------
  226. void
  227. doIncrementalRead()
  228. {
  229. test::stream ts{ioc_};
  230. std::string s(2048, '*');
  231. ostream(ts.buffer()) <<
  232. "HTTP/1.1 200 OK\r\n"
  233. "Content-Length: 2048\r\n"
  234. "Server: test\r\n"
  235. "\r\n" <<
  236. s;
  237. error_code ec;
  238. flat_buffer b;
  239. std::stringstream ss;
  240. read_and_print_body<false>(ss, ts, b, ec);
  241. if(BEAST_EXPECTS(! ec, ec.message()))
  242. BEAST_EXPECT(ss.str() == s);
  243. }
  244. //--------------------------------------------------------------------------
  245. void
  246. doExplicitChunkSerialize()
  247. {
  248. auto const buf =
  249. [](string_view s)
  250. {
  251. return net::const_buffer{
  252. s.data(), s.size()};
  253. };
  254. test::stream ts{ioc_}, tr{ioc_};
  255. ts.connect(tr);
  256. response<empty_body> res{status::ok, 11};
  257. res.set(field::server, "test");
  258. res.set(field::accept, "Expires, Content-MD5");
  259. res.chunked(true);
  260. error_code ec;
  261. response_serializer<empty_body> sr{res};
  262. write_header(ts, sr, ec);
  263. chunk_extensions exts;
  264. net::write(ts,
  265. make_chunk(buf("First")), ec);
  266. exts.insert("quality", "1.0");
  267. net::write(ts,
  268. make_chunk(buf("Hello, world!"), exts), ec);
  269. exts.clear();
  270. exts.insert("file", "abc.txt");
  271. exts.insert("quality", "0.7");
  272. net::write(ts,
  273. make_chunk(buf("The Next Chunk"), std::move(exts)), ec);
  274. exts.clear();
  275. exts.insert("last");
  276. net::write(ts,
  277. make_chunk(buf("Last one"), std::move(exts),
  278. std::allocator<double>{}), ec);
  279. fields trailers;
  280. trailers.set(field::expires, "never");
  281. trailers.set(field::content_md5, "f4a5c16584f03d90");
  282. net::write(ts,
  283. make_chunk_last(
  284. trailers,
  285. std::allocator<double>{}
  286. ), ec);
  287. BEAST_EXPECT(
  288. buffers_to_string(tr.buffer().data()) ==
  289. "HTTP/1.1 200 OK\r\n"
  290. "Server: test\r\n"
  291. "Accept: Expires, Content-MD5\r\n"
  292. "Transfer-Encoding: chunked\r\n"
  293. "\r\n"
  294. "5\r\n"
  295. "First\r\n"
  296. "d;quality=1.0\r\n"
  297. "Hello, world!\r\n"
  298. "e;file=abc.txt;quality=0.7\r\n"
  299. "The Next Chunk\r\n"
  300. "8;last\r\n"
  301. "Last one\r\n"
  302. "0\r\n"
  303. "Expires: never\r\n"
  304. "Content-MD5: f4a5c16584f03d90\r\n"
  305. "\r\n");
  306. }
  307. //--------------------------------------------------------------------------
  308. void
  309. doExplicitChunkParse()
  310. {
  311. test::stream ts(ioc_,
  312. "HTTP/1.1 200 OK\r\n"
  313. "Server: test\r\n"
  314. "Trailer: Expires, Content-MD5\r\n"
  315. "Transfer-Encoding: chunked\r\n"
  316. "\r\n"
  317. "5\r\n"
  318. "First\r\n"
  319. "d;quality=1.0\r\n"
  320. "Hello, world!\r\n"
  321. "e;file=abc.txt;quality=0.7\r\n"
  322. "The Next Chunk\r\n"
  323. "8;last\r\n"
  324. "Last one\r\n"
  325. "0\r\n"
  326. "Expires: never\r\n"
  327. "Content-MD5: f4a5c16584f03d90\r\n"
  328. "\r\n");
  329. error_code ec;
  330. flat_buffer b;
  331. std::stringstream ss;
  332. print_chunked_body<false>(ss, ts, b, ec);
  333. BEAST_EXPECTS(! ec, ec.message());
  334. BEAST_EXPECT(ss.str() ==
  335. "Chunk Body: First\n"
  336. "Extension: quality = 1.0\n"
  337. "Chunk Body: Hello, world!\n"
  338. "Extension: file = abc.txt\n"
  339. "Extension: quality = 0.7\n"
  340. "Chunk Body: The Next Chunk\n"
  341. "Extension: last\n"
  342. "Chunk Body: Last one\n"
  343. "Expires: never\n"
  344. "Content-MD5: f4a5c16584f03d90\n");
  345. }
  346. //--------------------------------------------------------------------------
  347. void
  348. run()
  349. {
  350. doExpect100Continue();
  351. doCgiResponse();
  352. doRelay();
  353. doReadStdStream();
  354. doWriteStdStream();
  355. doHEAD();
  356. doDeferredBody();
  357. doIncrementalRead();
  358. doExplicitChunkSerialize();
  359. doExplicitChunkParse();
  360. }
  361. };
  362. BEAST_DEFINE_TESTSUITE(beast,http,examples);
  363. } // http
  364. } // beast
  365. } // boost