A C++ Web Framework built on top of Qt, using the simple approach of Catalyst (Perl) framework.

Overview

Cutelyst - The Qt Web Framework Cutelyst logo

Build Status Windows Build status Codacy Badge Code Quality: Cpp Total Alerts

A Web Framework built on top of Qt, using the simple and elegant approach of Catalyst (Perl) framework.

Qt's meta object system is what powers the core of Cutelyst, it allows for introspecting controller's methods signatures and generate matching actions that can be invoked later.

BENCHMARKS

Don't trust us on being fast, check out the most comprehensive web framework benchmarks by TechEmpower http://www.techempower.com/benchmarks/

FEATURES:

  • Cross-platform
  • Stable API/ABI - v1 on v1.x.x branch and v2 on tagged from master
  • Pluggable Engines
    • Cutelyst-WSGI - A cross-platform and fast WSGI engine
      • HTTP/1.1 - Pipelining and Keep-Alive
      • HTTP/2 - Upgrade to H2, ALPN negotiation on HTTPS and direct H2C
      • FastCGI - Pipelining and Keep-Alive
    • uWSGI - Multiple protocols support (HTTP 1.0, FastCGI, uWSGI)
  • WebSockets
  • REST with ActionREST
  • Plugin based views
  • Dispatcher
    • Chained
    • Path
  • Plugins
    • Session
    • Authentication (with PBKDF2)
    • Authorization with RoleACL
    • StatusMessage
    • Validator (to validate user input)
    • CSRF protection
    • Memcached
    • UserAgent
  • Asynchronous processing (just don't use local QEventLoops or it will eventually crash)
    • Async SQL with ASql
  • Upload parser
  • JSON body as QJsonDocument when uploaded data is in JSON format
  • C++11
  • Chunked reponses (via QIODevice write API)
  • Request profiling/stats
  • Unit tested
  • QtCreator integration

DOCUMENTATION

Get started with our Tutorial or check the API.

COMMUNITY

The Cutelyst project IRC channel is #cutelyst on freenode.

Or you can use the Mailing List

REQUIREMENTS

  • CMake - for the build system (>= 3.1)
  • Qt - the core library of this framework (>= 5.6)

OPTIONAL

  • uWSGI - to receive and parse protocols requests (>= 1.9 recommended)

LICENSE

The library is under the LGPLv2+ and public header files, documentation and examples are under MIT license.

Comments
  • Implement a validation infrastracture.

    Implement a validation infrastracture.

    This can be used to validate input data. See the code documentation for further information. It's a bit inspired by the validator implementation of Laravel. :) (I never used catalyst)

    opened by buschmann23 40
  • SSE server

    SSE server

    I am trying to implement a SSE (Server Sent Event) in my cutelyst application following the steps in this example http://stefanfrings.de/qtwebapp/tutorial/sse_example.html , but I have some issues:

    1. while(response.isConnected()) isConnected is not implemented in cutelyst
    2. response.flush(); even not implemented

    Both methods are implemented in the demo app as:

    bool HttpResponse::isConnected() const { return socket->isOpen(); }

    void HttpResponse::flush() { socket->flush(); }

    How can I access the underlying socket from the c->response() ?

    opened by iastinf 24
  • Organizing multithreaded single-process REST controller with Websocket support.

    Organizing multithreaded single-process REST controller with Websocket support.

    Hello! I use cutelyst-wsgi2 in a single-process mode. Is it possible to use Cutelyst websockets for multiple threads (multiple controller instances) within the same process? AFAIK, there are warnings like these: QSocketNotifier: socket notifiers cannot be disabled from another thread. Actually, I'd like to have a separate thread for a sort of WebSocket manager which is shared among Controller instances. BTW, I use some static members within controller in order to share them between controller instances. I adjust them in postFork, using mutex and checking isInitialized flag. Examples of static members are worker object (with business logic) and corresponding worker thread. Controller emits signals for worker objects. Is it reasonable approach?

    opened by arietto 16
  • Unable to serve static files via HTTP/2

    Unable to serve static files via HTTP/2

    Hi,

    it seems that this line https://github.com/cutelyst/cutelyst/blob/master/Cutelyst/Plugins/StaticSimple/staticsimple.cpp#L77 returns "/" at start when HTTP/2 over SSL is used (wsgi->setHttpsH2(true)) resulting in files not being able to be found.

    Way to replicate

    int main(int argc, char *argv[])
    {
      CWSGI::WSGI *wsgi = new CWSGI::WSGI();
      Cutelyst::Application *myapp = new Hello();
      QCoreApplication app(argc, argv);
      wsgi->setProcesses("1");
      wsgi->setThreads("4");
      wsgi->setHttpsSocket({{QStringLiteral("0.0.0.0:443,/etc/ssl/certs/certificate.crt,/etc/ssl/private/server.key")}});
      wsgi->setHttpsH2(true);
      wsgi->setBufferSize(16393);
      wsgi->setSoKeepalive(true);
      wsgi->setReusePort(true);
      wsgi->setMaster(true);
      wsgi->exec(myapp);
    }
    
    bool Hello::init()
    {
        //initialize controllers
        new Root(this);
    
        //initialize file serving plugin
        auto staticSimple = new StaticSimple(this);
        staticSimple->setDirs({"public"});
        staticSimple->setIncludePaths({QDir::currentPath()});
    
        //initialize templates plugin
        auto grantleeView = new GrantleeView(this);
        grantleeView->setCache(true);
        grantleeView->setIncludePaths({pathTo("views")});
    
        return true;
    }
    

    Even when I fix the line to const QString path = c->req()->path().mid(1); for this scenario and files can actually be found, I am getting net::ERR_SPDY_FRAME_SIZE_ERROR.

    opened by brano543 16
  • Need help with starting HTTP/2 server

    Need help with starting HTTP/2 server

    Hi guys,

    I am new to Cutelyst and after having tough time to compile it on RHEL (had to compile QT5 Base from source as packages are archaic) I am unable to start CWSGI::WSGI server to listen for HTTP/2, because every time I do it just refuses to send reply. (curl: (52) Empty reply from server), for standard HTTP it works fine and sends HTTP/1.1 response. This is the code of my main program. What am I doing wrong?

    CWSGI::WSGI *wsgi = new CWSGI::WSGI();
      Cutelyst::Application *myapp = new Hello();
      QCoreApplication app(argc, argv);
      wsgi->setThreads("auto");
      wsgi->setProcesses("1");
      wsgi->setBufferSize(16393);
      // wsgi->setUpgradeH2c(true); -> tried also turning this on and off
      wsgi->setHttp2Socket({QStringLiteral("0.0.0.0:80")});
      wsgi->setSoKeepalive(true);
      wsgi->setReusePort(true);
      wsgi->setMaster(true);
      wsgi->exec(myapp);
    
    opened by brano543 16
  • install package cannot be used in a cross compile environment

    install package cannot be used in a cross compile environment

    I'm working on an embedded system and trying Cutelyst. I have successfully built Cutelyst and created an install package, but the package cannot be used in downstream cmake projects when it is installed into my sysroot. (I use a cmake toolchain file to find the sysroot and otherwise setup my enviornment)

    When cmake gets to the FIND_PACKAGE(CutelystQt5) line I get the following error.

    CMake Error at [sysroot]/usr/lib/cmake/Cutelyst2Qt5/Cutelyst2Qt5Targets.cmake:122 (message):
    -- Configuring incomplete, errors occurred!
    
    The imported target "Cutelyst::Core" references the file
    
         "/usr/lib/libCutelyst2Qt5.so.2.8.0"
    

    I depend on other cmake packages that work. So this is a problem with Cutelyst cmake packages, not cmake or my enviornment.

    opened by HenryMiller1 14
  • Upload files greater than 2Gb

    Upload files greater than 2Gb

    It seems to be a problem uploading files bigger than 2GB.

    Following code

    const auto uploads = c->request()->uploads(); for (Upload *upload : uploads) { upload->save("/tmp/" + upload->filename()); } produces this error message and the file is empty in /tmp/ QIODevice::read (Cutelyst::Upload): Called with maxSize < 0

    With files smaller than 2GB there is no problem except a warning

    Cannot create /tmp/ for output

    Although the file is created successfully

    opened by haralambop 14
  • uriFor in Grantlee Template

    uriFor in Grantlee Template

    Hi! This is not really an issue but more like a question of best practice. In Catalyst or Flask/Jinja2 I can access the uri_for method directly for creating links for an action. Unfortunately in Grantlee there is no direct way of calling a function with a string parameter. E.g. {{c.uriFor("authen/logout")}} does not work. The Parser is choking on the parameter "Could not parse the remainder, (\"authen/logout\") from c.uriFor(\"authen/logout\")

    Right now, as a workaround, I created a two-level map so that I can access the routes via dot-lookup:

    QVariantHash controllers;
    for( Controller *controller: c->app()->controllers() ) {
      QVariantHash routes;
      for( Action *action: controller->actions() ) {
        routes[action->name()] = c->uriFor(action);
      }
      controllers[controller->objectName()] = routes;
    }
    c->setStash("controllers", controllers);
    

    Having this routes map on my stash I can do something like this in the template:

    <p> <a href="{{controllers.Authen.logout}}">Logout</a> </p>
    

    Sure, better have it in the init method to not have the map generated on every request.

    Or is there another (easier) way to do this? -- Besides creating a Grantlee Filter that appearently accepts string parameters.

    opened by ghost 13
  • Soft termination of user threads using slot for Application::shutdown signal

    Soft termination of user threads using slot for Application::shutdown signal

    Hello! I have a couple of threads which must be gently terminated in the Controller slot slotShutdown() linked with Application::shutdown. I have typical worker objects (QObject descendants) and corresponding QThreads. I emit finalize() signal within slotShutdown(). Then I periodically check worker object atomic bool flag isFinalized in a loop. I quit worker QThread after that. AFAIK, I cannot rely on other slots within Controller after Application::shutdown, that's why I have to check other workers state in a loop using synchronized flag. But I expect that eventloops of other threads are still working when I emit signal within Controller slotShutdown().
    Sometimes the signal is not catched within worker objects, so the loop is eternal. What can be done? I don't want to call methods of worker objects within Controller thread, because I've got Qt warnings about killing timers in the wrong threads etc. BTW, I've used single process (master), single REST Controller thread for this experiment.

    opened by arietto 12
  • [WIP] Prometheus Plugin

    [WIP] Prometheus Plugin

    This is an attempt to provide Prometheus compatible metrics in an easy manner. This plugin uses the existing statistics feature to calculate metrics.

    What do you think?

    opened by sibbi77 12
  • Parallel processing of requests

    Parallel processing of requests

    I am new here and recently I am dealing with Cutelyst. My englich is not gut ;). I have studied the tutorials and implemented. When I have many requests and the processing of one takes 2 seconds (waiting for response from embedded devices), the other requests wait. Is there a possibility in Cutelyst to process the requests in parallel. A simple example would be very helpful.

    opened by cppusta 11
  • Crash when calling Context::finalize()

    Crash when calling Context::finalize()

    As proposed in #344 I tried to use Context::finalize() instead of Context::detach() but that crashes the application.

    I use a private action to show CSRF denied message. CSRFProtection plugin detaches to that action.

    void Root::csrfDenied(Context *c)
    {
        qCDebug(GIK_CORE) << "Entering Root::csrfDenied()";
    
        c->response()->setBody(QStringLiteral("CSRF check failed"));
        c->response()->setContentType(QStringLiteral("text/html; charset=utf-8"));
        c->finalize();
    }
    

    Logging output:

    16136:16136 cutelyst.dispatcher[debug] Path is "login"
    16136:16136 cutelyst.plugin.csrfprotection[debug] Got token "GD4nxPfxQwSKMUjPnh0lQAKk6-NncjS-pGpN7n6Dvn0s9Eby_lz4qeD_M6NJ-ly6" from cookie.
    16136:16136 cutelyst.plugin.csrfprotection[debug] Can not get token from HTTP header or form field.
    16136:16136 cutelyst.plugin.csrfprotection[warning] Forbidden: (CSRF token missing or incorrect): /login [IP logging disabled]
    16136:16136 gikwimi.core[debug] Entering Root::csrfDenied()
    16136:16136 cutelyst.stats[debug] Response Code: 403; Content-Type: text/html; charset=utf-8; Content-Length: 17
    DAMN ! worker 1 (pid: 16136) died, killed by signal 0 :( trying respawn ..
    Respawned WSGI worker 1 (new pid: 16485, cores: 1)
    

    Backtrace:

    Program received signal SIGSEGV, Segmentation fault.
    0x00007ffff74bdbd7 in QHash<QString, QString>::findNode (ahp=0x0, akey=..., this=0x5555555e11b0) at /usr/include/qt5/QtCore/qhash.h:945
    945         if (d->numBuckets || ahp) {
    Missing separate debuginfos, use: zypper install libX11-6-debuginfo-1.8-1.1.x86_64 libbz2-1-debuginfo-1.0.8-4.1.x86_64 libfreetype6-debuginfo-2.12.1-1.1.x86_64 libxcb1-debuginfo-1.15-1.1.x86_64
    (gdb) bt
    #0  0x00007ffff74bdbd7 in QHash<QString, QString>::findNode (ahp=0x0, akey=..., this=0x5555555e11b0) at /usr/include/qt5/QtCore/qhash.h:945
    #1  QHash<QString, QString>::constFind (akey=..., this=0x5555555e11b0) at /usr/include/qt5/QtCore/qhash.h:907
    #2  Cutelyst::Headers::contentType (this=0x5555555e11b0) at /usr/src/debug/cutelyst3-qt5-3.3.60~git.1651935712.84b1cdc-5.1.x86_64/Cutelyst/headers.cpp:73
    #3  0x00007ffff74c9bd2 in Cutelyst::Response::contentType (this=this@entry=0x5555555e8830) at /usr/src/debug/cutelyst3-qt5-3.3.60~git.1651935712.84b1cdc-5.1.x86_64/Cutelyst/response.cpp:207
    #4  0x00007ffff2e877eb in Cutelyst::RenderView::doExecute (this=<optimized out>, c=0x5555555d1f80)
        at /usr/src/debug/cutelyst3-qt5-3.3.60~git.1651935712.84b1cdc-5.1.x86_64/Cutelyst/Actions/RenderView/renderview.cpp:90
    #5  0x00007ffff74df172 in Cutelyst::Component::execute (this=0x5555555c6740, c=0x5555555d1f80) at /usr/src/debug/cutelyst3-qt5-3.3.60~git.1651935712.84b1cdc-5.1.x86_64/Cutelyst/component.cpp:90
    #6  0x00007ffff74cc07d in Cutelyst::Context::execute (this=0x5555555d1f80, code=<optimized out>) at /usr/src/debug/cutelyst3-qt5-3.3.60~git.1651935712.84b1cdc-5.1.x86_64/Cutelyst/context.cpp:452
    #7  0x00007ffff40eb5cb in Cutelyst::CSRFProtectionPrivate::reject (c=0x5555555d1f80, logReason=..., displayReason=...)
        at /usr/src/debug/cutelyst3-qt5-3.3.60~git.1651935712.84b1cdc-5.1.x86_64/Cutelyst/Plugins/CSRFProtection/csrfprotection.cpp:452
    #8  0x00007ffff40efea4 in Cutelyst::CSRFProtectionPrivate::beforeDispatch (c=0x5555555d1f80, this=<optimized out>)
        at /usr/src/debug/cutelyst3-qt5-3.3.60~git.1651935712.84b1cdc-5.1.x86_64/Cutelyst/Plugins/CSRFProtection/csrfprotection.cpp:645
    #9  0x00007ffff7c98453 in QtPrivate::QSlotObjectBase::call (a=0x7fffffffcb00, r=0x5555555c3480, this=0x5555555c0cf0) at ../../include/QtCore/../../src/corelib/kernel/qobjectdefs_impl.h:398
    #10 doActivate<false> (sender=0x5555555b2080, signal_index=4, argv=0x7fffffffcb00) at kernel/qobject.cpp:3886
    #11 0x00007ffff7c917af in QMetaObject::activate (sender=sender@entry=0x5555555b2080, m=<optimized out>, local_signal_index=local_signal_index@entry=1, argv=argv@entry=0x7fffffffcb00) at kernel/qobject.cpp:3946
    #12 0x00007ffff74e5662 in Cutelyst::Application::beforeDispatch (this=this@entry=0x5555555b2080, _t1=<optimized out>, _t1@entry=0x5555555d1f80)
        at /usr/src/debug/cutelyst3-qt5-3.3.60~git.1651935712.84b1cdc-5.1.x86_64/build/Cutelyst/Cutelyst3Qt5_autogen/include/moc_application.cpp:228
    #13 0x00007ffff74ed855 in Cutelyst::Application::handleRequest (this=<optimized out>, request=0x5555555d2528) at /usr/src/debug/cutelyst3-qt5-3.3.60~git.1651935712.84b1cdc-5.1.x86_64/Cutelyst/application.cpp:400
    #14 0x00007ffff7f753b7 in Cutelyst::ProtocolHttp::processRequest (io=0x5555555d14f0, sock=0x5555555d1500, this=0x5555555a01c0)
        at /usr/src/debug/cutelyst3-qt5-3.3.60~git.1651935712.84b1cdc-5.1.x86_64/server/protocolhttp.cpp:212
    #15 Cutelyst::ProtocolHttp::parse (this=0x5555555a01c0, sock=0x5555555d1500, io=0x5555555d14f0) at /usr/src/debug/cutelyst3-qt5-3.3.60~git.1651935712.84b1cdc-5.1.x86_64/server/protocolhttp.cpp:175
    #16 0x00007ffff7c98453 in QtPrivate::QSlotObjectBase::call (a=0x7fffffffcdc0, r=0x5555555d14f0, this=0x5555555d06e0) at ../../include/QtCore/../../src/corelib/kernel/qobjectdefs_impl.h:398
    #17 doActivate<false> (sender=0x5555555d14f0, signal_index=3, argv=0x7fffffffcdc0) at kernel/qobject.cpp:3886
    #18 0x00007ffff7c917af in QMetaObject::activate (sender=sender@entry=0x5555555d14f0, m=m@entry=0x7ffff7f34040 <QIODevice::staticMetaObject>, local_signal_index=local_signal_index@entry=0, argv=argv@entry=0x0)
        at kernel/qobject.cpp:3946
    #19 0x00007ffff7b90050 in QIODevice::readyRead (this=this@entry=0x5555555d14f0) at .moc/moc_qiodevice.cpp:190
    #20 0x00007ffff73d41bf in QAbstractSocketPrivate::emitReadyRead (channel=0, this=0x555555596000) at socket/qabstractsocket.cpp:1323
    #21 QAbstractSocketPrivate::canReadNotification (this=0x555555596000) at socket/qabstractsocket.cpp:748
    --Type <RET> for more, q to quit, c to continue without paging--
    #22 0x00007ffff73e9fd1 in QReadNotifier::event (this=<optimized out>, e=<optimized out>) at socket/qnativesocketengine.cpp:1274
    #23 0x00007ffff7c61b2f in doNotify (event=0x7fffffffced0, receiver=0x5555555d1d50) at kernel/qcoreapplication.cpp:1154
    #24 QCoreApplication::notify (event=<optimized out>, receiver=<optimized out>, this=<optimized out>) at kernel/qcoreapplication.cpp:1140
    #25 QCoreApplication::notifyInternal2 (receiver=0x5555555d1d50, event=0x7fffffffced0) at kernel/qcoreapplication.cpp:1064
    #26 0x00007ffff7cb9e6d in socketNotifierSourceDispatch (source=source@entry=0x5555555972d0) at kernel/qeventdispatcher_glib.cpp:107
    #27 0x00007ffff6a5e122 in g_main_dispatch (context=0x555555594fc0) at ../glib/gmain.c:3417
    #28 g_main_context_dispatch (context=0x555555594fc0) at ../glib/gmain.c:4135
    #29 0x00007ffff6a5e4b8 in g_main_context_iterate (context=context@entry=0x555555594fc0, block=block@entry=1, dispatch=dispatch@entry=1, self=<optimized out>) at ../glib/gmain.c:4211
    #30 0x00007ffff6a5e56f in g_main_context_iteration (context=0x555555594fc0, may_block=1) at ../glib/gmain.c:4276
    #31 0x00007ffff7cb92b4 in QEventDispatcherGlib::processEvents (this=0x55555558e9e0, flags=...) at kernel/qeventdispatcher_glib.cpp:423
    #32 0x00007ffff7c6055b in QEventLoop::exec (this=this@entry=0x7fffffffd0e0, flags=..., flags@entry=...) at ../../include/QtCore/../../src/corelib/global/qflags.h:69
    #33 0x00007ffff7c68820 in QCoreApplication::exec () at ../../include/QtCore/../../src/corelib/global/qflags.h:121
    #34 0x00007ffff7f63edd in Cutelyst::Server::exec (this=this@entry=0x7fffffffd6b0, app=app@entry=0x0) at /usr/src/debug/cutelyst3-qt5-3.3.60~git.1651935712.84b1cdc-5.1.x86_64/server/server.cpp:652
    #35 0x000055555555641e in main (argc=<optimized out>, argv=<optimized out>) at /usr/src/debug/cutelyst3-qt5-3.3.60~git.1651935712.84b1cdc-5.1.x86_64/server/main.cpp:53
    
    opened by buschmann23 2
  • Bootstrapping WebSockets with HTTP/2

    Bootstrapping WebSockets with HTTP/2

    Suppose a web page has a script to create a new websocket, then every tab that loads that page (at each time) will create a new websocket. In HTTP1.1, a websocket is in fact a TCP socket connection :-(. And browsers like chrome and firefox limit number of websocket connections.

    Bootstrapping WebSockets with HTTP/2, as specified by https://tools.ietf.org/html/rfc8441, allow multiple websockets to live in one Http2 connection, as a stream, and already gets supported by chrome and firefox.

    However the work to support Websocket in Cutelyst seems not easy. I noticed that the design of http2 is far different from http's, which stop my steps: For Http

    1. ProtoRequestHttp is ProtocolData and EngineRequest
    2. ProtocolHttp is Protocol
    3. ProtocolWebSocket is Protocol

    For Http2

    1. H2Stream is EngineRequest
    2. ProtoRequestHttp2 is ProtocolData
    3. ProtocolHttp2 is Protocol

    @dantti , I would greatly appreciate it if you have plan to support it. Thanks!

    opened by lyarbean 3
  • Setting the action name for chaining

    Setting the action name for chaining

    I'm implementing a REST API (code is here, and I successfully got these endpoints exposed:

    .-------------------+---------------------.
    | Path              | Private             |
    .-------------------+---------------------.
    | /...              | /defaultPage        |
    | /                 | /index              |
    | /api/v1/login     | /api/v1/login/index |
    | /api/v1/users/... | /api/v1/users/user  |
    | /api/v1/users     | /api/v1/users/index |
    .-------------------+---------------------.
    

    Now I want to add a new method, say on /api/v1/users/{id}/changePassword, but I haven't been able to figure out how to achieve that. I've been trying to use the :Chained attribute, but I cannot make the action appear at the desired path. I don't fully understand what the value of the :Chained attribute is; I'd like to be able to set an action ID on the base action, and then chain to that. For example,

        C_ATTR(user, :Path :CaptureArgs(1) :ActionClass(REST) :ActionId("user"))
        // this is the new attribute I wish existed ----------^^^^^^^^^^^^^^^^^
        void user(Context *c, const QString &userId);
    
        C_ATTR(changePassword, :Chained("user") :PathPart("changePassword") :CaptureArgs(1) :ActionClass(REST))
        void ChangePassword(Context *c);
    

    What is the way to achieve what I need? Does it involve playing with the Dispatcher classes, or is there an easier (and better) way?

    opened by mardy 6
  • Using the Session class in a REST application

    Using the Session class in a REST application

    Hi, I'm developing a server which should offer a REST API, most of which should be available only after the user has been authenticated. I was playing with the idea of using the Session class to store the authentication info, like this:

    1. When the user authenticates, I would repeatedly call Session::setValue() to store the information about the authenticated user (like his ID)
    2. Return the Session::id() to the client, аs an authentication token
    3. In the following calls, the client will set the ID we returned in the X-Authentication-Token header
    4. I read the token in the server from the header and set it as the session ID for the context, so that the proper session data gets loaded

    I'm not sure about point 4, because looking at the API I cannot find an obvious way to achieve what I need. Looking at the source code, it would appear that I could do something like:

    c->setStash("_c_session_id", authenticationToken);
    QString userId = Session::value(c, "userId");
    // ...and get any other useful info from the session...
    

    But indeed, the _c_session_id is a string defined in the cpp file, which is supposed to be private. So, I guess there must be some better way to achieve my goal, but I cannot find the right API for it. Any hints? :-)

    opened by mardy 1
Releases(v3.7.0)
Owner
Cutelyst
Cutelyst an elegant C++/Qt Web Framework
Cutelyst
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
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 Dec 22, 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 Dec 31, 2022
Crow is very fast and easy to use C++ micro web framework (inspired by Python Flask)

Crow is C++ microframework for web. (inspired by Python Flask) #include "crow.h" int main() { crow::SimpleApp app; CROW_ROUTE(app, "/")([]()

Jaeseung Ha 7k Jan 8, 2023
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 8.5k Dec 31, 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.7k Dec 29, 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é 249 Dec 22, 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
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 375 Dec 25, 2022
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 Dec 17, 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.3k Jan 8, 2023
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 696 Dec 28, 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 43 Nov 6, 2022
The C++ REST SDK is a Microsoft project for cloud-based client-server communication in native code using a modern asynchronous C++ API design. This project aims to help C++ developers connect to and interact with services.

Welcome! The C++ REST SDK is a Microsoft project for cloud-based client-server communication in native code using a modern asynchronous C++ API design

Microsoft 7.2k Jan 8, 2023
Query C++ codebases using SQLite

ClangQL: query C++ codebases using SQLite and clangd What is it? ClangQL is a proof-of-concept SQLite extension for querying C++ codebases that have b

Francesco Bertolaccini 151 Nov 18, 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.8k Jan 7, 2023
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 950 Dec 24, 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