blob: f427a2f3245540062fb58be3759fdd694208a805 [file] [log] [blame]
Ed Tanous8041f312017-04-03 09:47:01 -07001#include <iostream>
2#include <sstream>
3#include <vector>
Ed Tanous1abe55e2018-09-05 08:30:59 -07004
5#include "crow.h"
6
Ed Tanous8041f312017-04-03 09:47:01 -07007#include "gtest/gtest.h"
Ed Tanous8041f312017-04-03 09:47:01 -07008
9using namespace std;
10using namespace crow;
11
12bool failed__ = false;
Ed Tanous1abe55e2018-09-05 08:30:59 -070013void error_print()
14{
15 cerr << endl;
16}
Ed Tanous1ff48782017-04-18 12:45:08 -070017
18template <typename A, typename... Args>
Ed Tanous1abe55e2018-09-05 08:30:59 -070019void error_print(const A& a, Args... args)
20{
21 cerr << a;
22 error_print(args...);
Ed Tanous8041f312017-04-03 09:47:01 -070023}
24
Ed Tanous1abe55e2018-09-05 08:30:59 -070025template <typename... Args> void fail(Args... args)
26{
27 error_print(args...);
28 failed__ = true;
Ed Tanous8041f312017-04-03 09:47:01 -070029}
30
Ed Tanous1abe55e2018-09-05 08:30:59 -070031#define ASSERT_EQUAL(a, b) \
32 if ((a) != (b)) \
33 fail(__FILE__ ":", __LINE__, ": Assert fail: expected ", (a), " actual ", \
34 (b), ", " #a " == " #b ", at " __FILE__ ":", __LINE__)
35#define ASSERT_NOTEQUAL(a, b) \
36 if ((a) == (b)) \
37 fail(__FILE__ ":", __LINE__, ": Assert fail: not expected ", (a), \
38 ", " #a " != " #b ", at " __FILE__ ":", __LINE__)
Ed Tanous8041f312017-04-03 09:47:01 -070039
Ed Tanous1abe55e2018-09-05 08:30:59 -070040#define DISABLE_TEST(x) \
41 struct test##x \
42 { \
43 void test(); \
44 } x##_; \
45 void test##x::test()
Ed Tanous8041f312017-04-03 09:47:01 -070046
47#define LOCALHOST_ADDRESS "127.0.0.1"
48
Ed Tanous1abe55e2018-09-05 08:30:59 -070049TEST(Crow, Rule)
50{
51 TaggedRule<> r("/http/");
52 r.name("abc");
Ed Tanous8041f312017-04-03 09:47:01 -070053
Ed Tanous1abe55e2018-09-05 08:30:59 -070054 // empty handler - fail to validate
55 try
56 {
57 r.validate();
58 fail("empty handler should fail to validate");
59 }
60 catch (runtime_error& e)
61 {
62 }
63
64 int x = 0;
65
66 // registering handler
67 r([&x] {
68 x = 1;
69 return "";
70 });
71
Ed Tanous8041f312017-04-03 09:47:01 -070072 r.validate();
73
Ed Tanous55c7b7a2018-05-22 15:27:24 -070074 Response res;
Ed Tanous8041f312017-04-03 09:47:01 -070075
Ed Tanous1abe55e2018-09-05 08:30:59 -070076 // executing handler
77 ASSERT_EQUAL(0, x);
78 boost::beast::http::request<boost::beast::http::string_body> req{};
79 r.handle(Request(req), res, RoutingParams());
Ed Tanous1ff48782017-04-18 12:45:08 -070080 ASSERT_EQUAL(1, x);
Ed Tanous1ff48782017-04-18 12:45:08 -070081
Ed Tanous1abe55e2018-09-05 08:30:59 -070082 // registering handler with Request argument
83 r([&x](const crow::Request&) {
84 x = 2;
85 return "";
86 });
Ed Tanous1ff48782017-04-18 12:45:08 -070087
Ed Tanous1abe55e2018-09-05 08:30:59 -070088 r.validate();
89
90 // executing handler
91 ASSERT_EQUAL(1, x);
92 r.handle(Request(req), res, RoutingParams());
93 ASSERT_EQUAL(2, x);
Ed Tanous8041f312017-04-03 09:47:01 -070094}
95
Ed Tanous1abe55e2018-09-05 08:30:59 -070096TEST(Crow, ParameterTagging)
97{
98 static_assert(black_magic::isValid("<int><int><int>"), "valid url");
99 static_assert(!black_magic::isValid("<int><int<<int>"), "invalid url");
100 static_assert(!black_magic::isValid("nt>"), "invalid url");
101 ASSERT_EQUAL(1, black_magic::get_parameter_tag("<int>"));
102 ASSERT_EQUAL(2, black_magic::get_parameter_tag("<uint>"));
103 ASSERT_EQUAL(3, black_magic::get_parameter_tag("<float>"));
104 ASSERT_EQUAL(3, black_magic::get_parameter_tag("<double>"));
105 ASSERT_EQUAL(4, black_magic::get_parameter_tag("<str>"));
106 ASSERT_EQUAL(4, black_magic::get_parameter_tag("<string>"));
107 ASSERT_EQUAL(5, black_magic::get_parameter_tag("<path>"));
108 ASSERT_EQUAL(6 * 6 + 6 + 1,
109 black_magic::get_parameter_tag("<int><int><int>"));
110 ASSERT_EQUAL(6 * 6 + 6 + 2,
111 black_magic::get_parameter_tag("<uint><int><int>"));
112 ASSERT_EQUAL(6 * 6 + 6 * 3 + 2,
113 black_magic::get_parameter_tag("<uint><double><int>"));
Ed Tanous1ff48782017-04-18 12:45:08 -0700114
Ed Tanous1abe55e2018-09-05 08:30:59 -0700115 // url definition parsed in compile time, build into *one number*, and given
116 // to template argument
117 static_assert(
118 std::is_same<black_magic::S<uint64_t, double, int64_t>,
119 black_magic::Arguments<6 * 6 + 6 * 3 + 2>::type>::value,
120 "tag to type container");
121}
Ed Tanous1ff48782017-04-18 12:45:08 -0700122
Ed Tanous1abe55e2018-09-05 08:30:59 -0700123TEST(Crow, PathRouting)
124{
125 SimpleApp app;
Ed Tanous1ff48782017-04-18 12:45:08 -0700126
Ed Tanous1abe55e2018-09-05 08:30:59 -0700127 BMCWEB_ROUTE(app, "/file")
128 ([] { return "file"; });
129
130 BMCWEB_ROUTE(app, "/path/")
131 ([] { return "path"; });
132
133 {
134 boost::beast::http::request<boost::beast::http::string_body> r{};
135 Request req{r};
136 Response res;
137
138 req.url = "/file";
139
140 app.handle(req, res);
141
142 ASSERT_EQUAL(200, res.resultInt());
143 }
144 {
145 boost::beast::http::request<boost::beast::http::string_body> r{};
146 Request req{r};
147 Response res;
148
149 req.url = "/file/";
150
151 app.handle(req, res);
152 ASSERT_EQUAL(404, res.resultInt());
153 }
154 {
155 boost::beast::http::request<boost::beast::http::string_body> r{};
156 Request req{r};
157 Response res;
158
159 req.url = "/path";
160
161 app.handle(req, res);
162 ASSERT_NOTEQUAL(404, res.resultInt());
163 }
164 {
165 boost::beast::http::request<boost::beast::http::string_body> r{};
166 Request req{r};
167 Response res;
168
169 req.url = "/path/";
170
171 app.handle(req, res);
172 ASSERT_EQUAL(200, res.resultInt());
173 }
174}
175
176TEST(Crow, RoutingTest)
177{
178 SimpleApp app;
179 int A{};
180 uint32_t b{};
181 double C{};
182 string D{};
183 string E{};
184
185 BMCWEB_ROUTE(app, "/0/<uint>")
186 ([&](uint32_t b) {
187 b = b;
188 return "OK";
189 });
190
191 BMCWEB_ROUTE(app, "/1/<int>/<uint>")
192 ([&](int a, uint32_t b) {
193 A = a;
194 b = b;
195 return "OK";
196 });
197
198 BMCWEB_ROUTE(app, "/4/<int>/<uint>/<double>/<string>")
199 ([&](int a, uint32_t b, double c, string d) {
200 A = a;
201 b = b;
202 C = c;
203 D = d;
204 return "OK";
205 });
206
207 BMCWEB_ROUTE(app, "/5/<int>/<uint>/<double>/<string>/<path>")
208 ([&](int a, uint32_t b, double c, string d, string e) {
209 A = a;
210 b = b;
211 C = c;
212 D = d;
213 E = e;
214 return "OK";
215 });
216
217 app.validate();
218 // app.debugPrint();
219 {
220 boost::beast::http::request<boost::beast::http::string_body> r{};
221 Request req{r};
222 Response res;
223
224 req.url = "/-1";
225
226 app.handle(req, res);
227
228 ASSERT_EQUAL(404, res.resultInt());
229 }
230
231 {
232 boost::beast::http::request<boost::beast::http::string_body> r{};
233 Request req{r};
234 Response res;
235
236 req.url = "/0/1001999";
237
238 app.handle(req, res);
239
240 ASSERT_EQUAL(200, res.resultInt());
241
242 ASSERT_EQUAL(1001999, b);
243 }
244
245 {
246 boost::beast::http::request<boost::beast::http::string_body> r{};
247 Request req{r};
248 Response res;
249
250 req.url = "/1/-100/1999";
251
252 app.handle(req, res);
253
254 ASSERT_EQUAL(200, res.resultInt());
255
256 ASSERT_EQUAL(-100, A);
257 ASSERT_EQUAL(1999, b);
258 }
259 {
260 boost::beast::http::request<boost::beast::http::string_body> r{};
261 Request req{r};
262 Response res;
263
264 req.url = "/4/5000/3/-2.71828/hellhere";
265
266 app.handle(req, res);
267
268 ASSERT_EQUAL(200, res.resultInt());
269
270 ASSERT_EQUAL(5000, A);
271 ASSERT_EQUAL(3, b);
272 ASSERT_EQUAL(-2.71828, C);
273 ASSERT_EQUAL("hellhere", D);
274 }
275 {
276 boost::beast::http::request<boost::beast::http::string_body> r{};
277 Request req{r};
278 Response res;
279
280 req.url = "/5/-5/999/3.141592/hello_there/a/b/c/d";
281
282 app.handle(req, res);
283
284 ASSERT_EQUAL(200, res.resultInt());
285
286 ASSERT_EQUAL(-5, A);
287 ASSERT_EQUAL(999, b);
288 ASSERT_EQUAL(3.141592, C);
289 ASSERT_EQUAL("hello_there", D);
290 ASSERT_EQUAL("a/b/c/d", E);
291 }
292}
293
294TEST(Crow, simple_response_RoutingParams)
295{
296 ASSERT_EQUAL(100,
297 Response(boost::beast::http::status::continue_).resultInt());
298 ASSERT_EQUAL(200, Response("Hello there").resultInt());
299 ASSERT_EQUAL(500,
300 Response(boost::beast::http::status::internal_server_error,
301 "Internal Error?")
302 .resultInt());
303
304 RoutingParams rp;
305 rp.intParams.push_back(1);
306 rp.intParams.push_back(5);
307 rp.uintParams.push_back(2);
308 rp.doubleParams.push_back(3);
309 rp.stringParams.push_back("hello");
310 ASSERT_EQUAL(1, rp.get<int64_t>(0));
311 ASSERT_EQUAL(5, rp.get<int64_t>(1));
312 ASSERT_EQUAL(2, rp.get<uint64_t>(0));
313 ASSERT_EQUAL(3, rp.get<double>(0));
314 ASSERT_EQUAL("hello", rp.get<string>(0));
315}
316
317TEST(Crow, handler_with_response)
318{
319 SimpleApp app;
320 BMCWEB_ROUTE(app, "/")([](const crow::Request&, crow::Response&) {});
321}
322
323TEST(Crow, http_method)
324{
325 SimpleApp app;
326
327 BMCWEB_ROUTE(app, "/").methods("POST"_method,
328 "GET"_method)([](const Request& req) {
329 if (req.method() == "GET"_method)
330 return "2";
331 else
332 return "1";
333 });
334
335 BMCWEB_ROUTE(app, "/get_only")
336 .methods("GET"_method)([](const Request& /*req*/) { return "get"; });
337 BMCWEB_ROUTE(app, "/post_only")
338 .methods("POST"_method)([](const Request& /*req*/) { return "post"; });
339
340 // cannot have multiple handlers for the same url
341 // BMCWEB_ROUTE(app, "/")
342 //.methods("GET"_method)
343 //([]{ return "2"; });
344
345 {
346 boost::beast::http::request<boost::beast::http::string_body> r{};
347 Request req{r};
348 Response res;
349
350 req.url = "/";
351 app.handle(req, res);
352
353 ASSERT_EQUAL("2", res.body());
354 }
355 {
356 boost::beast::http::request<boost::beast::http::string_body> r{};
357 Request req{r};
358 Response res;
359
360 req.url = "/";
361 r.method("POST"_method);
362 app.handle(req, res);
363
364 ASSERT_EQUAL("1", res.body());
365 }
366
367 {
368 boost::beast::http::request<boost::beast::http::string_body> r{};
369 Request req{r};
370 Response res;
371
372 req.url = "/get_only";
373 app.handle(req, res);
374
375 ASSERT_EQUAL("get", res.body());
376 }
377
378 {
379 boost::beast::http::request<boost::beast::http::string_body> r{};
380 Request req{r};
381 Response res;
382
383 req.url = "/get_only";
384 r.method("POST"_method);
385 app.handle(req, res);
386
387 ASSERT_NOTEQUAL("get", res.body());
388 }
389}
390
391TEST(Crow, server_handling_error_request)
392{
393 static char buf[2048];
394 SimpleApp app;
395 BMCWEB_ROUTE(app, "/")([] { return "A"; });
396 Server<SimpleApp> server(&app, LOCALHOST_ADDRESS, 45451);
397 auto _ = async(launch::async, [&] { server.run(); });
398 std::string sendmsg = "POX";
Ed Tanous8f626352018-12-19 14:51:54 -0800399 asio::io_context is;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700400 {
Ed Tanous1ff48782017-04-18 12:45:08 -0700401 asio::ip::tcp::socket c(is);
402 c.connect(asio::ip::tcp::endpoint(
403 asio::ip::address::from_string(LOCALHOST_ADDRESS), 45451));
404
Ed Tanous1abe55e2018-09-05 08:30:59 -0700405 c.send(asio::buffer(sendmsg));
Ed Tanous1ff48782017-04-18 12:45:08 -0700406
Ed Tanous1abe55e2018-09-05 08:30:59 -0700407 try
408 {
409 c.receive(asio::buffer(buf, 2048));
410 fail();
Ed Tanous8041f312017-04-03 09:47:01 -0700411 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700412 catch (std::exception& e)
413 {
414 // std::cerr << e.what() << std::endl;
415 }
Ed Tanous8041f312017-04-03 09:47:01 -0700416 }
Ed Tanous1abe55e2018-09-05 08:30:59 -0700417 server.stop();
Ed Tanous8041f312017-04-03 09:47:01 -0700418}
419
Ed Tanous1abe55e2018-09-05 08:30:59 -0700420TEST(Crow, multi_server)
421{
422 static char buf[2048];
423 SimpleApp app1, app2;
424 BMCWEB_ROUTE(app1, "/").methods("GET"_method,
425 "POST"_method)([] { return "A"; });
426 BMCWEB_ROUTE(app2, "/").methods("GET"_method,
427 "POST"_method)([] { return "B"; });
Ed Tanous8041f312017-04-03 09:47:01 -0700428
Ed Tanous1abe55e2018-09-05 08:30:59 -0700429 Server<SimpleApp> server1(&app1, LOCALHOST_ADDRESS, 45451);
430 Server<SimpleApp> server2(&app2, LOCALHOST_ADDRESS, 45452);
Ed Tanous8041f312017-04-03 09:47:01 -0700431
Ed Tanous1abe55e2018-09-05 08:30:59 -0700432 auto _ = async(launch::async, [&] { server1.run(); });
433 auto _2 = async(launch::async, [&] { server2.run(); });
Ed Tanous8041f312017-04-03 09:47:01 -0700434
Ed Tanous1abe55e2018-09-05 08:30:59 -0700435 std::string sendmsg =
436 "POST /\r\nContent-Length:3\r\nX-HeaderTest: 123\r\n\r\nA=b\r\n";
Ed Tanous8f626352018-12-19 14:51:54 -0800437 asio::io_context is;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700438 {
439 asio::ip::tcp::socket c(is);
440 c.connect(asio::ip::tcp::endpoint(
441 asio::ip::address::from_string(LOCALHOST_ADDRESS), 45451));
Ed Tanous8041f312017-04-03 09:47:01 -0700442
Ed Tanous1abe55e2018-09-05 08:30:59 -0700443 c.send(asio::buffer(sendmsg));
Ed Tanous8041f312017-04-03 09:47:01 -0700444
Ed Tanous1abe55e2018-09-05 08:30:59 -0700445 size_t recved = c.receive(asio::buffer(buf, 2048));
446 ASSERT_EQUAL('A', buf[recved - 1]);
447 }
Ed Tanous1ff48782017-04-18 12:45:08 -0700448
Ed Tanous1abe55e2018-09-05 08:30:59 -0700449 {
450 asio::ip::tcp::socket c(is);
451 c.connect(asio::ip::tcp::endpoint(
452 asio::ip::address::from_string(LOCALHOST_ADDRESS), 45452));
Ed Tanous1ff48782017-04-18 12:45:08 -0700453
Ed Tanous1abe55e2018-09-05 08:30:59 -0700454 for (auto ch : sendmsg)
455 {
456 char buf[1] = {ch};
457 c.send(asio::buffer(buf));
458 }
Ed Tanous1ff48782017-04-18 12:45:08 -0700459
Ed Tanous1abe55e2018-09-05 08:30:59 -0700460 size_t recved = c.receive(asio::buffer(buf, 2048));
461 ASSERT_EQUAL('b', buf[recved - 1]);
462 }
Ed Tanous1ff48782017-04-18 12:45:08 -0700463
Ed Tanous1abe55e2018-09-05 08:30:59 -0700464 server1.stop();
465 server2.stop();
Ed Tanous8041f312017-04-03 09:47:01 -0700466}
467
Ed Tanous1abe55e2018-09-05 08:30:59 -0700468TEST(Crow, black_magic)
469{
470 using namespace black_magic;
471 static_assert(
472 std::is_same<void, LastElementType<int, char, void>::type>::value,
473 "LastElementType");
474 static_assert(
475 std::is_same<char, PopBack<int, char,
476 void>::rebind<LastElementType>::type>::value,
477 "pop_back");
478 static_assert(
479 std::is_same<int, PopBack<int, char, void>::rebind<PopBack>::rebind<
480 LastElementType>::type>::value,
481 "pop_back");
482}
Ed Tanous8041f312017-04-03 09:47:01 -0700483
Ed Tanous1abe55e2018-09-05 08:30:59 -0700484struct NullMiddleware
485{
486 struct Context
487 {
488 };
Ed Tanous8041f312017-04-03 09:47:01 -0700489
Ed Tanous1abe55e2018-09-05 08:30:59 -0700490 template <typename AllContext>
491 void beforeHandle(Request&, Response&, Context&, AllContext&)
492 {
493 }
Ed Tanous8041f312017-04-03 09:47:01 -0700494
Ed Tanous1abe55e2018-09-05 08:30:59 -0700495 template <typename AllContext>
496 void afterHandle(Request&, Response&, Context&, AllContext&)
497 {
498 }
499};
Ed Tanous8041f312017-04-03 09:47:01 -0700500
Ed Tanous1abe55e2018-09-05 08:30:59 -0700501struct NullSimpleMiddleware
502{
503 struct Context
504 {
505 };
Ed Tanous8041f312017-04-03 09:47:01 -0700506
Ed Tanous1abe55e2018-09-05 08:30:59 -0700507 void beforeHandle(Request& /*req*/, Response& /*res*/, Context& /*ctx*/)
508 {
509 }
510
511 void afterHandle(Request& /*req*/, Response& /*res*/, Context& /*ctx*/)
512 {
513 }
514};
515
516TEST(Crow, middleware_simple)
517{
518 App<NullMiddleware, NullSimpleMiddleware> app;
519 decltype(app)::server_t server(&app, LOCALHOST_ADDRESS, 45451);
520 BMCWEB_ROUTE(app, "/")
521 ([&](const crow::Request& req) {
522 app.getContext<NullMiddleware>(req);
523 app.getContext<NullSimpleMiddleware>(req);
524 return "";
525 });
526}
527
528struct IntSettingMiddleware
529{
530 struct Context
531 {
532 int val;
533 };
534
535 template <typename AllContext>
536 void beforeHandle(Request&, Response&, Context& ctx, AllContext&)
537 {
538 ctx.val = 1;
539 }
540
541 template <typename AllContext>
542 void afterHandle(Request&, Response&, Context& ctx, AllContext&)
543 {
544 ctx.val = 2;
545 }
546};
547
548std::vector<std::string> test_middleware_context_vector;
549
550struct FirstMW
551{
552 struct Context
553 {
554 std::vector<string> v;
555 };
556
557 void beforeHandle(Request& /*req*/, Response& /*res*/, Context& ctx)
558 {
559 ctx.v.push_back("1 before");
560 }
561
562 void afterHandle(Request& /*req*/, Response& /*res*/, Context& ctx)
563 {
564 ctx.v.push_back("1 after");
565 test_middleware_context_vector = ctx.v;
566 }
567};
568
569struct SecondMW
570{
571 struct Context
572 {
573 };
574 template <typename AllContext>
575 void beforeHandle(Request& req, Response& res, Context&,
576 AllContext& all_ctx)
577 {
578 all_ctx.template get<FirstMW>().v.push_back("2 before");
579 if (req.url == "/break")
580 res.end();
581 }
582
583 template <typename AllContext>
584 void afterHandle(Request&, Response&, Context&, AllContext& all_ctx)
585 {
586 all_ctx.template get<FirstMW>().v.push_back("2 after");
587 }
588};
589
590struct ThirdMW
591{
592 struct Context
593 {
594 };
595 template <typename AllContext>
596 void beforeHandle(Request&, Response&, Context&, AllContext& all_ctx)
597 {
598 all_ctx.template get<FirstMW>().v.push_back("3 before");
599 }
600
601 template <typename AllContext>
602 void afterHandle(Request&, Response&, Context&, AllContext& all_ctx)
603 {
604 all_ctx.template get<FirstMW>().v.push_back("3 after");
605 }
606};
607
608TEST(Crow, middlewareContext)
609{
610 static char buf[2048];
611 // SecondMW depends on FirstMW (it uses all_ctx.get<FirstMW>)
612 // so it leads to compile error if we remove FirstMW from definition
613 // App<IntSettingMiddleware, SecondMW> app;
614 // or change the order of FirstMW and SecondMW
615 // App<IntSettingMiddleware, SecondMW, FirstMW> app;
616
617 App<IntSettingMiddleware, FirstMW, SecondMW, ThirdMW> app;
618
619 int x{};
620 BMCWEB_ROUTE(app, "/")
621 ([&](const Request& req) {
622 {
623 auto& ctx = app.getContext<IntSettingMiddleware>(req);
624 x = ctx.val;
625 }
626 {
627 auto& ctx = app.getContext<FirstMW>(req);
628 ctx.v.push_back("handle");
629 }
630
631 return "";
632 });
633 BMCWEB_ROUTE(app, "/break")
634 ([&](const Request& req) {
635 {
636 auto& ctx = app.getContext<FirstMW>(req);
637 ctx.v.push_back("handle");
638 }
639
640 return "";
641 });
642
643 decltype(app)::server_t server(&app, LOCALHOST_ADDRESS, 45451);
644 auto _ = async(launch::async, [&] { server.run(); });
645 std::string sendmsg = "GET /\r\n\r\n";
Ed Tanous8f626352018-12-19 14:51:54 -0800646 asio::io_context is;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700647 {
648 asio::ip::tcp::socket c(is);
649 c.connect(asio::ip::tcp::endpoint(
650 asio::ip::address::from_string(LOCALHOST_ADDRESS), 45451));
651
652 c.send(asio::buffer(sendmsg));
653
654 c.receive(asio::buffer(buf, 2048));
655 c.close();
656 }
657 {
658 auto& out = test_middleware_context_vector;
659 ASSERT_EQUAL(1, x);
660 ASSERT_EQUAL(7, out.size());
661 ASSERT_EQUAL("1 before", out[0]);
662 ASSERT_EQUAL("2 before", out[1]);
663 ASSERT_EQUAL("3 before", out[2]);
664 ASSERT_EQUAL("handle", out[3]);
665 ASSERT_EQUAL("3 after", out[4]);
666 ASSERT_EQUAL("2 after", out[5]);
667 ASSERT_EQUAL("1 after", out[6]);
668 }
669 std::string sendmsg2 = "GET /break\r\n\r\n";
670 {
671 asio::ip::tcp::socket c(is);
672 c.connect(asio::ip::tcp::endpoint(
673 asio::ip::address::from_string(LOCALHOST_ADDRESS), 45451));
674
675 c.send(asio::buffer(sendmsg2));
676
677 c.receive(asio::buffer(buf, 2048));
678 c.close();
679 }
680 {
681 auto& out = test_middleware_context_vector;
682 ASSERT_EQUAL(4, out.size());
683 ASSERT_EQUAL("1 before", out[0]);
684 ASSERT_EQUAL("2 before", out[1]);
685 ASSERT_EQUAL("2 after", out[2]);
686 ASSERT_EQUAL("1 after", out[3]);
687 }
688 server.stop();
689}
690
691TEST(Crow, bug_quick_repeated_request)
692{
693 static char buf[2048];
694
695 SimpleApp app;
696
697 BMCWEB_ROUTE(app, "/")([&] { return "hello"; });
698
699 decltype(app)::server_t server(&app, LOCALHOST_ADDRESS, 45451);
700 auto _ = async(launch::async, [&] { server.run(); });
701 std::string sendmsg = "GET / HTTP/1.1\r\nHost: localhost\r\n\r\n";
Ed Tanous8f626352018-12-19 14:51:54 -0800702 asio::io_context is;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700703 {
704 std::vector<std::future<void>> v;
705 for (int i = 0; i < 5; i++)
706 {
707 v.push_back(async(launch::async, [&] {
708 asio::ip::tcp::socket c(is);
709 c.connect(asio::ip::tcp::endpoint(
710 asio::ip::address::from_string(LOCALHOST_ADDRESS), 45451));
711
712 for (int j = 0; j < 5; j++)
713 {
714 c.send(asio::buffer(sendmsg));
715
716 size_t received = c.receive(asio::buffer(buf, 2048));
717 ASSERT_EQUAL("hello", std::string(buf + received - 5,
718 buf + received));
719 }
720 c.close();
721 }));
722 }
723 }
724 server.stop();
725}
726
727TEST(Crow, simple_url_params)
728{
729 static char buf[2048];
730
731 SimpleApp app;
732
733 QueryString lastUrlParams;
734
735 BMCWEB_ROUTE(app, "/params")
736 ([&lastUrlParams](const crow::Request& req) {
737 lastUrlParams = std::move(req.urlParams);
738 return "OK";
739 });
740
741 /// params?h=1&foo=bar&lol&count[]=1&count[]=4&pew=5.2
742
743 decltype(app)::server_t server(&app, LOCALHOST_ADDRESS, 45451);
744 auto _ = async(launch::async, [&] { server.run(); });
Ed Tanous8f626352018-12-19 14:51:54 -0800745 asio::io_context is;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700746 std::string sendmsg;
747
748 // check empty params
749 sendmsg = "GET /params\r\n\r\n";
750 {
751 asio::ip::tcp::socket c(is);
752 c.connect(asio::ip::tcp::endpoint(
753 asio::ip::address::from_string(LOCALHOST_ADDRESS), 45451));
754 c.send(asio::buffer(sendmsg));
755 c.receive(asio::buffer(buf, 2048));
756 c.close();
757
758 stringstream ss;
759 ss << lastUrlParams;
760
761 ASSERT_EQUAL("[ ]", ss.str());
762 }
763 // check single presence
764 sendmsg = "GET /params?foobar\r\n\r\n";
765 {
766 asio::ip::tcp::socket c(is);
767 c.connect(asio::ip::tcp::endpoint(
768 asio::ip::address::from_string(LOCALHOST_ADDRESS), 45451));
769 c.send(asio::buffer(sendmsg));
770 c.receive(asio::buffer(buf, 2048));
771 c.close();
772
773 ASSERT_TRUE(lastUrlParams.get("missing") == nullptr);
774 ASSERT_TRUE(lastUrlParams.get("foobar") != nullptr);
775 ASSERT_TRUE(lastUrlParams.getList("missing").empty());
776 }
777 // check multiple presence
778 sendmsg = "GET /params?foo&bar&baz\r\n\r\n";
779 {
780 asio::ip::tcp::socket c(is);
781 c.connect(asio::ip::tcp::endpoint(
782 asio::ip::address::from_string(LOCALHOST_ADDRESS), 45451));
783 c.send(asio::buffer(sendmsg));
784 c.receive(asio::buffer(buf, 2048));
785 c.close();
786
787 ASSERT_TRUE(lastUrlParams.get("missing") == nullptr);
788 ASSERT_TRUE(lastUrlParams.get("foo") != nullptr);
789 ASSERT_TRUE(lastUrlParams.get("bar") != nullptr);
790 ASSERT_TRUE(lastUrlParams.get("baz") != nullptr);
791 }
792 // check single value
793 sendmsg = "GET /params?hello=world\r\n\r\n";
794 {
795 asio::ip::tcp::socket c(is);
796 c.connect(asio::ip::tcp::endpoint(
797 asio::ip::address::from_string(LOCALHOST_ADDRESS), 45451));
798 c.send(asio::buffer(sendmsg));
799 c.receive(asio::buffer(buf, 2048));
800 c.close();
801
802 ASSERT_EQUAL(string(lastUrlParams.get("hello")), "world");
803 }
804 // check multiple value
805 sendmsg = "GET /params?hello=world&left=right&up=down\r\n\r\n";
806 {
807 asio::ip::tcp::socket c(is);
808 c.connect(asio::ip::tcp::endpoint(
809 asio::ip::address::from_string(LOCALHOST_ADDRESS), 45451));
810 c.send(asio::buffer(sendmsg));
811 c.receive(asio::buffer(buf, 2048));
812 c.close();
813
814 ASSERT_EQUAL(string(lastUrlParams.get("hello")), "world");
815 ASSERT_EQUAL(string(lastUrlParams.get("left")), "right");
816 ASSERT_EQUAL(string(lastUrlParams.get("up")), "down");
817 }
818 // check multiple value, multiple types
819 sendmsg = "GET /params?int=100&double=123.45&boolean=1\r\n\r\n";
820 {
821 asio::ip::tcp::socket c(is);
822 c.connect(asio::ip::tcp::endpoint(
823 asio::ip::address::from_string(LOCALHOST_ADDRESS), 45451));
824 c.send(asio::buffer(sendmsg));
825 c.receive(asio::buffer(buf, 2048));
826 c.close();
827
828 ASSERT_EQUAL(boost::lexical_cast<int>(lastUrlParams.get("int")), 100);
829 ASSERT_EQUAL(boost::lexical_cast<double>(lastUrlParams.get("double")),
830 123.45);
831 ASSERT_EQUAL(boost::lexical_cast<bool>(lastUrlParams.get("boolean")),
832 true);
833 }
834 // check single array value
835 sendmsg = "GET /params?tmnt[]=leonardo\r\n\r\n";
836 {
837 asio::ip::tcp::socket c(is);
838
839 c.connect(asio::ip::tcp::endpoint(
840 asio::ip::address::from_string(LOCALHOST_ADDRESS), 45451));
841 c.send(asio::buffer(sendmsg));
842 c.receive(asio::buffer(buf, 2048));
843 c.close();
844
845 ASSERT_TRUE(lastUrlParams.get("tmnt") == nullptr);
846 ASSERT_EQUAL(lastUrlParams.getList("tmnt").size(), 1);
847 ASSERT_EQUAL(string(lastUrlParams.getList("tmnt")[0]), "leonardo");
848 }
849 // check multiple array value
850 sendmsg =
851 "GET /params?tmnt[]=leonardo&tmnt[]=donatello&tmnt[]=raphael\r\n\r\n";
852 {
853 asio::ip::tcp::socket c(is);
854
855 c.connect(asio::ip::tcp::endpoint(
856 asio::ip::address::from_string(LOCALHOST_ADDRESS), 45451));
857 c.send(asio::buffer(sendmsg));
858 c.receive(asio::buffer(buf, 2048));
859 c.close();
860
861 ASSERT_EQUAL(lastUrlParams.getList("tmnt").size(), 3);
862 ASSERT_EQUAL(string(lastUrlParams.getList("tmnt")[0]), "leonardo");
863 ASSERT_EQUAL(string(lastUrlParams.getList("tmnt")[1]), "donatello");
864 ASSERT_EQUAL(string(lastUrlParams.getList("tmnt")[2]), "raphael");
865 }
866 server.stop();
867}
868
869TEST(Crow, routeDynamic)
870{
871 SimpleApp app;
872 int x = 1;
873 app.routeDynamic("/")([&] {
874 x = 2;
875 return "";
876 });
877
878 app.routeDynamic("/set4")([&](const Request&) {
879 x = 4;
880 return "";
881 });
882 app.routeDynamic("/set5")([&](const Request&, Response& res) {
883 x = 5;
884 res.end();
885 });
886
887 app.routeDynamic("/set_int/<int>")([&](int y) {
888 x = y;
889 return "";
890 });
891
892 try
893 {
894 app.routeDynamic("/invalid_test/<double>/<path>")([]() { return ""; });
895 fail();
896 }
897 catch (std::exception&)
898 {
899 }
900
901 // app is in an invalid state when routeDynamic throws an exception.
902 try
903 {
904 app.validate();
905 fail();
906 }
907 catch (std::exception&)
908 {
909 }
910
911 {
912 boost::beast::http::request<boost::beast::http::string_body> r{};
913 Request req{r};
914 Response res;
915 req.url = "/";
916 app.handle(req, res);
917 ASSERT_EQUAL(x, 2);
918 }
919 {
920 boost::beast::http::request<boost::beast::http::string_body> r{};
921 Request req{r};
922 Response res;
923 req.url = "/set_int/42";
924 app.handle(req, res);
925 ASSERT_EQUAL(x, 42);
926 }
927 {
928 boost::beast::http::request<boost::beast::http::string_body> r{};
929 Request req{r};
930 Response res;
931 req.url = "/set5";
932 app.handle(req, res);
933 ASSERT_EQUAL(x, 5);
934 }
935 {
936 boost::beast::http::request<boost::beast::http::string_body> r{};
937 Request req{r};
938 Response res;
939 req.url = "/set4";
940 app.handle(req, res);
941 ASSERT_EQUAL(x, 4);
942 }
Ed Tanous8041f312017-04-03 09:47:01 -0700943}