From 7f4b7c8ff9ed9501952612eed182cd39b3588188 Mon Sep 17 00:00:00 2001 From: The-EDev Date: Thu, 25 Nov 2021 14:45:38 +0300 Subject: [PATCH 1/8] created new rules, used bot to enforce rules in PRs --- .clang-format | 77 +- .drone.yml | 12 +- examples/example.cpp | 128 +- examples/example_blueprint.cpp | 11 +- examples/example_catchall.cpp | 10 +- examples/example_chat.cpp | 32 +- examples/example_compression.cpp | 19 +- examples/example_json_map.cpp | 20 +- examples/example_static_file.cpp | 16 +- examples/example_vs.cpp | 71 +- examples/example_with_all.cpp | 98 +- examples/helloworld.cpp | 5 +- examples/ssl/example_ssl.cpp | 5 +- examples/websocket/example_ws.cpp | 30 +- include/crow/app.h | 133 +- include/crow/ci_map.h | 4 +- include/crow/common.h | 91 +- include/crow/compression.h | 16 +- include/crow/http_connection.h | 410 ++- include/crow/http_request.h | 19 +- include/crow/http_response.h | 151 +- include/crow/http_server.h | 200 +- include/crow/json.h | 809 +++--- include/crow/logging.h | 199 +- include/crow/middleware_context.h | 38 +- include/crow/middlewares/cookie_parser.h | 24 +- include/crow/middlewares/utf-8.h | 2 +- include/crow/mime_types.h | 224 +- include/crow/multipart.h | 119 +- include/crow/mustache.h | 389 +-- include/crow/parser.h | 47 +- include/crow/returnable.h | 22 +- include/crow/routing.h | 598 ++-- include/crow/socket_adaptors.h | 23 +- include/crow/task_timer.h | 217 +- include/crow/utility.h | 410 ++- include/crow/version.h | 5 +- include/crow/websocket.h | 1006 +++---- tests/ssl/ssltest.cpp | 35 +- tests/template/mustachetest.cpp | 22 +- tests/unittest.cpp | 3346 +++++++++++----------- 41 files changed, 4635 insertions(+), 4458 deletions(-) diff --git a/.clang-format b/.clang-format index efb19b349..ac508dcd8 100644 --- a/.clang-format +++ b/.clang-format @@ -1,8 +1,77 @@ --- -BasedOnStyle: Google -BreakBeforeBraces: Mozilla -IndentWidth: '2' -TabWidth: '2' +BasedOnStyle: Mozilla +AccessModifierOffset: '-4' +AlignAfterOpenBracket: Align +AlignConsecutiveMacros: 'false' +AlignEscapedNewlines: Left +AlignOperands: AlignAfterOperator +AlignTrailingComments: 'true' +AllowShortBlocksOnASingleLine: 'true' +AllowShortCaseLabelsOnASingleLine: 'true' +AllowShortFunctionsOnASingleLine: All +AllowShortIfStatementsOnASingleLine: 'true' +AllowShortLambdasOnASingleLine: All +AllowShortLoopsOnASingleLine: 'false' +AlwaysBreakAfterDefinitionReturnType: None +AlwaysBreakAfterReturnType: None +AlwaysBreakBeforeMultilineStrings: 'false' +AlwaysBreakTemplateDeclarations: 'Yes' +BinPackArguments: 'true' +BinPackParameters: 'true' +BreakBeforeBraces: Allman +BreakBeforeTernaryOperators: 'false' +BreakConstructorInitializers: AfterColon +BreakInheritanceList: AfterColon +ColumnLimit: '0' +CompactNamespaces: 'false' +ConstructorInitializerAllOnOneLineOrOnePerLine: 'false' +ContinuationIndentWidth: '2' +Cpp11BracedListStyle: 'true' +FixNamespaceComments: 'true' +IncludeBlocks: Regroup +IncludeCategories: + - Regex: '^"(llvm|llvm-c|clang|clang-c)/' + Priority: 2 + SortPriority: 2 + CaseSensitive: true + - Regex: '^(<|"(gtest|gmock|isl|json)/)' + Priority: 3 + - Regex: '<[[:alnum:].]+>' + Priority: 4 + - Regex: '.*' + Priority: 1 + SortPriority: 0 +IndentCaseLabels: 'true' +IndentWidth: '4' +IndentWrappedFunctionNames: 'true' +Language: Cpp +MaxEmptyLinesToKeep: '3' +NamespaceIndentation: All +PointerAlignment: Left +ReflowComments: 'false' +SortIncludes: 'false' +SortUsingDeclarations: 'false' +SpaceAfterCStyleCast: 'false' +SpaceAfterLogicalNot: 'false' +SpaceAfterTemplateKeyword: 'false' +SpaceBeforeAssignmentOperators: 'true' +SpaceBeforeCpp11BracedList: 'false' +SpaceBeforeCtorInitializerColon: 'false' +SpaceBeforeInheritanceColon: 'true' +SpaceBeforeParens: ControlStatements +SpaceBeforeRangeBasedForLoopColon: 'true' +SpaceInEmptyParentheses: 'false' +SpacesBeforeTrailingComments: '1' +SpacesInAngles: 'false' +SpacesInCStyleCastParentheses: 'false' +SpacesInContainerLiterals: 'false' +SpacesInParentheses: 'false' +SpacesInSquareBrackets: 'false' +SpacesInLineCommentPrefix: + Minimum: 1 + Maximum: -1 +Standard: Cpp11 +TabWidth: '4' UseTab: Never ... diff --git a/.drone.yml b/.drone.yml index 47bd821b8..88e2c725f 100644 --- a/.drone.yml +++ b/.drone.yml @@ -12,6 +12,12 @@ steps: environment: COVERALLS_REPO_TOKEN: from_secret: coveralls_token + APP_ID: + from_secret: appid + APP_INSTALLATION: + from_secret: appins + PK: + from_secret: pk commands: - export DEBIAN_FRONTEND=noninteractive @@ -19,7 +25,7 @@ steps: - export TRAVIS_JOB_ID=$DRONE_BUILD_NUMBER - export COVERALLS_PULL_REQUEST=$DRONE_PULL_REQUEST - apt-get -y update - - apt-get -y install libboost-all-dev doxygen mkdocs graphviz zlib1g-dev gcc clang make cmake python3 python3-pip git openssl libssl-dev + - apt-get -y install libboost-all-dev doxygen mkdocs graphviz zlib1g-dev gcc clang clang-format make cmake python3 python3-pip git openssl libssl-dev jq - git clone https://github.com/CrowCpp/cpp-coveralls.git - cd cpp-coveralls - pip3 install . --no-input @@ -33,6 +39,10 @@ steps: - ctest -V -j4 - cd .. - coveralls --verbose --exclude-pattern .*/http_parser_merged.h --exclude-pattern .*/TinySHA1.hpp + - clone https://github.com/CrowCpp/crow-clang-format.git + - cd crow-clang-format + - chmod +x crow-clang-format.sh get-access-token.sh make-jwt.sh + - ./crow-clang-format.sh - export CC=/usr/bin/clang - export CXX=/usr/bin/clang++ - mkdir build-clang diff --git a/examples/example.cpp b/examples/example.cpp index 2fb29df6f..83f385d63 100644 --- a/examples/example.cpp +++ b/examples/example.cpp @@ -2,22 +2,25 @@ #include -class ExampleLogHandler : public crow::ILogHandler { - public: - void log(std::string /*message*/, crow::LogLevel /*level*/) override { -// cerr << "ExampleLogHandler -> " << message; - } +class ExampleLogHandler : public crow::ILogHandler +{ +public: + void log(std::string /*message*/, crow::LogLevel /*level*/) override + { + // cerr << "ExampleLogHandler -> " << message; + } }; struct ExampleMiddleware { std::string message; - ExampleMiddleware() : message("foo") + ExampleMiddleware(): + message("foo") { } - void setMessage(const std::string &newMsg) + void setMessage(const std::string& newMsg) { message = newMsg; } @@ -44,88 +47,83 @@ int main() app.get_middleware().setMessage("hello"); CROW_ROUTE(app, "/") - .name("hello") - ([]{ - return "Hello World!"; - }); + .name("hello")([] + { return "Hello World!"; }); CROW_ROUTE(app, "/about") - ([](){ - return "About Crow example."; - }); + ([]() + { return "About Crow example."; }); // a request to /path should be forwarded to /path/ CROW_ROUTE(app, "/path/") - ([](){ - return "Trailing slash test case.."; - }); + ([]() + { return "Trailing slash test case.."; }); // simple json response CROW_ROUTE(app, "/json") - ([]{ + ([] + { crow::json::wvalue x({{"message", "Hello, World!"}}); x["message2"] = "Hello, World.. Again!"; - return x; - }); + return x; }); CROW_ROUTE(app, "/json-initializer-list-constructor") - ([] { - return crow::json::wvalue({ - {"first", "Hello world!"}, /* stores a char const* hence a json::type::String */ - {"second", std::string("How are you today?")}, /* stores a std::string hence a json::type::String. */ - {"third", std::int64_t(54)}, /* stores a 64-bit int hence a std::int64_t. */ - {"fourth", std::uint64_t(54)}, /* stores a 64-bit unsigned int hence a std::uint64_t. */ - {"fifth", 54}, /* stores an int (as 54 is an int literal) hence a std::int64_t. */ - {"sixth", 54u}, /* stores an unsigned int (as 54u is a unsigned int literal) hence a std::uint64_t. */ - {"seventh", 2.f}, /* stores a float (as 2.f is a float literal) hence a double. */ - {"eighth", 2.}, /* stores a double (as 2. is a double literal) hence a double. */ - {"ninth", nullptr}, /* stores a std::nullptr hence json::type::Null . */ - {"tenth", true} /* stores a bool hence json::type::True . */ - }); - }); + ([] + { return crow::json::wvalue({ + {"first", "Hello world!"}, /* stores a char const* hence a json::type::String */ + {"second", std::string("How are you today?")}, /* stores a std::string hence a json::type::String. */ + {"third", std::int64_t(54)}, /* stores a 64-bit int hence a std::int64_t. */ + {"fourth", std::uint64_t(54)}, /* stores a 64-bit unsigned int hence a std::uint64_t. */ + {"fifth", 54}, /* stores an int (as 54 is an int literal) hence a std::int64_t. */ + {"sixth", 54u}, /* stores an unsigned int (as 54u is a unsigned int literal) hence a std::uint64_t. */ + {"seventh", 2.f}, /* stores a float (as 2.f is a float literal) hence a double. */ + {"eighth", 2.}, /* stores a double (as 2. is a double literal) hence a double. */ + {"ninth", nullptr}, /* stores a std::nullptr hence json::type::Null . */ + {"tenth", true} /* stores a bool hence json::type::True . */ + }); }); // json list response CROW_ROUTE(app, "/json_list") - ([]{ + ([] + { crow::json::wvalue x(crow::json::wvalue::list({1,2,3})); - return x; - }); + return x; }); // To see it in action enter {ip}:18080/hello/{integer_between -2^32 and 100} and you should receive // {integer_between -2^31 and 100} bottles of beer! - CROW_ROUTE(app,"/hello/") - ([](int count){ + CROW_ROUTE(app, "/hello/") + ([](int count) + { if (count > 100) return crow::response(400); std::ostringstream os; os << count << " bottles of beer!"; - return crow::response(os.str()); - }); + return crow::response(os.str()); }); // Same as above, but using crow::status - CROW_ROUTE(app,"/hello_status/") - ([](int count){ + CROW_ROUTE(app, "/hello_status/") + ([](int count) + { if (count > 100) return crow::response(crow::status::BAD_REQUEST); std::ostringstream os; os << count << " bottles of beer!"; - return crow::response(os.str()); - }); + return crow::response(os.str()); }); // To see it in action submit {ip}:18080/add/1/2 and you should receive 3 (exciting, isn't it) - CROW_ROUTE(app,"/add//") - ([](crow::response& res, int a, int b){ + CROW_ROUTE(app, "/add//") + ([](crow::response& res, int a, int b) + { std::ostringstream os; os << a+b; res.write(os.str()); - res.end(); - }); + res.end(); }); // Compile error with message "Handler type is mismatched with URL paramters" //CROW_ROUTE(app,"/another/") //([](int a, int b){ - //return crow::response(500); + //return crow::response(500); //}); // more json example @@ -140,22 +138,22 @@ int main() // A simpler way for json example: // * curl -d '{"a":1,"b":2}' {ip}:18080/add_json CROW_ROUTE(app, "/add_json") - .methods("POST"_method) - ([](const crow::request& req){ + .methods("POST"_method)([](const crow::request& req) + { auto x = crow::json::load(req.body); if (!x) return crow::response(400); int sum = x["a"].i()+x["b"].i(); std::ostringstream os; os << sum; - return crow::response{os.str()}; - }); + return crow::response{os.str()}; }); // Example of a request taking URL parameters // If you want to activate all the functions just query // {ip}:18080/params?foo='blabla'&pew=32&count[]=a&count[]=b CROW_ROUTE(app, "/params") - ([](const crow::request& req){ + ([](const crow::request& req) + { std::ostringstream os; // To get a simple string from the url params @@ -186,27 +184,25 @@ int main() os << " - " << mydictVal.first << " -> " << mydictVal.second << '\n'; } - return crow::response{os.str()}; - }); + return crow::response{os.str()}; }); CROW_ROUTE(app, "/large") - ([]{ - return std::string(512*1024, ' '); - }); + ([] + { return std::string(512 * 1024, ' '); }); // Take a multipart/form-data request and print out its body - CROW_ROUTE(app,"/multipart") - ([](const crow::request& req){ + CROW_ROUTE(app, "/multipart") + ([](const crow::request& req) + { crow::multipart::message msg(req); CROW_LOG_INFO << "body of the first part " << msg.parts[0].body; - return "it works!"; - }); + return "it works!"; }); // enables all log app.loglevel(crow::LogLevel::Debug); //crow::logger::setHandler(std::make_shared()); app.port(18080) - .multithreaded() - .run(); + .multithreaded() + .run(); } diff --git a/examples/example_blueprint.cpp b/examples/example_blueprint.cpp index d8ff85033..3f9d6b10f 100644 --- a/examples/example_blueprint.cpp +++ b/examples/example_blueprint.cpp @@ -10,11 +10,10 @@ int main() crow::Blueprint sub_bp("bp2", "csstat", "cstemplate"); CROW_BP_ROUTE(sub_bp, "/") - ([]() { - return "Hello world!"; - }); + ([]() + { return "Hello world!"; }); -/* CROW_BP_ROUTE(bp, "/templatt") + /* CROW_BP_ROUTE(bp, "/templatt") ([]() { crow::mustache::context ctxdat; ctxdat["messg"] = "fifty five!!"; @@ -24,7 +23,9 @@ int main() return page.render(ctxdat); }); */ - CROW_BP_CATCHALL_ROUTE(sub_bp)([](){return "WRONG!!";}); + CROW_BP_CATCHALL_ROUTE(sub_bp) + ([]() + { return "WRONG!!"; }); bp.register_blueprint(sub_bp); diff --git a/examples/example_catchall.cpp b/examples/example_catchall.cpp index 036658b29..28ec10992 100644 --- a/examples/example_catchall.cpp +++ b/examples/example_catchall.cpp @@ -6,11 +6,14 @@ int main() { crow::SimpleApp app; - CROW_ROUTE(app, "/")([](){return "Hello";}); + CROW_ROUTE(app, "/") + ([]() + { return "Hello"; }); //Setting a custom route for any URL that isn't defined, instead of a simple 404. CROW_CATCHALL_ROUTE(app) - ([](crow::response& res) { + ([](crow::response& res) + { if (res.code == 404) { res.body = "The URL does not seem to be correct."; @@ -19,8 +22,7 @@ int main() { res.body = "The HTTP method does not seem to be correct."; } - res.end(); - }); + res.end(); }); app.port(18080).run(); } diff --git a/examples/example_chat.cpp b/examples/example_chat.cpp index 7b9ec90cb..c3907eb0e 100644 --- a/examples/example_chat.cpp +++ b/examples/example_chat.cpp @@ -15,7 +15,7 @@ void broadcast(const string& msg) x["msgs"][0] = msgs.back(); x["last"] = msgs.size(); string body = x.dump(); - for(auto p : ress) + for (auto p : ress) { auto* res = p.first; CROW_LOG_DEBUG << res << " replied: " << body; @@ -30,13 +30,14 @@ int main() crow::mustache::set_base("."); CROW_ROUTE(app, "/") - ([]{ + ([] + { crow::mustache::context ctx; - return crow::mustache::load("example_chat.html").render(); - }); + return crow::mustache::load("example_chat.html").render(); }); CROW_ROUTE(app, "/logs") - ([]{ + ([] + { CROW_LOG_INFO << "logs requested"; crow::json::wvalue x; int start = max(0, (int)msgs.size()-100); @@ -44,11 +45,11 @@ int main() x["msgs"][i-start] = msgs[i]; x["last"] = msgs.size(); CROW_LOG_INFO << "logs completed"; - return x; - }); + return x; }); CROW_ROUTE(app, "/logs/") - ([](const crow::request& /*req*/, crow::response& res, int after){ + ([](const crow::request& /*req*/, crow::response& res, int after) + { CROW_LOG_INFO << "logs with last " << after; if (after < (int)msgs.size()) { @@ -73,19 +74,16 @@ int main() ress.swap(filtered); ress.push_back({&res, chrono::steady_clock::now()}); CROW_LOG_DEBUG << &res << " stored " << ress.size(); - } - }); + } }); CROW_ROUTE(app, "/send") - .methods("GET"_method, "POST"_method) - ([](const crow::request& req) - { + .methods("GET"_method, "POST"_method)([](const crow::request& req) + { CROW_LOG_INFO << "msg from client: " << req.body; broadcast(req.body); - return ""; - }); + return ""; }); app.port(40080) - //.multithreaded() - .run(); + //.multithreaded() + .run(); } diff --git a/examples/example_compression.cpp b/examples/example_compression.cpp index 55e014a13..8055a8429 100644 --- a/examples/example_compression.cpp +++ b/examples/example_compression.cpp @@ -7,23 +7,22 @@ int main() //crow::App app; CROW_ROUTE(app, "/hello") - ([&](const crow::request&, crow::response& res){ + ([&](const crow::request&, crow::response& res) + { res.compressed = false; res.body = "Hello World! This is uncompressed!"; - res.end(); - }); + res.end(); }); CROW_ROUTE(app, "/hello_compressed") - ([](){ - return "Hello World! This is compressed by default!"; - }); + ([]() + { return "Hello World! This is compressed by default!"; }); app.port(18080) - .use_compression(crow::compression::algorithm::DEFLATE) + .use_compression(crow::compression::algorithm::DEFLATE) //.use_compression(crow::compression::algorithm::GZIP) - .loglevel(crow::LogLevel::Debug) - .multithreaded() - .run(); + .loglevel(crow::LogLevel::Debug) + .multithreaded() + .run(); } diff --git a/examples/example_json_map.cpp b/examples/example_json_map.cpp index bff2f4bb8..f441436b4 100644 --- a/examples/example_json_map.cpp +++ b/examples/example_json_map.cpp @@ -5,17 +5,17 @@ int main() { crow::SimpleApp app; -// simple json response using a map -// To see it in action enter {ip}:18080/json -// it shoud show amessage before zmessage despite adding zmessage first. -CROW_ROUTE(app, "/json") -([]{ + // simple json response using a map + // To see it in action enter {ip}:18080/json + // it shoud show amessage before zmessage despite adding zmessage first. + CROW_ROUTE(app, "/json") + ([] + { crow::json::wvalue x({{"zmessage", "Hello, World!"}, {"amessage", "Hello, World2!"}}); - return x; -}); + return x; }); -app.port(18080) - .multithreaded() - .run(); + app.port(18080) + .multithreaded() + .run(); } diff --git a/examples/example_static_file.cpp b/examples/example_static_file.cpp index c909d3e46..c965a4812 100644 --- a/examples/example_static_file.cpp +++ b/examples/example_static_file.cpp @@ -6,22 +6,22 @@ int main() { - //Crow app initialization - crow::SimpleApp app; + //Crow app initialization + crow::SimpleApp app; // -CROW_ROUTE(app, "/") -([](const crow::request&, crow::response& res) { + CROW_ROUTE(app, "/") + ([](const crow::request&, crow::response& res) + { //replace cat.jpg with your file path res.set_static_file_info("cat.jpg"); - res.end(); -}); + res.end(); }); - app.port(18080).run(); + app.port(18080).run(); - return 0; + return 0; } /// You can also use the `/static` directory and endpoint (the directory needs to have the same path as your executable). diff --git a/examples/example_vs.cpp b/examples/example_vs.cpp index 108577b45..8fa1d59fe 100644 --- a/examples/example_vs.cpp +++ b/examples/example_vs.cpp @@ -2,22 +2,25 @@ #include -class ExampleLogHandler : public crow::ILogHandler { - public: - void log(std::string message, crow::LogLevel level) override { -// cerr << "ExampleLogHandler -> " << message; - } +class ExampleLogHandler : public crow::ILogHandler +{ +public: + void log(std::string message, crow::LogLevel level) override + { + // cerr << "ExampleLogHandler -> " << message; + } }; struct ExampleMiddleware { std::string message; - ExampleMiddleware() : message("foo") + ExampleMiddleware(): + message("foo") { } - void setMessage(const std::string &newMsg) + void setMessage(const std::string& newMsg) { message = newMsg; } @@ -44,68 +47,63 @@ int main() app.get_middleware().setMessage("hello"); CROW_ROUTE(app, "/") - .name("hello") - ([]{ - return "Hello World!"; - }); + .name("hello")([] + { return "Hello World!"; }); CROW_ROUTE(app, "/about") - ([](){ - return "About Crow example."; - }); + ([]() + { return "About Crow example."; }); // a request to /path should be forwarded to /path/ CROW_ROUTE(app, "/path/") - ([](){ - return "Trailing slash test case.."; - }); + ([]() + { return "Trailing slash test case.."; }); // simple json response CROW_ROUTE(app, "/json") - ([]{ + ([] + { crow::json::wvalue x; x["message"] = "Hello, World!"; - return x; - }); + return x; }); CROW_ROUTE(app, "/hello/") - ([](int count){ + ([](int count) + { if (count > 100) return crow::response(400); std::ostringstream os; os << count << " bottles of beer!"; - return crow::response(os.str()); - }); + return crow::response(os.str()); }); CROW_ROUTE(app, "/add//") - ([](crow::response& res, int a, int b){ + ([](crow::response& res, int a, int b) + { std::ostringstream os; os << a+b; res.write(os.str()); - res.end(); - }); + res.end(); }); // Compile error with message "Handler type is mismatched with URL paramters" //CROW_ROUTE(app,"/another/") //([](int a, int b){ - //return crow::response(500); + //return crow::response(500); //}); // more json example CROW_ROUTE(app, "/add_json") - .methods(crow::HTTPMethod::Post) - ([](const crow::request& req){ + .methods(crow::HTTPMethod::Post)([](const crow::request& req) + { auto x = crow::json::load(req.body); if (!x) return crow::response(400); auto sum = x["a"].i()+x["b"].i(); std::ostringstream os; os << sum; - return crow::response{os.str()}; - }); + return crow::response{os.str()}; }); - app.route_dynamic("/params") - ([](const crow::request& req){ + app.route_dynamic("/params")([](const crow::request& req) + { std::ostringstream os; os << "Params: " << req.url_params << "\n\n"; os << "The key 'foo' was " << (req.url_params.get("foo") == nullptr ? "not " : "") << "found.\n"; @@ -118,14 +116,13 @@ int main() for(const auto& countVal : count) { os << " - " << countVal << '\n'; } - return crow::response{os.str()}; - }); + return crow::response{os.str()}; }); // ignore all log crow::logger::setLogLevel(crow::LogLevel::Debug); //crow::logger::setHandler(std::make_shared()); app.port(18080) - .multithreaded() - .run(); + .multithreaded() + .run(); } diff --git a/examples/example_with_all.cpp b/examples/example_with_all.cpp index 8f0f028bc..8bb0db225 100644 --- a/examples/example_with_all.cpp +++ b/examples/example_with_all.cpp @@ -2,11 +2,13 @@ #include -class ExampleLogHandler : public crow::ILogHandler { - public: - void log(std::string /*message*/, crow::LogLevel /*level*/) override { -// cerr << "ExampleLogHandler -> " << message; - } +class ExampleLogHandler : public crow::ILogHandler +{ +public: + void log(std::string /*message*/, crow::LogLevel /*level*/) override + { + // cerr << "ExampleLogHandler -> " << message; + } }; int main() @@ -14,86 +16,83 @@ int main() crow::SimpleApp app; CROW_ROUTE(app, "/") - .name("hello") - ([]{ - return "Hello World!"; - }); + .name("hello")([] + { return "Hello World!"; }); CROW_ROUTE(app, "/about") - ([](){ - return "About Crow example."; - }); + ([]() + { return "About Crow example."; }); // simple json response CROW_ROUTE(app, "/json") - ([]{ + ([] + { crow::json::wvalue x({{"message", "Hello, World!"}}); x["message2"] = "Hello, World.. Again!"; - return x; - }); + return x; }); CROW_ROUTE(app, "/json-initializer-list-constructor") - ([] { - return crow::json::wvalue({ - {"first", "Hello world!"}, /* stores a char const* hence a json::type::String */ - {"second", std::string("How are you today?")}, /* stores a std::string hence a json::type::String. */ - {"third", 54}, /* stores an int (as 54 is an int literal) hence a std::int64_t. */ - {"fourth", 54l}, /* stores a long (as 54l is a long literal) hence a std::int64_t. */ - {"fifth", 54u}, /* stores an unsigned int (as 54u is a unsigned int literal) hence a std::uint64_t. */ - {"sixth", 54ul}, /* stores an unsigned long (as 54ul is an unsigned long literal) hence a std::uint64_t. */ - {"seventh", 2.f}, /* stores a float (as 2.f is a float literal) hence a double. */ - {"eighth", 2.}, /* stores a double (as 2. is a double literal) hence a double. */ - {"ninth", nullptr}, /* stores a std::nullptr hence json::type::Null . */ - {"tenth", true} /* stores a bool hence json::type::True . */ - }); - }); + ([] + { return crow::json::wvalue({ + {"first", "Hello world!"}, /* stores a char const* hence a json::type::String */ + {"second", std::string("How are you today?")}, /* stores a std::string hence a json::type::String. */ + {"third", 54}, /* stores an int (as 54 is an int literal) hence a std::int64_t. */ + {"fourth", 54l}, /* stores a long (as 54l is a long literal) hence a std::int64_t. */ + {"fifth", 54u}, /* stores an unsigned int (as 54u is a unsigned int literal) hence a std::uint64_t. */ + {"sixth", 54ul}, /* stores an unsigned long (as 54ul is an unsigned long literal) hence a std::uint64_t. */ + {"seventh", 2.f}, /* stores a float (as 2.f is a float literal) hence a double. */ + {"eighth", 2.}, /* stores a double (as 2. is a double literal) hence a double. */ + {"ninth", nullptr}, /* stores a std::nullptr hence json::type::Null . */ + {"tenth", true} /* stores a bool hence json::type::True . */ + }); }); // json list response CROW_ROUTE(app, "/json_list") - ([]{ + ([] + { crow::json::wvalue x(crow::json::wvalue::list({1,2,3})); - return x; - }); + return x; }); - CROW_ROUTE(app,"/hello/") - ([](int count){ + CROW_ROUTE(app, "/hello/") + ([](int count) + { if (count > 100) return crow::response(400); std::ostringstream os; os << count << " bottles of beer!"; - return crow::response(os.str()); - }); + return crow::response(os.str()); }); // example which uses only response as a paramter without // request being a parameter. - CROW_ROUTE(app,"/add//") - ([](crow::response& res, int a, int b){ + CROW_ROUTE(app, "/add//") + ([](crow::response& res, int a, int b) + { std::ostringstream os; os << a+b; res.write(os.str()); - res.end(); - }); + res.end(); }); // Compile error with message "Handler type is mismatched with URL paramters" //CROW_ROUTE(app,"/another/") //([](int a, int b){ - //return crow::response(500); + //return crow::response(500); //}); // more json example CROW_ROUTE(app, "/add_json") - ([](const crow::request& req){ + ([](const crow::request& req) + { auto x = crow::json::load(req.body); if (!x) return crow::response(400); int sum = x["a"].i()+x["b"].i(); std::ostringstream os; os << sum; - return crow::response{os.str()}; - }); + return crow::response{os.str()}; }); CROW_ROUTE(app, "/params") - ([](const crow::request& req){ + ([](const crow::request& req) + { std::ostringstream os; os << "Params: " << req.url_params << "\n\n"; os << "The key 'foo' was " << (req.url_params.get("foo") == nullptr ? "not " : "") << "found.\n"; @@ -106,15 +105,14 @@ int main() for(const auto& countVal : count) { os << " - " << countVal << '\n'; } - return crow::response{os.str()}; - }); + return crow::response{os.str()}; }); // ignore all log crow::logger::setLogLevel(crow::LogLevel::Debug); //crow::logger::setHandler(std::make_shared()); app.port(18080) - .server_name("CrowCpp") - .multithreaded() - .run(); + .server_name("CrowCpp") + .multithreaded() + .run(); } diff --git a/examples/helloworld.cpp b/examples/helloworld.cpp index 2a44c65c3..388b3ab41 100644 --- a/examples/helloworld.cpp +++ b/examples/helloworld.cpp @@ -5,9 +5,8 @@ int main() crow::SimpleApp app; CROW_ROUTE(app, "/") - ([]() { - return "Hello, world!"; - }); + ([]() + { return "Hello, world!"; }); app.port(18080).run(); } diff --git a/examples/ssl/example_ssl.cpp b/examples/ssl/example_ssl.cpp index a8a1cfc5c..ddbb96433 100644 --- a/examples/ssl/example_ssl.cpp +++ b/examples/ssl/example_ssl.cpp @@ -5,9 +5,8 @@ int main() crow::SimpleApp app; CROW_ROUTE(app, "/") - ([]() { - return "Hello world!"; - }); + ([]() + { return "Hello world!"; }); app.port(18080).ssl_file("test.crt", "test.key").run(); diff --git a/examples/websocket/example_ws.cpp b/examples/websocket/example_ws.cpp index bc2832b40..b0ddeb074 100644 --- a/examples/websocket/example_ws.cpp +++ b/examples/websocket/example_ws.cpp @@ -11,38 +11,38 @@ int main() std::unordered_set users; CROW_ROUTE(app, "/ws") - .websocket() - .onopen([&](crow::websocket::connection& conn){ + .websocket() + .onopen([&](crow::websocket::connection& conn) + { CROW_LOG_INFO << "new websocket connection from " << conn.get_remote_ip(); std::lock_guard _(mtx); - users.insert(&conn); - }) - .onclose([&](crow::websocket::connection& conn, const std::string& reason){ + users.insert(&conn); }) + .onclose([&](crow::websocket::connection& conn, const std::string& reason) + { CROW_LOG_INFO << "websocket connection closed: " << reason; std::lock_guard _(mtx); - users.erase(&conn); - }) - .onmessage([&](crow::websocket::connection& /*conn*/, const std::string& data, bool is_binary){ + users.erase(&conn); }) + .onmessage([&](crow::websocket::connection& /*conn*/, const std::string& data, bool is_binary) + { std::lock_guard _(mtx); for(auto u:users) if (is_binary) u->send_binary(data); else - u->send_text(data); - }); + u->send_text(data); }); CROW_ROUTE(app, "/") - ([]{ + ([] + { char name[256]; gethostname(name, 256); crow::mustache::context x; x["servername"] = name; auto page = crow::mustache::load("ws.html"); - return page.render(x); - }); + return page.render(x); }); app.port(40080) - .multithreaded() - .run(); + .multithreaded() + .run(); } diff --git a/include/crow/app.h b/include/crow/app.h index 3d2f22fb8..5b21e9488 100644 --- a/include/crow/app.h +++ b/include/crow/app.h @@ -38,63 +38,59 @@ namespace crow #ifdef CROW_ENABLE_SSL using ssl_context_t = boost::asio::ssl::context; #endif - ///The main server application - + /// The main server application /// /// Use `SimpleApp` or `App` - template + template class Crow { public: - ///This crow application + /// This crow application using self_t = Crow; - ///The HTTP server + /// The HTTP server using server_t = Server; #ifdef CROW_ENABLE_SSL - ///An HTTP server that runs on SSL with an SSLAdaptor + /// An HTTP server that runs on SSL with an SSLAdaptor using ssl_server_t = Server; #endif Crow() { } - ///Process an Upgrade request - + /// Process an Upgrade request /// - ///Currently used to upgrrade an HTTP connection to a WebSocket connection - template + /// Currently used to upgrrade an HTTP connection to a WebSocket connection + template void handle_upgrade(const request& req, response& res, Adaptor&& adaptor) { router_.handle_upgrade(req, res, adaptor); } - ///Process the request and generate a response for it + /// Process the request and generate a response for it void handle(const request& req, response& res) { router_.handle(req, res); } - ///Create a dynamic route using a rule (**Use CROW_ROUTE instead**) + /// Create a dynamic route using a rule (**Use CROW_ROUTE instead**) DynamicRule& route_dynamic(std::string&& rule) { return router_.new_rule_dynamic(std::move(rule)); } - ///Create a route using a rule (**Use CROW_ROUTE instead**) - template + /// Create a route using a rule (**Use CROW_ROUTE instead**) + template auto route(std::string&& rule) #ifdef CROW_CAN_USE_CPP17 - -> typename std::invoke_result), - Router, std::string&&>::type + -> typename std::invoke_result), Router, std::string&&>::type #else - -> typename std::result_of)( - Router, std::string&&)>::type + -> typename std::result_of)(Router, std::string&&)>::type #endif { return router_.new_rule_tagged(std::move(rule)); } - ///Create a route for any requests without a proper route (**Use CROW_CATCHALL_ROUTE instead**) + /// Create a route for any requests without a proper route (**Use CROW_CATCHALL_ROUTE instead**) CatchallRule& catchall_route() { return router_.catchall_rule(); @@ -112,7 +108,7 @@ namespace crow return *this; } - ///Set the port that Crow will handle requests on + /// Set the port that Crow will handle requests on self_t& port(std::uint16_t port) { port_ = port; @@ -124,34 +120,35 @@ namespace crow return port_; } - ///Set the connection timeout in seconds (default is 5) + + /// Set the connection timeout in seconds (default is 5) self_t& timeout(std::uint8_t timeout) { timeout_ = timeout; return *this; } - ///Set the server name + /// Set the server name self_t& server_name(std::string server_name) { server_name_ = server_name; return *this; } - ///The IP address that Crow will handle requests on (default is 0.0.0.0) + /// The IP address that Crow will handle requests on (default is 0.0.0.0) self_t& bindaddr(std::string bindaddr) { bindaddr_ = bindaddr; return *this; } - ///Run the server on multiple threads using all available threads + /// Run the server on multiple threads using all available threads self_t& multithreaded() { return concurrency(std::thread::hardware_concurrency()); } - ///Run the server on multiple threads using a specific number + /// Run the server on multiple threads using a specific number self_t& concurrency(std::uint16_t concurrency) { if (concurrency < 1) @@ -160,8 +157,7 @@ namespace crow return *this; } - ///Set the server's log level - + /// Set the server's log level /// /// Possible values are:
/// crow::LogLevel::Debug (0)
@@ -176,7 +172,6 @@ namespace crow } /// Set a response body size (in bytes) beyond which Crow automatically streams responses (Default is 1MiB) - /// /// Any streamed response is unaffected by Crow's timer, and therefore won't timeout before a response is fully sent. self_t& stream_threshold(size_t threshold) @@ -196,9 +191,10 @@ namespace crow return *this; } - ///Set a custom duration and function to run on every tick - template - self_t& tick(Duration d, Func f) { + /// Set a custom duration and function to run on every tick + template + self_t& tick(Duration d, Func f) + { tick_interval_ = std::chrono::duration_cast(d); tick_function_ = f; return *this; @@ -222,22 +218,19 @@ namespace crow return compression_used_; } #endif - ///A wrapper for `validate()` in the router - + /// A wrapper for `validate()` in the router /// - ///Go through the rules, upgrade them if possible, and add them to the list of rules + /// Go through the rules, upgrade them if possible, and add them to the list of rules void validate() { if (!validated_) { #ifndef CROW_DISABLE_STATIC_DIR - route(CROW_STATIC_ENDPOINT) - ([](crow::response& res, std::string file_path_partial) - { + route(CROW_STATIC_ENDPOINT)([](crow::response& res, std::string file_path_partial) + { res.set_static_file_info(CROW_STATIC_DIRECTORY + file_path_partial); - res.end(); - }); + res.end(); }); #if defined(__APPLE__) || defined(__MACH__) if (!router_.blueprints().empty()) @@ -247,12 +240,10 @@ namespace crow { if (!bp->static_dir().empty()) { - bp->new_rule_tagged(CROW_STATIC_ENDPOINT) - ([bp](crow::response& res, std::string file_path_partial) - { + bp->new_rule_tagged(CROW_STATIC_ENDPOINT)([bp](crow::response& res, std::string file_path_partial) + { res.set_static_file_info(bp->static_dir() + '/' + file_path_partial); - res.end(); - }); + res.end(); }); } } } @@ -263,7 +254,7 @@ namespace crow } } - ///Notify anything using `wait_for_server_start()` to proceed + /// Notify anything using `wait_for_server_start()` to proceed void notify_server_start() { std::unique_lock lock(start_mutex_); @@ -271,7 +262,7 @@ namespace crow cv_started_.notify_all(); } - ///Run the server + /// Run the server void run() { @@ -300,22 +291,18 @@ namespace crow } } - ///Stop the server + /// Stop the server void stop() { #ifdef CROW_ENABLE_SSL if (ssl_used_) { - if (ssl_server_) { - ssl_server_->stop(); - } + if (ssl_server_) { ssl_server_->stop(); } } else #endif { - if (server_) { - server_->stop(); - } + if (server_) { server_->stop(); } } } @@ -328,7 +315,7 @@ namespace crow #ifdef CROW_ENABLE_SSL - ///use certificate and key files for SSL + /// use certificate and key files for SSL self_t& ssl_file(const std::string& crt_filename, const std::string& key_filename) { ssl_used_ = true; @@ -337,14 +324,11 @@ namespace crow ssl_context_.use_certificate_file(crt_filename, ssl_context_t::pem); ssl_context_.use_private_key_file(key_filename, ssl_context_t::pem); ssl_context_.set_options( - boost::asio::ssl::context::default_workarounds - | boost::asio::ssl::context::no_sslv2 - | boost::asio::ssl::context::no_sslv3 - ); + boost::asio::ssl::context::default_workarounds | boost::asio::ssl::context::no_sslv2 | boost::asio::ssl::context::no_sslv3); return *this; } - ///use .pem file for SSL + /// use .pem file for SSL self_t& ssl_file(const std::string& pem_filename) { ssl_used_ = true; @@ -352,10 +336,7 @@ namespace crow ssl_context_.set_verify_mode(boost::asio::ssl::verify_client_once); ssl_context_.load_verify_file(pem_filename); ssl_context_.set_options( - boost::asio::ssl::context::default_workarounds - | boost::asio::ssl::context::no_sslv2 - | boost::asio::ssl::context::no_sslv3 - ); + boost::asio::ssl::context::default_workarounds | boost::asio::ssl::context::no_sslv2 | boost::asio::ssl::context::no_sslv3); return *this; } @@ -371,25 +352,25 @@ namespace crow return ssl_used_; } #else - template + template self_t& ssl_file(T&&, Remain&&...) { // We can't call .ssl() member function unless CROW_ENABLE_SSL is defined. static_assert( - // make static_assert dependent to T; always false - std::is_base_of::value, - "Define CROW_ENABLE_SSL to enable ssl support."); + // make static_assert dependent to T; always false + std::is_base_of::value, + "Define CROW_ENABLE_SSL to enable ssl support."); return *this; } - template + template self_t& ssl(T&&) { // We can't call .ssl() member function unless CROW_ENABLE_SSL is defined. static_assert( - // make static_assert dependent to T; always false - std::is_base_of::value, - "Define CROW_ENABLE_SSL to enable ssl support."); + // make static_assert dependent to T; always false + std::is_base_of::value, + "Define CROW_ENABLE_SSL to enable ssl support."); return *this; } @@ -401,7 +382,7 @@ namespace crow // middleware using context_t = detail::context; - template + template typename T::context& get_context(const request& req) { static_assert(black_magic::contains::value, "App doesn't have the specified middleware type."); @@ -409,13 +390,13 @@ namespace crow return ctx.template get(); } - template + template T& get_middleware() { return utility::get_element_by_type(middlewares_); } - ///Wait until the server has properly started + /// Wait until the server has properly started void wait_for_server_start() { std::unique_lock lock(start_mutex_); @@ -458,7 +439,7 @@ namespace crow std::condition_variable cv_started_; std::mutex start_mutex_; }; - template + template using App = Crow; using SimpleApp = Crow<>; -} +} // namespace crow diff --git a/include/crow/ci_map.h b/include/crow/ci_map.h index 4bf055ff1..d9463f225 100644 --- a/include/crow/ci_map.h +++ b/include/crow/ci_map.h @@ -14,7 +14,7 @@ namespace crow std::size_t seed = 0; std::locale locale; - for(auto c : key) + for (auto c : key) { boost::hash_combine(seed, std::toupper(c, locale)); } @@ -33,4 +33,4 @@ namespace crow }; using ci_map = std::unordered_multimap; -} +} // namespace crow diff --git a/include/crow/common.h b/include/crow/common.h index 9acc1caad..b657daa76 100644 --- a/include/crow/common.h +++ b/include/crow/common.h @@ -39,6 +39,8 @@ namespace crow // should not add an item below this line: used for array count }; + // clang-format off + enum status { CONTINUE = 100, @@ -87,32 +89,23 @@ namespace crow { switch(method) { - case HTTPMethod::Delete: - return "DELETE"; - case HTTPMethod::Get: - return "GET"; - case HTTPMethod::Head: - return "HEAD"; - case HTTPMethod::Post: - return "POST"; - case HTTPMethod::Put: - return "PUT"; - case HTTPMethod::Connect: - return "CONNECT"; - case HTTPMethod::Options: - return "OPTIONS"; - case HTTPMethod::Trace: - return "TRACE"; - case HTTPMethod::Patch: - return "PATCH"; - case HTTPMethod::Purge: - return "PURGE"; - default: - return "invalid"; + case HTTPMethod::Delete: return "DELETE"; + case HTTPMethod::Get: return "GET"; + case HTTPMethod::Head: return "HEAD"; + case HTTPMethod::Post: return "POST"; + case HTTPMethod::Put: return "PUT"; + case HTTPMethod::Connect: return "CONNECT"; + case HTTPMethod::Options: return "OPTIONS"; + case HTTPMethod::Trace: return "TRACE"; + case HTTPMethod::Patch: return "PATCH"; + case HTTPMethod::Purge: return "PURGE"; + default: return "invalid"; } return "invalid"; } + // clang-format on + enum class ParamType : char { INT, @@ -134,23 +127,22 @@ namespace crow void debug_print() const { std::cerr << "routing_params" << std::endl; - for(auto i:int_params) - std::cerr< + template T get(unsigned) const; - }; template<> @@ -176,22 +168,21 @@ namespace crow { return string_params[index]; } -} +} // namespace crow #ifndef CROW_MSVC_WORKAROUND -constexpr crow::HTTPMethod operator "" _method(const char* str, size_t /*len*/) +constexpr crow::HTTPMethod operator"" _method(const char* str, size_t /*len*/) { - return - crow::black_magic::is_equ_p(str, "GET", 3) ? crow::HTTPMethod::Get : - crow::black_magic::is_equ_p(str, "DELETE", 6) ? crow::HTTPMethod::Delete : - crow::black_magic::is_equ_p(str, "HEAD", 4) ? crow::HTTPMethod::Head : - crow::black_magic::is_equ_p(str, "POST", 4) ? crow::HTTPMethod::Post : - crow::black_magic::is_equ_p(str, "PUT", 3) ? crow::HTTPMethod::Put : - crow::black_magic::is_equ_p(str, "OPTIONS", 7) ? crow::HTTPMethod::Options : - crow::black_magic::is_equ_p(str, "CONNECT", 7) ? crow::HTTPMethod::Connect : - crow::black_magic::is_equ_p(str, "TRACE", 5) ? crow::HTTPMethod::Trace : - crow::black_magic::is_equ_p(str, "PATCH", 5) ? crow::HTTPMethod::Patch : - crow::black_magic::is_equ_p(str, "PURGE", 5) ? crow::HTTPMethod::Purge : - throw std::runtime_error("invalid http method"); + return crow::black_magic::is_equ_p(str, "GET", 3) ? crow::HTTPMethod::Get : + crow::black_magic::is_equ_p(str, "DELETE", 6) ? crow::HTTPMethod::Delete : + crow::black_magic::is_equ_p(str, "HEAD", 4) ? crow::HTTPMethod::Head : + crow::black_magic::is_equ_p(str, "POST", 4) ? crow::HTTPMethod::Post : + crow::black_magic::is_equ_p(str, "PUT", 3) ? crow::HTTPMethod::Put : + crow::black_magic::is_equ_p(str, "OPTIONS", 7) ? crow::HTTPMethod::Options : + crow::black_magic::is_equ_p(str, "CONNECT", 7) ? crow::HTTPMethod::Connect : + crow::black_magic::is_equ_p(str, "TRACE", 5) ? crow::HTTPMethod::Trace : + crow::black_magic::is_equ_p(str, "PATCH", 5) ? crow::HTTPMethod::Patch : + crow::black_magic::is_equ_p(str, "PURGE", 5) ? crow::HTTPMethod::Purge : + throw std::runtime_error("invalid http method"); } #endif diff --git a/include/crow/compression.h b/include/crow/compression.h index 25d4f1849..c33cb426e 100644 --- a/include/crow/compression.h +++ b/include/crow/compression.h @@ -16,10 +16,10 @@ namespace crow DEFLATE = 15, // windowBits can also be greater than 15 for optional gzip encoding. // Add 16 to windowBits to write a simple gzip header and trailer around the compressed data instead of a zlib wrapper. - GZIP = 15|16, + GZIP = 15 | 16, }; - inline std::string compress_string(std::string const & str, algorithm algo) + inline std::string compress_string(std::string const& str, algorithm algo) { std::string compressed_str; z_stream stream{}; @@ -30,13 +30,13 @@ namespace crow stream.avail_in = str.size(); // zlib does not take a const pointer. The data is not altered. - stream.next_in = const_cast(reinterpret_cast(str.c_str())); + stream.next_in = const_cast(reinterpret_cast(str.c_str())); int code = Z_OK; do { stream.avail_out = sizeof(buffer); - stream.next_out = reinterpret_cast(&buffer[0]); + stream.next_out = reinterpret_cast(&buffer[0]); code = ::deflate(&stream, Z_FINISH); // Successful and non-fatal error code returned by deflate when used with Z_FINISH flush @@ -56,7 +56,7 @@ namespace crow return compressed_str; } - inline std::string decompress_string(std::string const & deflated_string) + inline std::string decompress_string(std::string const& deflated_string) { std::string inflated_string; Bytef tmp[8192]; @@ -64,7 +64,7 @@ namespace crow z_stream zstream{}; zstream.avail_in = deflated_string.size(); // Nasty const_cast but zlib won't alter its contents - zstream.next_in = const_cast(reinterpret_cast(deflated_string.c_str())); + zstream.next_in = const_cast(reinterpret_cast(deflated_string.c_str())); // Initialize with automatic header detection, for gzip support if (::inflateInit2(&zstream, MAX_WBITS | 32) == Z_OK) { @@ -93,7 +93,7 @@ namespace crow return inflated_string; } - } -} + } // namespace compression +} // namespace crow #endif diff --git a/include/crow/http_connection.h b/include/crow/http_connection.h index 306412329..c32090cb6 100644 --- a/include/crow/http_connection.h +++ b/include/crow/http_connection.h @@ -8,7 +8,6 @@ #include #include "crow/http_parser_merged.h" - #include "crow/common.h" #include "crow/parser.h" #include "crow/http_response.h" @@ -26,110 +25,106 @@ namespace crow namespace detail { - template + template struct check_before_handle_arity_3_const { - template + template struct get - { }; + { + }; }; - template + template struct check_before_handle_arity_3 { - template + template struct get - { }; + { + }; }; - template + template struct check_after_handle_arity_3_const { - template + template struct get - { }; + { + }; }; - template + template struct check_after_handle_arity_3 { - template + template struct get - { }; + { + }; }; - template + template struct is_before_handle_arity_3_impl { - template + template static std::true_type f(typename check_before_handle_arity_3_const::template get*); - template + template static std::true_type f(typename check_before_handle_arity_3::template get*); - template + template static std::false_type f(...); public: static const bool value = decltype(f(nullptr))::value; }; - template + template struct is_after_handle_arity_3_impl { - template + template static std::true_type f(typename check_after_handle_arity_3_const::template get*); - template + template static std::true_type f(typename check_after_handle_arity_3::template get*); - template + template static std::false_type f(...); public: static const bool value = decltype(f(nullptr))::value; }; - template + template typename std::enable_if::value>::type - before_handler_call(MW& mw, request& req, response& res, Context& ctx, ParentContext& /*parent_ctx*/) + before_handler_call(MW& mw, request& req, response& res, Context& ctx, ParentContext& /*parent_ctx*/) { mw.before_handle(req, res, ctx.template get(), ctx); } - template + template typename std::enable_if::value>::type - before_handler_call(MW& mw, request& req, response& res, Context& ctx, ParentContext& /*parent_ctx*/) + before_handler_call(MW& mw, request& req, response& res, Context& ctx, ParentContext& /*parent_ctx*/) { mw.before_handle(req, res, ctx.template get()); } - template + template typename std::enable_if::value>::type - after_handler_call(MW& mw, request& req, response& res, Context& ctx, ParentContext& /*parent_ctx*/) + after_handler_call(MW& mw, request& req, response& res, Context& ctx, ParentContext& /*parent_ctx*/) { mw.after_handle(req, res, ctx.template get(), ctx); } - template + template typename std::enable_if::value>::type - after_handler_call(MW& mw, request& req, response& res, Context& ctx, ParentContext& /*parent_ctx*/) + after_handler_call(MW& mw, request& req, response& res, Context& ctx, ParentContext& /*parent_ctx*/) { mw.after_handle(req, res, ctx.template get()); } - template + template bool middleware_call_helper(Container& middlewares, request& req, response& res, Context& ctx) { - using parent_context_t = typename Context::template partial; + using parent_context_t = typename Context::template partial; before_handler_call(std::get(middlewares), req, res, ctx, static_cast(ctx)); if (res.is_completed()) @@ -138,7 +133,7 @@ namespace crow return true; } - if (middleware_call_helper(middlewares, req, res, ctx)) + if (middleware_call_helper(middlewares, req, res, ctx)) { after_handler_call(std::get(middlewares), req, res, ctx, static_cast(ctx)); return true; @@ -147,76 +142,76 @@ namespace crow return false; } - template + template bool middleware_call_helper(Container& /*middlewares*/, request& /*req*/, response& /*res*/, Context& /*ctx*/) { return false; } - template - typename std::enable_if<(N<0)>::type - after_handlers_call_helper(Container& /*middlewares*/, Context& /*context*/, request& /*req*/, response& /*res*/) + template + typename std::enable_if<(N < 0)>::type + after_handlers_call_helper(Container& /*middlewares*/, Context& /*context*/, request& /*req*/, response& /*res*/) { } - template - typename std::enable_if<(N==0)>::type after_handlers_call_helper(Container& middlewares, Context& ctx, request& req, response& res) + template + typename std::enable_if<(N == 0)>::type after_handlers_call_helper(Container& middlewares, Context& ctx, request& req, response& res) { - using parent_context_t = typename Context::template partial; + using parent_context_t = typename Context::template partial; using CurrentMW = typename std::tuple_element::type>::type; after_handler_call(std::get(middlewares), req, res, ctx, static_cast(ctx)); } - template - typename std::enable_if<(N>0)>::type after_handlers_call_helper(Container& middlewares, Context& ctx, request& req, response& res) + template + typename std::enable_if<(N > 0)>::type after_handlers_call_helper(Container& middlewares, Context& ctx, request& req, response& res) { - using parent_context_t = typename Context::template partial; + using parent_context_t = typename Context::template partial; using CurrentMW = typename std::tuple_element::type>::type; after_handler_call(std::get(middlewares), req, res, ctx, static_cast(ctx)); - after_handlers_call_helper(middlewares, ctx, req, res); + after_handlers_call_helper(middlewares, ctx, req, res); } - } + } // namespace detail #ifdef CROW_ENABLE_DEBUG static std::atomic connectionCount; #endif /// An HTTP connection. - template + template class Connection { friend struct crow::response; + public: Connection( - boost::asio::io_service& io_service, - Handler* handler, - const std::string& server_name, - std::tuple* middlewares, - std::function& get_cached_date_str_f, - detail::task_timer& task_timer, - typename Adaptor::context* adaptor_ctx_ - ) - : adaptor_(io_service, adaptor_ctx_), - handler_(handler), - parser_(this), - server_name_(server_name), - middlewares_(middlewares), - get_cached_date_str(get_cached_date_str_f), - task_timer_(task_timer), - res_stream_threshold_(handler->stream_threshold()) + boost::asio::io_service& io_service, + Handler* handler, + const std::string& server_name, + std::tuple* middlewares, + std::function& get_cached_date_str_f, + detail::task_timer& task_timer, + typename Adaptor::context* adaptor_ctx_): + adaptor_(io_service, adaptor_ctx_), + handler_(handler), + parser_(this), + server_name_(server_name), + middlewares_(middlewares), + get_cached_date_str(get_cached_date_str_f), + task_timer_(task_timer), + res_stream_threshold_(handler->stream_threshold()) { #ifdef CROW_ENABLE_DEBUG - connectionCount ++; + connectionCount++; CROW_LOG_DEBUG << "Connection open, total " << connectionCount << ", " << this; #endif } - + ~Connection() { res.complete_request_handler_ = nullptr; cancel_deadline_timer(); #ifdef CROW_ENABLE_DEBUG - connectionCount --; + connectionCount--; CROW_LOG_DEBUG << "Connection closed, total " << connectionCount << ", " << this; #endif } @@ -229,7 +224,8 @@ namespace crow void start() { - adaptor_.start([this](const boost::system::error_code& ec) { + adaptor_.start([this](const boost::system::error_code& ec) + { if (!ec) { start_deadline(); @@ -240,8 +236,7 @@ namespace crow { CROW_LOG_ERROR << "Could not start adaptor: " << ec.message(); check_destroy(); - } - }); + } }); } void handle_header() @@ -272,7 +267,7 @@ namespace crow // HTTP/1.0 if (req.headers.count("connection")) { - if (boost::iequals(req.get_header_value("connection"),"Keep-Alive")) + if (boost::iequals(req.get_header_value("connection"), "Keep-Alive")) add_keep_alive_ = true; } else @@ -285,7 +280,7 @@ namespace crow { if (req.get_header_value("connection") == "close") close_connection_ = true; - else if (boost::iequals(req.get_header_value("connection"),"Keep-Alive")) + else if (boost::iequals(req.get_header_value("connection"), "Keep-Alive")) add_keep_alive_ = true; } if (!req.headers.count("host")) @@ -293,31 +288,32 @@ namespace crow is_invalid_request = true; res = response(400); } - if (parser_.is_upgrade()) - { - if (req.get_header_value("upgrade") == "h2c") - { - // TODO HTTP/2 + if (parser_.is_upgrade()) + { + if (req.get_header_value("upgrade") == "h2c") + { + // TODO HTTP/2 // currently, ignore upgrade header - } + } else { close_connection_ = true; handler_->handle_upgrade(req, res, std::move(adaptor_)); return; } - } + } } CROW_LOG_INFO << "Request: " << boost::lexical_cast(adaptor_.remote_endpoint()) << " " << this << " HTTP/" << parser_.http_major << "." << parser_.http_minor << ' ' - << method_name(req.method) << " " << req.url; + << method_name(req.method) << " " << req.url; need_to_call_after_handlers_ = false; if (!is_invalid_request) { - res.complete_request_handler_ = []{}; - res.is_alive_helper_ = [this]()->bool{ return adaptor_.is_open(); }; + res.complete_request_handler_ = [] {}; + res.is_alive_helper_ = [this]() -> bool + { return adaptor_.is_open(); }; ctx_ = detail::context(); req.middleware_context = static_cast(&ctx_); @@ -326,7 +322,8 @@ namespace crow if (!res.completed_) { - res.complete_request_handler_ = [this]{ this->complete_request(); }; + res.complete_request_handler_ = [this] + { this->complete_request(); }; need_to_call_after_handlers_ = true; handler_->handle(req, res); if (add_keep_alive_) @@ -354,13 +351,13 @@ namespace crow // call all after_handler of middlewares detail::after_handlers_call_helper< - (static_cast(sizeof...(Middlewares))-1), - decltype(ctx_), - decltype(*middlewares_)> - (*middlewares_, ctx_, req_, res); + (static_cast(sizeof...(Middlewares)) - 1), + decltype(ctx_), + decltype(*middlewares_)>(*middlewares_, ctx_, req_, res); } #ifdef CROW_ENABLE_COMPRESSION - if (handler_->compression_used()) { + if (handler_->compression_used()) + { std::string accept_encoding = req_.get_header_value("Accept-Encoding"); if (!accept_encoding.empty() && res.compressed) { @@ -390,28 +387,28 @@ namespace crow std::string location = res.get_header_value("Location"); if (!location.empty() && location.find("://", 0) == std::string::npos) { - #ifdef CROW_ENABLE_SSL +#ifdef CROW_ENABLE_SSL if (handler_->ssl_used()) location.insert(0, "https://" + req_.get_header_value("Host")); else - #endif - location.insert(0, "http://" + req_.get_header_value("Host")); +#endif + location.insert(0, "http://" + req_.get_header_value("Host")); res.set_header("location", location); } - prepare_buffers(); + prepare_buffers(); if (res.is_static_type()) { do_write_static(); - }else { + } + else + { do_write_general(); } - } private: - void prepare_buffers() { //auto self = this->shared_from_this(); @@ -426,53 +423,53 @@ namespace crow // Keep in sync with common.h/status static std::unordered_map statusCodes = { - {status::CONTINUE, "HTTP/1.1 100 Continue\r\n"}, - {status::SWITCHING_PROTOCOLS, "HTTP/1.1 101 Switching Protocols\r\n"}, + {status::CONTINUE, "HTTP/1.1 100 Continue\r\n"}, + {status::SWITCHING_PROTOCOLS, "HTTP/1.1 101 Switching Protocols\r\n"}, - {status::OK, "HTTP/1.1 200 OK\r\n"}, - {status::CREATED, "HTTP/1.1 201 Created\r\n"}, - {status::ACCEPTED, "HTTP/1.1 202 Accepted\r\n"}, - {status::NON_AUTHORITATIVE_INFORMATION, "HTTP/1.1 203 Non-Authoritative Information\r\n"}, - {status::NO_CONTENT, "HTTP/1.1 204 No Content\r\n"}, - {status::RESET_CONTENT, "HTTP/1.1 205 Reset Content\r\n"}, - {status::PARTIAL_CONTENT, "HTTP/1.1 206 Partial Content\r\n"}, + {status::OK, "HTTP/1.1 200 OK\r\n"}, + {status::CREATED, "HTTP/1.1 201 Created\r\n"}, + {status::ACCEPTED, "HTTP/1.1 202 Accepted\r\n"}, + {status::NON_AUTHORITATIVE_INFORMATION, "HTTP/1.1 203 Non-Authoritative Information\r\n"}, + {status::NO_CONTENT, "HTTP/1.1 204 No Content\r\n"}, + {status::RESET_CONTENT, "HTTP/1.1 205 Reset Content\r\n"}, + {status::PARTIAL_CONTENT, "HTTP/1.1 206 Partial Content\r\n"}, - {status::MULTIPLE_CHOICES, "HTTP/1.1 300 Multiple Choices\r\n"}, - {status::MOVED_PERMANENTLY, "HTTP/1.1 301 Moved Permanently\r\n"}, - {status::FOUND, "HTTP/1.1 302 Found\r\n"}, - {status::SEE_OTHER, "HTTP/1.1 303 See Other\r\n"}, - {status::NOT_MODIFIED, "HTTP/1.1 304 Not Modified\r\n"}, - {status::TEMPORARY_REDIRECT, "HTTP/1.1 307 Temporary Redirect\r\n"}, - {status::PERMANENT_REDIRECT, "HTTP/1.1 308 Permanent Redirect\r\n"}, + {status::MULTIPLE_CHOICES, "HTTP/1.1 300 Multiple Choices\r\n"}, + {status::MOVED_PERMANENTLY, "HTTP/1.1 301 Moved Permanently\r\n"}, + {status::FOUND, "HTTP/1.1 302 Found\r\n"}, + {status::SEE_OTHER, "HTTP/1.1 303 See Other\r\n"}, + {status::NOT_MODIFIED, "HTTP/1.1 304 Not Modified\r\n"}, + {status::TEMPORARY_REDIRECT, "HTTP/1.1 307 Temporary Redirect\r\n"}, + {status::PERMANENT_REDIRECT, "HTTP/1.1 308 Permanent Redirect\r\n"}, - {status::BAD_REQUEST, "HTTP/1.1 400 Bad Request\r\n"}, - {status::UNAUTHORIZED, "HTTP/1.1 401 Unauthorized\r\n"}, - {status::FORBIDDEN, "HTTP/1.1 403 Forbidden\r\n"}, - {status::NOT_FOUND, "HTTP/1.1 404 Not Found\r\n"}, - {status::METHOD_NOT_ALLOWED, "HTTP/1.1 405 Method Not Allowed\r\n"}, - {status::PROXY_AUTHENTICATION_REQUIRED, "HTTP/1.1 407 Proxy Authentication Required\r\n"}, - {status::CONFLICT, "HTTP/1.1 409 Conflict\r\n"}, - {status::GONE, "HTTP/1.1 410 Gone\r\n"}, - {status::PAYLOAD_TOO_LARGE, "HTTP/1.1 413 Payload Too Large\r\n"}, - {status::UNSUPPORTED_MEDIA_TYPE, "HTTP/1.1 415 Unsupported Media Type\r\n"}, - {status::RANGE_NOT_SATISFIABLE, "HTTP/1.1 416 Range Not Satisfiable\r\n"}, - {status::EXPECTATION_FAILED, "HTTP/1.1 417 Expectation Failed\r\n"}, - {status::PRECONDITION_REQUIRED, "HTTP/1.1 428 Precondition Required\r\n"}, - {status::TOO_MANY_REQUESTS, "HTTP/1.1 429 Too Many Requests\r\n"}, - {status::UNAVAILABLE_FOR_LEGAL_REASONS, "HTTP/1.1 451 Unavailable For Legal Reasons\r\n"}, + {status::BAD_REQUEST, "HTTP/1.1 400 Bad Request\r\n"}, + {status::UNAUTHORIZED, "HTTP/1.1 401 Unauthorized\r\n"}, + {status::FORBIDDEN, "HTTP/1.1 403 Forbidden\r\n"}, + {status::NOT_FOUND, "HTTP/1.1 404 Not Found\r\n"}, + {status::METHOD_NOT_ALLOWED, "HTTP/1.1 405 Method Not Allowed\r\n"}, + {status::PROXY_AUTHENTICATION_REQUIRED, "HTTP/1.1 407 Proxy Authentication Required\r\n"}, + {status::CONFLICT, "HTTP/1.1 409 Conflict\r\n"}, + {status::GONE, "HTTP/1.1 410 Gone\r\n"}, + {status::PAYLOAD_TOO_LARGE, "HTTP/1.1 413 Payload Too Large\r\n"}, + {status::UNSUPPORTED_MEDIA_TYPE, "HTTP/1.1 415 Unsupported Media Type\r\n"}, + {status::RANGE_NOT_SATISFIABLE, "HTTP/1.1 416 Range Not Satisfiable\r\n"}, + {status::EXPECTATION_FAILED, "HTTP/1.1 417 Expectation Failed\r\n"}, + {status::PRECONDITION_REQUIRED, "HTTP/1.1 428 Precondition Required\r\n"}, + {status::TOO_MANY_REQUESTS, "HTTP/1.1 429 Too Many Requests\r\n"}, + {status::UNAVAILABLE_FOR_LEGAL_REASONS, "HTTP/1.1 451 Unavailable For Legal Reasons\r\n"}, - {status::INTERNAL_SERVER_ERROR, "HTTP/1.1 500 Internal Server Error\r\n"}, - {status::NOT_IMPLEMENTED, "HTTP/1.1 501 Not Implemented\r\n"}, - {status::BAD_GATEWAY, "HTTP/1.1 502 Bad Gateway\r\n"}, - {status::SERVICE_UNAVAILABLE, "HTTP/1.1 503 Service Unavailable\r\n"}, - {status::VARIANT_ALSO_NEGOTIATES, "HTTP/1.1 506 Variant Also Negotiates\r\n"}, + {status::INTERNAL_SERVER_ERROR, "HTTP/1.1 500 Internal Server Error\r\n"}, + {status::NOT_IMPLEMENTED, "HTTP/1.1 501 Not Implemented\r\n"}, + {status::BAD_GATEWAY, "HTTP/1.1 502 Bad Gateway\r\n"}, + {status::SERVICE_UNAVAILABLE, "HTTP/1.1 503 Service Unavailable\r\n"}, + {status::VARIANT_ALSO_NEGOTIATES, "HTTP/1.1 506 Variant Also Negotiates\r\n"}, }; static std::string seperator = ": "; static std::string crlf = "\r\n"; buffers_.clear(); - buffers_.reserve(4*(res.headers.size()+5)+3); + buffers_.reserve(4 * (res.headers.size() + 5) + 3); if (!statusCodes.count(res.code)) res.code = 500; @@ -484,13 +481,12 @@ namespace crow if (res.code >= 400 && res.body.empty()) res.body = statusCodes[res.code].substr(9); - for(auto& kv : res.headers) + for (auto& kv : res.headers) { buffers_.emplace_back(kv.first.data(), kv.first.size()); buffers_.emplace_back(seperator.data(), seperator.size()); buffers_.emplace_back(kv.second.data(), kv.second.size()); buffers_.emplace_back(crlf.data(), crlf.size()); - } if (!res.manual_length_header && !res.headers.count("content-length")) @@ -524,7 +520,6 @@ namespace crow } buffers_.emplace_back(crlf.data(), crlf.size()); - } void do_write_static() @@ -570,76 +565,78 @@ namespace crow { //auto self = this->shared_from_this(); is_reading = true; - adaptor_.socket().async_read_some(boost::asio::buffer(buffer_), - [this](const boost::system::error_code& ec, std::size_t bytes_transferred) - { - bool error_while_reading = true; - if (!ec) - { - bool ret = parser_.feed(buffer_.data(), bytes_transferred); - if (ret && adaptor_.is_open()) - { - error_while_reading = false; - } - } + adaptor_.socket().async_read_some( + boost::asio::buffer(buffer_), + [this](const boost::system::error_code& ec, std::size_t bytes_transferred) + { + bool error_while_reading = true; + if (!ec) + { + bool ret = parser_.feed(buffer_.data(), bytes_transferred); + if (ret && adaptor_.is_open()) + { + error_while_reading = false; + } + } - if (error_while_reading) - { - cancel_deadline_timer(); - parser_.done(); - adaptor_.shutdown_read(); - adaptor_.close(); - is_reading = false; - CROW_LOG_DEBUG << this << " from read(1)"; - check_destroy(); - } - else if (close_connection_) - { - cancel_deadline_timer(); - parser_.done(); - is_reading = false; - check_destroy(); - // adaptor will close after write - } - else if (!need_to_call_after_handlers_) - { - start_deadline(); - do_read(); - } - else - { - // res will be completed later by user - need_to_start_read_after_complete_ = true; - } - }); + if (error_while_reading) + { + cancel_deadline_timer(); + parser_.done(); + adaptor_.shutdown_read(); + adaptor_.close(); + is_reading = false; + CROW_LOG_DEBUG << this << " from read(1)"; + check_destroy(); + } + else if (close_connection_) + { + cancel_deadline_timer(); + parser_.done(); + is_reading = false; + check_destroy(); + // adaptor will close after write + } + else if (!need_to_call_after_handlers_) + { + start_deadline(); + do_read(); + } + else + { + // res will be completed later by user + need_to_start_read_after_complete_ = true; + } + }); } void do_write() { //auto self = this->shared_from_this(); is_writing = true; - boost::asio::async_write(adaptor_.socket(), buffers_, - [&](const boost::system::error_code& ec, std::size_t /*bytes_transferred*/) - { - is_writing = false; - res.clear(); - res_body_copy_.clear(); - if (!ec) - { - if (close_connection_) - { - adaptor_.shutdown_write(); - adaptor_.close(); - CROW_LOG_DEBUG << this << " from write(1)"; - check_destroy(); - } - } - else - { - CROW_LOG_DEBUG << this << " from write(2)"; - check_destroy(); - } - }); + boost::asio::async_write( + adaptor_.socket(), buffers_, + [&](const boost::system::error_code& ec, std::size_t /*bytes_transferred*/) + { + is_writing = false; + res.clear(); + res_body_copy_.clear(); + if (!ec) + { + if (close_connection_) + { + adaptor_.shutdown_write(); + adaptor_.close(); + CROW_LOG_DEBUG << this << " from write(1)"; + check_destroy(); + } + } + else + { + CROW_LOG_DEBUG << this << " from write(2)"; + check_destroy(); + } + }); } void check_destroy() @@ -663,14 +660,13 @@ namespace crow cancel_deadline_timer(); task_id_ = task_timer_.schedule([this] - { + { if (!adaptor_.is_open()) { return; } adaptor_.shutdown_readwrite(); - adaptor_.close(); - }); + adaptor_.close(); }); CROW_LOG_DEBUG << this << " timer added: " << &task_timer_ << ' ' << task_id_; } @@ -710,4 +706,4 @@ namespace crow size_t res_stream_threshold_; }; -} +} // namespace crow diff --git a/include/crow/http_request.h b/include/crow/http_request.h index fbd002669..768540ed7 100644 --- a/include/crow/http_request.h +++ b/include/crow/http_request.h @@ -9,7 +9,7 @@ namespace crow { /// Find and return the value associated with the key. (returns an empty string if nothing is found) - template + template inline const std::string& get_header_value(const T& headers, const std::string& key) { if (headers.count(key)) @@ -20,14 +20,14 @@ namespace crow return empty; } - struct DetachHelper; + struct DetachHelper; /// An HTTP request. struct request { HTTPMethod method; - std::string raw_url; ///< The full URL containing the `?` and URL parameters. - std::string url; ///< The endpoint without any parameters. + std::string raw_url; ///< The full URL containing the `?` and URL parameters. + std::string url; ///< The endpoint without any parameters. query_string url_params; ///< The parameters associated with the request. (everything after the `?`) ci_map headers; std::string body; @@ -37,14 +37,14 @@ namespace crow boost::asio::io_service* io_service{}; /// Construct an empty request. (sets the method to `GET`) - request() - : method(HTTPMethod::Get) + request(): + method(HTTPMethod::Get) { } /// Construct a request with all values assigned. - request(HTTPMethod method, std::string raw_url, std::string url, query_string url_params, ci_map headers, std::string body) - : method(method), raw_url(std::move(raw_url)), url(std::move(url)), url_params(std::move(url_params)), headers(std::move(headers)), body(std::move(body)) + request(HTTPMethod method, std::string raw_url, std::string url, query_string url_params, ci_map headers, std::string body): + method(method), raw_url(std::move(raw_url)), url(std::move(url)), url_params(std::move(url_params)), headers(std::move(headers)), body(std::move(body)) { } @@ -71,6 +71,5 @@ namespace crow { io_service->dispatch(handler); } - }; -} +} // namespace crow diff --git a/include/crow/http_response.h b/include/crow/http_response.h index aad683acd..d00426b20 100644 --- a/include/crow/http_response.h +++ b/include/crow/http_response.h @@ -16,23 +16,23 @@ namespace crow { - template + template class Connection; /// HTTP response struct response { - template + template friend class crow::Connection; - int code{200}; ///< The Status code for the response. + int code{200}; ///< The Status code for the response. std::string body; ///< The actual payload containing the response data. - ci_map headers; ///< HTTP headers. + ci_map headers; ///< HTTP headers. #ifdef CROW_ENABLE_COMPRESSION bool compressed = true; ///< If compression is enabled and this is false, the individual response will not be compressed. #endif - bool is_head_response = false; ///< Whether this is a response to a HEAD request. + bool is_head_response = false; ///< Whether this is a response to a HEAD request. bool manual_length_header = false; ///< Whether Crow should automatically add a "Content-Length" header. /// Set the value of an existing header in the response. @@ -53,25 +53,28 @@ namespace crow return crow::get_header_value(headers, key); } - + // TODO find a better way to format this so that stuff aren't moved down a line + // clang-format off response() {} explicit response(int code) : code(code) {} response(std::string body) : body(std::move(body)) {} response(int code, std::string body) : code(code), body(std::move(body)) {} - response (returnable&& value) + // clang-format on + response(returnable&& value) { body = value.dump(); - set_header("Content-Type",value.content_type); + set_header("Content-Type", value.content_type); } - response (returnable& value) + response(returnable& value) { body = value.dump(); - set_header("Content-Type",value.content_type); + set_header("Content-Type", value.content_type); } - response (int code, returnable& value) : code(code) + response(int code, returnable& value): + code(code) { body = value.dump(); - set_header("Content-Type",value.content_type); + set_header("Content-Type", value.content_type); } response(response&& r) @@ -79,19 +82,21 @@ namespace crow *this = std::move(r); } - response(std::string contentType, std::string body) : body(std::move(body)) + response(std::string contentType, std::string body): + body(std::move(body)) { set_header("Content-Type", mime_types.at(contentType)); } - response(int code, std::string contentType, std::string body): code(code),body(std::move(body)) + response(int code, std::string contentType, std::string body): + code(code), body(std::move(body)) { set_header("Content-Type", mime_types.at(contentType)); } - response& operator = (const response& r) = delete; + response& operator=(const response& r) = delete; - response& operator = (response&& r) noexcept + response& operator=(response&& r) noexcept { body = std::move(r.body); code = r.code; @@ -196,17 +201,18 @@ namespace crow } /// This constains metadata (coming from the `stat` command) related to any static files associated with this response. - - /// Either a static file or a string body can be returned as 1 response. /// - struct static_file_info{ + /// Either a static file or a string body can be returned as 1 response. + struct static_file_info + { std::string path = ""; struct stat statbuf; int statResult; }; ///Return a static file as the response body - void set_static_file_info(std::string path){ + void set_static_file_info(std::string path) + { file_info.path = path; file_info.statResult = stat(file_info.path.c_str(), &file_info.statbuf); #ifdef CROW_ENABLE_COMPRESSION @@ -215,17 +221,18 @@ namespace crow if (file_info.statResult == 0) { std::size_t last_dot = path.find_last_of("."); - std::string extension = path.substr(last_dot+1); + std::string extension = path.substr(last_dot + 1); std::string mimeType = ""; code = 200; this->add_header("Content-length", std::to_string(file_info.statbuf.st_size)); - if (extension != ""){ + if (extension != "") + { mimeType = mime_types.at(extension); if (mimeType != "") - this-> add_header("Content-Type", mimeType); + this->add_header("Content-Type", mimeType); else - this-> add_header("content-Type", "text/plain"); + this->add_header("content-Type", "text/plain"); } } else @@ -256,58 +263,58 @@ namespace crow } } - private: - bool completed_{}; - std::function complete_request_handler_; - std::function is_alive_helper_; - static_file_info file_info; + private: + bool completed_{}; + std::function complete_request_handler_; + std::function is_alive_helper_; + static_file_info file_info; - template - void write_streamed(Stream& is, Adaptor& adaptor) + template + void write_streamed(Stream& is, Adaptor& adaptor) + { + char buf[16384]; + while (is.read(buf, sizeof(buf)).gcount() > 0) { - char buf[16384]; - while (is.read(buf, sizeof(buf)).gcount() > 0) - { - std::vector buffers; - buffers.push_back(boost::asio::buffer(buf)); - write_buffer_list(buffers, adaptor); - } - } - - //THIS METHOD DOES MODIFY THE BODY, AS IN IT EMPTIES IT - template - void write_streamed_string(std::string& is, Adaptor& adaptor) - { - std::string buf; std::vector buffers; - - while (is.length() > 16384) - { - //buf.reserve(16385); - buf = is.substr(0, 16384); - is = is.substr(16384); - push_and_write(buffers, buf, adaptor); - } - //Collect whatever is left (less than 16KB) and send it down the socket - //buf.reserve(is.length()); - buf = is; - is.clear(); - push_and_write(buffers, buf, adaptor); - } - - template - inline void push_and_write(std::vector& buffers, std::string& buf, Adaptor& adaptor) - { - buffers.clear(); buffers.push_back(boost::asio::buffer(buf)); write_buffer_list(buffers, adaptor); } + } - template - inline void write_buffer_list(std::vector& buffers, Adaptor& adaptor) + // THIS METHOD DOES MODIFY THE BODY, AS IN IT EMPTIES IT + template + void write_streamed_string(std::string& is, Adaptor& adaptor) + { + std::string buf; + std::vector buffers; + + while (is.length() > 16384) { - boost::asio::write(adaptor.socket(), buffers, [this](std::error_code ec, std::size_t) - { + //buf.reserve(16385); + buf = is.substr(0, 16384); + is = is.substr(16384); + push_and_write(buffers, buf, adaptor); + } + // Collect whatever is left (less than 16KB) and send it down the socket + // buf.reserve(is.length()); + buf = is; + is.clear(); + push_and_write(buffers, buf, adaptor); + } + + template + inline void push_and_write(std::vector& buffers, std::string& buf, Adaptor& adaptor) + { + buffers.clear(); + buffers.push_back(boost::asio::buffer(buf)); + write_buffer_list(buffers, adaptor); + } + + template + inline void write_buffer_list(std::vector& buffers, Adaptor& adaptor) + { + boost::asio::write(adaptor.socket(), buffers, [this](std::error_code ec, std::size_t) + { if (!ec) { return false; @@ -317,9 +324,7 @@ namespace crow CROW_LOG_ERROR << ec << " - happened while sending buffers"; this->end(); return true; - } - }); - } - + } }); + } }; -} +} // namespace crow diff --git a/include/crow/http_server.h b/include/crow/http_server.h index 176046feb..061b69d69 100644 --- a/include/crow/http_server.h +++ b/include/crow/http_server.h @@ -10,7 +10,6 @@ #include #include #include - #include #include "crow/version.h" @@ -23,22 +22,22 @@ namespace crow using namespace boost; using tcp = asio::ip::tcp; - template + template class Server { public: - Server(Handler* handler, std::string bindaddr, uint16_t port, std::string server_name = std::string("Crow/") + VERSION, std::tuple* middlewares = nullptr, uint16_t concurrency = 1, uint8_t timeout = 5, typename Adaptor::context* adaptor_ctx = nullptr) - : acceptor_(io_service_, tcp::endpoint(boost::asio::ip::address::from_string(bindaddr), port)), - signals_(io_service_, SIGINT, SIGTERM), - tick_timer_(io_service_), - handler_(handler), - concurrency_(concurrency == 0 ? 1 : concurrency), - timeout_(timeout), - server_name_(server_name), - port_(port), - bindaddr_(bindaddr), - middlewares_(middlewares), - adaptor_ctx_(adaptor_ctx) + Server(Handler* handler, std::string bindaddr, uint16_t port, std::string server_name = std::string("Crow/") + VERSION, std::tuple* middlewares = nullptr, uint16_t concurrency = 1, uint8_t timeout = 5, typename Adaptor::context* adaptor_ctx = nullptr): + acceptor_(io_service_, tcp::endpoint(boost::asio::ip::address::from_string(bindaddr), port)), + signals_(io_service_, SIGINT, SIGTERM), + tick_timer_(io_service_), + handler_(handler), + concurrency_(concurrency == 0 ? 1 : concurrency), + timeout_(timeout), + server_name_(server_name), + port_(port), + bindaddr_(bindaddr), + middlewares_(middlewares), + adaptor_ctx_(adaptor_ctx) { } @@ -53,116 +52,121 @@ namespace crow tick_function_(); tick_timer_.expires_from_now(boost::posix_time::milliseconds(tick_interval_.count())); tick_timer_.async_wait([this](const boost::system::error_code& ec) - { + { if (ec) return; - on_tick(); - }); + on_tick(); }); } void run() { - for(int i = 0; i < concurrency_; i++) + for (int i = 0; i < concurrency_; i++) io_service_pool_.emplace_back(new boost::asio::io_service()); get_cached_date_str_pool_.resize(concurrency_); task_timer_pool_.resize(concurrency_); std::vector> v; std::atomic init_count(0); - for(uint16_t i = 0; i < concurrency_; i ++) + for (uint16_t i = 0; i < concurrency_; i++) v.push_back( - std::async(std::launch::async, [this, i, &init_count]{ + std::async( + std::launch::async, [this, i, &init_count] + { - // thread local date string get function - auto last = std::chrono::steady_clock::now(); + // thread local date string get function + auto last = std::chrono::steady_clock::now(); - std::string date_str; - auto update_date_str = [&] - { - auto last_time_t = time(0); - tm my_tm; + std::string date_str; + auto update_date_str = [&] + { + auto last_time_t = time(0); + tm my_tm; #if defined(_MSC_VER) || defined(__MINGW32__) - gmtime_s(&my_tm, &last_time_t); + gmtime_s(&my_tm, &last_time_t); #else - gmtime_r(&last_time_t, &my_tm); + gmtime_r(&last_time_t, &my_tm); #endif - date_str.resize(100); - size_t date_str_sz = strftime(&date_str[0], 99, "%a, %d %b %Y %H:%M:%S GMT", &my_tm); - date_str.resize(date_str_sz); - }; - update_date_str(); - get_cached_date_str_pool_[i] = [&]()->std::string + date_str.resize(100); + size_t date_str_sz = strftime(&date_str[0], 99, "%a, %d %b %Y %H:%M:%S GMT", &my_tm); + date_str.resize(date_str_sz); + }; + update_date_str(); + get_cached_date_str_pool_[i] = [&]()->std::string + { + if (std::chrono::steady_clock::now() - last >= std::chrono::seconds(1)) { - if (std::chrono::steady_clock::now() - last >= std::chrono::seconds(1)) - { - last = std::chrono::steady_clock::now(); - update_date_str(); - } - return date_str; - }; - - // initializing task timers - detail::task_timer task_timer(*io_service_pool_[i]); - task_timer.set_default_timeout(timeout_); - task_timer_pool_[i] = &task_timer; - - init_count ++; - while(1) - { - try - { - if (io_service_pool_[i]->run() == 0) - { - // when io_service.run returns 0, there are no more works to do. - break; - } - } catch(std::exception& e) - { - CROW_LOG_ERROR << "Worker Crash: An uncaught exception occurred: " << e.what(); - } + last = std::chrono::steady_clock::now(); + update_date_str(); } - })); + return date_str; + }; + + // initializing task timers + detail::task_timer task_timer(*io_service_pool_[i]); + task_timer.set_default_timeout(timeout_); + task_timer_pool_[i] = &task_timer; + + init_count ++; + while(1) + { + try + { + if (io_service_pool_[i]->run() == 0) + { + // when io_service.run returns 0, there are no more works to do. + break; + } + } catch(std::exception& e) + { + CROW_LOG_ERROR << "Worker Crash: An uncaught exception occurred: " << e.what(); + } + } })); if (tick_function_ && tick_interval_.count() > 0) { tick_timer_.expires_from_now(boost::posix_time::milliseconds(tick_interval_.count())); - tick_timer_.async_wait([this](const boost::system::error_code& ec) - { - if (ec) - return; - on_tick(); - }); + tick_timer_.async_wait( + [this](const boost::system::error_code& ec) + { + if (ec) + return; + on_tick(); + }); } port_ = acceptor_.local_endpoint().port(); handler_->port(port_); - CROW_LOG_INFO << server_name_ << " server is running at " << (handler_->ssl_used() ? "https://" : "http://") << bindaddr_ <<":" << acceptor_.local_endpoint().port() + CROW_LOG_INFO << server_name_ << " server is running at " << (handler_->ssl_used() ? "https://" : "http://") << bindaddr_ << ":" << acceptor_.local_endpoint().port() << " using " << concurrency_ << " threads"; CROW_LOG_INFO << "Call `app.loglevel(crow::LogLevel::Warning)` to hide Info level logs."; signals_.async_wait( - [&](const boost::system::error_code& /*error*/, int /*signal_number*/){ - stop(); - }); + [&](const boost::system::error_code& /*error*/, int /*signal_number*/) + { + stop(); + }); - while(concurrency_ != init_count) + while (concurrency_ != init_count) std::this_thread::yield(); do_accept(); - std::thread([this]{ - io_service_.run(); - CROW_LOG_INFO << "Exiting."; - }).join(); + std::thread( + [this] + { + io_service_.run(); + CROW_LOG_INFO << "Exiting."; + }) + .join(); } void stop() { io_service_.stop(); - for(auto& io_service:io_service_pool_) + for (auto& io_service : io_service_pool_) io_service->stop(); } @@ -190,24 +194,24 @@ namespace crow { asio::io_service& is = pick_io_service(); auto p = new Connection( - is, handler_, server_name_, middlewares_, - get_cached_date_str_pool_[roundrobin_index_], *task_timer_pool_[roundrobin_index_], adaptor_ctx_); - acceptor_.async_accept(p->socket(), - [this, p, &is](boost::system::error_code ec) - { - if (!ec) - { - is.post([p] - { - p->start(); - }); - } - else - { - delete p; - } - do_accept(); - }); + is, handler_, server_name_, middlewares_, + get_cached_date_str_pool_[roundrobin_index_], *task_timer_pool_[roundrobin_index_], adaptor_ctx_); + acceptor_.async_accept( + p->socket(), + [this, p, &is](boost::system::error_code ec) + { + if (!ec) + { + is.post( + [p] + { p->start(); }); + } + else + { + delete p; + } + do_accept(); + }); } private: @@ -234,4 +238,4 @@ namespace crow typename Adaptor::context* adaptor_ctx_; }; -} +} // namespace crow diff --git a/include/crow/json.h b/include/crow/json.h index de4ec99cb..7caa8a4fd 100644 --- a/include/crow/json.h +++ b/include/crow/json.h @@ -40,10 +40,10 @@ namespace crow { inline void escape(const std::string& str, std::string& ret) { - ret.reserve(ret.size() + str.size()+str.size()/4); - for(auto c:str) + ret.reserve(ret.size() + str.size() + str.size() / 4); + for (auto c : str) { - switch(c) + switch (c) { case '"': ret += "\\\""; break; case '\\': ret += "\\\\"; break; @@ -58,13 +58,13 @@ namespace crow ret += "\\u00"; auto to_hex = [](char c) { - c = c&0xf; + c = c & 0xf; if (c < 10) return '0' + c; - return 'a'+c-10; + return 'a' + c - 10; }; - ret += to_hex(c/16); - ret += to_hex(c%16); + ret += to_hex(c / 16); + ret += to_hex(c % 16); } else ret += c; @@ -90,8 +90,10 @@ namespace crow Object, }; - inline const char* get_type_str(type t) { - switch(t){ + inline const char* get_type_str(type t) + { + switch (t) + { case type::Number: return "Number"; case type::False: return "False"; case type::True: return "True"; @@ -102,7 +104,8 @@ namespace crow } } - enum class num_type : char { + enum class num_type : char + { Signed_integer, Unsigned_integer, Floating_point, @@ -112,19 +115,14 @@ namespace crow class rvalue; rvalue load(const char* data, size_t size); - namespace detail + namespace detail { /// A read string implementation with comparison functionality. - struct r_string - : boost::less_than_comparable, - boost::less_than_comparable, - boost::equality_comparable, - boost::equality_comparable + struct r_string : boost::less_than_comparable, boost::less_than_comparable, boost::equality_comparable, boost::equality_comparable { - r_string() {}; - r_string(char* s, char* e) - : s_(s), e_(e) - {}; + r_string(){}; + r_string(char* s, char* e): + s_(s), e_(e){}; ~r_string() { if (owned_) @@ -141,7 +139,7 @@ namespace crow *this = r; } - r_string& operator = (r_string&& r) + r_string& operator=(r_string&& r) { s_ = r.s_; e_ = r.e_; @@ -151,7 +149,7 @@ namespace crow return *this; } - r_string& operator = (const r_string& r) + r_string& operator=(const r_string& r) { s_ = r.s_; e_ = r.e_; @@ -159,7 +157,7 @@ namespace crow return *this; } - operator std::string () const + operator std::string() const { return std::string(s_, e_); } @@ -172,14 +170,15 @@ namespace crow using iterator = const char*; using const_iterator = const char*; - char* s_; ///< Start. + char* s_; ///< Start. mutable char* e_; ///< End. uint8_t owned_{0}; - friend std::ostream& operator << (std::ostream& os, const r_string& s) + friend std::ostream& operator<<(std::ostream& os, const r_string& s) { os << static_cast(s); return os; } + private: void force(char* s, uint32_t length) { @@ -190,31 +189,31 @@ namespace crow friend rvalue crow::json::load(const char* data, size_t size); }; - inline bool operator < (const r_string& l, const r_string& r) + inline bool operator<(const r_string& l, const r_string& r) { - return boost::lexicographical_compare(l,r); + return boost::lexicographical_compare(l, r); } - inline bool operator < (const r_string& l, const std::string& r) + inline bool operator<(const r_string& l, const std::string& r) { - return boost::lexicographical_compare(l,r); + return boost::lexicographical_compare(l, r); } - inline bool operator > (const r_string& l, const std::string& r) + inline bool operator>(const r_string& l, const std::string& r) { - return boost::lexicographical_compare(r,l); + return boost::lexicographical_compare(r, l); } - inline bool operator == (const r_string& l, const r_string& r) + inline bool operator==(const r_string& l, const r_string& r) { - return boost::equals(l,r); + return boost::equals(l, r); } - inline bool operator == (const r_string& l, const std::string& r) + inline bool operator==(const r_string& l, const std::string& r) { - return boost::equals(l,r); + return boost::equals(l, r); } - } + } // namespace detail /// JSON read value. @@ -225,27 +224,24 @@ namespace crow { static const int cached_bit = 2; static const int error_bit = 4; + public: - rvalue() noexcept : option_{error_bit} - {} - rvalue(type t) noexcept - : lsize_{}, lremain_{}, t_{t} - {} - rvalue(type t, char* s, char* e) noexcept - : start_{s}, - end_{e}, - t_{t} + rvalue() noexcept: + option_{error_bit} + { + } + rvalue(type t) noexcept: + lsize_{}, lremain_{}, t_{t} + { + } + rvalue(type t, char* s, char* e) noexcept: + start_{s}, end_{e}, t_{t} { determine_num_type(); } - rvalue(const rvalue& r) - : start_(r.start_), - end_(r.end_), - key_(r.key_), - t_(r.t_), - nt_(r.nt_), - option_(r.option_) + rvalue(const rvalue& r): + start_(r.start_), end_(r.end_), key_(r.key_), t_(r.t_), nt_(r.nt_), option_(r.option_) { copy_l(r); } @@ -255,7 +251,7 @@ namespace crow *this = std::move(r); } - rvalue& operator = (const rvalue& r) + rvalue& operator=(const rvalue& r) { start_ = r.start_; end_ = r.end_; @@ -266,7 +262,7 @@ namespace crow copy_l(r); return *this; } - rvalue& operator = (rvalue&& r) noexcept + rvalue& operator=(rvalue&& r) noexcept { start_ = r.start_; end_ = r.end_; @@ -318,7 +314,7 @@ namespace crow case type::False: return std::string("false"); default: - return std::string(start_, end_-start_); + return std::string(start_, end_ - start_); } } @@ -350,32 +346,33 @@ namespace crow int64_t i() const { #ifndef CROW_JSON_NO_ERROR_CHECK - switch (t()) { + switch (t()) + { case type::Number: case type::String: - return boost::lexical_cast(start_, end_-start_); + return boost::lexical_cast(start_, end_ - start_); default: - const std::string msg = "expected number, got: " - + std::string(get_type_str(t())); + const std::string msg = "expected number, got: " + std::string(get_type_str(t())); throw std::runtime_error(msg); } #endif - return boost::lexical_cast(start_, end_-start_); + return boost::lexical_cast(start_, end_ - start_); } /// The unsigned integer value. uint64_t u() const { #ifndef CROW_JSON_NO_ERROR_CHECK - switch (t()) { + switch (t()) + { case type::Number: case type::String: - return boost::lexical_cast(start_, end_-start_); + return boost::lexical_cast(start_, end_ - start_); default: throw std::runtime_error(std::string("expected number, got: ") + get_type_str(t())); } #endif - return boost::lexical_cast(start_, end_-start_); + return boost::lexical_cast(start_, end_ - start_); } /// The double precision floating-point number value. @@ -385,7 +382,7 @@ namespace crow if (t() != type::Number) throw std::runtime_error("value is not number"); #endif - return boost::lexical_cast(start_, end_-start_); + return boost::lexical_cast(start_, end_ - start_); } /// The boolean value. @@ -418,7 +415,7 @@ namespace crow #endif std::vector ret; ret.reserve(lsize_); - for (uint32_t i = 0; i '\n'). void unescape() const { - if (*(start_-1)) + if (*(start_ - 1)) { char* head = start_; char* tail = start_; - while(head != end_) + while (head != end_) { if (*head == '\\') { - switch(*++head) + switch (*++head) { - case '"': *tail++ = '"'; break; + case '"': *tail++ = '"'; break; case '\\': *tail++ = '\\'; break; - case '/': *tail++ = '/'; break; - case 'b': *tail++ = '\b'; break; - case 'f': *tail++ = '\f'; break; - case 'n': *tail++ = '\n'; break; - case 'r': *tail++ = '\r'; break; - case 't': *tail++ = '\t'; break; + case '/': *tail++ = '/'; break; + case 'b': *tail++ = '\b'; break; + case 'f': *tail++ = '\f'; break; + case 'n': *tail++ = '\n'; break; + case 'r': *tail++ = '\r'; break; + case 't': *tail++ = '\t'; break; case 'u': + { + auto from_hex = [](char c) { - auto from_hex = [](char c) - { - if (c >= 'a') - return c - 'a' + 10; - if (c >= 'A') - return c - 'A' + 10; - return c - '0'; - }; - unsigned int code = - (from_hex(head[1])<<12) + - (from_hex(head[2])<< 8) + - (from_hex(head[3])<< 4) + - from_hex(head[4]); - if (code >= 0x800) - { - *tail++ = 0xE0 | (code >> 12); - *tail++ = 0x80 | ((code >> 6) & 0x3F); - *tail++ = 0x80 | (code & 0x3F); - } - else if (code >= 0x80) - { - *tail++ = 0xC0 | (code >> 6); - *tail++ = 0x80 | (code & 0x3F); - } - else - { - *tail++ = code; - } - head += 4; + if (c >= 'a') + return c - 'a' + 10; + if (c >= 'A') + return c - 'A' + 10; + return c - '0'; + }; + unsigned int code = + (from_hex(head[1]) << 12) + + (from_hex(head[2]) << 8) + + (from_hex(head[3]) << 4) + + from_hex(head[4]); + if (code >= 0x800) + { + *tail++ = 0xE0 | (code >> 12); + *tail++ = 0x80 | ((code >> 6) & 0x3F); + *tail++ = 0x80 | (code & 0x3F); } - break; + else if (code >= 0x80) + { + *tail++ = 0xC0 | (code >> 6); + *tail++ = 0x80 | (code & 0x3F); + } + else + { + *tail++ = code; + } + head += 4; + } + break; } } else @@ -487,11 +484,11 @@ namespace crow } end_ = tail; *end_ = 0; - *(start_-1) = 0; + *(start_ - 1) = 0; } } - ///Check if the json object has the passed string as a key. + /// Check if the json object has the passed string as a key. bool has(const char* str) const { return has(std::string(str)); @@ -499,7 +496,7 @@ namespace crow bool has(const std::string& str) const { - struct Pred + struct Pred { bool operator()(const rvalue& l, const rvalue& r) const { @@ -528,21 +525,21 @@ namespace crow return has(str) ? 1 : 0; } - rvalue* begin() const - { + rvalue* begin() const + { #ifndef CROW_JSON_NO_ERROR_CHECK if (t() != type::Object && t() != type::List) throw std::runtime_error("value is not a container"); #endif - return l_.get(); + return l_.get(); } - rvalue* end() const - { + rvalue* end() const + { #ifndef CROW_JSON_NO_ERROR_CHECK if (t() != type::Object && t() != type::List) throw std::runtime_error("value is not a container"); #endif - return l_.get()+lsize_; + return l_.get() + lsize_; } const detail::r_string& key() const @@ -594,7 +591,7 @@ namespace crow if (t() != type::Object) throw std::runtime_error("value is not an object"); #endif - struct Pred + struct Pred { bool operator()(const rvalue& l, const rvalue& r) const { @@ -627,12 +624,12 @@ namespace crow void set_error() { - option_|=error_bit; + option_ |= error_bit; } bool error() const { - return (option_&error_bit)!=0; + return (option_ & error_bit) != 0; } std::vector keys() @@ -643,16 +640,17 @@ namespace crow #endif std::vector ret; ret.reserve(lsize_); - for (uint32_t i = 0; i("\2\2\7\3\4\6\6"[state]); @@ -982,11 +980,18 @@ namespace crow else return {};*/ break; - case '1': case '2': case '3': - case '4': case '5': case '6': - case '7': case '8': case '9': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': state = static_cast("\3\3\7\3\4\6\6"[state]); - while(*(data+1) >= '0' && *(data+1) <= '9') data++; + while (*(data + 1) >= '0' && *(data + 1) <= '9') + data++; /*if (state == NumberParsingState::Minus || state == NumberParsingState::AfterMinus) { state = NumberParsingState::Digits; @@ -1037,7 +1042,8 @@ namespace crow else return {};*/ break; - case 'e': case 'E': + case 'e': + case 'E': state = static_cast("\7\7\7\5\5\7\7"[state]); /*if (state == NumberParsingState::Digits || state == NumberParsingState::DigitsAfterPoints) @@ -1048,10 +1054,10 @@ namespace crow return {};*/ break; default: - if (crow_json_likely(state == NumberParsingState::ZeroFirst || - state == NumberParsingState::Digits || - state == NumberParsingState::DigitsAfterPoints || - state == NumberParsingState::DigitsAfterE)) + if (crow_json_likely(state == NumberParsingState::ZeroFirst || + state == NumberParsingState::Digits || + state == NumberParsingState::DigitsAfterPoints || + state == NumberParsingState::DigitsAfterE)) return {type::Number, start, data}; else return {}; @@ -1064,7 +1070,7 @@ namespace crow rvalue decode_value() { - switch(*data) + switch (*data) { case '[': return decode_list(); @@ -1073,10 +1079,10 @@ namespace crow case '"': return decode_string(); case 't': - if (//e-data >= 4 && - data[1] == 'r' && - data[2] == 'u' && - data[3] == 'e') + if ( //e-data >= 4 && + data[1] == 'r' && + data[2] == 'u' && + data[3] == 'e') { data += 4; return {type::True}; @@ -1084,11 +1090,11 @@ namespace crow else return {}; case 'f': - if (//e-data >= 5 && - data[1] == 'a' && - data[2] == 'l' && - data[3] == 's' && - data[4] == 'e') + if ( //e-data >= 5 && + data[1] == 'a' && + data[2] == 'l' && + data[3] == 's' && + data[4] == 'e') { data += 5; return {type::False}; @@ -1096,18 +1102,18 @@ namespace crow else return {}; case 'n': - if (//e-data >= 4 && - data[1] == 'u' && - data[2] == 'l' && - data[3] == 'l') + if ( //e-data >= 4 && + data[1] == 'u' && + data[2] == 'l' && + data[3] == 'l') { data += 4; return {type::Null}; } else return {}; - //case '1': case '2': case '3': - //case '4': case '5': case '6': + //case '1': case '2': case '3': + //case '4': case '5': case '6': //case '7': case '8': case '9': //case '0': case '-': default: @@ -1133,7 +1139,7 @@ namespace crow return ret; } - while(1) + while (1) { auto t = decode_string(); if (crow_json_unlikely(!t)) @@ -1195,7 +1201,7 @@ namespace crow } inline rvalue load(const char* data, size_t size) { - char* s = new char[size+1]; + char* s = new char[size + 1]; memcpy(s, data, size); s[size] = 0; auto ret = load_nocopy_internal(s, size); @@ -1218,7 +1224,6 @@ namespace crow /// JSON write value. - /// /// Value can mean any json value, including a JSON object. /// Write means this class is used to primarily assemble JSON objects using keys and values and export those into a string. @@ -1227,87 +1232,114 @@ namespace crow friend class crow::mustache::template_t; public: - using object = #ifdef CROW_JSON_USE_MAP - std::map; + std::map; #else - std::unordered_map; + std::unordered_map; #endif using list = std::vector; type t() const { return t_; } + private: - type t_{type::Null}; ///< The type of the value. + type t_{type::Null}; ///< The type of the value. num_type nt{num_type::Null}; ///< The specific type of the number if \ref t_ is a number. - union number { - double d; - int64_t si; - uint64_t ui; + union number + { + double d; + int64_t si; + uint64_t ui; public: - constexpr number() noexcept : ui() {} /* default constructor initializes unsigned integer. */ - constexpr number(std::uint64_t value) noexcept : ui(value) {} - constexpr number(std::int64_t value) noexcept : si(value) {} - constexpr number(double value) noexcept : d(value) {} - } num; ///< Value if type is a number. - std::string s; ///< Value if type is a string. - std::unique_ptr l; ///< Value if type is a list. + constexpr number() noexcept: + ui() {} /* default constructor initializes unsigned integer. */ + constexpr number(std::uint64_t value) noexcept: + ui(value) {} + constexpr number(std::int64_t value) noexcept: + si(value) {} + constexpr number(double value) noexcept: + d(value) {} + } num; ///< Value if type is a number. + std::string s; ///< Value if type is a string. + std::unique_ptr l; ///< Value if type is a list. std::unique_ptr o; ///< Value if type is a JSON object. public: - wvalue() : returnable("application/json") {} + wvalue(): + returnable("application/json") {} - wvalue(std::nullptr_t) : returnable("application/json"), t_(type::Null) {} + wvalue(std::nullptr_t): + returnable("application/json"), t_(type::Null) {} - wvalue(bool value) : returnable("application/json"), t_(value ? type::True : type::False) {} + wvalue(bool value): + returnable("application/json"), t_(value ? type::True : type::False) {} - wvalue(std::uint8_t value) : returnable("application/json"), t_(type::Number), nt(num_type::Unsigned_integer), num(static_cast(value)) {} - wvalue(std::uint16_t value) : returnable("application/json"), t_(type::Number), nt(num_type::Unsigned_integer), num(static_cast(value)) {} - wvalue(std::uint32_t value) : returnable("application/json"), t_(type::Number), nt(num_type::Unsigned_integer), num(static_cast(value)) {} - wvalue(std::uint64_t value) : returnable("application/json"), t_(type::Number), nt(num_type::Unsigned_integer), num(static_cast(value)) {} + wvalue(std::uint8_t value): + returnable("application/json"), t_(type::Number), nt(num_type::Unsigned_integer), num(static_cast(value)) {} + wvalue(std::uint16_t value): + returnable("application/json"), t_(type::Number), nt(num_type::Unsigned_integer), num(static_cast(value)) {} + wvalue(std::uint32_t value): + returnable("application/json"), t_(type::Number), nt(num_type::Unsigned_integer), num(static_cast(value)) {} + wvalue(std::uint64_t value): + returnable("application/json"), t_(type::Number), nt(num_type::Unsigned_integer), num(static_cast(value)) {} - wvalue(std::int8_t value) : returnable("application/json"), t_(type::Number), nt(num_type::Signed_integer), num(static_cast(value)) {} - wvalue(std::int16_t value) : returnable("application/json"), t_(type::Number), nt(num_type::Signed_integer), num(static_cast(value)) {} - wvalue(std::int32_t value) : returnable("application/json"), t_(type::Number), nt(num_type::Signed_integer), num(static_cast(value)) {} - wvalue(std::int64_t value) : returnable("application/json"), t_(type::Number), nt(num_type::Signed_integer), num(static_cast(value)) {} + wvalue(std::int8_t value): + returnable("application/json"), t_(type::Number), nt(num_type::Signed_integer), num(static_cast(value)) {} + wvalue(std::int16_t value): + returnable("application/json"), t_(type::Number), nt(num_type::Signed_integer), num(static_cast(value)) {} + wvalue(std::int32_t value): + returnable("application/json"), t_(type::Number), nt(num_type::Signed_integer), num(static_cast(value)) {} + wvalue(std::int64_t value): + returnable("application/json"), t_(type::Number), nt(num_type::Signed_integer), num(static_cast(value)) {} - wvalue(float value) : returnable("application/json"), t_(type::Number), nt(num_type::Floating_point), num(static_cast(value)) {} - wvalue(double value) : returnable("application/json"), t_(type::Number), nt(num_type::Floating_point), num(static_cast(value)) {} + wvalue(float value): + returnable("application/json"), t_(type::Number), nt(num_type::Floating_point), num(static_cast(value)) {} + wvalue(double value): + returnable("application/json"), t_(type::Number), nt(num_type::Floating_point), num(static_cast(value)) {} - wvalue(char const* value) : returnable("application/json"), t_(type::String), s(value) {} + wvalue(char const* value): + returnable("application/json"), t_(type::String), s(value) {} - wvalue(std::string const& value) : returnable("application/json"), t_(type::String), s(value) {} - wvalue(std::string&& value) : returnable("application/json"), t_(type::String), s(std::move(value)) {} + wvalue(std::string const& value): + returnable("application/json"), t_(type::String), s(value) {} + wvalue(std::string&& value): + returnable("application/json"), t_(type::String), s(std::move(value)) {} - wvalue(std::initializer_list> initializer_list) : returnable("application/json"), t_(type::Object), o(new object(initializer_list)) {} + wvalue(std::initializer_list> initializer_list): + returnable("application/json"), t_(type::Object), o(new object(initializer_list)) {} - wvalue(object const& value) : returnable("application/json"), t_(type::Object), o(new object(value)) {} - wvalue(object&& value) : returnable("application/json"), t_(type::Object), o(new object(std::move(value))) {} + wvalue(object const& value): + returnable("application/json"), t_(type::Object), o(new object(value)) {} + wvalue(object&& value): + returnable("application/json"), t_(type::Object), o(new object(std::move(value))) {} - wvalue(const list& r) : returnable("application/json") + wvalue(const list& r): + returnable("application/json") { t_ = type::List; l = std::unique_ptr(new list{}); l->reserve(r.size()); - for(auto it = r.begin(); it != r.end(); ++it) + for (auto it = r.begin(); it != r.end(); ++it) l->emplace_back(*it); } - wvalue(list& r) : returnable("application/json") + wvalue(list& r): + returnable("application/json") { t_ = type::List; l = std::unique_ptr(new list{}); l->reserve(r.size()); - for(auto it = r.begin(); it != r.end(); ++it) + for (auto it = r.begin(); it != r.end(); ++it) l->emplace_back(*it); } /// Create a write value from a read value (useful for editing JSON strings). - wvalue(const rvalue& r) : returnable("application/json") + wvalue(const rvalue& r): + returnable("application/json") { t_ = r.t(); - switch(r.t()) + switch (r.t()) { case type::Null: case type::False: @@ -1316,11 +1348,11 @@ namespace crow case type::Number: nt = r.nt(); if (nt == num_type::Floating_point) - num.d = r.d(); + num.d = r.d(); else if (nt == num_type::Signed_integer) - num.si = r.i(); + num.si = r.i(); else - num.ui = r.u(); + num.ui = r.u(); return; case type::String: s = r.s(); @@ -1328,21 +1360,22 @@ namespace crow case type::List: l = std::unique_ptr(new list{}); l->reserve(r.size()); - for(auto it = r.begin(); it != r.end(); ++it) + for (auto it = r.begin(); it != r.end(); ++it) l->emplace_back(*it); return; case type::Object: o = std::unique_ptr(new object{}); - for(auto it = r.begin(); it != r.end(); ++it) + for (auto it = r.begin(); it != r.end(); ++it) o->emplace(it->key(), *it); return; } } - wvalue(const wvalue& r) : returnable("application/json") + wvalue(const wvalue& r): + returnable("application/json") { t_ = r.t(); - switch(r.t()) + switch (r.t()) { case type::Null: case type::False: @@ -1351,11 +1384,11 @@ namespace crow case type::Number: nt = r.nt; if (nt == num_type::Floating_point) - num.d = r.num.d; + num.d = r.num.d; else if (nt == num_type::Signed_integer) - num.si = r.num.si; + num.si = r.num.si; else - num.ui = r.num.ui; + num.ui = r.num.ui; return; case type::String: s = r.s; @@ -1363,7 +1396,7 @@ namespace crow case type::List: l = std::unique_ptr(new list{}); l->reserve(r.size()); - for(auto it = r.l->begin(); it != r.l->end(); ++it) + for (auto it = r.l->begin(); it != r.l->end(); ++it) l->emplace_back(*it); return; case type::Object: @@ -1373,12 +1406,13 @@ namespace crow } } - wvalue(wvalue&& r) : returnable("application/json") + wvalue(wvalue&& r): + returnable("application/json") { *this = std::move(r); } - wvalue& operator = (wvalue&& r) + wvalue& operator=(wvalue&& r) { t_ = r.t_; num = r.num; @@ -1401,12 +1435,12 @@ namespace crow o.reset(); } - wvalue& operator = (std::nullptr_t) + wvalue& operator=(std::nullptr_t) { reset(); return *this; } - wvalue& operator = (bool value) + wvalue& operator=(bool value) { reset(); if (value) @@ -1416,7 +1450,7 @@ namespace crow return *this; } - wvalue& operator = (double value) + wvalue& operator=(double value) { reset(); t_ = type::Number; @@ -1425,7 +1459,7 @@ namespace crow return *this; } - wvalue& operator = (unsigned short value) + wvalue& operator=(unsigned short value) { reset(); t_ = type::Number; @@ -1434,7 +1468,7 @@ namespace crow return *this; } - wvalue& operator = (short value) + wvalue& operator=(short value) { reset(); t_ = type::Number; @@ -1443,7 +1477,7 @@ namespace crow return *this; } - wvalue& operator = (long long value) + wvalue& operator=(long long value) { reset(); t_ = type::Number; @@ -1452,7 +1486,7 @@ namespace crow return *this; } - wvalue& operator = (long value) + wvalue& operator=(long value) { reset(); t_ = type::Number; @@ -1461,7 +1495,7 @@ namespace crow return *this; } - wvalue& operator = (int value) + wvalue& operator=(int value) { reset(); t_ = type::Number; @@ -1470,7 +1504,7 @@ namespace crow return *this; } - wvalue& operator = (unsigned long long value) + wvalue& operator=(unsigned long long value) { reset(); t_ = type::Number; @@ -1479,7 +1513,7 @@ namespace crow return *this; } - wvalue& operator = (unsigned long value) + wvalue& operator=(unsigned long value) { reset(); t_ = type::Number; @@ -1488,7 +1522,7 @@ namespace crow return *this; } - wvalue& operator = (unsigned int value) + wvalue& operator=(unsigned int value) { reset(); t_ = type::Number; @@ -1523,14 +1557,14 @@ namespace crow l->clear(); l->resize(v.size()); size_t idx = 0; - for(auto& x:v) + for (auto& x : v) { (*l)[idx++] = std::move(x); } return *this; } - template + template wvalue& operator=(const std::vector& v) { if (t_ != type::List) @@ -1541,7 +1575,7 @@ namespace crow l->clear(); l->resize(v.size()); size_t idx = 0; - for(auto& x:v) + for (auto& x : v) { (*l)[idx++] = x; } @@ -1550,11 +1584,14 @@ namespace crow wvalue& operator=(std::initializer_list> initializer_list) { - if (t_ != type::Object) { + if (t_ != type::Object) + { reset(); t_ = type::Object; o = std::unique_ptr(new object(initializer_list)); - } else { + } + else + { #if defined(__APPLE__) || defined(__MACH__) o = std::unique_ptr(new object(initializer_list)); #else @@ -1566,11 +1603,14 @@ namespace crow wvalue& operator=(object const& value) { - if (t_ != type::Object) { + if (t_ != type::Object) + { reset(); t_ = type::Object; o = std::unique_ptr(new object(value)); - } else { + } + else + { #if defined(__APPLE__) || defined(__MACH__) o = std::unique_ptr(new object(value)); #else @@ -1582,11 +1622,14 @@ namespace crow wvalue& operator=(object&& value) { - if (t_ != type::Object) { + if (t_ != type::Object) + { reset(); t_ = type::Object; o = std::unique_ptr(new object(std::move(value))); - } else { + } + else + { (*o) = std::move(value); } return *this; @@ -1599,8 +1642,8 @@ namespace crow t_ = type::List; if (!l) l = std::unique_ptr(new list{}); - if (l->size() < index+1) - l->resize(index+1); + if (l->size() < index + 1) + l->resize(index + 1); return (*l)[index]; } @@ -1619,16 +1662,16 @@ namespace crow reset(); t_ = type::Object; if (!o) - o = std::unique_ptr(new object{}); + o = std::unique_ptr(new object{}); return (*o)[str]; } - std::vector keys() const + std::vector keys() const { - if (t_ != type::Object) + if (t_ != type::Object) return {}; std::vector result; - for (auto& kv:*o) + for (auto& kv : *o) { result.push_back(kv.first); } @@ -1646,46 +1689,45 @@ namespace crow /// Returns an estimated size of the value in bytes. size_t estimate_length() const { - switch(t_) + switch (t_) { case type::Null: return 4; case type::False: return 5; case type::True: return 4; case type::Number: return 30; - case type::String: return 2+s.size()+s.size()/2; - case type::List: + case type::String: return 2 + s.size() + s.size() / 2; + case type::List: + { + size_t sum{}; + if (l) { - size_t sum{}; - if (l) + for (auto& x : *l) { - for(auto& x:*l) - { - sum += 1; - sum += x.estimate_length(); - } + sum += 1; + sum += x.estimate_length(); } - return sum+2; } + return sum + 2; + } case type::Object: + { + size_t sum{}; + if (o) { - size_t sum{}; - if (o) + for (auto& kv : *o) { - for(auto& kv:*o) - { - sum += 2; - sum += 2+kv.first.size()+kv.first.size()/2; - sum += kv.second.estimate_length(); - } + sum += 2; + sum += 2 + kv.first.size() + kv.first.size() / 2; + sum += kv.second.estimate_length(); } - return sum+2; } + return sum + 2; + } } return 1; } private: - inline void dump_string(const std::string& str, std::string& out) const { out.push_back('"'); @@ -1695,38 +1737,40 @@ namespace crow inline void dump_internal(const wvalue& v, std::string& out) const { - switch(v.t_) + switch (v.t_) { case type::Null: out += "null"; break; case type::False: out += "false"; break; case type::True: out += "true"; break; case type::Number: + { + if (v.nt == num_type::Floating_point) { - if (v.nt == num_type::Floating_point) +#ifdef _MSC_VER +#define MSC_COMPATIBLE_SPRINTF(BUFFER_PTR, FORMAT_PTR, VALUE) sprintf_s((BUFFER_PTR), 128, (FORMAT_PTR), (VALUE)) +#else +#define MSC_COMPATIBLE_SPRINTF(BUFFER_PTR, FORMAT_PTR, VALUE) sprintf((BUFFER_PTR), (FORMAT_PTR), (VALUE)) +#endif + enum { - #ifdef _MSC_VER - #define MSC_COMPATIBLE_SPRINTF(BUFFER_PTR, FORMAT_PTR, VALUE) sprintf_s((BUFFER_PTR), 128, (FORMAT_PTR), (VALUE)) - #else - #define MSC_COMPATIBLE_SPRINTF(BUFFER_PTR, FORMAT_PTR, VALUE) sprintf((BUFFER_PTR), (FORMAT_PTR), (VALUE)) - #endif - enum { - start, - decp, - zero - } f_state; - char outbuf[128]; - MSC_COMPATIBLE_SPRINTF(outbuf, "%f", v.num.d); - char *p = &outbuf[0], *o = nullptr; - f_state = start; - while (*p != '\0') + start, + decp, + zero + } f_state; + char outbuf[128]; + MSC_COMPATIBLE_SPRINTF(outbuf, "%f", v.num.d); + char *p = &outbuf[0], *o = nullptr; + f_state = start; + while (*p != '\0') + { + //std::cout << *p << std::endl; + char ch = *p; + switch (f_state) { - //std::cout << *p << std::endl; - char ch = *p; - switch (f_state){ case start: if (ch == '.') { - if (p+1 && *(p+1) == '0') p++; + if (p + 1 && *(p + 1) == '0') p++; f_state = decp; } p++; @@ -1747,64 +1791,64 @@ namespace crow } p++; break; - } } - if (o != nullptr) - *o = '\0'; - out += outbuf; - #undef MSC_COMPATIBLE_SPRINTF - } - else if (v.nt == num_type::Signed_integer) - { - out += std::to_string(v.num.si); - } - else - { - out += std::to_string(v.num.ui); } + if (o != nullptr) + *o = '\0'; + out += outbuf; +#undef MSC_COMPATIBLE_SPRINTF } - break; + else if (v.nt == num_type::Signed_integer) + { + out += std::to_string(v.num.si); + } + else + { + out += std::to_string(v.num.ui); + } + } + break; case type::String: dump_string(v.s, out); break; case type::List: - { - out.push_back('['); - if (v.l) - { - bool first = true; - for(auto& x:*v.l) - { - if (!first) - { - out.push_back(','); - } - first = false; - dump_internal(x, out); - } - } - out.push_back(']'); - } - break; + { + out.push_back('['); + if (v.l) + { + bool first = true; + for (auto& x : *v.l) + { + if (!first) + { + out.push_back(','); + } + first = false; + dump_internal(x, out); + } + } + out.push_back(']'); + } + break; case type::Object: - { - out.push_back('{'); - if (v.o) - { - bool first = true; - for(auto& kv:*v.o) - { - if (!first) - { - out.push_back(','); - } - first = false; - dump_string(kv.first, out); - out.push_back(':'); - dump_internal(kv.second, out); - } - } - out.push_back('}'); - } - break; + { + out.push_back('{'); + if (v.o) + { + bool first = true; + for (auto& kv : *v.o) + { + if (!first) + { + out.push_back(','); + } + first = false; + dump_string(kv.first, out); + out.push_back(':'); + dump_internal(kv.second, out); + } + } + out.push_back('}'); + } + break; } } @@ -1816,7 +1860,6 @@ namespace crow dump_internal(*this, ret); return ret; } - }; @@ -1824,8 +1867,8 @@ namespace crow //std::vector dump_ref(wvalue& v) //{ //} - } -} + } // namespace json +} // namespace crow #undef crow_json_likely #undef crow_json_unlikely diff --git a/include/crow/logging.h b/include/crow/logging.h index 0156d067c..d5777f265 100644 --- a/include/crow/logging.h +++ b/include/crow/logging.h @@ -30,115 +30,124 @@ namespace crow Critical, }; - class ILogHandler { - public: - virtual void log(std::string message, LogLevel level) = 0; + class ILogHandler + { + public: + virtual void log(std::string message, LogLevel level) = 0; }; - class CerrLogHandler : public ILogHandler { - public: - void log(std::string message, LogLevel /*level*/) override { - std::cerr << message; - } + class CerrLogHandler : public ILogHandler + { + public: + void log(std::string message, LogLevel /*level*/) override + { + std::cerr << message; + } }; - class logger { + class logger + { - private: - // - static std::string timestamp() - { - char date[32]; - time_t t = time(0); + private: + // + static std::string timestamp() + { + char date[32]; + time_t t = time(0); - tm my_tm; + tm my_tm; #if defined(_MSC_VER) || defined(__MINGW32__) - gmtime_s(&my_tm, &t); + gmtime_s(&my_tm, &t); #else - gmtime_r(&t, &my_tm); + gmtime_r(&t, &my_tm); #endif - size_t sz = strftime(date, sizeof(date), "%Y-%m-%d %H:%M:%S", &my_tm); - return std::string(date, date+sz); - } + size_t sz = strftime(date, sizeof(date), "%Y-%m-%d %H:%M:%S", &my_tm); + return std::string(date, date + sz); + } - public: - - - logger(std::string prefix, LogLevel level) : level_(level) { - #ifdef CROW_ENABLE_LOGGING - stringstream_ << "(" << timestamp() << ") [" << prefix << "] "; - #endif - - } - ~logger() { - #ifdef CROW_ENABLE_LOGGING - if(level_ >= get_current_log_level()) { - stringstream_ << std::endl; - get_handler_ref()->log(stringstream_.str(), level_); - } - #endif - } - - // - template - logger& operator<<(T const &value) { - - #ifdef CROW_ENABLE_LOGGING - if(level_ >= get_current_log_level()) { - stringstream_ << value; - } - #endif - return *this; - } - - // - static void setLogLevel(LogLevel level) { - get_log_level_ref() = level; - } - - static void setHandler(ILogHandler* handler) { - get_handler_ref() = handler; - } - - static LogLevel get_current_log_level() { - return get_log_level_ref(); - } - - private: - // - static LogLevel& get_log_level_ref() + public: + logger(std::string prefix, LogLevel level): + level_(level) + { +#ifdef CROW_ENABLE_LOGGING + stringstream_ << "(" << timestamp() << ") [" << prefix << "] "; +#endif + } + ~logger() + { +#ifdef CROW_ENABLE_LOGGING + if (level_ >= get_current_log_level()) { - static LogLevel current_level = static_cast(CROW_LOG_LEVEL); - return current_level; - } - static ILogHandler*& get_handler_ref() - { - static CerrLogHandler default_handler; - static ILogHandler* current_handler = &default_handler; - return current_handler; + stringstream_ << std::endl; + get_handler_ref()->log(stringstream_.str(), level_); } +#endif + } - // - std::ostringstream stringstream_; - LogLevel level_; + // + template + logger& operator<<(T const& value) + { + +#ifdef CROW_ENABLE_LOGGING + if (level_ >= get_current_log_level()) + { + stringstream_ << value; + } +#endif + return *this; + } + + // + static void setLogLevel(LogLevel level) + { + get_log_level_ref() = level; + } + + static void setHandler(ILogHandler* handler) + { + get_handler_ref() = handler; + } + + static LogLevel get_current_log_level() + { + return get_log_level_ref(); + } + + private: + // + static LogLevel& get_log_level_ref() + { + static LogLevel current_level = static_cast(CROW_LOG_LEVEL); + return current_level; + } + static ILogHandler*& get_handler_ref() + { + static CerrLogHandler default_handler; + static ILogHandler* current_handler = &default_handler; + return current_handler; + } + + // + std::ostringstream stringstream_; + LogLevel level_; }; -} - -#define CROW_LOG_CRITICAL \ - if (crow::logger::get_current_log_level() <= crow::LogLevel::Critical) \ - crow::logger("CRITICAL", crow::LogLevel::Critical) -#define CROW_LOG_ERROR \ - if (crow::logger::get_current_log_level() <= crow::LogLevel::Error) \ - crow::logger("ERROR ", crow::LogLevel::Error) -#define CROW_LOG_WARNING \ - if (crow::logger::get_current_log_level() <= crow::LogLevel::Warning) \ - crow::logger("WARNING ", crow::LogLevel::Warning) -#define CROW_LOG_INFO \ - if (crow::logger::get_current_log_level() <= crow::LogLevel::Info) \ - crow::logger("INFO ", crow::LogLevel::Info) -#define CROW_LOG_DEBUG \ - if (crow::logger::get_current_log_level() <= crow::LogLevel::Debug) \ - crow::logger("DEBUG ", crow::LogLevel::Debug) +} // namespace crow +#define CROW_LOG_CRITICAL \ + if (crow::logger::get_current_log_level() <= crow::LogLevel::Critical) \ + crow::logger("CRITICAL", crow::LogLevel::Critical) +#define CROW_LOG_ERROR \ + if (crow::logger::get_current_log_level() <= crow::LogLevel::Error) \ + crow::logger("ERROR ", crow::LogLevel::Error) +#define CROW_LOG_WARNING \ + if (crow::logger::get_current_log_level() <= crow::LogLevel::Warning) \ + crow::logger("WARNING ", crow::LogLevel::Warning) +#define CROW_LOG_INFO \ + if (crow::logger::get_current_log_level() <= crow::LogLevel::Info) \ + crow::logger("INFO ", crow::LogLevel::Info) +#define CROW_LOG_DEBUG \ + if (crow::logger::get_current_log_level() <= crow::LogLevel::Debug) \ + crow::logger("DEBUG ", crow::LogLevel::Debug) diff --git a/include/crow/middleware_context.h b/include/crow/middleware_context.h index b4924c820..3ac5b488b 100644 --- a/include/crow/middleware_context.h +++ b/include/crow/middleware_context.h @@ -10,16 +10,14 @@ namespace crow { - template - struct partial_context - : public black_magic::pop_back::template rebind - , public black_magic::last_element_type::type::context + template + struct partial_context : public black_magic::pop_back::template rebind, public black_magic::last_element_type::type::context { using parent_context = typename black_magic::pop_back::template rebind<::crow::detail::partial_context>; - template - using partial = typename std::conditional>::type; + template + using partial = typename std::conditional>::type; - template + template typename T::context& get() { return static_cast(*this); @@ -28,40 +26,40 @@ namespace crow - template <> + template<> struct partial_context<> { - template + template using partial = partial_context; }; - template + template bool middleware_call_helper(Container& middlewares, request& req, response& res, Context& ctx); - template + template struct context : private partial_context //struct context : private Middlewares::context... // simple but less type-safe { - template - friend typename std::enable_if<(N==0)>::type after_handlers_call_helper(Container& middlewares, Context& ctx, request& req, response& res); - template - friend typename std::enable_if<(N>0)>::type after_handlers_call_helper(Container& middlewares, Context& ctx, request& req, response& res); + template + friend typename std::enable_if<(N == 0)>::type after_handlers_call_helper(Container& middlewares, Context& ctx, request& req, response& res); + template + friend typename std::enable_if<(N > 0)>::type after_handlers_call_helper(Container& middlewares, Context& ctx, request& req, response& res); - template + template friend bool middleware_call_helper(Container& middlewares, request& req, response& res, Context& ctx); - template + template typename T::context& get() { return static_cast(*this); } - template + template using partial = typename partial_context::template partial; }; - } -} + } // namespace detail +} // namespace crow diff --git a/include/crow/middlewares/cookie_parser.h b/include/crow/middlewares/cookie_parser.h index 38580182a..3e5002db8 100644 --- a/include/crow/middlewares/cookie_parser.h +++ b/include/crow/middlewares/cookie_parser.h @@ -12,7 +12,7 @@ namespace crow // before_handle // called before handling the request. - // if res.end() is called, the operation is halted. + // if res.end() is called, the operation is halted. // (still call after_handle of this middleware) // 2 signatures: // void before_handle(request& req, response& res, context& ctx) @@ -62,25 +62,26 @@ namespace crow } std::string cookies = req.get_header_value("Cookie"); size_t pos = 0; - while(pos < cookies.size()) + while (pos < cookies.size()) { size_t pos_equal = cookies.find('=', pos); if (pos_equal == cookies.npos) break; - std::string name = cookies.substr(pos, pos_equal-pos); + std::string name = cookies.substr(pos, pos_equal - pos); boost::trim(name); - pos = pos_equal+1; - while(pos < cookies.size() && cookies[pos] == ' ') pos++; + pos = pos_equal + 1; + while (pos < cookies.size() && cookies[pos] == ' ') + pos++; if (pos == cookies.size()) break; size_t pos_semicolon = cookies.find(';', pos); - std::string value = cookies.substr(pos, pos_semicolon-pos); + std::string value = cookies.substr(pos, pos_semicolon - pos); boost::trim(value); - if (value[0] == '"' && value[value.size()-1] == '"') + if (value[0] == '"' && value[value.size() - 1] == '"') { - value = value.substr(1, value.size()-2); + value = value.substr(1, value.size() - 2); } ctx.jar.emplace(std::move(name), std::move(value)); @@ -89,13 +90,14 @@ namespace crow if (pos == cookies.npos) break; pos++; - while(pos < cookies.size() && cookies[pos] == ' ') pos++; + while (pos < cookies.size() && cookies[pos] == ' ') + pos++; } } void after_handle(request& /*req*/, response& res, context& ctx) { - for(auto& cookie:ctx.cookies_to_add) + for (auto& cookie : ctx.cookies_to_add) { if (cookie.second.empty()) res.add_header("Set-Cookie", cookie.first + "=\"\""); @@ -128,4 +130,4 @@ namespace crow SimpleApp */ -} +} // namespace crow diff --git a/include/crow/middlewares/utf-8.h b/include/crow/middlewares/utf-8.h index d0cce2498..2a1707998 100644 --- a/include/crow/middlewares/utf-8.h +++ b/include/crow/middlewares/utf-8.h @@ -24,4 +24,4 @@ namespace crow } }; -} +} // namespace crow diff --git a/include/crow/mime_types.h b/include/crow/mime_types.h index 36b536441..38cfefe07 100644 --- a/include/crow/mime_types.h +++ b/include/crow/mime_types.h @@ -1,116 +1,116 @@ -//This file is generated from nginx/conf/mime.types using nginx_mime2cpp.py +// This file is generated from nginx/conf/mime.types using nginx_mime2cpp.py #include #include -namespace crow { - const std::unordered_map mime_types { - {"shtml", "text/html"}, - {"htm", "text/html"}, - {"html", "text/html"}, - {"css", "text/css"}, - {"xml", "text/xml"}, - {"gif", "image/gif"}, - {"jpg", "image/jpeg"}, - {"jpeg", "image/jpeg"}, - {"js", "application/javascript"}, - {"atom", "application/atom+xml"}, - {"rss", "application/rss+xml"}, - {"mml", "text/mathml"}, - {"txt", "text/plain"}, - {"jad", "text/vnd.sun.j2me.app-descriptor"}, - {"wml", "text/vnd.wap.wml"}, - {"htc", "text/x-component"}, - {"png", "image/png"}, - {"svgz", "image/svg+xml"}, - {"svg", "image/svg+xml"}, - {"tiff", "image/tiff"}, - {"tif", "image/tiff"}, - {"wbmp", "image/vnd.wap.wbmp"}, - {"webp", "image/webp"}, - {"ico", "image/x-icon"}, - {"jng", "image/x-jng"}, - {"bmp", "image/x-ms-bmp"}, - {"woff", "font/woff"}, - {"woff2", "font/woff2"}, - {"ear", "application/java-archive"}, - {"war", "application/java-archive"}, - {"jar", "application/java-archive"}, - {"json", "application/json"}, - {"hqx", "application/mac-binhex40"}, - {"doc", "application/msword"}, - {"pdf", "application/pdf"}, - {"ai", "application/postscript"}, - {"eps", "application/postscript"}, - {"ps", "application/postscript"}, - {"rtf", "application/rtf"}, - {"m3u8", "application/vnd.apple.mpegurl"}, - {"kml", "application/vnd.google-earth.kml+xml"}, - {"kmz", "application/vnd.google-earth.kmz"}, - {"xls", "application/vnd.ms-excel"}, - {"eot", "application/vnd.ms-fontobject"}, - {"ppt", "application/vnd.ms-powerpoint"}, - {"odg", "application/vnd.oasis.opendocument.graphics"}, - {"odp", "application/vnd.oasis.opendocument.presentation"}, - {"ods", "application/vnd.oasis.opendocument.spreadsheet"}, - {"odt", "application/vnd.oasis.opendocument.text"}, - {"pptx", "application/vnd.openxmlformats-officedocument.presentationml.presentation"}, - {"xlsx", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"}, - {"docx", "application/vnd.openxmlformats-officedocument.wordprocessingml.document"}, - {"wmlc", "application/vnd.wap.wmlc"}, - {"7z", "application/x-7z-compressed"}, - {"cco", "application/x-cocoa"}, - {"jardiff", "application/x-java-archive-diff"}, - {"jnlp", "application/x-java-jnlp-file"}, - {"run", "application/x-makeself"}, - {"pm", "application/x-perl"}, - {"pl", "application/x-perl"}, - {"pdb", "application/x-pilot"}, - {"prc", "application/x-pilot"}, - {"rar", "application/x-rar-compressed"}, - {"rpm", "application/x-redhat-package-manager"}, - {"sea", "application/x-sea"}, - {"swf", "application/x-shockwave-flash"}, - {"sit", "application/x-stuffit"}, - {"tk", "application/x-tcl"}, - {"tcl", "application/x-tcl"}, - {"crt", "application/x-x509-ca-cert"}, - {"pem", "application/x-x509-ca-cert"}, - {"der", "application/x-x509-ca-cert"}, - {"xpi", "application/x-xpinstall"}, - {"xhtml", "application/xhtml+xml"}, - {"xspf", "application/xspf+xml"}, - {"zip", "application/zip"}, - {"dll", "application/octet-stream"}, - {"exe", "application/octet-stream"}, - {"bin", "application/octet-stream"}, - {"deb", "application/octet-stream"}, - {"dmg", "application/octet-stream"}, - {"img", "application/octet-stream"}, - {"iso", "application/octet-stream"}, - {"msm", "application/octet-stream"}, - {"msp", "application/octet-stream"}, - {"msi", "application/octet-stream"}, - {"kar", "audio/midi"}, - {"midi", "audio/midi"}, - {"mid", "audio/midi"}, - {"mp3", "audio/mpeg"}, - {"ogg", "audio/ogg"}, - {"m4a", "audio/x-m4a"}, - {"ra", "audio/x-realaudio"}, - {"3gp", "video/3gpp"}, - {"3gpp", "video/3gpp"}, - {"ts", "video/mp2t"}, - {"mp4", "video/mp4"}, - {"mpg", "video/mpeg"}, - {"mpeg", "video/mpeg"}, - {"mov", "video/quicktime"}, - {"webm", "video/webm"}, - {"flv", "video/x-flv"}, - {"m4v", "video/x-m4v"}, - {"mng", "video/x-mng"}, - {"asf", "video/x-ms-asf"}, - {"asx", "video/x-ms-asf"}, - {"wmv", "video/x-ms-wmv"}, - {"avi", "video/x-msvideo"} - }; +namespace crow +{ + const std::unordered_map mime_types{ + {"shtml", "text/html"}, + {"htm", "text/html"}, + {"html", "text/html"}, + {"css", "text/css"}, + {"xml", "text/xml"}, + {"gif", "image/gif"}, + {"jpg", "image/jpeg"}, + {"jpeg", "image/jpeg"}, + {"js", "application/javascript"}, + {"atom", "application/atom+xml"}, + {"rss", "application/rss+xml"}, + {"mml", "text/mathml"}, + {"txt", "text/plain"}, + {"jad", "text/vnd.sun.j2me.app-descriptor"}, + {"wml", "text/vnd.wap.wml"}, + {"htc", "text/x-component"}, + {"png", "image/png"}, + {"svgz", "image/svg+xml"}, + {"svg", "image/svg+xml"}, + {"tiff", "image/tiff"}, + {"tif", "image/tiff"}, + {"wbmp", "image/vnd.wap.wbmp"}, + {"webp", "image/webp"}, + {"ico", "image/x-icon"}, + {"jng", "image/x-jng"}, + {"bmp", "image/x-ms-bmp"}, + {"woff", "font/woff"}, + {"woff2", "font/woff2"}, + {"ear", "application/java-archive"}, + {"war", "application/java-archive"}, + {"jar", "application/java-archive"}, + {"json", "application/json"}, + {"hqx", "application/mac-binhex40"}, + {"doc", "application/msword"}, + {"pdf", "application/pdf"}, + {"ai", "application/postscript"}, + {"eps", "application/postscript"}, + {"ps", "application/postscript"}, + {"rtf", "application/rtf"}, + {"m3u8", "application/vnd.apple.mpegurl"}, + {"kml", "application/vnd.google-earth.kml+xml"}, + {"kmz", "application/vnd.google-earth.kmz"}, + {"xls", "application/vnd.ms-excel"}, + {"eot", "application/vnd.ms-fontobject"}, + {"ppt", "application/vnd.ms-powerpoint"}, + {"odg", "application/vnd.oasis.opendocument.graphics"}, + {"odp", "application/vnd.oasis.opendocument.presentation"}, + {"ods", "application/vnd.oasis.opendocument.spreadsheet"}, + {"odt", "application/vnd.oasis.opendocument.text"}, + {"pptx", "application/vnd.openxmlformats-officedocument.presentationml.presentation"}, + {"xlsx", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"}, + {"docx", "application/vnd.openxmlformats-officedocument.wordprocessingml.document"}, + {"wmlc", "application/vnd.wap.wmlc"}, + {"7z", "application/x-7z-compressed"}, + {"cco", "application/x-cocoa"}, + {"jardiff", "application/x-java-archive-diff"}, + {"jnlp", "application/x-java-jnlp-file"}, + {"run", "application/x-makeself"}, + {"pm", "application/x-perl"}, + {"pl", "application/x-perl"}, + {"pdb", "application/x-pilot"}, + {"prc", "application/x-pilot"}, + {"rar", "application/x-rar-compressed"}, + {"rpm", "application/x-redhat-package-manager"}, + {"sea", "application/x-sea"}, + {"swf", "application/x-shockwave-flash"}, + {"sit", "application/x-stuffit"}, + {"tk", "application/x-tcl"}, + {"tcl", "application/x-tcl"}, + {"crt", "application/x-x509-ca-cert"}, + {"pem", "application/x-x509-ca-cert"}, + {"der", "application/x-x509-ca-cert"}, + {"xpi", "application/x-xpinstall"}, + {"xhtml", "application/xhtml+xml"}, + {"xspf", "application/xspf+xml"}, + {"zip", "application/zip"}, + {"dll", "application/octet-stream"}, + {"exe", "application/octet-stream"}, + {"bin", "application/octet-stream"}, + {"deb", "application/octet-stream"}, + {"dmg", "application/octet-stream"}, + {"img", "application/octet-stream"}, + {"iso", "application/octet-stream"}, + {"msm", "application/octet-stream"}, + {"msp", "application/octet-stream"}, + {"msi", "application/octet-stream"}, + {"kar", "audio/midi"}, + {"midi", "audio/midi"}, + {"mid", "audio/midi"}, + {"mp3", "audio/mpeg"}, + {"ogg", "audio/ogg"}, + {"m4a", "audio/x-m4a"}, + {"ra", "audio/x-realaudio"}, + {"3gp", "video/3gpp"}, + {"3gpp", "video/3gpp"}, + {"ts", "video/mp2t"}, + {"mp4", "video/mp4"}, + {"mpg", "video/mpeg"}, + {"mpeg", "video/mpeg"}, + {"mov", "video/quicktime"}, + {"webm", "video/webm"}, + {"flv", "video/x-flv"}, + {"m4v", "video/x-m4v"}, + {"mng", "video/x-mng"}, + {"asf", "video/x-ms-asf"}, + {"asx", "video/x-ms-asf"}, + {"wmv", "video/x-ms-wmv"}, + {"avi", "video/x-msvideo"}}; } diff --git a/include/crow/multipart.h b/include/crow/multipart.h index 95f13eefa..44310027b 100644 --- a/include/crow/multipart.h +++ b/include/crow/multipart.h @@ -9,34 +9,33 @@ namespace crow { - ///Encapsulates anything related to processing and organizing `multipart/xyz` messages + /// Encapsulates anything related to processing and organizing `multipart/xyz` messages namespace multipart { const std::string dd = "--"; const std::string crlf = "\r\n"; - ///The first part in a section, contains metadata about the part + /// The first part in a section, contains metadata about the part struct header { - std::pair value; ///< The first part of the header, usually `Content-Type` or `Content-Disposition` - std::unordered_map params; ///< The parameters of the header, come after the `value` + std::pair value; ///< The first part of the header, usually `Content-Type` or `Content-Disposition` + std::unordered_map params; ///< The parameters of the header, come after the `value` }; ///One part of the multipart message - - ///It is usually separated from other sections by a `boundary` /// + /// It is usually separated from other sections by a `boundary` struct part { std::vector
headers; ///< (optional) The first part before the data, Contains information regarding the type of data and encoding - std::string body; ///< The actual data in the part + std::string body; ///< The actual data in the part }; - ///The parsed multipart request/response + /// The parsed multipart request/response struct message : public returnable { ci_map headers; - std::string boundary; ///< The text boundary that separates different `parts` + std::string boundary; ///< The text boundary that separates different `parts` std::vector parts; ///< The individual parts of the message const std::string& get_header_value(const std::string& key) const @@ -44,13 +43,13 @@ namespace crow return crow::get_header_value(headers, key); } - ///Represent all parts as a string (**does not include message headers**) + /// Represent all parts as a string (**does not include message headers**) std::string dump() const override { std::stringstream str; std::string delimiter = dd + boundary; - for (unsigned i=0 ; i(header.substr(0, header_split), header.substr(header_split+2)); + to_add.value = std::pair(header.substr(0, header_split), header.substr(header_split + 2)); } - //add the parameters + // Add the parameters while (!line.empty()) { size_t found = line.find("; "); std::string param = line.substr(0, found); if (found != std::string::npos) - line.erase(0, found+2); + line.erase(0, found + 2); else line = std::string(); size_t param_split = param.find('='); - std::string value = param.substr(param_split+1); + std::string value = param.substr(param_split + 1); to_add.params.emplace(param.substr(0, param_split), trim(value)); } @@ -181,18 +179,17 @@ namespace crow } } - inline std::string trim (std::string& string, const char& excess = '"') const + inline std::string trim(std::string& string, const char& excess = '"') const { - if (string.length() > 1 && string[0] == excess && string[string.length()-1] == excess) - return string.substr(1, string.length()-2); + if (string.length() > 1 && string[0] == excess && string[string.length() - 1] == excess) + return string.substr(1, string.length() - 2); return string; } - inline std::string pad (std::string& string, const char& padding = '"') const + inline std::string pad(std::string& string, const char& padding = '"') const { - return (padding + string + padding); + return (padding + string + padding); } - }; - } -} + } // namespace multipart +} // namespace crow diff --git a/include/crow/mustache.h b/include/crow/mustache.h index 5be8db737..0431193d7 100644 --- a/include/crow/mustache.h +++ b/include/crow/mustache.h @@ -16,9 +16,9 @@ namespace crow class invalid_template_exception : public std::exception { - public: - invalid_template_exception(const std::string& msg) - : msg("crow::mustache error: " + msg) + public: + invalid_template_exception(const std::string& msg): + msg("crow::mustache error: " + msg) { } virtual const char* what() const throw() @@ -45,17 +45,18 @@ namespace crow int end; int pos; ActionType t; - Action(ActionType t, size_t start, size_t end, size_t pos = 0) - : start(static_cast(start)), end(static_cast(end)), pos(static_cast(pos)), t(t) - {} + Action(ActionType t, size_t start, size_t end, size_t pos = 0): + start(static_cast(start)), end(static_cast(end)), pos(static_cast(pos)), t(t) + { + } }; /// A mustache template object. - class template_t + class template_t { public: - template_t(std::string body) - : body_(std::move(body)) + template_t(std::string body): + body_(std::move(body)) { // {{ {{# {{/ {{^ {{! {{> {{= parse(); @@ -66,7 +67,7 @@ namespace crow { return body_.substr(action.start, action.end - action.start); } - auto find_context(const std::string& name, const std::vector& stack, bool shouldUseOnlyFirstStackValue = false)->std::pair + auto find_context(const std::string& name, const std::vector& stack, bool shouldUseOnlyFirstStackValue = false) -> std::pair { if (name == ".") { @@ -78,7 +79,7 @@ namespace crow int dotPosition = name.find("."); if (dotPosition == static_cast(name.npos)) { - for(auto it = stack.rbegin(); it != stack.rend(); ++it) + for (auto it = stack.rbegin(); it != stack.rend(); ++it) { if ((*it)->t() == json::type::Object) { @@ -91,22 +92,22 @@ namespace crow { std::vector dotPositions; dotPositions.push_back(-1); - while(dotPosition != static_cast(name.npos)) + while (dotPosition != static_cast(name.npos)) { dotPositions.push_back(dotPosition); - dotPosition = name.find(".", dotPosition+1); + dotPosition = name.find(".", dotPosition + 1); } dotPositions.push_back(name.size()); std::vector names; - names.reserve(dotPositions.size()-1); - for(int i = 1; i < static_cast(dotPositions.size()); i ++) - names.emplace_back(name.substr(dotPositions[i-1]+1, dotPositions[i]-dotPositions[i-1]-1)); + names.reserve(dotPositions.size() - 1); + for (int i = 1; i < static_cast(dotPositions.size()); i++) + names.emplace_back(name.substr(dotPositions[i - 1] + 1, dotPositions[i] - dotPositions[i - 1] - 1)); - for(auto it = stack.rbegin(); it != stack.rend(); ++it) + for (auto it = stack.rbegin(); it != stack.rend(); ++it) { context* view = *it; bool found = true; - for(auto jt = names.begin(); jt != names.end(); ++jt) + for (auto jt = names.begin(); jt != names.end(); ++jt) { if (view->t() == json::type::Object && view->count(*jt)) @@ -115,7 +116,8 @@ namespace crow } else { - if (shouldUseOnlyFirstStackValue) { + if (shouldUseOnlyFirstStackValue) + { return {false, empty_str}; } found = false; @@ -125,7 +127,6 @@ namespace crow if (found) return {true, *view}; } - } return {false, empty_str}; @@ -134,9 +135,9 @@ namespace crow void escape(const std::string& in, std::string& out) { out.reserve(out.size() + in.size()); - for(auto it = in.begin(); it != in.end(); ++it) + for (auto it = in.begin(); it != in.end(); ++it) { - switch(*it) + switch (*it) { case '&': out += "&"; break; case '<': out += "<"; break; @@ -149,20 +150,25 @@ namespace crow } } - bool isTagInsideObjectBlock(const int& current, const std::vector& stack) + bool isTagInsideObjectBlock(const int& current, const std::vector& stack) { int openedBlock = 0; int totalBlocksBefore = 0; - for (int i = current; i > 0; --i) { + for (int i = current; i > 0; --i) + { ++totalBlocksBefore; auto& action = actions_[i - 1]; - if (action.t == ActionType::OpenBlock) { - if (openedBlock == 0 && (*stack.rbegin())->t() == json::type::Object) { + if (action.t == ActionType::OpenBlock) + { + if (openedBlock == 0 && (*stack.rbegin())->t() == json::type::Object) + { return true; } --openedBlock; - } else if (action.t == ActionType::CloseBlock) { + } + else if (action.t == ActionType::CloseBlock) + { ++openedBlock; } } @@ -177,116 +183,117 @@ namespace crow if (indent) out.insert(out.size(), indent, ' '); - while(current < actionEnd) + while (current < actionEnd) { auto& fragment = fragments_[current]; auto& action = actions_[current]; render_fragment(fragment, indent, out); - switch(action.t) + switch (action.t) { case ActionType::Ignore: // do nothing break; case ActionType::Partial: - { - std::string partial_name = tag_name(action); - auto partial_templ = load(partial_name); - int partial_indent = action.pos; - partial_templ.render_internal(0, partial_templ.fragments_.size()-1, stack, out, partial_indent?indent+partial_indent:0); - } - break; + { + std::string partial_name = tag_name(action); + auto partial_templ = load(partial_name); + int partial_indent = action.pos; + partial_templ.render_internal(0, partial_templ.fragments_.size() - 1, stack, out, partial_indent ? indent + partial_indent : 0); + } + break; case ActionType::UnescapeTag: case ActionType::Tag: + { + bool shouldUseOnlyFirstStackValue = false; + if (isTagInsideObjectBlock(current, stack)) { - bool shouldUseOnlyFirstStackValue = false; - if (isTagInsideObjectBlock(current, stack)) { - shouldUseOnlyFirstStackValue = true; - } - auto optional_ctx = find_context(tag_name(action), stack, shouldUseOnlyFirstStackValue); - auto& ctx = optional_ctx.second; - switch(ctx.t()) - { - case json::type::Number: - out += ctx.dump(); - break; - case json::type::String: - if (action.t == ActionType::Tag) - escape(ctx.s, out); - else - out += ctx.s; - break; - default: - throw std::runtime_error("not implemented tag type" + boost::lexical_cast(static_cast(ctx.t()))); - } + shouldUseOnlyFirstStackValue = true; } - break; - case ActionType::ElseBlock: + auto optional_ctx = find_context(tag_name(action), stack, shouldUseOnlyFirstStackValue); + auto& ctx = optional_ctx.second; + switch (ctx.t()) { - static context nullContext; - auto optional_ctx = find_context(tag_name(action), stack); - if (!optional_ctx.first) - { + case json::type::Number: + out += ctx.dump(); + break; + case json::type::String: + if (action.t == ActionType::Tag) + escape(ctx.s, out); + else + out += ctx.s; + break; + default: + throw std::runtime_error("not implemented tag type" + boost::lexical_cast(static_cast(ctx.t()))); + } + } + break; + case ActionType::ElseBlock: + { + static context nullContext; + auto optional_ctx = find_context(tag_name(action), stack); + if (!optional_ctx.first) + { + stack.emplace_back(&nullContext); + break; + } + + auto& ctx = optional_ctx.second; + switch (ctx.t()) + { + case json::type::List: + if (ctx.l && !ctx.l->empty()) + current = action.pos; + else + stack.emplace_back(&nullContext); + break; + case json::type::False: + case json::type::Null: stack.emplace_back(&nullContext); break; - } - - auto& ctx = optional_ctx.second; - switch(ctx.t()) - { - case json::type::List: - if (ctx.l && !ctx.l->empty()) - current = action.pos; - else - stack.emplace_back(&nullContext); - break; - case json::type::False: - case json::type::Null: - stack.emplace_back(&nullContext); - break; - default: - current = action.pos; - break; - } - break; - } - case ActionType::OpenBlock: - { - auto optional_ctx = find_context(tag_name(action), stack); - if (!optional_ctx.first) - { + default: current = action.pos; break; - } - - auto& ctx = optional_ctx.second; - switch(ctx.t()) - { - case json::type::List: - if (ctx.l) - for(auto it = ctx.l->begin(); it != ctx.l->end(); ++it) - { - stack.push_back(&*it); - render_internal(current+1, action.pos, stack, out, indent); - stack.pop_back(); - } - current = action.pos; - break; - case json::type::Number: - case json::type::String: - case json::type::Object: - case json::type::True: - stack.push_back(&ctx); - break; - case json::type::False: - case json::type::Null: - current = action.pos; - break; - default: - throw std::runtime_error("{{#: not implemented context type: " + boost::lexical_cast(static_cast(ctx.t()))); - break; - } + } + break; + } + case ActionType::OpenBlock: + { + auto optional_ctx = find_context(tag_name(action), stack); + if (!optional_ctx.first) + { + current = action.pos; break; } + + auto& ctx = optional_ctx.second; + switch (ctx.t()) + { + case json::type::List: + if (ctx.l) + for (auto it = ctx.l->begin(); it != ctx.l->end(); ++it) + { + stack.push_back(&*it); + render_internal(current + 1, action.pos, stack, out, indent); + stack.pop_back(); + } + current = action.pos; + break; + case json::type::Number: + case json::type::String: + case json::type::Object: + case json::type::True: + stack.push_back(&ctx); + break; + case json::type::False: + case json::type::Null: + current = action.pos; + break; + default: + throw std::runtime_error("{{#: not implemented context type: " + boost::lexical_cast(static_cast(ctx.t()))); + break; + } + break; + } case ActionType::CloseBlock: stack.pop_back(); break; @@ -302,16 +309,17 @@ namespace crow { if (indent) { - for(int i = fragment.first; i < fragment.second; i ++) + for (int i = fragment.first; i < fragment.second; i++) { out += body_[i]; - if (body_[i] == '\n' && i+1 != static_cast(body_.size())) + if (body_[i] == '\n' && i + 1 != static_cast(body_.size())) out.insert(out.size(), indent, ' '); } } else - out.insert(out.size(), body_, fragment.first, fragment.second-fragment.first); + out.insert(out.size(), body_, fragment.first, fragment.second - fragment.first); } + public: std::string render() { @@ -320,7 +328,7 @@ namespace crow stack.emplace_back(&empty_ctx); std::string ret; - render_internal(0, fragments_.size()-1, stack, ret, 0); + render_internal(0, fragments_.size() - 1, stack, ret, 0); return ret; } std::string render(context& ctx) @@ -329,21 +337,20 @@ namespace crow stack.emplace_back(&ctx); std::string ret; - render_internal(0, fragments_.size()-1, stack, ret, 0); + render_internal(0, fragments_.size() - 1, stack, ret, 0); return ret; } private: - void parse() { std::string tag_open = "{{"; std::string tag_close = "}}"; std::vector blockPositions; - + size_t current = 0; - while(1) + while (1) { size_t idx = body_.find(tag_open, current); if (idx == body_.npos) @@ -366,27 +373,31 @@ namespace crow throw invalid_template_exception("not matched opening tag"); } current = endIdx + tag_close.size(); - switch(body_[idx]) + switch (body_[idx]) { case '#': idx++; - while(body_[idx] == ' ') idx++; - while(body_[endIdx-1] == ' ') endIdx--; + while (body_[idx] == ' ') + idx++; + while (body_[endIdx - 1] == ' ') + endIdx--; blockPositions.emplace_back(static_cast(actions_.size())); actions_.emplace_back(ActionType::OpenBlock, idx, endIdx); break; case '/': idx++; - while(body_[idx] == ' ') idx++; - while(body_[endIdx-1] == ' ') endIdx--; + while (body_[idx] == ' ') + idx++; + while (body_[endIdx - 1] == ' ') + endIdx--; { auto& matched = actions_[blockPositions.back()]; - if (body_.compare(idx, endIdx-idx, - body_, matched.start, matched.end - matched.start) != 0) + if (body_.compare(idx, endIdx - idx, + body_, matched.start, matched.end - matched.start) != 0) { - throw invalid_template_exception("not matched {{# {{/ pair: " + - body_.substr(matched.start, matched.end - matched.start) + ", " + - body_.substr(idx, endIdx-idx)); + throw invalid_template_exception("not matched {{# {{/ pair: " + + body_.substr(matched.start, matched.end - matched.start) + ", " + + body_.substr(idx, endIdx - idx)); } matched.pos = actions_.size(); } @@ -395,68 +406,79 @@ namespace crow break; case '^': idx++; - while(body_[idx] == ' ') idx++; - while(body_[endIdx-1] == ' ') endIdx--; + while (body_[idx] == ' ') + idx++; + while (body_[endIdx - 1] == ' ') + endIdx--; blockPositions.emplace_back(static_cast(actions_.size())); actions_.emplace_back(ActionType::ElseBlock, idx, endIdx); break; case '!': // do nothing action - actions_.emplace_back(ActionType::Ignore, idx+1, endIdx); + actions_.emplace_back(ActionType::Ignore, idx + 1, endIdx); break; case '>': // partial idx++; - while(body_[idx] == ' ') idx++; - while(body_[endIdx-1] == ' ') endIdx--; + while (body_[idx] == ' ') + idx++; + while (body_[endIdx - 1] == ' ') + endIdx--; actions_.emplace_back(ActionType::Partial, idx, endIdx); break; case '{': if (tag_open != "{{" || tag_close != "}}") throw invalid_template_exception("cannot use triple mustache when delimiter changed"); - idx ++; - if (body_[endIdx+2] != '}') + idx++; + if (body_[endIdx + 2] != '}') { throw invalid_template_exception("{{{: }}} not matched"); } - while(body_[idx] == ' ') idx++; - while(body_[endIdx-1] == ' ') endIdx--; + while (body_[idx] == ' ') + idx++; + while (body_[endIdx - 1] == ' ') + endIdx--; actions_.emplace_back(ActionType::UnescapeTag, idx, endIdx); current++; break; case '&': - idx ++; - while(body_[idx] == ' ') idx++; - while(body_[endIdx-1] == ' ') endIdx--; + idx++; + while (body_[idx] == ' ') + idx++; + while (body_[endIdx - 1] == ' ') + endIdx--; actions_.emplace_back(ActionType::UnescapeTag, idx, endIdx); break; case '=': // tag itself is no-op - idx ++; + idx++; actions_.emplace_back(ActionType::Ignore, idx, endIdx); - endIdx --; + endIdx--; if (body_[endIdx] != '=') - throw invalid_template_exception("{{=: not matching = tag: "+body_.substr(idx, endIdx-idx)); - endIdx --; - while(body_[idx] == ' ') idx++; - while(body_[endIdx] == ' ') endIdx--; + throw invalid_template_exception("{{=: not matching = tag: " + body_.substr(idx, endIdx - idx)); + endIdx--; + while (body_[idx] == ' ') + idx++; + while (body_[endIdx] == ' ') + endIdx--; endIdx++; { bool succeeded = false; - for(size_t i = idx; i < endIdx; i++) + for (size_t i = idx; i < endIdx; i++) { if (body_[i] == ' ') { - tag_open = body_.substr(idx, i-idx); - while(body_[i] == ' ') i++; - tag_close = body_.substr(i, endIdx-i); + tag_open = body_.substr(idx, i - idx); + while (body_[i] == ' ') + i++; + tag_close = body_.substr(i, endIdx - i); if (tag_open.empty()) throw invalid_template_exception("{{=: empty open tag"); if (tag_close.empty()) throw invalid_template_exception("{{=: empty close tag"); if (tag_close.find(" ") != tag_close.npos) - throw invalid_template_exception("{{=: invalid open/close tag: "+tag_open+" " + tag_close); + throw invalid_template_exception("{{=: invalid open/close tag: " + tag_open + " " + tag_close); succeeded = true; break; } @@ -467,24 +489,26 @@ namespace crow break; default: // normal tag case; - while(body_[idx] == ' ') idx++; - while(body_[endIdx-1] == ' ') endIdx--; + while (body_[idx] == ' ') + idx++; + while (body_[endIdx - 1] == ' ') + endIdx--; actions_.emplace_back(ActionType::Tag, idx, endIdx); break; } } // removing standalones - for(int i = actions_.size()-2; i >= 0; i --) + for (int i = actions_.size() - 2; i >= 0; i--) { if (actions_[i].t == ActionType::Tag || actions_[i].t == ActionType::UnescapeTag) continue; auto& fragment_before = fragments_[i]; - auto& fragment_after = fragments_[i+1]; - bool is_last_action = i == static_cast(actions_.size())-2; + auto& fragment_after = fragments_[i + 1]; + bool is_last_action = i == static_cast(actions_.size()) - 2; bool all_space_before = true; int j, k; - for(j = fragment_before.second-1;j >= fragment_before.first;j--) + for (j = fragment_before.second - 1; j >= fragment_before.first; j--) { if (body_[j] != ' ') { @@ -497,7 +521,7 @@ namespace crow if (!all_space_before && body_[j] != '\n') continue; bool all_space_after = true; - for(k = fragment_after.first; k < static_cast(body_.size()) && k < fragment_after.second; k ++) + for (k = fragment_after.first; k < static_cast(body_.size()) && k < fragment_after.second; k++) { if (body_[k] != ' ') { @@ -507,31 +531,30 @@ namespace crow } if (all_space_after && !is_last_action) continue; - if (!all_space_after && - !( - body_[k] == '\n' - || - (body_[k] == '\r' && - k + 1 < static_cast(body_.size()) && - body_[k+1] == '\n'))) + if (!all_space_after && + !( + body_[k] == '\n' || + (body_[k] == '\r' && + k + 1 < static_cast(body_.size()) && + body_[k + 1] == '\n'))) continue; if (actions_[i].t == ActionType::Partial) { actions_[i].pos = fragment_before.second - j - 1; } - fragment_before.second = j+1; + fragment_before.second = j + 1; if (!all_space_after) { if (body_[k] == '\n') k++; - else + else k += 2; fragment_after.first = k; } } } - - std::vector> fragments_; + + std::vector> fragments_; std::vector actions_; std::string body_; }; @@ -547,7 +570,7 @@ namespace crow static std::string template_base_directory = "templates"; return template_base_directory; } - } + } // namespace detail inline std::string default_loader(const std::string& filename) { @@ -566,18 +589,18 @@ namespace crow namespace detail { - inline std::function& get_loader_ref() + inline std::function& get_loader_ref() { - static std::function loader = default_loader; + static std::function loader = default_loader; return loader; } - } + } // namespace detail inline void set_base(const std::string& path) { auto& base = detail::get_template_base_directory_ref(); base = path; - if (base.back() != '\\' && + if (base.back() != '\\' && base.back() != '/') { base += '/'; @@ -598,5 +621,5 @@ namespace crow { return compile(detail::get_loader_ref()(filename)); } - } -} + } // namespace mustache +} // namespace crow diff --git a/include/crow/parser.h b/include/crow/parser.h index f333451df..ad98dbf3d 100644 --- a/include/crow/parser.h +++ b/include/crow/parser.h @@ -11,10 +11,9 @@ namespace crow { /// A wrapper for `nodejs/http-parser`. - - /// Used to generate a \ref crow.request from the TCP socket buffer. /// - template + /// Used to generate a \ref crow.request from the TCP socket buffer. + template struct HTTPParser : public http_parser { static int on_message_begin(http_parser* self_) @@ -26,7 +25,7 @@ namespace crow static int on_url(http_parser* self_, const char* at, size_t length) { HTTPParser* self = static_cast(self_); - self->raw_url.insert(self->raw_url.end(), at, at+length); + self->raw_url.insert(self->raw_url.end(), at, at + length); return 0; } static int on_header_field(http_parser* self_, const char* at, size_t length) @@ -39,11 +38,11 @@ namespace crow { self->headers.emplace(std::move(self->header_field), std::move(self->header_value)); } - self->header_field.assign(at, at+length); + self->header_field.assign(at, at + length); self->header_building_state = 1; break; case 1: - self->header_field.insert(self->header_field.end(), at, at+length); + self->header_field.insert(self->header_field.end(), at, at + length); break; } return 0; @@ -54,11 +53,11 @@ namespace crow switch (self->header_building_state) { case 0: - self->header_value.insert(self->header_value.end(), at, at+length); + self->header_value.insert(self->header_value.end(), at, at + length); break; case 1: self->header_building_state = 0; - self->header_value.assign(at, at+length); + self->header_value.assign(at, at + length); break; } return 0; @@ -76,7 +75,7 @@ namespace crow static int on_body(http_parser* self_, const char* at, size_t length) { HTTPParser* self = static_cast(self_); - self->body.insert(self->body.end(), at, at+length); + self->body.insert(self->body.end(), at, at + length); return 0; } static int on_message_complete(http_parser* self_) @@ -90,8 +89,8 @@ namespace crow self->process_message(); return 0; } - HTTPParser(Handler* handler) : - handler_(handler) + HTTPParser(Handler* handler): + handler_(handler) { http_parser_init(this, HTTP_REQUEST); } @@ -101,14 +100,14 @@ namespace crow bool feed(const char* buffer, int length) { const static http_parser_settings settings_{ - on_message_begin, - on_url, - nullptr, - on_header_field, - on_header_value, - on_headers_complete, - on_body, - on_message_complete, + on_message_begin, + on_url, + nullptr, + on_header_field, + on_header_value, + on_headers_complete, + on_body, + on_message_complete, }; int nparsed = http_parser_execute(this, &settings_, buffer, length); @@ -152,10 +151,10 @@ namespace crow return request{static_cast(method), std::move(raw_url), std::move(url), std::move(url_params), std::move(headers), std::move(body)}; } - bool is_upgrade() const - { - return upgrade; - } + bool is_upgrade() const + { + return upgrade; + } bool check_version(int major, int minor) const { @@ -174,4 +173,4 @@ namespace crow Handler* handler_; ///< This is currently an HTTP connection object (\ref crow.Connection). }; -} +} // namespace crow diff --git a/include/crow/returnable.h b/include/crow/returnable.h index f38511ec2..e7e6370c7 100644 --- a/include/crow/returnable.h +++ b/include/crow/returnable.h @@ -4,15 +4,17 @@ namespace crow { -/// An abstract class that allows any other class to be returned by a handler. -struct returnable -{ - std::string content_type; - virtual std::string dump() const = 0; + /// An abstract class that allows any other class to be returned by a handler. + struct returnable + { + std::string content_type; + virtual std::string dump() const = 0; - returnable(std::string ctype) : content_type {ctype} - {} + returnable(std::string ctype): + content_type{ctype} + { + } - virtual ~returnable(){}; -}; -} + virtual ~returnable(){}; + }; +} // namespace crow diff --git a/include/crow/routing.h b/include/crow/routing.h index d313e54fe..66c6e6dde 100644 --- a/include/crow/routing.h +++ b/include/crow/routing.h @@ -22,14 +22,14 @@ namespace crow constexpr const uint16_t INVALID_BP_ID{0xFFFF}; /// A base class for all rules. - - /// Used to provide a common interface for code dealing with different types of rules. + /// + /// Used to provide a common interface for code dealing with different types of rules.
/// A Rule provides a URL, allowed HTTP methods, and handlers. class BaseRule { public: - BaseRule(std::string rule) - : rule_(std::move(rule)) + BaseRule(std::string rule): + rule_(std::move(rule)) { } @@ -64,10 +64,10 @@ namespace crow return methods_; } - template + template void foreach_method(F f) { - for(uint32_t method = 0, method_bit = 1; method < static_cast(HTTPMethod::InternalMethodCount); method++, method_bit<<=1) + for (uint32_t method = 0, method_bit = 1; method < static_cast(HTTPMethod::InternalMethodCount); method++, method_bit <<= 1) { if (methods_ & method_bit) f(method); @@ -80,7 +80,7 @@ namespace crow const std::string& rule() { return rule_; } protected: - uint32_t methods_{1<(HTTPMethod::Get)}; + uint32_t methods_{1 << static_cast(HTTPMethod::Get)}; std::string rule_; std::string name_; @@ -89,7 +89,7 @@ namespace crow friend class Router; friend class Blueprint; - template + template friend struct RuleParameterTraits; }; @@ -98,14 +98,14 @@ namespace crow { namespace routing_handler_call_helper { - template + template struct call_pair { using type = T; static const int pos = Pos; }; - template + template struct call_params { H1& handler; @@ -114,93 +114,87 @@ namespace crow response& res; }; - template + template struct call { }; - template + template struct call, black_magic::S> { void operator()(F cparams) { using pushed = typename black_magic::S::template push_back>; - call, pushed>()(cparams); + call, pushed>()(cparams); } }; - template + template struct call, black_magic::S> { void operator()(F cparams) { using pushed = typename black_magic::S::template push_back>; - call, pushed>()(cparams); + call, pushed>()(cparams); } }; - template + template struct call, black_magic::S> { void operator()(F cparams) { using pushed = typename black_magic::S::template push_back>; - call, pushed>()(cparams); + call, pushed>()(cparams); } }; - template + template struct call, black_magic::S> { void operator()(F cparams) { using pushed = typename black_magic::S::template push_back>; - call, pushed>()(cparams); + call, pushed>()(cparams); } }; - template + template struct call, black_magic::S> { void operator()(F cparams) { cparams.handler( - cparams.req, - cparams.res, - cparams.params.template get(Args1::pos)... - ); + cparams.req, + cparams.res, + cparams.params.template get(Args1::pos)...); } }; - template + template struct Wrapped { - template - void set_(Func f, typename std::enable_if< - !std::is_same>::type, const request&>::value - , int>::type = 0) + template + void set_(Func f, typename std::enable_if>::type, const request&>::value, int>::type = 0) { handler_ = ( #ifdef CROW_CAN_USE_CPP14 - [f = std::move(f)] + [f = std::move(f)] #else - [f] + [f] #endif - (const request&, response& res, Args... args){ - res = response(f(args...)); - res.end(); - }); + (const request&, response& res, Args... args) + { + res = response(f(args...)); + res.end(); + }); } - template + template struct req_handler_wrapper { - req_handler_wrapper(Func f) - : f(std::move(f)) + req_handler_wrapper(Func f): + f(std::move(f)) { } @@ -213,11 +207,11 @@ namespace crow Func f; }; - template + template void set_(Func f, typename std::enable_if< - std::is_same>::type, const request&>::value && - !std::is_same>::type, response&>::value - , int>::type = 0) + std::is_same>::type, const request&>::value && + !std::is_same>::type, response&>::value, + int>::type = 0) { handler_ = req_handler_wrapper(std::move(f)); /*handler_ = ( @@ -228,30 +222,30 @@ namespace crow });*/ } - template + template void set_(Func f, typename std::enable_if< - std::is_same>::type, const request&>::value && - std::is_same>::type, response&>::value - , int>::type = 0) + std::is_same>::type, const request&>::value && + std::is_same>::type, response&>::value, + int>::type = 0) { handler_ = std::move(f); } - template + template struct handler_type_helper { using type = std::function; using args_type = black_magic::S...>; }; - template + template struct handler_type_helper { using type = std::function; using args_type = black_magic::S...>; }; - template + template struct handler_type_helper { using type = std::function; @@ -263,103 +257,102 @@ namespace crow void operator()(const request& req, response& res, const routing_params& params) { detail::routing_handler_call_helper::call< - detail::routing_handler_call_helper::call_params< - decltype(handler_)>, - 0, 0, 0, 0, - typename handler_type_helper::args_type, - black_magic::S<> - >()( - detail::routing_handler_call_helper::call_params< - decltype(handler_)> - {handler_, params, req, res} - ); + detail::routing_handler_call_helper::call_params< + decltype(handler_)>, + 0, 0, 0, 0, + typename handler_type_helper::args_type, + black_magic::S<>>()( + detail::routing_handler_call_helper::call_params< + decltype(handler_)>{handler_, params, req, res}); } }; - } - } + } // namespace routing_handler_call_helper + } // namespace detail class CatchallRule { public: - CatchallRule(){} + CatchallRule() {} - template + template typename std::enable_if>::value, void>::type - operator()(Func&& f) + operator()(Func&& f) { static_assert(!std::is_same::value, - "Handler function cannot have void return type; valid return types: string, int, crow::response, crow::returnable"); + "Handler function cannot have void return type; valid return types: string, int, crow::response, crow::returnable"); handler_ = ( #ifdef CROW_CAN_USE_CPP14 - [f = std::move(f)] + [f = std::move(f)] #else - [f] + [f] #endif - (const request&, response& res){ - res = response(f()); - res.end(); - }); - + (const request&, response& res) + { + res = response(f()); + res.end(); + }); } - template + template typename std::enable_if< - !black_magic::CallHelper>::value && + !black_magic::CallHelper>::value && black_magic::CallHelper>::value, - void>::type - operator()(Func&& f) + void>::type + operator()(Func&& f) { static_assert(!std::is_same()))>::value, - "Handler function cannot have void return type; valid return types: string, int, crow::response, crow::returnable"); + "Handler function cannot have void return type; valid return types: string, int, crow::response, crow::returnable"); handler_ = ( #ifdef CROW_CAN_USE_CPP14 - [f = std::move(f)] + [f = std::move(f)] #else - [f] + [f] #endif - (const crow::request& req, crow::response& res){ - res = response(f(req)); - res.end(); - }); + (const crow::request& req, crow::response& res) + { + res = response(f(req)); + res.end(); + }); } - template + template typename std::enable_if< - !black_magic::CallHelper>::value && + !black_magic::CallHelper>::value && !black_magic::CallHelper>::value && black_magic::CallHelper>::value, - void>::type - operator()(Func&& f) + void>::type + operator()(Func&& f) { - static_assert(std::is_same()))>::value, - "Handler function with response argument should have void return type"); - handler_ = ( + static_assert(std::is_same()))>::value, + "Handler function with response argument should have void return type"); + handler_ = ( #ifdef CROW_CAN_USE_CPP14 - [f = std::move(f)] + [f = std::move(f)] #else - [f] + [f] #endif - (const crow::request&, crow::response& res){ + (const crow::request&, crow::response& res) + { f(res); - }); + }); } - template + template typename std::enable_if< - !black_magic::CallHelper>::value && + !black_magic::CallHelper>::value && !black_magic::CallHelper>::value && !black_magic::CallHelper>::value, - void>::type - operator()(Func&& f) + void>::type + operator()(Func&& f) { static_assert(std::is_same(), std::declval()))>::value, - "Handler function with response argument should have void return type"); + "Handler function with response argument should have void return type"); - handler_ = std::move(f); + handler_ = std::move(f); } bool has_handler() @@ -369,21 +362,22 @@ namespace crow protected: friend class Router; + private: std::function handler_; }; /// A rule dealing with websockets. - - /// Provides the interface for the user to put in the necessary handlers for a websocket to work. /// + /// Provides the interface for the user to put in the necessary handlers for a websocket to work. class WebSocketRule : public BaseRule { using self_t = WebSocketRule; + public: - WebSocketRule(std::string rule) - : BaseRule(std::move(rule)) + WebSocketRule(std::string rule): + BaseRule(std::move(rule)) { } @@ -408,35 +402,35 @@ namespace crow } #endif - template + template self_t& onopen(Func f) { open_handler_ = f; return *this; } - template + template self_t& onmessage(Func f) { message_handler_ = f; return *this; } - template + template self_t& onclose(Func f) { close_handler_ = f; return *this; } - template + template self_t& onerror(Func f) { error_handler_ = f; return *this; } - template + template self_t& onaccept(Func f) { accept_handler_ = f; @@ -454,13 +448,13 @@ namespace crow /// Allows the user to assign parameters using functions. /// /// `rule.name("name").methods(HTTPMethod::POST)` - template + template struct RuleParameterTraits { using self_t = T; WebSocketRule& websocket() { - auto p =new WebSocketRule(static_cast(this)->rule_); + auto p = new WebSocketRule(static_cast(this)->rule_); static_cast(this)->rule_to_upgrade_.reset(p); return *p; } @@ -477,23 +471,21 @@ namespace crow return static_cast(*this); } - template - self_t& methods(HTTPMethod method, MethodArgs ... args_method) + template + self_t& methods(HTTPMethod method, MethodArgs... args_method) { methods(args_method...); static_cast(this)->methods_ |= 1 << static_cast(method); return static_cast(*this); } - }; /// A rule that can change its parameters during runtime. class DynamicRule : public BaseRule, public RuleParameterTraits { public: - - DynamicRule(std::string rule) - : BaseRule(std::move(rule)) + DynamicRule(std::string rule): + BaseRule(std::move(rule)) { } @@ -514,7 +506,7 @@ namespace crow erased_handler_(req, res, params); } - template + template void operator()(Func f) { #ifdef CROW_MSVC_WORKAROUND @@ -529,12 +521,12 @@ namespace crow // enable_if Arg1 == request && Arg2 != resposne // enable_if Arg1 != request #ifdef CROW_MSVC_WORKAROUND - template + template #else - template + template #endif std::function - wrap(Func f, black_magic::seq) + wrap(Func f, black_magic::seq) { #ifdef CROW_MSVC_WORKAROUND using function_t = utility::function_traits; @@ -542,39 +534,38 @@ namespace crow using function_t = utility::function_traits; #endif if (!black_magic::is_parameter_tag_compatible( - black_magic::get_parameter_tag_runtime(rule_.c_str()), - black_magic::compute_parameter_tag_from_args_list< + black_magic::get_parameter_tag_runtime(rule_.c_str()), + black_magic::compute_parameter_tag_from_args_list< typename function_t::template arg...>::value)) { throw std::runtime_error("route_dynamic: Handler type is mismatched with URL parameters: " + rule_); } auto ret = detail::routing_handler_call_helper::Wrapped...>(); ret.template set_< - typename function_t::template arg... - >(std::move(f)); + typename function_t::template arg...>(std::move(f)); return ret; } - template + template void operator()(std::string name, Func&& f) { name_ = std::move(name); (*this).template operator()(std::forward(f)); } + private: std::function erased_handler_; - }; /// Default rule created when CROW_ROUTE is called. - template + template class TaggedRule : public BaseRule, public RuleParameterTraits> { public: using self_t = TaggedRule; - TaggedRule(std::string rule) - : BaseRule(std::move(rule)) + TaggedRule(std::string rule): + BaseRule(std::move(rule)) { } @@ -586,98 +577,99 @@ namespace crow } } - template + template typename std::enable_if>::value, void>::type - operator()(Func&& f) + operator()(Func&& f) { static_assert(black_magic::CallHelper>::value || - black_magic::CallHelper>::value , - "Handler type is mismatched with URL parameters"); + black_magic::CallHelper>::value, + "Handler type is mismatched with URL parameters"); static_assert(!std::is_same()...))>::value, - "Handler function cannot have void return type; valid return types: string, int, crow::response, crow::returnable"); + "Handler function cannot have void return type; valid return types: string, int, crow::response, crow::returnable"); handler_ = ( #ifdef CROW_CAN_USE_CPP14 - [f = std::move(f)] + [f = std::move(f)] #else - [f] + [f] #endif - (const request&, response& res, Args ... args){ - res = response(f(args...)); - res.end(); - }); + (const request&, response& res, Args... args) + { + res = response(f(args...)); + res.end(); + }); } - template + template typename std::enable_if< - !black_magic::CallHelper>::value && + !black_magic::CallHelper>::value && black_magic::CallHelper>::value, - void>::type - operator()(Func&& f) + void>::type + operator()(Func&& f) { static_assert(black_magic::CallHelper>::value || - black_magic::CallHelper>::value, - "Handler type is mismatched with URL parameters"); + black_magic::CallHelper>::value, + "Handler type is mismatched with URL parameters"); static_assert(!std::is_same(), std::declval()...))>::value, - "Handler function cannot have void return type; valid return types: string, int, crow::response, crow::returnable"); + "Handler function cannot have void return type; valid return types: string, int, crow::response, crow::returnable"); handler_ = ( #ifdef CROW_CAN_USE_CPP14 - [f = std::move(f)] + [f = std::move(f)] #else - [f] + [f] #endif - (const crow::request& req, crow::response& res, Args ... args){ - res = response(f(req, args...)); - res.end(); - }); + (const crow::request& req, crow::response& res, Args... args) + { + res = response(f(req, args...)); + res.end(); + }); } - template + template typename std::enable_if< - !black_magic::CallHelper>::value && + !black_magic::CallHelper>::value && !black_magic::CallHelper>::value && black_magic::CallHelper>::value, - void>::type - operator()(Func&& f) - { - static_assert(black_magic::CallHelper>::value || - black_magic::CallHelper>::value - , - "Handler type is mismatched with URL parameters"); - static_assert(std::is_same(), std::declval()...))>::value, - "Handler function with response argument should have void return type"); - handler_ = ( -#ifdef CROW_CAN_USE_CPP14 - [f = std::move(f)] -#else - [f] -#endif - (const crow::request&, crow::response& res, Args ... args){ - f(res, args...); - }); - } - - template - typename std::enable_if< - !black_magic::CallHelper>::value && - !black_magic::CallHelper>::value && - !black_magic::CallHelper>::value, - void>::type - operator()(Func&& f) + void>::type + operator()(Func&& f) { static_assert(black_magic::CallHelper>::value || - black_magic::CallHelper>::value || - black_magic::CallHelper>::value - , - "Handler type is mismatched with URL parameters"); - static_assert(std::is_same(), std::declval(), std::declval()...))>::value, - "Handler function with response argument should have void return type"); - - handler_ = std::move(f); + black_magic::CallHelper>::value, + "Handler type is mismatched with URL parameters"); + static_assert(std::is_same(), std::declval()...))>::value, + "Handler function with response argument should have void return type"); + handler_ = ( +#ifdef CROW_CAN_USE_CPP14 + [f = std::move(f)] +#else + [f] +#endif + (const crow::request&, crow::response& res, Args... args) + { + f(res, args...); + }); } - template + template + typename std::enable_if< + !black_magic::CallHelper>::value && + !black_magic::CallHelper>::value && + !black_magic::CallHelper>::value, + void>::type + operator()(Func&& f) + { + static_assert(black_magic::CallHelper>::value || + black_magic::CallHelper>::value || + black_magic::CallHelper>::value, + "Handler type is mismatched with URL parameters"); + static_assert(std::is_same(), std::declval(), std::declval()...))>::value, + "Handler function with response argument should have void return type"); + + handler_ = std::move(f); + } + + template void operator()(std::string name, Func&& f) { name_ = std::move(name); @@ -692,21 +684,17 @@ namespace crow mustache::set_base("templates"); detail::routing_handler_call_helper::call< - detail::routing_handler_call_helper::call_params< - decltype(handler_)>, - 0, 0, 0, 0, - black_magic::S, - black_magic::S<> - >()( - detail::routing_handler_call_helper::call_params< - decltype(handler_)> - {handler_, params, req, res} - ); + detail::routing_handler_call_helper::call_params< + decltype(handler_)>, + 0, 0, 0, 0, + black_magic::S, + black_magic::S<>>()( + detail::routing_handler_call_helper::call_params< + decltype(handler_)>{handler_, params, req, res}); } private: std::function handler_; - }; const int RULE_SPECIAL_REDIRECT_SLASH = 1; @@ -727,12 +715,12 @@ namespace crow bool IsSimpleNode() const { - return - !rule_index && - blueprint_index == INVALID_BP_ID && - children.size() < 2 && - param == ParamType::MAX && - std::all_of(std::begin(children), std::end(children), [](Node* x){ return x->param == ParamType::MAX; }); + return !rule_index && + blueprint_index == INVALID_BP_ID && + children.size() < 2 && + param == ParamType::MAX && + std::all_of(std::begin(children), std::end(children), [](Node* x) + { return x->param == ParamType::MAX; }); } }; @@ -749,7 +737,7 @@ namespace crow void optimize() { - for (auto child: head_.children) + for (auto child : head_.children) { optimizeNode(child); } @@ -757,8 +745,6 @@ namespace crow private: - - void optimizeNode(Node* node) { if (node->children.empty()) @@ -770,12 +756,12 @@ namespace crow node->rule_index = child_temp->rule_index; node->blueprint_index = child_temp->blueprint_index; node->children = std::move(child_temp->children); - delete(child_temp); + delete (child_temp); optimizeNode(node); } else { - for(auto& child : node->children) + for (auto& child : node->children) { optimizeNode(child); } @@ -786,38 +772,38 @@ namespace crow { if (node->param != ParamType::MAX) { - switch(node->param) + switch (node->param) { case ParamType::INT: - CROW_LOG_DEBUG << std::string(2*level, ' ') << ""; + CROW_LOG_DEBUG << std::string(2 * level, ' ') << ""; break; case ParamType::UINT: - CROW_LOG_DEBUG << std::string(2*level, ' ') << ""; + CROW_LOG_DEBUG << std::string(2 * level, ' ') << ""; break; case ParamType::DOUBLE: - CROW_LOG_DEBUG << std::string(2*level, ' ') << ""; + CROW_LOG_DEBUG << std::string(2 * level, ' ') << ""; break; case ParamType::STRING: - CROW_LOG_DEBUG << std::string(2*level, ' ') << ""; + CROW_LOG_DEBUG << std::string(2 * level, ' ') << ""; break; case ParamType::PATH: - CROW_LOG_DEBUG << std::string(2*level, ' ') << ""; + CROW_LOG_DEBUG << std::string(2 * level, ' ') << ""; break; default: - CROW_LOG_DEBUG << std::string(2*level, ' ') << ""; + CROW_LOG_DEBUG << std::string(2 * level, ' ') << ""; break; } } else - CROW_LOG_DEBUG << std::string(2*level, ' ') << node->key; + CROW_LOG_DEBUG << std::string(2 * level, ' ') << node->key; - for(auto& child : node->children) + for (auto& child : node->children) { - debug_node_print(child, level+1); + debug_node_print(child, level + 1); } } - public: + public: void debug_print() { CROW_LOG_DEBUG << "HEAD"; @@ -844,9 +830,9 @@ namespace crow if (blueprints == nullptr) blueprints = &MT; - uint16_t found{}; //The rule index to be found + uint16_t found{}; //The rule index to be found std::vector found_BP; //The Blueprint indices to be found - routing_params match_params; //supposedly the final matched parameters + routing_params match_params; //supposedly the final matched parameters //start from the head node if (node == nullptr) @@ -871,7 +857,7 @@ namespace crow bool found_fragment = false; - for(auto& child : node->children) + for (auto& child : node->children) { if (child->param != ParamType::MAX) { @@ -882,8 +868,8 @@ namespace crow { char* eptr; errno = 0; - long long int value = strtoll(req_url.data()+pos, &eptr, 10); - if (errno != ERANGE && eptr != req_url.data()+pos) + long long int value = strtoll(req_url.data() + pos, &eptr, 10); + if (errno != ERANGE && eptr != req_url.data() + pos) { found_fragment = true; params->int_params.push_back(value); @@ -903,8 +889,8 @@ namespace crow { char* eptr; errno = 0; - unsigned long long int value = strtoull(req_url.data()+pos, &eptr, 10); - if (errno != ERANGE && eptr != req_url.data()+pos) + unsigned long long int value = strtoull(req_url.data() + pos, &eptr, 10); + if (errno != ERANGE && eptr != req_url.data() + pos) { found_fragment = true; params->uint_params.push_back(value); @@ -924,8 +910,8 @@ namespace crow { char* eptr; errno = 0; - double value = strtod(req_url.data()+pos, &eptr); - if (errno != ERANGE && eptr != req_url.data()+pos) + double value = strtod(req_url.data() + pos, &eptr); + if (errno != ERANGE && eptr != req_url.data() + pos) { found_fragment = true; params->double_params.push_back(value); @@ -941,7 +927,7 @@ namespace crow else if (child->param == ParamType::STRING) { size_t epos = pos; - for(; epos < req_url.size(); epos ++) + for (; epos < req_url.size(); epos++) { if (req_url[epos] == '/') break; @@ -950,7 +936,7 @@ namespace crow if (epos != pos) { found_fragment = true; - params->string_params.push_back(req_url.substr(pos, epos-pos)); + params->string_params.push_back(req_url.substr(pos, epos - pos)); if (child->blueprint_index != INVALID_BP_ID) blueprints->push_back(child->blueprint_index); auto ret = find(req_url, child, epos, params, blueprints); update_found(ret); @@ -966,7 +952,7 @@ namespace crow if (epos != pos) { found_fragment = true; - params->string_params.push_back(req_url.substr(pos, epos-pos)); + params->string_params.push_back(req_url.substr(pos, epos - pos)); if (child->blueprint_index != INVALID_BP_ID) blueprints->push_back(child->blueprint_index); auto ret = find(req_url, child, epos, params, blueprints); update_found(ret); @@ -1003,7 +989,7 @@ namespace crow bool has_blueprint = bp_prefix_length != 0 && blueprint_index != INVALID_BP_ID; - for(unsigned i = 0; i < url.size(); i ++) + for (unsigned i = 0; i < url.size(); i++) { char c = url[i]; if (c == '<') @@ -1013,17 +999,17 @@ namespace crow ParamType type; std::string name; } paramTraits[] = - { - { ParamType::INT, "" }, - { ParamType::UINT, "" }, - { ParamType::DOUBLE, "" }, - { ParamType::DOUBLE, "" }, - { ParamType::STRING, "" }, - { ParamType::STRING, "" }, - { ParamType::PATH, "" }, - }; + { + {ParamType::INT, ""}, + {ParamType::UINT, ""}, + {ParamType::DOUBLE, ""}, + {ParamType::DOUBLE, ""}, + {ParamType::STRING, ""}, + {ParamType::STRING, ""}, + {ParamType::PATH, ""}, + }; - for(auto& x:paramTraits) + for (auto& x : paramTraits) { if (url.compare(i, x.name.size(), x.name) == 0) { @@ -1049,7 +1035,7 @@ namespace crow } } - i --; + i--; } else { @@ -1089,9 +1075,9 @@ namespace crow size_t get_size(Node* node) { - unsigned size = 5 ; //rule_index, blueprint_index, and param + unsigned size = 5; //rule_index, blueprint_index, and param size += (node->key.size()); //each character in the key is 1 byte - for (auto child: node->children) + for (auto child : node->children) { size += get_size(child); } @@ -1100,13 +1086,12 @@ namespace crow private: - Node* new_node(Node* parent) { auto& children = parent->children; - children.resize(children.size()+1); - children[children.size()-1] = new Node(); - return children[children.size()-1]; + children.resize(children.size() + 1); + children[children.size() - 1] = new Node(); + return children[children.size() - 1]; } @@ -1120,17 +1105,16 @@ namespace crow class Blueprint { public: - Blueprint(const std::string& prefix): - prefix_(prefix){}; + prefix_(prefix){}; Blueprint(const std::string& prefix, const std::string& static_dir): - prefix_(prefix), static_dir_(static_dir){}; + prefix_(prefix), static_dir_(static_dir){}; Blueprint(const std::string& prefix, const std::string& static_dir, const std::string& templates_dir): - prefix_(prefix), static_dir_(static_dir), templates_dir_(templates_dir){}; + prefix_(prefix), static_dir_(static_dir), templates_dir_(templates_dir){}; -/* + /* Blueprint(Blueprint& other) { prefix_ = std::move(other.prefix_); @@ -1148,9 +1132,9 @@ namespace crow *this = std::move(value); } - Blueprint& operator = (const Blueprint& value) = delete; + Blueprint& operator=(const Blueprint& value) = delete; - Blueprint& operator = (Blueprint&& value) noexcept + Blueprint& operator=(Blueprint&& value) noexcept { prefix_ = std::move(value.prefix_); all_rules_ = std::move(value.all_rules_); @@ -1158,12 +1142,12 @@ namespace crow return *this; } - bool operator == (const Blueprint& value) + bool operator==(const Blueprint& value) { return value.prefix() == prefix_; } - bool operator != (const Blueprint& value) + bool operator!=(const Blueprint& value) { return value.prefix() != prefix_; } @@ -1189,7 +1173,7 @@ namespace crow return *ruleObject; } - template + template typename black_magic::arguments::type::template rebind& new_rule_tagged(std::string&& rule) { std::string new_rule = std::move(rule); @@ -1221,7 +1205,6 @@ namespace crow } private: - void apply_blueprint(Blueprint& blueprint) { @@ -1266,7 +1249,7 @@ namespace crow return *ruleObject; } - template + template typename black_magic::arguments::type::template rebind& new_rule_tagged(const std::string& rule) { using RuleT = typename black_magic::arguments::type::template rebind; @@ -1294,7 +1277,7 @@ namespace crow } ruleObject->foreach_method([&](int method) - { + { per_methods_[method].rules.emplace_back(ruleObject); per_methods_[method].trie.add(rule, per_methods_[method].rules.size() - 1, BP_index != INVALID_BP_ID ? blueprints[BP_index]->prefix().length() : 0, BP_index); @@ -1303,9 +1286,7 @@ namespace crow if (has_trailing_slash) { per_methods_[method].trie.add(rule_without_trailing_slash, RULE_SPECIAL_REDIRECT_SLASH, BP_index != INVALID_BP_ID ? blueprints_[BP_index]->prefix().length() : 0, BP_index); - } - }); - + } }); } void register_blueprint(Blueprint& blueprint) @@ -1323,20 +1304,20 @@ namespace crow //we only need to deal with children if the blueprint has absolutely no methods (meaning its index won't be added to the trie) if (blueprint->static_dir_.empty() && blueprint->all_rules_.empty()) { - for(Blueprint* bp : blueprint->blueprints_) + for (Blueprint* bp : blueprint->blueprints_) { get_recursive_child_methods(bp, methods); } } else if (!blueprint->static_dir_.empty()) methods.emplace_back(HTTPMethod::Get); - for (auto& rule: blueprint->all_rules_) + for (auto& rule : blueprint->all_rules_) { - rule->foreach_method([&methods](unsigned method){ + rule->foreach_method([&methods](unsigned method) + { HTTPMethod method_final = static_cast(method); if (std::find(methods.begin(), methods.end(), method_final) == methods.end()) - methods.emplace_back(method_final); - }); + methods.emplace_back(method_final); }); } } @@ -1355,7 +1336,7 @@ namespace crow per_methods_[i].trie.add(blueprint->prefix(), 0, blueprint->prefix().length(), i); } } - for (auto& rule: blueprint->all_rules_) + for (auto& rule : blueprint->all_rules_) { if (rule) { @@ -1375,7 +1356,7 @@ namespace crow //Take all the routes from the registered blueprints and add them to `all_rules_` to be processed. validate_bp(blueprints_); - for(auto& rule:all_rules_) + for (auto& rule : all_rules_) { if (rule) { @@ -1386,14 +1367,14 @@ namespace crow internal_add_rule_object(rule->rule(), rule.get(), INVALID_BP_ID, blueprints_); } } - for(auto& per_method:per_methods_) + for (auto& per_method : per_methods_) { per_method.trie.validate(); } } - //TODO maybe add actual_method - template + // TODO maybe add actual_method + template void handle_upgrade(const request& req, response& res, Adaptor&& adaptor) { if (req.method >= HTTPMethod::InternalMethodCount) @@ -1405,7 +1386,7 @@ namespace crow if (!rule_index) { - for (auto& per_method: per_methods_) + for (auto& per_method : per_methods_) { if (std::get<0>(per_method.trie.find(req.url))) { @@ -1450,14 +1431,14 @@ namespace crow { rules[rule_index]->handle_upgrade(req, res, std::move(adaptor)); } - catch(std::exception& e) + catch (std::exception& e) { CROW_LOG_ERROR << "An uncaught exception occurred: " << e.what(); res = response(500); res.end(); return; } - catch(...) + catch (...) { CROW_LOG_ERROR << "An uncaught exception occurred. The type was unknown so no information was available."; res = response(500); @@ -1479,9 +1460,8 @@ namespace crow auto verify_prefix = [&bp_i, &index, &blueprints, &found_bps]() { return index > 0 && - bp_i[index] < blueprints.size() && - blueprints[bp_i[index]]->prefix().substr(0,found_bps[index-1]->prefix().length()+1) - .compare(std::string(found_bps[index-1]->prefix()+'/')) == 0; + bp_i[index] < blueprints.size() && + blueprints[bp_i[index]]->prefix().substr(0, found_bps[index - 1]->prefix().length() + 1).compare(std::string(found_bps[index - 1]->prefix() + '/')) == 0; }; if (index < bp_i.size()) { @@ -1501,7 +1481,7 @@ namespace crow else { found_bps.pop_back(); - Blueprint* last_element = found_bps.back(); + Blueprint* last_element = found_bps.back(); found_bps.push_back(last_element->blueprints_[bp_i[index]]); } get_found_bp(bp_i, found_bps.back()->blueprints_, found_bps, ++index); @@ -1515,7 +1495,7 @@ namespace crow res.code = code; std::vector bps_found; get_found_bp(std::get<1>(found), blueprints_, bps_found); - for (int i = bps_found.size()-1; i > 0; i--) + for (int i = bps_found.size() - 1; i > 0; i--) { std::vector bpi = std::get<1>(found); if (bps_found[i]->catchall_rule().has_handler()) @@ -1556,23 +1536,23 @@ namespace crow if (req.url == "/*") { - for(int i = 0; i < static_cast(HTTPMethod::InternalMethodCount); i ++) + for (int i = 0; i < static_cast(HTTPMethod::InternalMethodCount); i++) { if (!per_methods_[i].trie.is_empty()) { allow += method_name(static_cast(i)) + ", "; } } - allow = allow.substr(0, allow.size()-2); - res = response(204); - res.set_header("Allow", allow); - res.manual_length_header = true; - res.end(); - return; + allow = allow.substr(0, allow.size() - 2); + res = response(204); + res.set_header("Allow", allow); + res.manual_length_header = true; + res.end(); + return; } else { - for(int i = 0; i < static_cast(HTTPMethod::InternalMethodCount); i ++) + for (int i = 0; i < static_cast(HTTPMethod::InternalMethodCount); i++) { if (std::get<0>(per_methods_[i].trie.find(req.url))) { @@ -1581,7 +1561,7 @@ namespace crow } if (allow != "OPTIONS, HEAD, ") { - allow = allow.substr(0, allow.size()-2); + allow = allow.substr(0, allow.size() - 2); res = response(204); res.set_header("Allow", allow); res.manual_length_header = true; @@ -1608,7 +1588,7 @@ namespace crow if (!rule_index) { - for (auto& per_method: per_methods_) + for (auto& per_method : per_methods_) { if (std::get<0>(per_method.trie.find(req.url))) //Route found, but in another method { @@ -1654,14 +1634,14 @@ namespace crow { rules[rule_index]->handle(req, res, std::get<2>(found)); } - catch(std::exception& e) + catch (std::exception& e) { CROW_LOG_ERROR << "An uncaught exception occurred: " << e.what(); res = response(500); res.end(); return; } - catch(...) + catch (...) { CROW_LOG_ERROR << "An uncaught exception occurred. The type was unknown so no information was available."; res = response(500); @@ -1672,7 +1652,7 @@ namespace crow void debug_print() { - for(int i = 0; i < static_cast(HTTPMethod::InternalMethodCount); i ++) + for (int i = 0; i < static_cast(HTTPMethod::InternalMethodCount); i++) { CROW_LOG_DEBUG << method_name(static_cast(i)); per_methods_[i].trie.debug_print(); @@ -1693,11 +1673,11 @@ namespace crow Trie trie; // rule index 0, 1 has special meaning; preallocate it to avoid duplication. - PerMethod() : rules(2) {} + PerMethod(): + rules(2) {} }; std::array(HTTPMethod::InternalMethodCount)> per_methods_; std::vector> all_rules_; std::vector blueprints_; - }; -} +} // namespace crow diff --git a/include/crow/socket_adaptors.h b/include/crow/socket_adaptors.h index a6c49ac9a..8eb864833 100644 --- a/include/crow/socket_adaptors.h +++ b/include/crow/socket_adaptors.h @@ -18,8 +18,8 @@ namespace crow struct SocketAdaptor { using context = void; - SocketAdaptor(boost::asio::io_service& io_service, context*) - : socket_(io_service) + SocketAdaptor(boost::asio::io_service& io_service, context*): + socket_(io_service) { } @@ -74,7 +74,7 @@ namespace crow socket_.shutdown(boost::asio::socket_base::shutdown_type::shutdown_receive, ec); } - template + template void start(F f) { f(boost::system::error_code()); @@ -88,8 +88,8 @@ namespace crow { using context = boost::asio::ssl::context; using ssl_socket_t = boost::asio::ssl::stream; - SSLAdaptor(boost::asio::io_service& io_service, context* ctx) - : ssl_socket_(new ssl_socket_t(io_service, *ctx)) + SSLAdaptor(boost::asio::io_service& io_service, context* ctx): + ssl_socket_(new ssl_socket_t(io_service, *ctx)) { } @@ -99,7 +99,7 @@ namespace crow } tcp::socket::lowest_layer_type& - raw_socket() + raw_socket() { return ssl_socket_->lowest_layer(); } @@ -155,16 +155,17 @@ namespace crow return GET_IO_SERVICE(raw_socket()); } - template + template void start(F f) { ssl_socket_->async_handshake(boost::asio::ssl::stream_base::server, - [f](const boost::system::error_code& ec) { - f(ec); - }); + [f](const boost::system::error_code& ec) + { + f(ec); + }); } std::unique_ptr> ssl_socket_; }; #endif -} +} // namespace crow diff --git a/include/crow/task_timer.h b/include/crow/task_timer.h index b7875c853..1cc838376 100644 --- a/include/crow/task_timer.h +++ b/include/crow/task_timer.h @@ -8,128 +8,131 @@ #include "crow/logging.h" -namespace crow { -namespace detail { -/// -/// A class for scheduling functions to be called after a specific amount -/// of ticks. A tick is equal to 1 second. -/// -class task_timer +namespace crow { - public: - using task_type = std::function; - using identifier_type = size_t; + namespace detail + { - private: - using clock_type = std::chrono::steady_clock; - using time_type = clock_type::time_point; + /// A class for scheduling functions to be called after a specific amount of ticks. A tick is equal to 1 second. + class task_timer + { + public: + using task_type = std::function; + using identifier_type = size_t; - public: - task_timer(boost::asio::io_service& io_service) - : io_service_(io_service), deadline_timer_(io_service_) - { - deadline_timer_.expires_from_now(boost::posix_time::seconds(1)); - deadline_timer_.async_wait( - std::bind(&task_timer::tick_handler, this, std::placeholders::_1)); - } + private: + using clock_type = std::chrono::steady_clock; + using time_type = clock_type::time_point; - ~task_timer() { deadline_timer_.cancel(); } + public: + task_timer(boost::asio::io_service& io_service): + io_service_(io_service), deadline_timer_(io_service_) + { + deadline_timer_.expires_from_now(boost::posix_time::seconds(1)); + deadline_timer_.async_wait( + std::bind(&task_timer::tick_handler, this, std::placeholders::_1)); + } - void cancel(identifier_type id) - { - tasks_.erase(id); - CROW_LOG_DEBUG << "task_timer cancelled: " << this << ' ' << id; - } + ~task_timer() { deadline_timer_.cancel(); } - /// - /// Schedule the given task to be executed after the default amount of - /// ticks. - /// - /// \return identifier_type Used to cancel the thread. - /// It is not bound to this task_timer instance and in some cases could lead to - /// undefined behavior if used with other task_timer objects or after the task - /// has been successfully executed. - /// - identifier_type schedule(const task_type& task) - { - tasks_.insert( - {++highest_id_, - {clock_type::now() + std::chrono::seconds(get_default_timeout()), - task}}); - CROW_LOG_DEBUG << "task_timer scheduled: " << this << ' ' << highest_id_; - return highest_id_; - } + void cancel(identifier_type id) + { + tasks_.erase(id); + CROW_LOG_DEBUG << "task_timer cancelled: " << this << ' ' << id; + } - /// - /// Schedule the given task to be executed after the given time. - /// - /// \param timeout The amount of ticks (seconds) to wait before execution. - /// - /// \return identifier_type Used to cancel the thread. - /// It is not bound to this task_timer instance and in some cases could lead to - /// undefined behavior if used with other task_timer objects or after the task - /// has been successfully executed. - /// - identifier_type schedule(const task_type& task, std::uint8_t timeout) - { - tasks_.insert({++highest_id_, - {clock_type::now() + std::chrono::seconds(timeout), task}}); - CROW_LOG_DEBUG << "task_timer scheduled: " << this << ' ' << highest_id_; - return highest_id_; - } + /// + /// Schedule the given task to be executed after the default amount of + /// ticks. + /// + /// \return identifier_type Used to cancel the thread. + /// It is not bound to this task_timer instance and in some cases could lead to + /// undefined behavior if used with other task_timer objects or after the task + /// has been successfully executed. + /// + identifier_type schedule(const task_type& task) + { + tasks_.insert( + {++highest_id_, + {clock_type::now() + std::chrono::seconds(get_default_timeout()), + task}}); + CROW_LOG_DEBUG << "task_timer scheduled: " << this << ' ' << highest_id_; + return highest_id_; + } - /// - /// Set the default timeout for this task_timer instance. (Default: 5) - /// - /// \param timeout The amount of ticks (seconds) to wait before execution. - /// - void set_default_timeout(std::uint8_t timeout) { default_timeout_ = timeout; } + /// + /// Schedule the given task to be executed after the given time. + /// + /// \param timeout The amount of ticks (seconds) to wait before execution. + /// + /// \return identifier_type Used to cancel the thread. + /// It is not bound to this task_timer instance and in some cases could lead to + /// undefined behavior if used with other task_timer objects or after the task + /// has been successfully executed. + /// + identifier_type schedule(const task_type& task, std::uint8_t timeout) + { + tasks_.insert({++highest_id_, + {clock_type::now() + std::chrono::seconds(timeout), task}}); + CROW_LOG_DEBUG << "task_timer scheduled: " << this << ' ' << highest_id_; + return highest_id_; + } - /// - /// Get the default timeout. (Default: 5) - /// - std::uint8_t get_default_timeout() const { return default_timeout_; } + /// + /// Set the default timeout for this task_timer instance. (Default: 5) + /// + /// \param timeout The amount of ticks (seconds) to wait before execution. + /// + void set_default_timeout(std::uint8_t timeout) { default_timeout_ = timeout; } - private: - void process_tasks() - { - time_type current_time = clock_type::now(); - std::vector finished_tasks; + /// + /// Get the default timeout. (Default: 5) + /// + std::uint8_t get_default_timeout() const { return default_timeout_; } - for (const auto& task : tasks_) { - if (task.second.first < current_time) { - (task.second.second)(); - finished_tasks.push_back(task.first); - CROW_LOG_DEBUG << "task_timer called: " << this << ' ' << task.first; - } - } + private: + void process_tasks() + { + time_type current_time = clock_type::now(); + std::vector finished_tasks; - for (const auto& task : finished_tasks) tasks_.erase(task); + for (const auto& task : tasks_) + { + if (task.second.first < current_time) + { + (task.second.second)(); + finished_tasks.push_back(task.first); + CROW_LOG_DEBUG << "task_timer called: " << this << ' ' << task.first; + } + } - // If no task is currently scheduled, reset the issued ids back to 0. - if (tasks_.empty()) highest_id_ = 0; - } + for (const auto& task : finished_tasks) + tasks_.erase(task); - void tick_handler(const boost::system::error_code& ec) - { - if (ec) return; + // If no task is currently scheduled, reset the issued ids back to 0. + if (tasks_.empty()) highest_id_ = 0; + } - process_tasks(); + void tick_handler(const boost::system::error_code& ec) + { + if (ec) return; - deadline_timer_.expires_from_now(boost::posix_time::seconds(1)); - deadline_timer_.async_wait( - std::bind(&task_timer::tick_handler, this, std::placeholders::_1)); - } + process_tasks(); - private: - std::uint8_t default_timeout_{5}; - boost::asio::io_service& io_service_; - boost::asio::deadline_timer deadline_timer_; - std::map> tasks_; + deadline_timer_.expires_from_now(boost::posix_time::seconds(1)); + deadline_timer_.async_wait( + std::bind(&task_timer::tick_handler, this, std::placeholders::_1)); + } - // A continuosly increasing number to be issued to threads to identify them. - // If no tasks are scheduled, it will be reset to 0. - identifier_type highest_id_{0}; -}; -} // namespace detail -} // namespace crow + private: + std::uint8_t default_timeout_{5}; + boost::asio::io_service& io_service_; + boost::asio::deadline_timer deadline_timer_; + std::map> tasks_; + + // A continuosly increasing number to be issued to threads to identify them. + // If no tasks are scheduled, it will be reset to 0. + identifier_type highest_id_{0}; + }; + } // namespace detail +} // namespace crow diff --git a/include/crow/utility.h b/include/crow/utility.h index 829a2a0ed..9e6fe8f27 100644 --- a/include/crow/utility.h +++ b/include/crow/utility.h @@ -20,7 +20,7 @@ namespace crow { OutOfRange(unsigned /*pos*/, unsigned /*length*/) {} }; - constexpr unsigned requires_in_range( unsigned i, unsigned len ) + constexpr unsigned requires_in_range(unsigned i, unsigned len) { return i >= len ? throw OutOfRange(i, len) : i; } @@ -28,73 +28,64 @@ namespace crow /// A constant string implementation. class const_str { - const char * const begin_; + const char* const begin_; unsigned size_; - public: - template< unsigned N > - constexpr const_str( const char(&arr)[N] ) : begin_(arr), size_(N - 1) { - static_assert( N >= 1, "not a string literal"); - } - constexpr char operator[]( unsigned i ) const { - return requires_in_range(i, size_), begin_[i]; + public: + template + constexpr const_str(const char (&arr)[N]): + begin_(arr), size_(N - 1) + { + static_assert(N >= 1, "not a string literal"); + } + constexpr char operator[](unsigned i) const + { + return requires_in_range(i, size_), begin_[i]; } - constexpr operator const char *() const { - return begin_; + constexpr operator const char*() const + { + return begin_; } constexpr const char* begin() const { return begin_; } constexpr const char* end() const { return begin_ + size_; } - constexpr unsigned size() const { - return size_; + constexpr unsigned size() const + { + return size_; } }; constexpr unsigned find_closing_tag(const_str s, unsigned p) { - return s[p] == '>' ? p : find_closing_tag(s, p+1); + return s[p] == '>' ? p : find_closing_tag(s, p + 1); } constexpr bool is_valid(const_str s, unsigned i = 0, int f = 0) { - return - i == s.size() - ? f == 0 : - f < 0 || f >= 2 - ? false : - s[i] == '<' - ? is_valid(s, i+1, f+1) : - s[i] == '>' - ? is_valid(s, i+1, f-1) : - is_valid(s, i+1, f); + return i == s.size() ? f == 0 : + f < 0 || f >= 2 ? false : + s[i] == '<' ? is_valid(s, i + 1, f + 1) : + s[i] == '>' ? is_valid(s, i + 1, f - 1) : + is_valid(s, i + 1, f); } constexpr bool is_equ_p(const char* a, const char* b, unsigned n) { - return - *a == 0 && *b == 0 && n == 0 - ? true : - (*a == 0 || *b == 0) - ? false : - n == 0 - ? true : - *a != *b - ? false : - is_equ_p(a+1, b+1, n-1); + return *a == 0 && *b == 0 && n == 0 ? true : + (*a == 0 || *b == 0) ? false : + n == 0 ? true : + *a != *b ? false : + is_equ_p(a + 1, b + 1, n - 1); } constexpr bool is_equ_n(const_str a, unsigned ai, const_str b, unsigned bi, unsigned n) { - return - ai + n > a.size() || bi + n > b.size() - ? false : - n == 0 - ? true : - a[ai] != b[bi] - ? false : - is_equ_n(a,ai+1,b,bi+1,n-1); + return ai + n > a.size() || bi + n > b.size() ? false : + n == 0 ? true : + a[ai] != b[bi] ? false : + is_equ_n(a, ai + 1, b, bi + 1, n - 1); } constexpr bool is_int(const_str s, unsigned i) @@ -110,13 +101,13 @@ namespace crow constexpr bool is_float(const_str s, unsigned i) { return is_equ_n(s, i, "", 0, 7) || - is_equ_n(s, i, "", 0, 8); + is_equ_n(s, i, "", 0, 8); } constexpr bool is_str(const_str s, unsigned i) { return is_equ_n(s, i, "", 0, 5) || - is_equ_n(s, i, "", 0, 8); + is_equ_n(s, i, "", 0, 8); } constexpr bool is_path(const_str s, unsigned i) @@ -124,17 +115,17 @@ namespace crow return is_equ_n(s, i, "", 0, 6); } #endif - template + template struct parameter_tag { static const int value = 0; }; #define CROW_INTERNAL_PARAMETER_TAG(t, i) \ -template <> \ -struct parameter_tag \ -{ \ - static const int value = i; \ -} + template<> \ + struct parameter_tag \ + { \ + static const int value = i; \ + } CROW_INTERNAL_PARAMETER_TAG(int, 1); CROW_INTERNAL_PARAMETER_TAG(char, 1); CROW_INTERNAL_PARAMETER_TAG(short, 1); @@ -148,24 +139,22 @@ struct parameter_tag \ CROW_INTERNAL_PARAMETER_TAG(double, 3); CROW_INTERNAL_PARAMETER_TAG(std::string, 4); #undef CROW_INTERNAL_PARAMETER_TAG - template + template struct compute_parameter_tag_from_args_list; - template <> + template<> struct compute_parameter_tag_from_args_list<> { static const int value = 0; }; - template + template struct compute_parameter_tag_from_args_list { - static const int sub_value = - compute_parameter_tag_from_args_list::value; - static const int value = - parameter_tag::type>::value - ? sub_value* 6 + parameter_tag::type>::value - : sub_value; + static const int sub_value = + compute_parameter_tag_from_args_list::value; + static const int value = + parameter_tag::type>::value ? sub_value * 6 + parameter_tag::type>::value : sub_value; }; static inline bool is_parameter_tag_compatible(uint64_t a, uint64_t b) @@ -174,237 +163,238 @@ struct parameter_tag \ return b == 0; if (b == 0) return a == 0; - int sa = a%6; - int sb = a%6; + int sa = a % 6; + int sb = a % 6; if (sa == 5) sa = 4; if (sb == 5) sb = 4; if (sa != sb) return false; - return is_parameter_tag_compatible(a/6, b/6); + return is_parameter_tag_compatible(a / 6, b / 6); } static inline unsigned find_closing_tag_runtime(const char* s, unsigned p) { - return - s[p] == 0 - ? throw std::runtime_error("unmatched tag <") : - s[p] == '>' - ? p : find_closing_tag_runtime(s, p + 1); + return s[p] == 0 ? throw std::runtime_error("unmatched tag <") : + s[p] == '>' ? p : + find_closing_tag_runtime(s, p + 1); } - + static inline uint64_t get_parameter_tag_runtime(const char* s, unsigned p = 0) { - return - s[p] == 0 - ? 0 : - s[p] == '<' ? ( - std::strncmp(s+p, "", 5) == 0 - ? get_parameter_tag_runtime(s, find_closing_tag_runtime(s, p)) * 6 + 1 : - std::strncmp(s+p, "", 6) == 0 - ? get_parameter_tag_runtime(s, find_closing_tag_runtime(s, p)) * 6 + 2 : - (std::strncmp(s+p, "", 7) == 0 || - std::strncmp(s+p, "", 8) == 0) - ? get_parameter_tag_runtime(s, find_closing_tag_runtime(s, p)) * 6 + 3 : - (std::strncmp(s+p, "", 5) == 0 || - std::strncmp(s+p, "", 8) == 0) - ? get_parameter_tag_runtime(s, find_closing_tag_runtime(s, p)) * 6 + 4 : - std::strncmp(s+p, "", 6) == 0 - ? get_parameter_tag_runtime(s, find_closing_tag_runtime(s, p)) * 6 + 5 : - throw std::runtime_error("invalid parameter type") - ) : - get_parameter_tag_runtime(s, p+1); + return s[p] == 0 ? 0 : + s[p] == '<' ? ( + std::strncmp(s + p, "", 5) == 0 ? get_parameter_tag_runtime(s, find_closing_tag_runtime(s, p)) * 6 + 1 : + std::strncmp(s + p, "", 6) == 0 ? get_parameter_tag_runtime(s, find_closing_tag_runtime(s, p)) * 6 + 2 : + (std::strncmp(s + p, "", 7) == 0 || + std::strncmp(s + p, "", 8) == 0) ? + get_parameter_tag_runtime(s, find_closing_tag_runtime(s, p)) * 6 + 3 : + (std::strncmp(s + p, "", 5) == 0 || + std::strncmp(s + p, "", 8) == 0) ? + get_parameter_tag_runtime(s, find_closing_tag_runtime(s, p)) * 6 + 4 : + std::strncmp(s + p, "", 6) == 0 ? get_parameter_tag_runtime(s, find_closing_tag_runtime(s, p)) * 6 + 5 : + throw std::runtime_error("invalid parameter type")) : + get_parameter_tag_runtime(s, p + 1); } #ifndef CROW_MSVC_WORKAROUND constexpr uint64_t get_parameter_tag(const_str s, unsigned p = 0) { - return - p == s.size() - ? 0 : - s[p] == '<' ? ( - is_int(s, p) - ? get_parameter_tag(s, find_closing_tag(s, p)) * 6 + 1 : - is_uint(s, p) - ? get_parameter_tag(s, find_closing_tag(s, p)) * 6 + 2 : - is_float(s, p) - ? get_parameter_tag(s, find_closing_tag(s, p)) * 6 + 3 : - is_str(s, p) - ? get_parameter_tag(s, find_closing_tag(s, p)) * 6 + 4 : - is_path(s, p) - ? get_parameter_tag(s, find_closing_tag(s, p)) * 6 + 5 : - throw std::runtime_error("invalid parameter type") - ) : - get_parameter_tag(s, p+1); + return p == s.size() ? 0 : + s[p] == '<' ? ( + is_int(s, p) ? get_parameter_tag(s, find_closing_tag(s, p)) * 6 + 1 : + is_uint(s, p) ? get_parameter_tag(s, find_closing_tag(s, p)) * 6 + 2 : + is_float(s, p) ? get_parameter_tag(s, find_closing_tag(s, p)) * 6 + 3 : + is_str(s, p) ? get_parameter_tag(s, find_closing_tag(s, p)) * 6 + 4 : + is_path(s, p) ? get_parameter_tag(s, find_closing_tag(s, p)) * 6 + 5 : + throw std::runtime_error("invalid parameter type")) : + get_parameter_tag(s, p + 1); } #endif - template + template struct S { - template + template using push = S; - template + template using push_back = S; - template class U> + template class U> using rebind = U; }; -template + template struct CallHelper; - template + template struct CallHelper> { - template ()(std::declval()...)) - > + template()(std::declval()...))> static char __test(int); - template + template static int __test(...); static constexpr bool value = sizeof(__test(0)) == sizeof(char); }; - template + template struct single_tag_to_type { }; - template <> + template<> struct single_tag_to_type<1> { using type = int64_t; }; - template <> + template<> struct single_tag_to_type<2> { using type = uint64_t; }; - template <> + template<> struct single_tag_to_type<3> { using type = double; }; - template <> + template<> struct single_tag_to_type<4> { using type = std::string; }; - template <> + template<> struct single_tag_to_type<5> { using type = std::string; }; - template + template struct arguments { - using subarguments = typename arguments::type; - using type = - typename subarguments::template push::type>; + using subarguments = typename arguments::type; + using type = + typename subarguments::template push::type>; }; - template <> + template<> struct arguments<0> { using type = S<>; }; - template + template struct last_element_type { - using type = typename std::tuple_element>::type; + using type = typename std::tuple_element>::type; }; - template <> + template<> struct last_element_type<> { }; // from http://stackoverflow.com/questions/13072359/c11-compile-time-array-with-logarithmic-evaluation-depth - template using Invoke = typename T::type; + template + using Invoke = typename T::type; - template struct seq{ using type = seq; }; + template + struct seq + { + using type = seq; + }; - template struct concat; + template + struct concat; template - struct concat, seq> - : seq{}; + struct concat, seq> : seq + { + }; template using Concat = Invoke>; - template struct gen_seq; - template using GenSeq = Invoke>; + template + struct gen_seq; + template + using GenSeq = Invoke>; template - struct gen_seq : Concat, GenSeq>{}; + struct gen_seq : Concat, GenSeq> + { + }; - template<> struct gen_seq<0> : seq<>{}; - template<> struct gen_seq<1> : seq<0>{}; + template<> + struct gen_seq<0> : seq<> + { + }; + template<> + struct gen_seq<1> : seq<0> + { + }; - template + template struct pop_back_helper; - template + template struct pop_back_helper, Tuple> { - template