Crow is very fast and easy to use C++ micro web framework (inspired by Python Flask)

Overview

Crow logo

Crow is C++ microframework for web. (inspired by Python Flask)

Travis Build Coverage Status

#include "crow.h"

int main()
{
    crow::SimpleApp app;

    CROW_ROUTE(app, "/")([](){
        return "Hello world";
    });

    app.port(18080).multithreaded().run();
}

Features

  • Easy routing
    • Similiar to Flask
    • Type-safe Handlers (see Example)
  • Very Fast
  • Fast built-in JSON parser (crow::json)
  • Mustache based templating library (crow::mustache)
  • Header only
  • Provide an amalgamated header file crow_all.h with every features (Download from here)
  • Middleware support
  • Websocket support

Still in development

  • Built-in ORM

Examples

JSON Response

CROW_ROUTE(app, "/json")
([]{
    crow::json::wvalue x;
    x["message"] = "Hello, World!";
    return x;
});

Arguments

CROW_ROUTE(app,"/hello/<int>")
([](int count){
    if (count > 100)
        return crow::response(400);
    std::ostringstream os;
    os << count << " bottles of beer!";
    return crow::response(os.str());
});

Handler arguments type check at compile time

// Compile error with message "Handler type is mismatched with URL paramters"
CROW_ROUTE(app,"/another/<int>")
([](int a, int b){
    return crow::response(500);
});

Handling JSON Requests

CROW_ROUTE(app, "/add_json")
.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()};
});

How to Build

If you just want to use crow, copy amalgamate/crow_all.h and include it.

Requirements

  • C++ compiler with good C++11 support (tested with g++>=4.8)

  • boost library

  • CMake for build examples

  • Linking with tcmalloc/jemalloc is recommended for speed.

  • Now supporting VS2013 with limited functionality (only run-time check for url is available.)

Building (Tests, Examples)

Out-of-source build with CMake is recommended.

mkdir build
cd build
cmake ..
make

You can run tests with following commands:

ctest

Installing missing dependencies

Ubuntu

sudo apt-get install build-essential libtcmalloc-minimal4 && sudo ln -s /usr/lib/libtcmalloc_minimal.so.4 /usr/lib/libtcmalloc_minimal.so

OSX

brew install boost google-perftools

Attributions

Crow uses the following libraries.

http-parser

https://github.com/nodejs/http-parser

http_parser.c is based on src/http/ngx_http_parse.c from NGINX copyright
Igor Sysoev.

Additional changes are licensed under the same terms as NGINX and
copyright Joyent, Inc. and other Node contributors. All rights reserved.

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to
deal in the Software without restriction, including without limitation the
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
sell copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE. 


qs_parse

https://github.com/bartgrantham/qs_parse

Copyright (c) 2010 Bart Grantham
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.


TinySHA1

https://github.com/mohaps/TinySHA1

TinySHA1 - a header only implementation of the SHA1 algorithm. Based on the implementation in boost::uuid::details

Copyright (c) 2012-22 SAURAV MOHAPATRA [email protected]
Permission to use, copy, modify, and distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
Comments
  • kept receiving a 404 while trying to access a basic crow server from a js fetch request

    kept receiving a 404 while trying to access a basic crow server from a js fetch request

    Here is my basic crow server

    crow::SimpleApp app;

    CROW_ROUTE(app, "/")
    .methods("GET"_method)
    ([](){
    		crow::json::wvalue x;
    	    x["message"] = "Hello, World!";
    	    return x;
    });
    CROW_ROUTE(app, "/api")([](){
    	crow::json::wvalue x;
    	x["message"] = "Hello, World!";
    	return x;
    });
    
    app.port(4500).multithreaded().run();
    

    I was trying to send a standard fetch request from Javascript, however, I kept receiving a 404 request from it. When I tried to access the crow server on both browser and postman, they work! So I am not sure if there is something wrong with my js fetch or just crow itself. Here is my fetch

    return fetch('http://localhost:4500', { method: 'GET', headers: { 'Accept': 'application/json', 'Content-Type': 'application/json', } }) .then((response) => { console.log(response) if (response.status != 200){ console.log('errors') return } else{ return response.json() } }) .then((responseJson)=>{ console.log(responseJson) }) .catch((error) => { console.error(error); });

    opened by percyteng 15
  • URL query string parse crash

    URL query string parse crash

    I wrote a forum https://leanclub.org using crow , but it crash every 10 minutes , so I use gdb to get the trace

    (gdb) backtrace
    #0  0x00007ffff5b3b528 in _int_free (av=0x7fffc4000020, p=<optimized out>, have_lock=0) at malloc.c:3996
    #1  0x000000000057df86 in __gnu_cxx::new_allocator<char*>::deallocate (this=0x7fffe00148c0, __p=0x7fffc4014f20)
        at /usr/include/c++/4.9/ext/new_allocator.h:110
    #2  0x000000000057734d in std::allocator_traits<std::allocator<char*> >::deallocate (__a=..., __p=0x7fffc4014f20, __n=256)
        at /usr/include/c++/4.9/bits/alloc_traits.h:383
    #3  0x000000000056efbe in std::_Vector_base<char*, std::allocator<char*> >::_M_deallocate (this=0x7fffe00148c0, __p=0x7fffc4014f20, __n=256)
        at /usr/include/c++/4.9/bits/stl_vector.h:178
    #4  0x0000000000565fc3 in std::_Vector_base<char*, std::allocator<char*> >::~_Vector_base (this=0x7fffe00148c0, __in_chrg=<optimized out>)
        at /usr/include/c++/4.9/bits/stl_vector.h:160
    #5  0x000000000055e5fb in std::vector<char*, std::allocator<char*> >::~vector (this=0x7fffe00148c0, __in_chrg=<optimized out>)
        at /usr/include/c++/4.9/bits/stl_vector.h:425
    #6  0x00000000005484da in crow::query_string::~query_string (this=0x7fffe00148b8, __in_chrg=<optimized out>)
        at /home/typcncom_gmail_com/leanclub/include/query_string.h:238
    #7  0x000000000057cb1e in crow::HTTPParser<crow::Connection<crow::Crow<>> >::~HTTPParser() (this=0x7fffe0014838, __in_chrg=<optimized out>)
        at /home/typcncom_gmail_com/leanclub/include/parser.h:15
    #8  0x00000000005889b2 in crow::Connection<crow::Crow<>>::~Connection() (this=0x7fffe0013810, __in_chrg=<optimized out>)
        at /home/typcncom_gmail_com/leanclub/include/http_connection.h:213
    #9  0x0000000000585bcf in crow::Connection<crow::Crow<>>::check_destroy() (this=0x7fffe0013810)
        at /home/typcncom_gmail_com/leanclub/include/http_connection.h:502
    #10 0x00000000005823c1 in crow::Connection<crow::Crow<>>::do_read()::{lambda(boost::system::error_code const&, unsigned long)#1}::operator()(boost::system::error_code const&, unsigned long) const (__closure=0x7fffb7fe65a0, ec=..., bytes_transferred=0)
        at /home/typcncom_gmail_com/leanclub/include/http_connection.h:456
    #11 0x000000000059349a in boost::asio::detail::binder2<crow::Connection<crow::Crow<>>::do_read()::{lambda(boost::system::error_code const&, unsigned long)#1}, boost::system::error_code, unsigned long>::operator()() (this=0x7fffb7fe65a0) at /usr/include/boost/asio/detail/bind_handler.hpp:127
    #12 0x0000000000591ec4 in boost::asio::asio_handler_invoke<boost::asio::detail::binder2<crow::Connection<crow::Crow<>>::do_read()::{lambda(boost::system::error_code const&, unsigned long)#1}, boost::system::error_code, unsigned long> >(boost::asio::detail::binder2<crow::Connection<crow::Crow<>>::do_read()::{lambda(boost::system::error_code const&, unsigned long)#1}, boost::system::error_code, unsigned long>&, ...) (function=...)
        at /usr/include/boost/asio/handler_invoke_hook.hpp:69
    #13 0x0000000000590719 in boost_asio_handler_invoke_helpers::invoke<boost::asio::detail::binder2<crow::Connection<crow::Crow<>>::do_read()::{lambda(boost::system::error_code const&, unsigned long)#1}, boost::system::error_code, unsigned long>, {lambda(boost::system::error_code const&, unsigned long)#1}>(boost::asio::detail::binder2<crow::Connection<crow::Crow<>>::do_read()::{lambda(boost::system::error_code const&, unsigned long)#1}, boost::system::error_code, unsigned long>&, {lambda(boost::system::error_code const&, unsigned long)#1}&) (function=..., context=...) at /usr/include/boost/asio/detail/handler_invoke_helpers.hpp:37
    ---Type <return> to continue, or q <return> to quit---
    
    opened by typcn 14
  • Getting

    Getting "invalid json object"

    when the code tries : auto x = crow::json::load(req.body); I get this error : An uncaught exception occurred: invalid json object

    Here is the full piece of code : CROW_ROUTE(app, "/") .methods("GET"_method, "POST"_method) ([](const request& req, response &res){ if(req.method == "POST"_method) { auto x = crow::json::load(req.body); cout << x["fname"] << " " << x["email"] << endl; } else sendHtml(res, "index"); });

    Yes i want to output the POST request body to stdout!

    opened by bougayez 8
  • Added middleware framework

    Added middleware framework

    NOTE: This branch is on built (and therefore includes) acron:logging

    Introducing middleware.h:

    Adds the ability to inject middleware handlers both pre and post response:

    class ExampleMiddlewareHandler : public crow::IMiddlewareHandler {
    public:
        crow::response handle(const crow::request& req, crow::middleware::context *c) override {
            // pre-response
            auto result = c->next();
            // post-response
            return result;
        }
    };
    
    crow::middleware::use(std::make_shared<ExampleMiddlewareHandler>());
    

    (Macros coming soon!)

    opened by acron0 8
  • How to create API's using, C++ crow web-framework

    How to create API's using, C++ crow web-framework

    I am new to C++, I am trying to implement web-server using C++ crow web-framework. The main task is to create GET and POST API's using 'crow' framework. I already have a JSON file that is created using cJSON library, What need to be implemented is,

    1)GET API need to access the sample.json file and need to show the information present in that file.

    And, suppose, if we made any changes in the sample.json file,

    2)By using, POST API we need to update the changes in that file.

    This is the sample.json:- ``

    { "log_enable": 1, "log_level": 1, "device": [ { "server_ip": "10.27.15.168", "server_port": "17001", "http_max_users": "16", } ],
    "user": [ { "username": "user", "password": "123456" } ], "proxy": [ { "suffix": "proxy", "url": "rtsp://10.27.15.178/proxyStreamer_profile_1", "user": "admin", } ] } ``

    I have seen the github examples, but not able to understand how this crow framework works to implement these API's and getting and updating the details using the web.

    Any help would be greatly appreciated.......

    opened by saivamsi98 7
  • How to access middleware context in CROW_ROUTE

    How to access middleware context in CROW_ROUTE

    Hello -- I have a bit of middleware that stores an object (a struct representing a user) in the middleware's context. I now need to be able to access that user object from the context for this request in a CROW_ROUTE. I've tried something like this:

    CROW_ROUTE(...) {
        const UserModel & user = app.get_middleware<MyMiddleware<UserModel>>()::context.get_user();
    }
    

    But obviously that doesn't work, and even if it did it wouldn't be the context specific to the current request that I need. Could anyone advise me as to how to access the middleware context for the current request? Thanks for any and all assistance, Doug.

    opened by biot023 7
  • Troubles while compiling on linux

    Troubles while compiling on linux

    Hello, I tried to compile the lib on my ubuntu 17.04 by following step from readme, I got some errors: After "cmake .." https://pastebin.com/uBxT278T CMakeOutput - https://pastebin.com/5dtgPmbG CMakeError - https://pastebin.com/5dza5CV8

    Cmake version: 3.10.2

    I'm sorry because some parts of logs may be in Polish, I hope I'll get help, it could be great if you would provide precompiled libs

    opened by marosiak 6
  • Using std::gmtime (Instead of gmtime_r and gmtime_s)

    Using std::gmtime (Instead of gmtime_r and gmtime_s)

    I'm using crow on MinGW, which does not build. Would it be possible to use std::gmtime as a more portable equivalent?

    (This is my very first Github pull request. Let me know if I am failing any rules of etiquette. Thank you very much for Crow.)

    opened by mwm126 6
  • Return json in response of apis ?

    Return json in response of apis ?

    I am using nlohmann json library in my crow project. Below is my sample POST method.

    // Add two numbers
        
        CROW_ROUTE(app,"/add")
                .methods("POST"_method)
        ([](const crow::request& req) {
            auto x = json::parse(req.body);
            if (x == nullptr)
                return crow::response(400);
            auto sum = x["a"].get<long double>() + x["b"].get<long double>();
            bool status = true;
            string message = "It doesn't matter, right ?";
            json return_json = {
                {"status", status},
                {"message", message},
                {"sum", sum},
            };
            return crow::response(return_json);
        });
    

    2nd last line of my code produces error because error: call of overloaded ‘response(json&)’ is ambiguous.

    When I replace it with return crow::response(return_json.dump()); it works perfectly, because this converts the json to string type. I would like to know, how can I return the actual json in response of my apis.

    opened by Shravan40 6
  • Suitable server for production enviroment  (apache/nginx) ?

    Suitable server for production enviroment (apache/nginx) ?

    I have written my APIs using crow, and for testing purpose i run the server using ./a.out. But server gets closed whenever any exceptions occurs. Since my code is all set to go into production, I would like to keep running my server irrespective of exception. Please suggest me a way, how to combine it with server like apache, nginx e.t.c

    opened by Shravan40 6
  • How to access POST data?

    How to access POST data?

    I have a form that is submited using POST. How do I get values of inidiviudal form fileds in Crow. req.body returns everything, in an unparsed form. Is there a way of accessing POST data, which is similar to GET data, i.e., req.url_params.get("txhash")?

    opened by moneroexamples 6
  • No rule to make target '/usr/lib/libtcmalloc_minimal.so', needed by 'examples/example'.  Stop.

    No rule to make target '/usr/lib/libtcmalloc_minimal.so', needed by 'examples/example'. Stop.

    make error:

    make[2]: *** No rule to make target '/usr/lib/libtcmalloc_minimal.so', needed by 'examples/example'. Stop. CMakeFiles/Makefile2:292: recipe for target 'examples/CMakeFiles/example.dir/all' failed make[1]: *** [examples/CMakeFiles/example.dir/all] Error 2 Makefile:97: recipe for target 'all' failed make: *** [all] Error 2

    opened by lonngxiang 1
  • Middleware.h

    Middleware.h

    Hi when i run my script i got this error:

    /usr/local/include/crow/middleware.h: In instantiation of ‘typename std::enable_if<crow::black_magic::is_callable<F, crow::request, Args ...>::value>::type crow::detail::wrapped_handler_call(crow::request&, crow::response&, const F&, Args&& ...) [with F = main()::<lambda(const crow::request&)>; Args = {}; typename std::enable_if<crow::black_magic::is_callable<F, crow::request, Args ...>::value>::type = void]’:
    /usr/local/include/crow/routing.h:583:47:   required from ‘void crow::TaggedRule<Args>::operator()(Func&&) [with Func = main()::<lambda(const crow::request&)>; Args = {}]’
    Run.cpp:55:6:   required from here
    /usr/local/include/crow/middleware.h:238:27: error: static assertion failed: Handler function cannot have void return type; valid return types: string, int, crow::response, crow::returnable
      238 |             static_assert(!std::is_same<void, decltype(f(std::declval<crow::request>(), std::declval<Args>()...))>::value,
          |                           ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    /usr/local/include/crow/middleware.h:241:25: error: invalid use of void expression
      241 |             res = crow::response(f(req, std::forward<Args>(args)...));
          |                         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    
    

    My code:

    #include <iostream>
    #include <ctime>
    #include <list>
    
    
    #include <crow.h>
    
    #include "Wallets/Wallets.hpp"
    #include "Headers/json.hpp"
    
    using namespace std;
    using namespace crow;
    
    Wallets wallets;
    
    
    int main()
    {
        SimpleApp server;
    
        CROW_ROUTE(server, "/")([]() {
            mustache::context ctx;
            auto main_page = mustache::load("index.html");
            return main_page.render();
        });
    
        CROW_ROUTE(server, "/wallet").methods("GET"_method)([](const crow::request& req) {
            auto main_page = mustache::load("add_wallet.html");
            return main_page.render();
        });
    
        CROW_ROUTE(server, "/create-wallet").methods("POST"_method)([](const crow::request& req) {
            cout << endl;
    
            const Wallet& newWallet = wallets.CreateWallet();
    
            cout << endl;
    
            crow::json::wvalue x({{}});
            x["Hash"] = newWallet.wallet_hash;
            x["Phrase"] = newWallet.secret_phrase;
    
            auto main_page = mustache::load("successfully_wallet_created.html");
            return main_page.render(x);
        });
    
        CROW_ROUTE(server, "/login").methods("GET"_method)([](const crow::request& req) {
            auto main_page = mustache::load("login_wallet.html");
            return main_page.render();
        });
    
        
        CROW_ROUTE(server, "/login-wallet").methods("POST"_method)([](const crow::request& req) {
            cout << req.url_params.get("hash") << endl;
        });
    
    
        server.port(8080).multithreaded().run();
    }
    

    I USE UBUNTU AND I RUN THE CODE WITH :

     #Delete the previous run
    rm Run
    
    #Run the server
    g++ -std=c++11 Run.cpp -o Run -L /usr/lib/ -lboost_system -lboost_thread -lpthread -ggdb -lz -D CROW_ENABLE_DEBUG $(pkg-config --cflags --libs libmongocxx)
    
    #clear
    
    ./Run
    
    
    

    Middleware.h

    
    #include "crow/http_request.h"
    #include "crow/http_response.h"
    #include "crow/utility.h"
    
    #include <tuple>
    #include <type_traits>
    #include <iostream>
    #include <utility>
    
    namespace crow
    {
    
        /// Local middleware should extend ILocalMiddleware
        struct ILocalMiddleware
        {
            using call_global = std::false_type;
        };
    
        namespace detail
        {
            template<typename MW>
            struct check_before_handle_arity_3_const
            {
                template<typename T, void (T::*)(request&, response&, typename MW::context&) const = &T::before_handle>
                struct get
                {};
            };
    
            template<typename MW>
            struct check_before_handle_arity_3
            {
                template<typename T, void (T::*)(request&, response&, typename MW::context&) = &T::before_handle>
                struct get
                {};
            };
    
            template<typename MW>
            struct check_after_handle_arity_3_const
            {
                template<typename T, void (T::*)(request&, response&, typename MW::context&) const = &T::after_handle>
                struct get
                {};
            };
    
            template<typename MW>
            struct check_after_handle_arity_3
            {
                template<typename T, void (T::*)(request&, response&, typename MW::context&) = &T::after_handle>
                struct get
                {};
            };
    
            template<typename MW>
            struct check_global_call_false
            {
                template<typename T, typename std::enable_if<T::call_global::value == false, bool>::type = true>
                struct get
                {};
            };
    
            template<typename T>
            struct is_before_handle_arity_3_impl
            {
                template<typename C>
                static std::true_type f(typename check_before_handle_arity_3_const<T>::template get<C>*);
    
                template<typename C>
                static std::true_type f(typename check_before_handle_arity_3<T>::template get<C>*);
    
                template<typename C>
                static std::false_type f(...);
    
            public:
                static const bool value = decltype(f<T>(nullptr))::value;
            };
    
            template<typename T>
            struct is_after_handle_arity_3_impl
            {
                template<typename C>
                static std::true_type f(typename check_after_handle_arity_3_const<T>::template get<C>*);
    
                template<typename C>
                static std::true_type f(typename check_after_handle_arity_3<T>::template get<C>*);
    
                template<typename C>
                static std::false_type f(...);
    
            public:
                static constexpr bool value = decltype(f<T>(nullptr))::value;
            };
    
            template<typename MW, typename Context, typename ParentContext>
            typename std::enable_if<!is_before_handle_arity_3_impl<MW>::value>::type
              before_handler_call(MW& mw, request& req, response& res, Context& ctx, ParentContext& /*parent_ctx*/)
            {
                mw.before_handle(req, res, ctx.template get<MW>(), ctx);
            }
    
            template<typename MW, typename Context, typename ParentContext>
            typename std::enable_if<is_before_handle_arity_3_impl<MW>::value>::type
              before_handler_call(MW& mw, request& req, response& res, Context& ctx, ParentContext& /*parent_ctx*/)
            {
                mw.before_handle(req, res, ctx.template get<MW>());
            }
    
            template<typename MW, typename Context, typename ParentContext>
            typename std::enable_if<!is_after_handle_arity_3_impl<MW>::value>::type
              after_handler_call(MW& mw, request& req, response& res, Context& ctx, ParentContext& /*parent_ctx*/)
            {
                mw.after_handle(req, res, ctx.template get<MW>(), ctx);
            }
    
            template<typename MW, typename Context, typename ParentContext>
            typename std::enable_if<is_after_handle_arity_3_impl<MW>::value>::type
              after_handler_call(MW& mw, request& req, response& res, Context& ctx, ParentContext& /*parent_ctx*/)
            {
                mw.after_handle(req, res, ctx.template get<MW>());
            }
    
    
            template<template<typename QueryMW> class CallCriteria, // Checks if QueryMW should be called in this context
                     int N, typename Context, typename Container>
            typename std::enable_if<(N < std::tuple_size<typename std::remove_reference<Container>::type>::value), bool>::type
              middleware_call_helper(Container& middlewares, request& req, response& res, Context& ctx)
            {
    
                using CurrentMW = typename std::tuple_element<N, typename std::remove_reference<Container>::type>::type;
    
                if (!CallCriteria<CurrentMW>::value)
                {
                    return middleware_call_helper<CallCriteria, N + 1, Context, Container>(middlewares, req, res, ctx);
                }
    
                using parent_context_t = typename Context::template partial<N - 1>;
                before_handler_call<CurrentMW, Context, parent_context_t>(std::get<N>(middlewares), req, res, ctx, static_cast<parent_context_t&>(ctx));
                if (res.is_completed())
                {
                    after_handler_call<CurrentMW, Context, parent_context_t>(std::get<N>(middlewares), req, res, ctx, static_cast<parent_context_t&>(ctx));
                    return true;
                }
    
                if (middleware_call_helper<CallCriteria, N + 1, Context, Container>(middlewares, req, res, ctx))
                {
                    after_handler_call<CurrentMW, Context, parent_context_t>(std::get<N>(middlewares), req, res, ctx, static_cast<parent_context_t&>(ctx));
                    return true;
                }
    
                return false;
            }
    
            template<template<typename QueryMW> class CallCriteria, int N, typename Context, typename Container>
            typename std::enable_if<(N >= std::tuple_size<typename std::remove_reference<Container>::type>::value), bool>::type
              middleware_call_helper(Container& /*middlewares*/, request& /*req*/, response& /*res*/, Context& /*ctx*/)
            {
                return false;
            }
    
            template<template<typename QueryMW> class CallCriteria, int N, typename Context, typename Container>
            typename std::enable_if<(N < 0)>::type
              after_handlers_call_helper(Container& /*middlewares*/, Context& /*context*/, request& /*req*/, response& /*res*/)
            {
            }
    
            template<template<typename QueryMW> class CallCriteria, int N, typename Context, typename Container>
            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<N - 1>;
                using CurrentMW = typename std::tuple_element<N, typename std::remove_reference<Container>::type>::type;
                if (CallCriteria<CurrentMW>::value)
                {
                    after_handler_call<CurrentMW, Context, parent_context_t>(std::get<N>(middlewares), req, res, ctx, static_cast<parent_context_t&>(ctx));
                }
            }
    
            template<template<typename QueryMW> class CallCriteria, int N, typename Context, typename Container>
            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<N - 1>;
                using CurrentMW = typename std::tuple_element<N, typename std::remove_reference<Container>::type>::type;
                if (CallCriteria<CurrentMW>::value)
                {
                    after_handler_call<CurrentMW, Context, parent_context_t>(std::get<N>(middlewares), req, res, ctx, static_cast<parent_context_t&>(ctx));
                }
                after_handlers_call_helper<CallCriteria, N - 1, Context, Container>(middlewares, ctx, req, res);
            }
    
            // A CallCriteria that accepts only global middleware
            template<typename MW>
            struct middleware_call_criteria_only_global
            {
                template<typename C>
                static std::false_type f(typename check_global_call_false<MW>::template get<C>*);
    
                template<typename C>
                static std::true_type f(...);
    
                static const bool value = decltype(f<MW>(nullptr))::value;
            };
    
            // wrapped_handler_call transparently wraps a handler call behind (req, res, args...)
            template<typename F, typename... Args>
            typename std::enable_if<black_magic::is_callable<F, const crow::request, crow::response&, Args...>::value>::type
              wrapped_handler_call(crow::request& req, crow::response& res, const F& f, Args&&... args)
            {
                static_assert(std::is_same<void, decltype(f(std::declval<crow::request>(), std::declval<crow::response&>(), std::declval<Args>()...))>::value,
                              "Handler function with response argument should have void return type");
    
                f(req, res, std::forward<Args>(args)...);
            }
    
            template<typename F, typename... Args>
            typename std::enable_if<black_magic::is_callable<F, crow::request&, crow::response&, Args...>::value && !black_magic::is_callable<F, const crow::request, crow::response&, Args...>::value>::type
              wrapped_handler_call(crow::request& req, crow::response& res, const F& f, Args&&... args)
            {
                static_assert(std::is_same<void, decltype(f(std::declval<crow::request&>(), std::declval<crow::response&>(), std::declval<Args>()...))>::value,
                              "Handler function with response argument should have void return type");
    
                f(req, res, std::forward<Args>(args)...);
            }
    
            template<typename F, typename... Args>
            typename std::enable_if<black_magic::is_callable<F, crow::response&, Args...>::value>::type
              wrapped_handler_call(crow::request& /*req*/, crow::response& res, const F& f, Args&&... args)
            {
                static_assert(std::is_same<void, decltype(f(std::declval<crow::response&>(), std::declval<Args>()...))>::value,
                              "Handler function with response argument should have void return type");
    
                f(res, std::forward<Args>(args)...);
            }
    
            template<typename F, typename... Args>
            typename std::enable_if<black_magic::is_callable<F, crow::request, Args...>::value>::type
              wrapped_handler_call(crow::request& req, crow::response& res, const F& f, Args&&... args)
            {
                static_assert(!std::is_same<void, decltype(f(std::declval<crow::request>(), std::declval<Args>()...))>::value,
                              "Handler function cannot have void return type; valid return types: string, int, crow::response, crow::returnable");
    
                res = crow::response(f(req, std::forward<Args>(args)...));
                res.end();
            }
    
            template<typename F, typename... Args>
            typename std::enable_if<black_magic::is_callable<F, Args...>::value>::type
              wrapped_handler_call(crow::request& /*req*/, crow::response& res, const F& f, Args&&... args)
            {
                static_assert(!std::is_same<void, decltype(f(std::declval<Args>()...))>::value,
                              "Handler function cannot have void return type; valid return types: string, int, crow::response, crow::returnable");
    
                res = crow::response(f(std::forward<Args>(args)...));
                res.end();
            }
    
            template<typename F, typename App, typename... Middlewares>
            struct handler_middleware_wrapper
            {
                // CallCriteria bound to the current Middlewares pack
                template<typename MW>
                struct middleware_call_criteria
                {
                    static constexpr bool value = black_magic::has_type<MW, std::tuple<Middlewares...>>::value;
                };
    
                template<typename... Args>
                void operator()(crow::request& req, crow::response& res, Args&&... args) const
                {
                    auto& ctx = *reinterpret_cast<typename App::context_t*>(req.middleware_context);
                    auto& container = *reinterpret_cast<typename App::mw_container_t*>(req.middleware_container);
    
                    auto glob_completion_handler = std::move(res.complete_request_handler_);
                    res.complete_request_handler_ = [] {};
    
                    middleware_call_helper<middleware_call_criteria,
                                           0, typename App::context_t, typename App::mw_container_t>(container, req, res, ctx);
    
                    if (res.completed_)
                    {
                        glob_completion_handler();
                        return;
                    }
    
                    res.complete_request_handler_ = [&ctx, &container, &req, &res, &glob_completion_handler] {
                        after_handlers_call_helper<
                          middleware_call_criteria,
                          std::tuple_size<typename App::mw_container_t>::value - 1,
                          typename App::context_t,
                          typename App::mw_container_t>(container, ctx, req, res);
                        glob_completion_handler();
                    };
    
                    wrapped_handler_call(req, res, f, std::forward<Args>(args)...);
                }
    
                F f;
            };
    
            template<typename Route, typename App, typename... Middlewares>
            struct handler_call_bridge
            {
                template<typename MW>
                using check_app_contains = typename black_magic::has_type<MW, typename App::mw_container_t>;
    
                static_assert(black_magic::all_true<(std::is_base_of<crow::ILocalMiddleware, Middlewares>::value)...>::value,
                              "Local middleware has to inherit crow::ILocalMiddleware");
    
                static_assert(black_magic::all_true<(check_app_contains<Middlewares>::value)...>::value,
                              "Local middleware has to be listed in app middleware");
    
                template<typename F>
                void operator()(F&& f) const
                {
                    auto wrapped = handler_middleware_wrapper<F, App, Middlewares...>{std::forward<F>(f)};
                    tptr->operator()(std::move(wrapped));
                }
    
                Route* tptr;
            };
    
        } // namespace detail
    } // namespace crow
    
    opened by AlexSteinerETH 2
  • Multi process

    Multi process

    I know Crow server supports multi-threading. However, the legacy code base that I would like to use Crow with is not thread-safe. Given that, I am wondering how difficult it is to add multi-process capability to Crow (instead of creating a new thread for each incoming request, fork a new process).

    opened by rj314 1
Releases(v0.1)
Owner
Jaeseung Ha
Jaeseung Ha
A high performance, middleware oriented C++14 http web framework please use matt-42/lithium instead

A high performance, middleware oriented C++14 http web framework please use matt-42/lithium instead

Matthieu Garrigues 1.7k Aug 26, 2022
A C++ Web Framework built on top of Qt, using the simple approach of Catalyst (Perl) framework.

Cutelyst - The Qt Web Framework A Web Framework built on top of Qt, using the simple and elegant approach of Catalyst (Perl) framework. Qt's meta obje

Cutelyst 790 Oct 3, 2022
TreeFrog Framework : High-speed C++ MVC Framework for Web Application

Small but Powerful and Efficient TreeFrog Framework is a high-speed and full-stack web application framework based on C++ and Qt, which supports HTTP

TreeFrog Framework 1.1k Sep 30, 2022
Tntnet is a web application server for web applications written in C++.

Tntnet is a web application server for web applications written in C++.

Tommi Mäkitalo 73 Sep 26, 2022
This is a proof-of-concept of a modern C web-framework that compiles to WASM and is used for building user interfaces.

DanCing Web ?? ?? (DCW) Getting Started Dancing Web is now distributed with the Tarantella Package Manager — a tool I've made to simplify setup of pro

Danilo Chiarlone 3 Sep 11, 2021
Drogon: A C++14/17 based HTTP web application framework running on Linux/macOS/Unix/Windows

English | 简体中文 | 繁體中文 Overview Drogon is a C++14/17-based HTTP application framework. Drogon can be used to easily build various types of web applicat

An Tao 8k Sep 27, 2022
Your high performance web application C framework

facil.io is a C micro-framework for web applications. facil.io includes: A fast HTTP/1.1 and Websocket static file + application server. Support for c

Bo 1.6k Sep 28, 2022
QDjango, a Qt-based C++ web framework

QDjango - a Qt-based C++ web framework Copyright (c) 2010-2015 Jeremy Lainé About QDjango is a web framework written in C++ and built on top of the Qt

Jeremy Lainé 246 Sep 18, 2022
CppCMS - High Performance C++ Web Framework

CppCMS - High Performance C++ Web Framework What is CppCMS? CppCMS is a Free High Performance Web Development Framework (not a CMS) aimed at Rapid Web

Artyom Beilis 368 Sep 23, 2022
a very based, minimal, and flexible static site generator written in pure C89 with no external deps.

based-ssg is a very based, minimal, and flexible static site generator written in pure C89 with no external deps.

null 14 Oct 2, 2022
C library to create simple HTTP servers and Web Applications.

Onion http server library Travis status Coverity status Onion is a C library to create simple HTTP servers and Web Applications. master the developmen

David Moreno Montero 1.9k Sep 21, 2022
cserv is an event-driven and non-blocking web server

cserv is an event-driven and non-blocking web server. It ideally has one worker process per cpu or processor core, and each one is capable of handling thousands of incoming network connections per worker. There is no need to create new threads or processes for each connection.

null 42 Sep 14, 2022
Embedded C/C++ web server

CivetWeb The official home of CivetWeb is https://github.com/civetweb/civetweb Continuous integration for Linux and macOS (Travis CI): Continuous inte

null 2.2k Sep 29, 2022
A C++11 RESTful web server library

Served Overview Served is a C++ library for building high performance RESTful web servers. Served builds upon Boost.ASIO to provide a simple API for d

Meltwater 694 Sep 26, 2022
C++ application development framework, to help developers create and deploy applications quickly and simply

ULib - C++ library Travis CI: Coverity Scan: ULib is a highly optimized class framework for writing C++ applications. I wrote this framework as my too

stefano casazza 948 Sep 17, 2022
Pistache is a modern and elegant HTTP and REST framework for C++

Pistache is a modern and elegant HTTP and REST framework for C++. It is entirely written in pure-C++17* and provides a clear and pleasant API.

null 2.8k Oct 3, 2022
Corvusoft's Restbed framework brings asynchronous RESTful functionality to C++14 applications.

Restbed Restbed is a comprehensive and consistent programming model for building applications that require seamless and secure communication over HTTP

Corvusoft 1.7k Sep 26, 2022
The application framework for developer module of EdgeGallery platform

crane-framework crane-framework将可复用的计算和软件功能抽象成插件,APP开发者面向使用插件进行MEC APP开发。这样屏蔽了和MEC平台交互的细节,实现MCE APP和MEC平台的松耦合。而且插件框架基础能力可裁剪,按需提供最小的APP系统。 特性介绍 为了方便开发者

EdgeGallery 21 Aug 30, 2021