Drogon: A C++14/17 based HTTP web application framework running on Linux/macOS/Unix/Windows

Overview

Build Status Build Status Build status Total alerts Join the chat at https://gitter.im/drogon-web/community Docker image

English | 简体中文 | 繁體中文

Overview

Drogon is a C++14/17-based HTTP application framework. Drogon can be used to easily build various types of web application server programs using C++. Drogon is the name of a dragon in the American TV series "Game of Thrones" that I really like.

Drogon is a cross-platform framework, It supports Linux, macOS, FreeBSD, OpenBSD, and Windows. Its main features are as follows:

  • Use a non-blocking I/O network lib based on epoll (kqueue under macOS/FreeBSD) to provide high-concurrency, high-performance network IO, please visit the TFB Tests Results for more details;
  • Provide a completely asynchronous programming mode;
  • Support Http1.0/1.1 (server side and client side);
  • Based on template, a simple reflection mechanism is implemented to completely decouple the main program framework, controllers and views.
  • Support cookies and built-in sessions;
  • Support back-end rendering, the controller generates the data to the view to generate the Html page. Views are described by CSP template files, C++ codes are embedded into Html pages through CSP tags. And the drogon command-line tool automatically generates the C++ code files for compilation;
  • Support view page dynamic loading (dynamic compilation and loading at runtime);
  • Provide a convenient and flexible routing solution from the path to the controller handler;
  • Support filter chains to facilitate the execution of unified logic (such as login verification, Http Method constraint verification, etc.) before handling HTTP requests;
  • Support https (based on OpenSSL);
  • Support WebSocket (server side and client side);
  • Support JSON format request and response, very friendly to the Restful API application development;
  • Support file download and upload;
  • Support gzip, brotli compression transmission;
  • Support pipelining;
  • Provide a lightweight command line tool, drogon_ctl, to simplify the creation of various classes in Drogon and the generation of view code;
  • Support non-blocking I/O based asynchronously reading and writing database (PostgreSQL and MySQL(MariaDB) database);
  • Support asynchronously reading and writing sqlite3 database based on thread pool;
  • Support ARM Architecture;
  • Provide a convenient lightweight ORM implementation that supports for regular object-to-database bidirectional mapping;
  • Support plugins which can be installed by the configuration file at load time;
  • Support AOP with build-in joinpoints.
  • Support C++ coroutines

A very simple example

Unlike most C++ frameworks, the main program of the drogon application can be kept clean and simple. Drogon uses a few tricks to decouple controllers from the main program. The routing settings of controllers can be done through macros or configuration file.

Below is the main program of a typical drogon application:

#include <drogon/drogon.h>
using namespace drogon;
int main()
{
    app().setLogPath("./")
         .setLogLevel(trantor::Logger::kWarn)
         .addListener("0.0.0.0", 80)
         .setThreadNum(16)
         .enableRunAsDaemon()
         .run();
}

It can be further simplified by using configuration file as follows:

#include <drogon/drogon.h>
using namespace drogon;
int main()
{
    app().loadConfigFile("./config.json").run();
}

Drogon provides some interfaces for adding controller logic directly in the main() function, for example, user can register a handler like this in Drogon:

app().registerHandler("/test?username={name}",
                    [](const HttpRequestPtr& req,
                       std::function<void (const HttpResponsePtr &)> &&callback,
                       const std::string &name)
                    {
                        Json::Value json;
                        json["result"]="ok";
                        json["message"]=std::string("hello,")+name;
                        auto resp=HttpResponse::newHttpJsonResponse(json);
                        callback(resp);
                    },
                    {Get,"LoginFilter"});

While such interfaces look intuitive, they are not suitable for complex business logic scenarios. Assuming there are tens or even hundreds of handlers that need to be registered in the framework, isn't it a better practice to implement them separately in their respective classes? So unless your logic is very simple, we don't recommend using above interfaces. Instead, we can create an HttpSimpleController as follows:

/// The TestCtrl.h file
#pragma once
#include <drogon/HttpSimpleController.h>
using namespace drogon;
class TestCtrl:public drogon::HttpSimpleController<TestCtrl>
{
public:
    virtual void asyncHandleHttpRequest(const HttpRequestPtr& req, std::function<void (const HttpResponsePtr &)> &&callback) override;
    PATH_LIST_BEGIN
    PATH_ADD("/test",Get);
    PATH_LIST_END
};

/// The TestCtrl.cc file
#include "TestCtrl.h"
void TestCtrl::asyncHandleHttpRequest(const HttpRequestPtr& req,
                                      std::function<void (const HttpResponsePtr &)> &&callback)
{
    //write your application logic here
    auto resp = HttpResponse::newHttpResponse();
    resp->setBody("<p>Hello, world!</p>");
    resp->setExpiredTime(0);
    callback(resp);
}

Most of the above programs can be automatically generated by the command line tool drogon_ctl provided by drogon (The command is drogon_ctl create controller TestCtrl). All the user needs to do is add their own business logic. In the example, the controller returns a Hello, world! string when the client accesses the http://ip/test URL.

For JSON format response, we create the controller as follows:

/// The header file
#pragma once
#include <drogon/HttpSimpleController.h>
using namespace drogon;
class JsonCtrl : public drogon::HttpSimpleController<JsonCtrl>
{
  public:
    virtual void asyncHandleHttpRequest(const HttpRequestPtr &req, std::function<void(const HttpResponsePtr &)> &&callback) override;
    PATH_LIST_BEGIN
    //list path definitions here;
    PATH_ADD("/json", Get);
    PATH_LIST_END
};

/// The source file
#include "JsonCtrl.h"
void JsonCtrl::asyncHandleHttpRequest(const HttpRequestPtr &req,
                                      std::function<void(const HttpResponsePtr &)> &&callback)
{
    Json::Value ret;
    ret["message"] = "Hello, World!";
    auto resp = HttpResponse::newHttpJsonResponse(ret);
    callback(resp);
}

Let's go a step further and create a demo RESTful API with the HttpController class, as shown below (Omit the source file):

/// The header file
#pragma once
#include <drogon/HttpController.h>
using namespace drogon;
namespace api
{
namespace v1
{
class User : public drogon::HttpController<User>
{
  public:
    METHOD_LIST_BEGIN
    //use METHOD_ADD to add your custom processing function here;
    METHOD_ADD(User::getInfo, "/{id}", Get);                  //path is /api/v1/User/{arg1}
    METHOD_ADD(User::getDetailInfo, "/{id}/detailinfo", Get);  //path is /api/v1/User/{arg1}/detailinfo
    METHOD_ADD(User::newUser, "/{name}", Post);                 //path is /api/v1/User/{arg1}
    METHOD_LIST_END
    //your declaration of processing function maybe like this:
    void getInfo(const HttpRequestPtr &req, std::function<void(const HttpResponsePtr &)> &&callback, int userId) const;
    void getDetailInfo(const HttpRequestPtr &req, std::function<void(const HttpResponsePtr &)> &&callback, int userId) const;
    void newUser(const HttpRequestPtr &req, std::function<void(const HttpResponsePtr &)> &&callback, std::string &&userName);
  public:
    User()
    {
        LOG_DEBUG << "User constructor!";
    }
};
} // namespace v1
} // namespace api

As you can see, users can use the HttpController to map paths and parameters at the same time. This is a very convenient way to create a RESTful API application.

In addition, you can also find that all handler interfaces are in asynchronous mode, where the response is returned by a callback object. This design is for performance reasons because in asynchronous mode the drogon application can handle a large number of concurrent requests with a small number of threads.

After compiling all of the above source files, we get a very simple web application. This is a good start. For more information, please visit the wiki or DocsForge

Contributions

Every contribution is welcome. Please refer to the contribution guidelines for more information.

Issues
  • MariaDB connection issue

    MariaDB connection issue

    Describe the bug Fail on the connection to MariaDB when testing the model create ctl. Copied the default model.json into a folder named /models/testModel and run the following command.

    drogon_ctl create model testModel
    
    Create model
    mysql
    Connect to server...
    Source files in the eshop folder will be overwritten, continue(y/n)?
    20200202 17:04:55.725077 UTC 3864 ERROR Failed to mysql_real_connect() - MysqlConnection.cc:229
    20200202 17:04:56.725637 UTC 3864 ERROR Failed to mysql_real_connect() - MysqlConnection.cc:229
    20200202 17:04:57.725777 UTC 3864 ERROR Failed to mysql_real_connect() - MysqlConnection.cc:229
    ...
    

    The database is running which I can use PhpMyAdmin to access it. Created a database name "cppwebserver" and some other credentials for testing. I tried different ports (failed) and thought there was a bug in the model.json ( "passwd" to "password" ) still failed.

    Capture

    BTW, THANKS for the good works to the C++ community. I would like to take deeper understanding on this web-framework and compare with the Cutelyst and Wt. Are there some examples for the ORM part? Say, using the default model in the model.json.

    To Reproduce Steps to reproduce the behavior:

    1. Go to '/models' directory
    2. mkdir testModel && cp model.json testModel/
    3. edit the parameters "rdbms": mysql, "port":3306, "host":"127.0.0.1", "dbname":"cppwebserver".......
    4. drogon_ctl create model testModel and see error

    Expected behavior ERROR Failed to mysql_real_connect() - MysqlConnection.cc:229 Desktop (please complete the following information):

    • OS: Linux
    opened by ihmc3jn09hk 36
  • Put generated views in a namespace to avoid name conflicts

    Put generated views in a namespace to avoid name conflicts

    Describe the bug Using the same name of a view in the global namespace cause conflicts.

    To Reproduce

    1. Create a view search.csp named "search"
    2. Create a controller named "search" (in the global namespace)
    3. Controller will be ignored

    It could be useful to be able to choose in wich namespace the views will be generated.

    enhancement 
    opened by arkena00 28
  • Question: how to use the resolver class

    Question: how to use the resolver class

    Hi everyone, I need to resolve smtp.gmail.com to an ip, I'd like to use the mail plugin which only accept ip.

    //Send an email
    auto *smtpmailPtr = app().getPlugin<SMTPMail>();
    auto id = smtpmailPtr->sendEmail(
             "127.0.0.1",                  //The server IP, dns not support by drogon tcp-socket at the moment
             587,                          //The port
             "[email protected]",       //Who send the email
             "[email protected]",    //Send to whom
             "Testing SMTPMail Function",  //Email Subject/Title
             "Hello from drogon plugin",   //Content
             "[email protected]",       //Login user
             "123456"                      //User password
             );
    

    in the readme it says dns not supported by drogon tcp-socket, but I see in trantor the Resolver.h and in the inner folder more of Resolver. I've tried

                            auto callbackPtr = std::make_shared<
                                std::function<void(const HttpResponsePtr &)>>(
                                std::move(callback));
                            auto &loopApp = trantor::EventLoop(app().getLoop(10));
    
                            std::shared_ptr<trantor::Resolver> resolvePtr =
                                trantor::Resolver::newResolver(*loopApp, 600);
                            auto resolve = resolvePtr.resolve(
                                "smpt.gmail.com",
                                [data,
                                 callbackPtr](const trantor::InetAddress &addr) {
                                    LOG_DEBUG << "****IIII " << addr.toIpPort();
                                });
    

    but with no success. I'm new to c++ grammar, btw I would thank you for this great project, much appreciated work.

    question 
    opened by seiichi-yoshimune 22
  • Async transaction execution failure

    Async transaction execution failure

    Describe the bug With DbFastClient, apply query with newTransactionAsync() keeps reporting error.

    To Reproduce

    ...
      const uint64_t id = 1;
      const ushort age = 16;
      auto clientPtr = drogon::app().getFastDbClient("FOO");
    
      clientPtr->newTransactionAsync([id=std::move(id),age=std::move(age)](const std::shared_ptr<Transaction> &transPtr) {
          assert(transPtr);
          transPtr->execSqlAsync( "select * from foo where id=$1",
            [=](const Result &r) {
                if ( 0 < r.size() )
                {
                    *transPtr << "update foo set age=$1 where id=$2"
                              << age          //Does it required to be std::string ?
                              << r[0]["id"].as<uint64_t>()
                              >> [](const Result &r)
                                 {
                                    LOG_INFO << "Updated!";
                                    //... do something about the task;
                                 }
                              >> [](const DrogonDbException &e)
                                 {
                                    LOG_ERROR << "err:" << e.base().what();
                                 };
                }
                else
                {
                    LOG_ERROR << "No new tasks found!";
                }
            },
            [](const DrogonDbException &e) {
                LOG_ERROR << "err:" << e.base().what();
            },
          id);   //Does it required to be std::string ?
        });
    
      return;
    ...
    

    Sometimes crashes but always returns the following

    20200313 04:24:41.332853 UTC 16597 ERROR error - MysqlConnection.cc:427
    20200313 04:24:41.332891 UTC 16597 ERROR Error(0) [00000] "" - MysqlConnection.cc:443
    20200313 04:24:41.349522 UTC 16597 ERROR Error occurred in transaction begin - TransactionImpl.cc:287
    20200313 04:24:41.349666 UTC 16597 ERROR err:The transaction has been rolled back - api_v0_foo.cc:163
    
    

    and sometimes with these

    20200313 04:35:36.383567 UTC 16676 ERROR error:1 status:1 - MysqlConnection.cc:258
    20200313 04:35:36.383629 UTC 16676 ERROR Error(1054) [42S22] "Unknown column '$1' in 'where clause'" - MysqlConnection.cc:443
    20200313 04:35:36.414844 UTC 16676 ERROR err:Unknown column '$1' in 'where clause' - api_v0_foo.cc:163
    20200313 04:35:36.415163 UTC 16676 DEBUG [operator()] Transaction roll back! - TransactionImpl.cc:159
    
    

    Expected behavior The record with id=1 in foo, the age field set to 16.

    Additional context Am I misunderstand the usage? Actually, I was trying to reference your example with the for update but failed with blocking call with newTransaction(). Then, I amended it with newTransactionAsync() but failed again even with the for update removed.

    opened by ihmc3jn09hk 20
  • Cannot capture returned value of second sql query in transaction

    Cannot capture returned value of second sql query in transaction

    Consider following code:

    auto clientPtr = drogon::app().getFastDbClient("default");
            clientPtr->newTransactionAsync([=, this](const std::shared_ptr<Transaction> &transPtr) mutable {
                assert(transPtr);
    
                transPtr->execSqlAsync(
                    "select t.id, t.visible, t.title, t.created_at , t.posted_by, t.updated_at, t.votes, t.slug, "
                    "users.username, users.id as uid, array_agg(topic_tags.tag_id) as tag_id, array_agg(tags.name) as tags from topics t left "
                    "join users on t.posted_by=users.id left join topic_tags on topic_tags.topic_id=t.id left join "
                    "tags on topic_tags.tag_id = tags.id where t.op_id=0 group by t.id, users.id order by "
                    "t.updated_at limit $1 offset $2",
                    [=, this](const Result &rows) mutable {
                        if (rows.size() == 0)
                        {
                            return;
                        }
                        else
                        {
                            ret["topics"] = Json::arrayValue;
                            for (auto &r : rows)
                            {
                                Json::Value topic;
                                std::string answers;
    
                                topic["id"] = r["id"].as<std::string>();
                                topic["visible"] = r["visible"].as<bool>();
                                topic["title"] = r["title"].as<std::string>();
                                topic["created_at"] = r["created_at"].as<std::string>();
                                topic["updated_at"] = r["updated_at"].as<std::string>();
                                topic["votes"] = r["votes"].as<std::string>();
                                topic["slug"] = r["slug"].as<std::string>();
                                topic["username"] = r["username"].as<std::string>();
                                topic["uid"] = r["uid"].as<std::string>();
                                topic["tid"] = r["tag_id"].as<std::string>();
                                topic["tags"] = r["tags"].as<std::string>();
                                transPtr->execSqlAsync(
                                    "select count(1) from topics where op_id is not null and op_id=$1",
                                    [=, &answers](const Result &rows1) mutable {
                                        for (auto &r1 : rows1)
                                        {
                                            answers = r1["count"].as<std::string>();
                                            // topic["answers"] = r1["count"].as<std::string>();
                                            // ret["topics"].append(topic);
                                        }
                                    },
                                    [=](const DrogonDbException &e) mutable {
                                        LOG_DEBUG << e.base().what();
                                        ret["error"] = (std::string)e.base().what();
                                        callback(HttpResponse::newHttpJsonResponse(std::move(ret)));
                                    },
                                    r["id"].as<int64_t>());
                                LOG_DEBUG << answers;
                                ret["topics"].append(topic);
                            }
                        }
    
                        callback(jsonResponse(std::move(ret)));
                        return;
                    },
                    [=](const DrogonDbException &e) mutable {
                        LOG_DEBUG << e.base().what();
                        ret["error"] = (std::string)e.base().what();
                        callback(HttpResponse::newHttpJsonResponse(std::move(ret)));
                    },
                    (long)limit, (long)limit * (page_no - 1));
            });
    

    The string answers is still empty after the second sql query.

    opened by shivshankardayal 18
  • Should Drogon have built-in cryptographic functions?

    Should Drogon have built-in cryptographic functions?

    Happy new year!

    #646 suggested to add security guidelines. I think that's a great idea. Especially if we could make Drogon secure by default. As of now. Drogon currently doesn't come with "security features" per se. Contrast to PHP have a built-in password_hash.

    I've password hashing/verification and secure number/string generation upstream-able in my webapp. But I'm not sure if it should be upstreamed. They pull in extra dependencies that the core framework don't need and is trivial to write. And languages like Go and Rust asks user to pull in their own library.

    I guess the question is:

    • Should Drogon provide cryptographic functions? Or is it the user's job?
    • How much security could we provide without extra dependencies?
    • If yes, To what extent should Drogon assist users?
      • I don't expect drogon to support full-on SRP and GPG. That's bloat.
      • In the mean while, I want to avoid users storing password in the database.

    What are your thoughts? Thanks.

    opened by marty1885 18
  • Allow thread to process other requests when waiting for asyncrinous HTTP requests

    Allow thread to process other requests when waiting for asyncrinous HTTP requests

    Hi, this issue is mostly related to the maximum throughput of an application. Currently Drogon have to wait if it makes a HTTP request inside a request handler. This may be a performance bottleneck when the request takes a while to response (ex: to a server across the globe, long RTT, etc...). It would be nice to be able to process other other requests while we're waiting for response.

    Now, sending requests within a handler looks like so

    app().registerHandler("/foo",[](const HttpRequestPtr& req, auto &&callback) {
    	// some API things
    	auto client = HttpClient::newHttpClient("http://my.api.endpoint.com");
    	auto req = HttpRequest::newHttpRequest();
    	std::promise<bool> valid;
    	req->setPath("/do_something");
    	client->sendRequest(req, [&](ReqResult result, const HttpResponsePtr &response) {
    		if(response == nullptr) // If no server responce
    			valid.set_value(false);
    		valid.set_value(true);
    	});
    	bool api_ok = valid.get_future().get(); // Wait for HTTP to response. Have to wait here otherwise crash the entire application
    	if(api_ok == false)
    		api_failed();
    	
    	// Keep doing our stuff
    });
    

    It would be great to do something like this.

    client->sendRequest(validation_req, [&](ReqResult result, const HttpResponsePtr &response) {
    	...});
    drogon::handleOtherRequest(valid); // Do other stuff until `valid` have been set. Don't waist time waiting
    

    Alternatively, it would be great to let HttpClient::sendRequest itself to do everything. So HttpClient::sendRequest looks to be a blocking call from the caller's perspective but in reality it only returns when it got an response or timeouts (and handle other requests in the mean time).

    bool api_ok = false;
    client->sendRequestSync(req, ...); // This looks like a blocking call from the caller
    // Since sendRequestSync only rerun when it have a response. The control flow is a lot easier
    if(api_ok == false)
    	api_failed();
    

    Thanks

    opened by marty1885 17
  • Database queries not being executed

    Database queries not being executed

    Describe the bug I came back after 2 weeks to continue on the project and suddenly all the database queries no more work. They stall infinitely eventually timing out the client. And this is not specific to one URL, this happens in all URLs.

    To Reproduce My team mate can't reproduce this. Its only happening with me.

    Desktop (please complete the following information):

    • OS: Debian 10 with Linux kernel 4.19

    Additional context Here is a small snippet of one of the HTTP handlers:

    void Posts::getPost(const HttpRequestPtr &req, Callback callback) {
    	LOG_DEBUG << "Get post";
    	Json::Value ret;
    	
    	auto clientPtr = app().getFastDbClient("default");
    	LOG_DEBUG << clientPtr->connectionInfo();
    	LOG_DEBUG << clientPtr->hasAvailableConnections();
    	LOG_DEBUG << "Got DB client";
    	clientPtr->execSqlAsync(
    	    "select * from topics where id = $1",
    		[=] (const Result &r) mutable {
    			LOG_DEBUG << "Debug got database result";
                            // do stuff
    			callback(jsonResponse(std::move(ret)));
    		},
    		[=](const DrogonDbException &e) {
                            LOG_DEBUG << e.base().what();
                    },
    	);
    
    	LOG_DEBUG << "Testing";
    }
    

    The output logs are:

    20210213 13:15:01.580010 UTC 13304 DEBUG [getPost] Get post - posts.cc:139
    20210213 13:15:01.580108 UTC 13304 DEBUG [getPost]  - posts.cc:143
    20210213 13:15:01.580120 UTC 13304 DEBUG [getPost] 0 - posts.cc:144
    20210213 13:15:01.580124 UTC 13304 DEBUG [getPost] Got DB client - posts.cc:145
    20210213 13:15:01.580166 UTC 13304 DEBUG [getPost] Testing - posts.cc:188
    

    Important observation is hasAvailableConnections is returning false.

    Here is my config.json:

    {
        "listeners": [
            {
                "address": "0.0.0.0",
                "port": 8000,
                "https": false
            }
        ],
        "app": {
            "threads_num": 0,
            "document_root": "./"
        },
        "db_clients": [
            {
                "rdbms": "postgresql",
                "host": "127.0.0.1",
                "port": 5432,
                "dbname": "database",
                "user": "user",
                "passwd": "password",
                "is_fast": true
            }
        ]
    }
    
    opened by HemilTheRebel 16
  • Add exports macro to allow Shared Library with hidden symbols by default (e.g. Windows)

    Add exports macro to allow Shared Library with hidden symbols by default (e.g. Windows)

    If you build drogon as a shared library with CMAKE_CXX_VISIBILITY_PRESET set to hidden and CMAKE_VISIBILITY_INLINES_HIDDEN to 1 all the symbols are hidden, thus linking a project with the drogon shared library will fail.

    On Windows, the symbols are hidden by default and you need to export them explicitely.

    This PR enable building trantor as a shared library on Windows.

    An abort() is raised when closing the project, I need to check if it is related to my work or not. In the meantime, I am interested in your feedback.

    This is Work In Progress as it points to my fork of trantor. I will update when https://github.com/an-tao/trantor/pull/127 is merged

    opened by BertrandD 16
  • Cannot stop WebsocketClient from trying to reconnect to a non-existent server

    Cannot stop WebsocketClient from trying to reconnect to a non-existent server

    I've implemented a WebSocketClient that tries to connect to a (non-existent) server using wsClient->connectToServer(). The callback I provided is repeatedly called with a NetworkFailure error. Digging deeper into the Drogon implementation I ran across this code.

    In WebSocketClientImpl.cc around line 75 I see this:

    tcpClientPtr_->setConnectionErrorCallback([weakPtr]() {
            auto thisPtr = weakPtr.lock();
            if (!thisPtr)
                return;
            // can't connect to server
            thisPtr->requestCallback_(ReqResult::NetworkFailure, nullptr, thisPtr);
            thisPtr->loop_->runAfter(1.0, [thisPtr]() { thisPtr->reconnect(); });
        });
    

    So it appears that after reporting a NetworkFailure it repeatedly schedules a function at a 1 second interval to re-connect. This repeats forever and I cannot figure out a way to control this behavior from my code. I'd like to disable this "auto-reconnect" behavior or at least set the number of re-connect attempts it will make. Can you suggest a way to stop the re-connect behavior and if that is not currently possible, add an option to control this feature?

    Thanks . . .

    enhancement 
    opened by gschmottlach-xse 15
Releases(v1.7.3)
  • v1.7.3(Oct 17, 2021)

    API Change List

    • Support sending files by range

    • Allow outside access to the file path of an HTTP response

    • Support custom MIME types and extensions

    • Add the getOptionalParameter method

    • Add async_run

    Changes

    • Experimental HaikuOS Support

    • Improve AccessLogger

    • Add Alpine Dockerfile

    • Add option to disable brotli if desired by the builder

    Fixed

    • Fix a bug in the getIOLoop method

    • Return on redis connection errors

    • Fix(MutliPart): Does not respect quotes in Content-Disposition header

    • Fix(cmake): error in FindFilesystem

    • Fix(style): Change the NotFound page text color

    • Fix a race condition in testing

    Source code(tar.gz)
    Source code(zip)
  • v1.7.2(Aug 24, 2021)

    @an-tao Is busy so I'm making the release in place of him.

    API Change List

    • Add port() and host() to HttpClient

    • Add stop() method to the WebSocketClient class

    Changes

    • Enables higher level of warnings when building on UNIX with GCC

    • Generic optimizations

    • Add redis example

    • Added support for paths containing unicode characters on Windows

    • Load ParseAndAddDrogonTests in DrogonConfig

    • Add BUILD_DOC to cmake options

    • Add websocket server example

    • CMake: Add CPack for .deb and .rpm package generation

    • cmake: Use GNUInstallDirs to figure out install dirs.

    Fixed

    • Fix WS client example not working with integration_test

    • Fix WS client example error when encountering bad IP addresses

    • CacheFile supports >2GB files on 64-bit Windows

    • drogon_ctl now emits error on failing to create view from CSP

    • Added the make program to Ubuntu docker environment

    • Correctly check the case-insensitive value of the upgrade header of responses in websocket connections

    • Fix incorrect MD5 hash when using internal MD5 implementation when input size == block size+1

    • Fix test success message incorrectly shown for a failed test when -s is flag present

    • Force using boost::filesystem when building for Android

    • Escape connection string in drogon_ctl create model

    • Fix some memory leak and race conditions in WebSocketClient

    Source code(tar.gz)
    Source code(zip)
  • v1.7.1(Jun 24, 2021)

    Changes

    • Updated Dockerfile to Ubuntu 20.04 & Fixed Timezone Hangup.

    • Add jsonstore example.

    • Fix some typos.

    Fixed

    • Fix single layer directory traversal in StaticFileRouter.
    Source code(tar.gz)
    Source code(zip)
  • v1.7.0(Jun 18, 2021)

    API changes list

    • Add the PreSendingAdvice to AOP.

    • Make Json::Value as a SQL parameters type.

    • Add the int type for the Row index parameter.

    • Add SSL_CONF_cmd support.

    • Add the setCustomStatusCode method.

    Changes

    • Fix sync_wait/co_future use-after-free.

    • Add the AccessLogger plugin.

    • Make AsyncTask only destruct when the coroutine reaches end of executions.

    • Add Drogon test framework.

    • Improve WebSocket mask handling.

    • Add minimal server side examples.

    • Optimize HttpControllersRouter for cases where regex is not needed.

    • Create controller instances after running instead of after being called.

    Fixed

    • Move resolverPtr when destroying an HttpClientImpl object.

    • Modify the way to create sqlite3 client.

    • Fix a bug when a network failure occurs on Redis connections.

    • Fix a bug of string_view for MSVC.

    • Fix 'build.sh -tshared'.

    • Fix compiler warnings.

    • Fix CacheMap crash in CI tests.

    Source code(tar.gz)
    Source code(zip)
  • v1.6.0(May 15, 2021)

    API changes list

    • Add option to set default handler.

    • Add the setTimeout() method to the DbClient class and the RedisClient class.

    • Add the validateCert parameter to the newWebSocketClient method.

    Changed

    • A few mini changes to drogon_ctl command.

    • Improve the MultiPartParser class.

    • Add GNU -Werror & fix warnings.

    • Enhancements on files part.

    • Add version/soversion to shared library.

    • Disallow coroutines to be resolved as plain subroutine handlers.

    • Send the content-length header even if the body(POST,PUT,OPTIONS,PATCH) is empty.

    • Use make_exception_ptr instead of throw/catch when possible.

    • Remove duplicated inclusion.

    • Print error before terminating in AsyncTask.

    • Allow users to override drogon Find modules.

    • Use two-phase construction for the DbClientImpl and the RedisClientImpl.

    • Add support 'select ' for redis.

    Fixed

    • Fix a bug of the Transaction class.

    • Copy CoroMapper.h to installation location.

    • Remove the related request from the buffer if it's not sent after the timeout.

    • Fix ORM with SQLite3 not compiling on Arch Linux.

    • Fix an error when constructing RedisClientImpl objects.

    • Fix coroutine frame leak upon assigning to awaitable.

    • Set running flag to true before installing plugins.

    • Fix double free in coroutine exception handling.

    Source code(tar.gz)
    Source code(zip)
  • v1.5.1(Apr 10, 2021)

  • v1.5.0(Apr 10, 2021)

    API changes list

    • Add option to disable signal handling.

    • Added newFileResponse Support for buffers in memory.

    • Add a method to HttpRequest to set the user_agent header.

    • Catch exceptions thrown by handlers.

    Changed

    • Add convert method to models.

    • Add Arch Dockerfile.

    • Add Redis support.

    • Print error and exit when IP parsing failed in server startup.

    • Use a canonical way of calling max() function on Windows.

    • Remove an assertion statement in the HttpClientImpl class.

    • Send ping messages by default for WebSockets.

    • Use canonical cmake logic for cross-compilation.

    • set make job count to the number of threads in GitHub Actions workflow.

    • Use lambda instead of std::bind in HttpServer.

    • Add exports macro to allow Shared Library with hidden symbols by default.

    • Remove repeated class names on relationships from the model generator.

    Fixed

    • Fix compile warnings in SQL client.

    • Fix compilation errors for the TimeFilter example.

    • Fix build.sh missing nproc error in build for macOS.

    • Fix a bug when creating sqlite3 models.

    • Fix two building corner cases, CMake quality of life improvements.

    • Add CoroMapper to models' friends.

    Source code(tar.gz)
    Source code(zip)
  • v1.4.1(Mar 7, 2021)

  • v1.4.0(Mar 6, 2021)

    API change list

    • Add coroutine support.

    • Add default value interface to SqlBinder for MySQL and PostgreSQL.

    • Support SNI in the HttpClient class.

    • Validate certificate in HttpClient.

    • HttpRequest: add a feature to avoid URL encoding of the path.

    Changed

    • Handle cross-compiling properly.

    • Lowercase all HTTP headers, add webp and avif types.

    • Modify FindMySQL.cmake

    Fixed

    • Fix an error in the HttpClient class when a response has no content-length.

    • Return 404 or 405 responses correctly.

    • Fix compilation errors on vs2019.

    • Fix stack use after scope error in client_example.

    • Fix the error when the SSL handshake fails.

    Note: an-tao is still the author. But marty1885 starts the draft and didn't expect it's his name.

    Source code(tar.gz)
    Source code(zip)
  • v1.3.0(Jan 17, 2021)

    API change list

    • Add an option for setting float precision in Json string.

    Fixed

    • Fix brotli link order.

    • Fix cmake with drogonctl cross-compilation.

    • sqlite3: Insert into stmtsMap_ as string_view.

    • Fix some bugs when creating models via drogon_ctl.

    • Fix an error in sqlite3 ORM generator.

    • Fix an error with missing composite key to sqlite3 ORM generator.

    Changed

    • Remove the use of std::filesystem to adapt to old compilers.

    • Add github actions.

    • Serve wasm files with the correct MIME type.

    Source code(tar.gz)
    Source code(zip)
  • v1.2.0(Dec 12, 2020)

    Fixed

    • Fix error when receiving response without content-length header.

    • Fix a stack-overflow error when high concurrency happening on sqlite3.

    • Fix MinGW ORM building by enabling htonll and ntohll.

    Changed

    • Modify the WebSocketTest controller to create a simple chat room.

    • Add support for OpenBSD.

    • Return 400 if the content-length is invalid.

    • Don't send content type in a 304 response.

    • Add the reuse_port option to app() interface.

    • Add the 'std::optional' support in the SqlBinder class and the Session class.

    • Add implicit page resolving capability.

    Source code(tar.gz)
    Source code(zip)
  • v1.1.0(Oct 31, 2020)

    Fixed

    • Fix failing to connect to DB if parameters contains spaces.

    • Fix a CMAKE bug when SHARED and EXAMPLES are on.

    • Fix the HttpServer::isWebSocket method.

    • Find mariadb client library correctly on Ubuntu 20.04.

    • Fix a bug when creating sqlite3 database models.

    • Fix a bug in the Mapper::insertFuture method.

    Changed

    • Disable TLS1.0/1.1 on HTTPS by default.

    • Use explicit lambda capture lists.

    • Modify the procedure of the app().run() method.

    • Support namespaces when creating view source files.

    • Add --path-to-namespace option to drogon_ctl for creating views.

    • Add the Host and Sec-WebSocket-Version headers when connecting to a websocket server.

    Source code(tar.gz)
    Source code(zip)
  • v1.0.0(Sep 27, 2020)

    Fixed

    • Fix an issue of simple_reverse_proxy when handling chunked transfer-encoding.

    • Fix a bug when losting connection to MySQL server during query.

    • Remove the expired std::iterator template.

    • Fix a bug when creating models in some special cases.

    API changes list

    • Modify methods related to headers.

    • Remove the expired std::iterator template.

    • Add getListeners() method to the HttpAppFramework class.

    • Remove the useless method stat() from the PluginBase class.

    • Add ConfigLoader::ConfigLoader(const Json::Value &data).

    Changed

    • Add support for status code 418.

    • Modify session handling.

    • Modify the FileUpload.csp in simple_example to avoid CORS.

    • remove execution permission on /tmp/drogon.lock.

    Source code(tar.gz)
    Source code(zip)
  • v1.0.0-beta21(Aug 19, 2020)

  • v1.0.0-beta20(Aug 15, 2020)

    API change list

    • Provide users with a method to change the session ID of a session.

    Changed

    • Modify parseContentType function.

    • Modify the docker file to build release version in docker.

    • Set session to requests for websockets.

    • Modify parseContentType function.

    • Change the return value type of the mktime() function in models.

    • Fix compilation warning of sprintf function.

    Fixed

    • Fix a bug when saving uploaded files on Windows.

    • Fix a mysql issue when connections are lost.

    • Resolve an issue when sending big files (>=2gB) on Windows.

    • Fix boost::string_view compilation error of MysqlConnection class.

    • Set the response Access-Control-Allow-Headers header correctly for CORS.

    • Fix a bug in drogon_ctl when creating a model, that causes to write source files multiple times.

    Source code(tar.gz)
    Source code(zip)
  • v1.0.0-beta19(Jul 16, 2020)

    API change list

    • Add a method to disable unicode escaping in json string.

    • Add a timeout parameter when sending HTTP requests.

    • Add the getJsonError method.

    Changed

    • Remove the restriction on the location of layout tags in views.

    • Add a way to set the character set when creating DbClient objects.

    • Make GET as the only method for accessing static files.

    • Modify the 404 pages generator.

    • Modify the DbClient class.

    • Optimize the HttpResponse class.

    Fixed

    • Properly handle chunked encoding requests.

    • Destroy DNS resolver of HttpClient in the correct thread.

    • Add the header to resolve build errors in VS2017.

    Source code(tar.gz)
    Source code(zip)
  • v1.0.0-beta18(Jun 14, 2020)

    API change list

    • Add a new joinpoint of AOP for modification on each HTTP response.

    • Add a method for the TERM signal handling.

    • Add getContextRef method to the WebSocketConnection class.

    Changed

    • Create a class template for publish subscribe pattern.

    • Add contribution recommendations.

    • Send a close message when closing a web socket connection.

    • Add additional formats for getHttpDate function.

    • Make app().run() method callable on a non-main thread.

    • Add digest filter in examples.

    • Use string_view to parse multipart/form-data requests.

    Fixed

    • Fix building of ORM on FreeBSD.

    • Fix a Mysql connection error on Windows.

    • Fix a bug in ListenerManager::getIOLoop().

    • Fix the count() method of Mysql ORM.

    • Fix a compilation issue on windows.

    • Fix model generation for PostgreSQL primary keys.

    • Fix a bug with quoted column names in sqlite3 databases.

    Source code(tar.gz)
    Source code(zip)
  • v1.0.0-beta17(May 22, 2020)

    API change list

    • Add methods to get DbClient connection status

    Changed

    • Add causal profiling with coz

    • Add filters on static file locations

    • Pass data from view to its layout container

    • Add additional HttpStatusCodes and implement a custom error handler

    • Modify drogon_ctl to show more compilation information

    Fixed

    • Fix a bug in drogon_ctl (when size of a line is larger than buffer size)

    • Fix a connection bug of mariadb clients

    Source code(tar.gz)
    Source code(zip)
  • v1.0.0-beta16(Apr 27, 2020)

    API change list

    • Standardize Row and Result api in ORM

    Changed

    • Add support for brotli compression

    • Parse content-type of HTTP requests

    • Remove non standard macros

    • Support url safe base64 codec

    Source code(tar.gz)
    Source code(zip)
  • v1.0.0-beta15(Mar 28, 2020)

    API change list

    • Modify the Attributes interface of the HttpRequest class

    • Add the getHomePage() method to HttpAppFramework

    Changed

    • Support br compression files

    • Update Content-Type support for PDF

    • Add support for MSVC 2015

    • Optimize the rendering of HTTP responses

    • Update the Dynamic Views Loading, add the layout tag

    • Graceful shutdown

    Fixed

    • Fix error when finding the jsoncpp library

    • Fix the 'many to many' relationship in ORM

    • Fix a bug when creating json responses

    • Fix a bug on filters with WebSocketControllers

    • Fix a fatal bug in the MysqlConnection class

    • Fix crash with partial matched url

    • Fix null jsonObject from newHttpJsonRequest

    Source code(tar.gz)
    Source code(zip)
  • v1.0.0-beta14(Feb 17, 2020)

    API change list

    • None

    Added

    • Add IOLoop access function

    Changed

    • Add support for regular expressions when routing

    • Add location configuration for static resources

    • Port drogon to Windows

    • Support 'password' keyword in configuration files

    • Remove get_version.sh

    • Modify dynamic view loading algorithm, add 'layout' tag for view generation.

    Fixed

    • Fix an issue of out-of-range (#334)

    • Fix a bug in views generation (#341)

    Source code(tar.gz)
    Source code(zip)
  • v1.0.0-beta13(Jan 4, 2020)

    API change list

    • None

    Changed

    • Add some unit tests (based on gtest)

    • Add a reverse proxy example

    • Make a patch to support the ossp UUID library

    • Make shared linking possible

    • Add the drogon::OStringStream class

    • Optimize ORM

    • Modify singleton logic of DrClassMap

    Fixed

    • Fix an error in the batch mode of libpq

    • Fix an error when clients use HTTP1.0

    Source code(tar.gz)
    Source code(zip)
  • v1.0.0-beta12(Nov 30, 2019)

    Changed

    • Make dg_ctl a symlink

    • Modify some code styles

    • Explicitly set path to '/' for JSESSIONID cookie

    • Handle gzip errors safely

    • Add the SecureSSLRedirector plugin

    Fixed

    • Fix a bug in dg_ctl for creating models of sqlite3

    • Reset the flag used to parse json to false before recycling HttpRequest objects

    Source code(tar.gz)
    Source code(zip)
  • v1.0.0-beta11(Nov 6, 2019)

  • v1.0.0-beta10(Nov 4, 2019)

    API change list

    • None

    Changed

    • Add the headers configuration option for static files

    Fixed

    • Fix(compilation on alpine): Replace u_short alias.
    Source code(tar.gz)
    Source code(zip)
  • v1.0.0-beta9(Oct 29, 2019)

    API change list

    • Add interfaces for accessing content of attachments.

    • Add option to disable setting the 404 status code of the custom 404 page.

    • Make user can use any string as a placeholder's name in routing patterns.

    • Add type conversion methods to the HttpRequest and HttpResponse classes.

    Changed

    • Modify cmake configuration.

    • Modify the quit() method.

    • Implement relationships in ORM.

    Fixed

    • Fix size_t underflow of drogon_ctl.

    • Fix some race conditions.

    • Fix a busy loop bug when connections to mysql server are timeout.

    Source code(tar.gz)
    Source code(zip)
  • v1.0.0-beta8(Oct 4, 2019)

    API change list

    • Add length() method to the Field class.

    • Add as<bool>() function template specialization to the Field class.

    • Add add attribute store methods to the HttpRequest class.

    • Add the setCustomContentTypeString() method to the HttpRequest class.

    • Add thread storage.

    Changed

    • Use .find('x') instead of .find("x") in a string search.

    • Add the ability to create restful API controllers.

    Fixed

    • Fix a bug of creating models for mysql.

    • Fix a bug when HTTP method is PUT.

    • Fix a bug when using 'is null' substatement in ORM.

    • Fix a sqlite3 bug when some SQL errors occur.

    • Fix bug with parsing json.

    • Fix url decode.

    • Fix a error in HttpClient.

    • Fix a error in setThreadNum method.

    • Fix some race conditions.

    Source code(tar.gz)
    Source code(zip)
  • v1.0.0-beta7(Aug 31, 2019)

    API change list

    • Remove the default value parameter of some methods (#220)

    Changed

    • Optimize DNS in HttpClient and WebSocketClient (support c-ares library).

    • Reduce dependencies between declarations.

    • Add database tests in the travis CI and add test cases to database tests.

    • Reduce size of docker image.

    • Make the framework API support chained calls.

    • Add a synchronous join point for AOP.

    • Modify the CMakeLists to modern cmake style.

    Fixed

    • Fix bugs in default return values of functions(#220),

    • Fix a bug in the cmake configuration file when there's '+' in the building path.

    • Fix a bug in drogon_ctl (when creating orm models)

    Source code(tar.gz)
    Source code(zip)
  • v1.0.0-beta6(Aug 8, 2019)

    API change list

    • None

    Changed

    • Modify the 'create view' sub-command of drogon_ctl

    • Optimize the transmission of pipelining responses.

    • Add the DrogonConfig.cmake file so that users can use drogon with the find_package(Drogon) command.

    Source code(tar.gz)
    Source code(zip)
  • v1.0.0-beta5(Aug 2, 2019)

    [1.0.0-beta5] - 2019-08-01

    API change list

    • None

    Added

    • Add two methods to control if the Server header or the Date header is sent to clients with HTTP responses.
      • void HttpAppFramework::enableServerHeader(bool);
      • void HttpAppFramework::enableDateHeader(bool);

    Changed

    • Support high performance batch mode of libpq.
    Source code(tar.gz)
    Source code(zip)
Owner
An Tao
Drogon QQ群: 1137909452
An Tao
🌱Light and powerful C++ web framework for highly scalable and resource-efficient web application. It's zero-dependency and easy-portable.

Oat++ News Hey, meet the new oatpp version 1.2.5! See the changelog for details. Check out the new oatpp ORM - read more here. Oat++ is a modern Web F

Oat++ 4.7k Dec 3, 2021
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 977 Nov 29, 2021
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.5k Dec 2, 2021
A http/websocket server framework on linux.

The framework is a Web-Server on unix based system. Without using any third-party libraries, the framework writes from unix system calls and standard C library functions.

xingyuuchen 12 Dec 7, 2021
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 721 Dec 7, 2021
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.8k Dec 2, 2021
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é 231 Nov 26, 2021
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 6.6k Dec 5, 2021
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
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 936 Nov 26, 2021
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
Embeddable Event-based Asynchronous Message/HTTP Server library for C/C++

libasyncd Embeddable Event-based Asynchronous Message/HTTP Server library for C/C++. What is libasyncd? Libasyncd is an embeddable event-driven asynch

Seungyoung 163 Nov 17, 2021
Experimental, scalable, high performance HTTP server

Lwan Web Server Lwan is a high-performance & scalable web server. The project web site contains more details. Build status OS Arch Release Debug Stati

Leandro A. F. Pereira 5.5k Dec 2, 2021
bittyhttp - A threaded HTTP library for building REST services in C.

bittyhttp - A threaded HTTP library for building REST services in C.

Colin Luoma 12 Nov 29, 2021
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 1.9k Nov 30, 2021
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 675 Nov 23, 2021
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 35 Sep 10, 2021
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.6k Nov 29, 2021