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