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.

Comments
  • 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
  • Can't connect to database (M1 MacOS)

    Can't connect to database (M1 MacOS)

    main.cpp

    #include <drogon/drogon.h>
    
    int main()
    {
      drogon::app().addListener("127.0.0.1", 8848);
      // Load config file
      // drogon::app().loadConfigFile("../config.json");
      drogon::app().createDbClient("mysql", "127.0.0.1", 3306, "database_test", "root", "******").run();
    
      return 0;
    }
    
    

    When I start the project, I get an unknown error. image

    drogon_ctl -v

    A utility for drogon
    Version: 1.7.5
    Git commit: f017b09947badc2e0516355358c8eb7843b44e19
    Compilation: 
      Compiler: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/c++
      Compiler ID: AppleClang
      Compilation flags: -std=c++17 -I/opt/homebrew/include -I/usr/local/include
    Libraries: 
      postgresql: no  (batch mode: no)
      mariadb: yes
      sqlite3: yes
      openssl: no
      brotli: no
      boost: no
      hiredis: yes
      c-ares: no
    

    brew ls

    ca-certificates	glew		hiredis		mariadb		msgpack		pcre2		ruby
    cmake		glfw		jsoncpp		mecab		[email protected]	readline	sqlite
    cocoapods	groonga		libyaml		mecab-ipadic	pcre		redis		zstd
    

    I can connect to MariaDB by DBeaver: image

    FAQ 
    opened by 1111mp 25
  • 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
  • Websocket not connected to server in native

    Websocket not connected to server in native

    #include <drogon/WebSocketClient.h>
    #include <drogon/WebSocketController.h>
    #include <drogon/HttpAppFramework.h>
    #include <trantor/net/EventLoopThread.h>
    
    #include <iostream>
    
    using namespace drogon;
    using namespace std::chrono_literals;
    
    class WebSocketTest : public drogon::WebSocketController<WebSocketTest> {
    public:
        virtual void handleNewMessage(const WebSocketConnectionPtr &,
                                      std::string &&,
                                      const WebSocketMessageType &) override;
    
        virtual void handleConnectionClosed(
                const WebSocketConnectionPtr &) override;
    
        virtual void handleNewConnection(const HttpRequestPtr &,
                                         const WebSocketConnectionPtr &) override;
    
        WS_PATH_LIST_BEGIN
        WS_PATH_ADD("/chat", "drogon::LocalHostFilter", Get);
        WS_PATH_LIST_END
    };
    
    
    void WebSocketTest::handleNewMessage(const WebSocketConnectionPtr &wsConnPtr,
                                         std::string &&message,
                                         const WebSocketMessageType &type) {
        // write your application logic here
        LOG_DEBUG << "new websocket message:" << message;
        if (type == WebSocketMessageType::Ping) {
            LOG_DEBUG << "recv a ping";
        }
    }
    
    void WebSocketTest::handleConnectionClosed(const WebSocketConnectionPtr &) {
        LOG_DEBUG << "websocket closed!";
    }
    
    void WebSocketTest::handleNewConnection(const HttpRequestPtr &,
                                            const WebSocketConnectionPtr &conn) {
        LOG_DEBUG << "new websocket connection!";
        conn->send("haha!!!");
    }
    
    
    int main(int argc, char *argv[]) {
    
        std::string host("0.0.0.0");
        int port(8848);
        app()
        .setLogLevel(trantor::Logger::kDebug)
        .addListener(host, port);
    
        auto wsPtr = WebSocketClient::newWebSocketClient(host, port);
        auto req = HttpRequest::newHttpRequest();
        req->setPath("/chat");
        wsPtr->setMessageHandler([](const std::string &message,
                                               const WebSocketClientPtr &wsPtr,
                                               const WebSocketMessageType &type) {
            std::cout << "new message:" << message << std::endl;
            if (type == WebSocketMessageType::Pong) {
                std::cout << "recv a pong" << std::endl;
            }
        });
        wsPtr->setConnectionClosedHandler([](const WebSocketClientPtr &wsPtr) {
            std::cout << "ws closed!" << std::endl;
        });
        wsPtr->connectToServer(req,
                               [](ReqResult r,
                                             const HttpResponsePtr &resp,
                                             const WebSocketClientPtr &wsPtr) {
                                   if (r == ReqResult::Ok) {
                                       std::cout << "ws connected!" << std::endl;
                                       wsPtr->getConnection()->setPingMessage("",
                                                                              2s);
                                       wsPtr->getConnection()->send("hello!");
                                   } else {
                                       std::cout << "ws failed!" << std::endl;
                                   }
                               });
        app().run();
    }
    

    Output:

    ws failed!
    

    But with:

    <!DOCTYPE html>
    <pre id="log"></pre>
    <script>
      // helper function: log message to screen
      function log(msg) {
        document.getElementById('log').textContent += msg + '\n';
      }
    
      // setup websocket with callbacks
      var ws = new WebSocket("ws://0.0.0.0:8848/chat");
      ws.onopen = function() {
        log('CONNECT');
        ws.send("hello!!!");
      };
      ws.onclose = function() {
        log('DISCONNECT');
      };
      ws.onmessage = function(event) {
        log('MESSAGE: ' + event.data);
        ws.send(event.data);
        ws.send(event.data);
      };
    </script>
    

    Works totaly fine;

    CONNECT
    MESSAGE: haha!!!
    

    Please explain this behavior.

    Regards.

    question 
    opened by SviatoslavKomkov 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
  • Even after installing hiredis, getting

    Even after installing hiredis, getting "Redis is not supported by Drogon...."

    Describe the bug Even after installing hiredis, getting "Redis is not supported by Drogon...."

    Expected behavior It should have worked properly

    Screenshots If applicable, add screenshots to help explain your problem.

    Desktop (please complete the following information):

    • OS: Kubuntu 22.04
    opened by MohammadArik 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
  • drogon project fail to build with mingw

    drogon project fail to build with mingw

    Describe the bug drogon项目使用mysys2编译失败。操作步骤如下:

    pacman -S mingw-w64-i686-gcc mingw-w64-i686-cmake make mingw-w64-i686-c-ares mingw-w64-i686-jsoncpp
    
    git clone https://github.com/drogonframework/drogon --recursive
    mkdir drogon/build
    cd drogon/build
    cmake .. -G "MSYS Makefiles"
    make -j
    

    错误提示如下:

    $ make -j
    C:/dev/drogon/trantor/trantor/net/EventLoop.cc:31:7: error: conflicting declaration 'using ssize_t = long long int'
       31 | using ssize_t = long long;
          |       ^~~~~~~
    In file included from D:/Program Files/msys64/mingw32/include/crtdefs.h:10,
                     from D:/Program Files/msys64/mingw32/include/stdint.h:28,
                     from D:/Program Files/msys64/mingw32/lib/gcc/i686-w64-mingw32/12.2.0/include/stdint.h:9,
                     from C:/dev/drogon/trantor/trantor/utils/Date.h:18,
                     from C:/dev/drogon/trantor/trantor/net/EventLoop.h:20,
                     from C:/dev/drogon/trantor/trantor/net/EventLoop.cc:18:
    D:/Program Files/msys64/mingw32/include/corecrt.h:47:13: note: previous declaration as 'typedef int ssize_t'
       47 | typedef int ssize_t;
          |             ^~~~~~~
    make[2]: *** [trantor/CMakeFiles/trantor.dir/build.make:202: trantor/CMakeFiles/trantor.dir/trantor/net/EventLoop.cc.obj] Error 1
    make[2]: *** Waiting for unfinished jobs....
    make[1]: *** [CMakeFiles/Makefile2:182: trantor/CMakeFiles/trantor.dir/all] Error 2
    make: *** [Makefile:156: all] Error 2
    

    直接用MinGW makefile 也报了同样的错误

    opened by Jalalidin 0
  • Open a WebSockets after Uploading a file

    Open a WebSockets after Uploading a file

    Description Attempting to open a WebSocket immediately after uploading a file using an XMLHttpRequest() cause a connection failure.

    To Reproduce Steps to reproduce the behavior:

    1. Create a WebPage that allow uploading as well as to create a websocket.
    2. upload a file using XMLHttpRequest()
    3. as soon as upload have been completed then create a WebSocket()
    4. See error connection fail.

    Expected behavior The connection will be completed sucessfully.

    Additional context Webserver have one single listener on port 8080 and different endpoints "/upload_endpoint" used for uploading files, "/output" used for the websockets and "/" that is the default.

    opened by fe-dagostino 3
  • Docsforge down

    Docsforge down

    The DocsForge documentation page is down. I've seen on the github page that the project has been discontinued. I also saw that the domain docsforge.com is for sale so I'm suspecting that this means that it's not going up anymore? The code is still available on github so maybe it's possible to host drogon.docsforge.com on the same server as drogon.org is?

    I realy liked the Docsforge documentation medium for Drogon and would like to see it (or an alternative) return.

    Thanks for creating Drogon!

    opened by rickiewars 0
  • createRedisClient  Error

    createRedisClient Error

    The following information is printed by the launcher console

    ERROR Error: (null) - RedisConnection.cc:45

    I'm not sure where the problem is. Has God ever encountered this problem

    opened by HoMiGT 0
  • Drogon HTTP server is limiting the number of concurrent requests

    Drogon HTTP server is limiting the number of concurrent requests

    Drogon HTTP server is limiting the number of concurrent requests being submitted to the handler. This is observed with all the recent versions of Drogon. I've tested with v1.8.0 and above.

    See this code to reproduce

    #include <chrono>
    #include <drogon/HttpController.h>
    
    class Handler : public drogon::HttpController<Handler> {
    public:
      METHOD_LIST_BEGIN
      ADD_METHOD_TO(Handler::longRuningFunc, "/api", drogon::Get);
      METHOD_LIST_END
    
      void longRuningFunc(
          const drogon::HttpRequestPtr &req,
          std::function<void(const drogon::HttpResponsePtr &)> &&cb) const {
        using namespace std::chrono_literals;
        std::cout << "Received request.. " << std::this_thread::get_id()
                  << std::endl;
        // simulate long running process
        std::this_thread::sleep_for(1s);
        auto res = drogon::HttpResponse::newHttpResponse();
        res->setContentTypeCode(drogon::ContentType::CT_APPLICATION_JSON);
        res->setStatusCode(drogon::HttpStatusCode::k200OK);
        res->setBody("");
        cb(res);
        std::cout << "..Responded" << std::this_thread::get_id() << std::endl;
      }
    };
    
    int main(int argc, char **argv) {
      drogon::app()
          .addListener("0.0.0.0", 8080)
          .setThreadNum(std::thread::hardware_concurrency() + 2)
          .setClientMaxBodySize(1 * 1024 * 1024 * 1024)
          .run();
    }
    

    Build using

    g++ -isystem /opt/dev-setup/drogon-1.8.2/include -isystem /usr/include/jsoncpp -O3 -DNDEBUG\
     -fdiagnostics-color=always -std=c++20 -pthread -std=c++20 -MD -MT -c ~/code/oss/drogon-sample/main.cpp \
     -o main /opt/dev-setup/drogon-1.8.2/lib/libdrogon.a -lm  -lsasl2  -ldl \
     /usr/lib/x86_64-linux-gnu/libz.so /opt/dev-setup/drogon-1.8.2/lib/libtrantor.a \
     /usr/lib/x86_64-linux-gnu/libssl.so /usr/lib/x86_64-linux-gnu/libcrypto.so \
     -lpthread /usr/lib/x86_64-linux-gnu/libjsoncpp.so /usr/lib/x86_64-linux-gnu/libuuid.so
    

    Test using

    wrk -d1s -t$(nproc) -c$(nproc) http://localhost:8080/api
    

    Expected behavior The expectation is all the requests from the client needs to be accepted at once, as the IO thread count is available to handle.

    Screenshots

    https://user-images.githubusercontent.com/471374/206050311-860e3e6a-1c6c-4850-a8ed-56718e2efd27.mp4

    The screen recording shows that wrk submits 16 concurrent requests, but Drogon handles only 12 at a time. This varies with every run. On a box with 96 cores, this gets even worse. Submitting 300 requests gets only 90 requests to the handler.

    Desktop (please complete the following information):

    • OS: Ubuntu 22.04 64 bit.
    opened by carun 16
Releases(v1.8.2)
  • v1.8.2(Nov 11, 2022)

    API changes list

    • Add the queueInLoopCoro function.

    • Avoid HashDoS attacks via random per-session hash initial state.

    Changed

    • Support the mediumint column when generate the mysql model.

    • Set Hiredis_FOUND to true when finding Hiredis library.

    • Add rate limiter.

    • Add some test cases for the sqlite datetime type.

    Fixed

    • Fix typo in drogon_test.h.

    • Fix a date race in drogon_test.

    • Fix a deadlock bug when closing all database connections.

    Source code(tar.gz)
    Source code(zip)
  • v1.8.1(Sep 25, 2022)

    API changes list

    • Support redis subscription.

    Changed

    • Remove redundant member functions of drogon::Task.

    • Small patches on orm_lib.

    • Add support for the string_view type to SqlBinder in orm.

    Fixed

    • Fix a conflict of ssize_t type with hiredis.

    • Fix a test bug when clients start before servers.

    • Fix model template file Unreachable code.

    • Use the mysql_library_end() function to avoid memory leaks.

    Source code(tar.gz)
    Source code(zip)
  • v1.8.0(Aug 31, 2022)

    API changes list

    • Add ‘not like‘ criteria.

    • Add HttpResponse::newStreamResponse().

    • Add the same site option for session cookie.

    • Add support for custom SQL query.

    Changed

    • Update issue templates.

    • Enable automatic reconnect in mysql.

    • Add typename for clang-14.

    • A workaround for redis sync exec.

    • Resolve redis server hostname from config file.

    • Add username option to redis databases.

    • Return nullptr if a plugin is not loaded when getting it.

    • Support controller registration in plugin.

    • Check mysql-optionsv support in cmake.

    • Check if host header is set before setting.

    • Clear all database connections before quitting.

    • Add namespace to views when using drogon_ctl.

    • Support pipeline mode on PostgreSQL 14+.

    • Add content type to multipart file upload.

    • Make orm::Result compatible with C++ STL container concepts.

    • Throw exceptions instead of exiting when loading configuration fails.

    • Rename BUILD_TRANTOR_SHARED to BUILD_SHARED_LIBS.

    • Support compressed request.

    • Prevent sending multiple responses for a single request.

    • Remove the virtual specifier from functions marked with override.

    • Remove redundancies from the CMake action.

    • Ensure requiring a semi-colon after macros.

    • Omit redundant virtual specifiers.

    • Refactor orm::SqlBinder.

    • Implement toJson to convert std::vector to Json::Value.

    • Resolve real ip from HttpRequest.

    • Delete the unmaintained test script.

    • Change the listener port of the cookie test.

    • Use a raw string literal for the drogon banner.

    • Change timeout of pipeline test for the CI environment.

    • Accept "postgres" for DbClient type as well.

    • Log remote real address in AccessLogger.

    • Support coroutine filter.

    • Refactor db_test.cc.

    • Use nullopt instead of the no-argument constructor.

    • Set the running flag to false after calling the quit() method.

    • Fix doc link in README files.

    Fixed

    • Fix XXXControllers created on MSVC even if specified not to do so.

    • To avoid accessing a null point, make sure result == OK before accessing the response ptr.

    • Fix a bug when stopping redis service.

    • Fix mutex lock missing.

    • Fix tolower with cfi sanitizer.

    • Add move constructor to fix clang-14 compile error.

    • Fix HttpClient dns cache.

    • Fix bug when resolving redis server hostname.

    • Reset timer afters relaunching on Linux.

    • Fix some configuration file issues.

    • Fix HttpFile unittest error on Windows.

    • Fix core dump causing by logging in destructor.

    • Fixing link error when linking with static c-ares.

    • Remove redundant resource release.

    • Install missing header file apply.h.

    • Fix deleteFutureByPrimaryKey compile fail.

    • Fix compilation failure without database support.

    • Fix Mapper::updateBy() async api.

    • Fix no BUILD_CTL with tests.

    • Fix some bugs in RedisClient.

    • Fix a misuse of std::move.

    • Fix a bug when creating models with composite keys in sqlite3.

    • Fix a bug when converting the content-length string to size_t.

    • Fix a bug when parsing multipart/form-data.

    • Export the getVersion method for Windows.

    • Add a pre-compilation macro in the pg pipeline test code.

    Source code(tar.gz)
    Source code(zip)
  • v1.7.5(Feb 19, 2022)

    API changes list

    • Add toString for drogon::ReqResult.

    • Add max-age, samesite options to Cookie.

    • Enable setup output of logs to files at any time.

    Changed

    • Use operator<< to convert ReqResult to string.

    • Remove sudo from build.sh.

    • Remove sudo from dependencies in Dockerfile.

    • Avoid attempt linking to std::fs when target does not exist.

    • Destroy fastdb client on quit.

    • Check HTTP client is not sending requests in sync mode on the same event loop.

    • Start listening after beginning advices.

    • Allow using json_cpp in other sublibraries.

    • Accept system lib for uuid on macOS.

    • Add Not In to ORM Criteria.

    Fixed

    • Fix WS test potentially can get stuck.

    • Fix a bug in model generation.

    • Prevent malformed upload path causing arbitrary write.

    • Fix missing "using namespace drogon::orm;" at autogenerated restful controllers.

    Source code(tar.gz)
    Source code(zip)
  • v1.7.4(Dec 11, 2021)

    API Change List

    • Support setting client certificate and SSL options on HTTP client

    • Add more method for mapper

    • Add overloads for SqlBinder::operator<< with non-const ref parameter

    Changes

    • Use decay_t instead of remove_cvref_t

    • Prevent drogon_ctl create_view appending empty new lines to resulting

    • Add an example for using coroutines of redis clients

    • Export some symbols for Windows

    • Mark all awaiters as nodiscard

    • Handle SIGINT too

    • Support CoroMapper method chaining

    • Remove setting c++17 in FindFilesystem

    Fixed

    • Fix Drogon not building caused by FindFilesystem

    • Fix deprecated warning when using openssl 3

    • Fix coroutine object destructing before coroutine ends in async_run

    • Fix build fail on CentOS8

    • Fix some compiler warnings

    • Fix the error with multiple results when calling a procedure in mysql

    • Fix an error when binding a function pointer to SqlBinder

    • Fix orm tests

    • Fix CI to actually build in C++14

    • Fix a race condition when resetting ws

    • Fix an error of std::bad_function_call

    • Update Trantor (fix sending partial files)

    Source code(tar.gz)
    Source code(zip)
  • 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)
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++ 6k Jan 4, 2023
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
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
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
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
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 17 Oct 15, 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 809 Dec 19, 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
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
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
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
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 Jan 4, 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
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 166 Dec 5, 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