C++ Web Framework REST API

Overview

wfrest: C++ Web Framework REST API

Fast, efficient, and easiest c++ async micro web framework based on C++ Workflow.

🌟 Contents

💥 Dicssussion

For more information, you can first see discussions:

https://github.com/chanchann/wfrest/discussions

⌛️ Build

Cmake

git clone https://github.com/chanchann/wfrest.git
cd wfrest
mkdir build && cd build
cmake ..
make -j 
make install

Docker

Use dockerfile

docker build -t wfrest .

Or you can Pull from DockerHub

docker pull wfrest/wfrest

🚀 Quick start

#include "wfrest/HttpServer.h"
using namespace wfrest;

int main()
{
    HttpServer svr;

    // curl -v http://ip:port/hello
    svr.GET("/hello", [](const HttpReq *req, HttpResp *resp)
    {
        resp->String("world\n");
    });
    // curl -v http://ip:port/data
    svr.GET("/data", [](const HttpReq *req, HttpResp *resp)
    {
        std::string str = "Hello world";
        resp->String(std::move(str));
    });

    // curl -v http://ip:port/post -d 'post hello world'
    svr.POST("/post", [](const HttpReq *req, HttpResp *resp)
    {
        std::string body = req->body();
        fprintf(stderr, "post data : %s\n", body.c_str());
    });

    if (svr.start(8888) == 0)
    {
        getchar();
        svr.stop();
    } else
    {
        fprintf(stderr, "Cannot start server");
        exit(1);
    }
    return 0;
}

🎆 API Examples

Parameters in path

#include "wfrest/HttpServer.h"
using namespace wfrest;

int main()
{
    HttpServer svr;

    // This handler will match /user/chanchan but will not match /user/ or /user
    // curl -v "ip:port/user/chanchan/"
    svr.GET("/user/{name}", [](HttpReq *req, HttpResp *resp)
    {
        std::string name = req->param("name");
        // resp->set_status(HttpStatusOK); // automatically
        resp->String("Hello " + name + "\n");
    });

    // wildcast/chanchan/action... (prefix)
    svr.GET("/wildcast/{name}/action*", [](HttpReq *req, HttpResp *resp)
    {
        std::string name = req->param("name");
        std::string message = name + " : path " + req->get_request_uri();

        resp->String("Hello " + message + "\n");
    });

    // request will hold the route definition
    svr.GET("/user/{name}/match*", [](HttpReq *req, HttpResp *resp)
    {
        std::string full_path = req->full_path();
        if (full_path == "/user/{name}/match*")
        {
            full_path += " match";
        } else
        {
            full_path += " dosen't match";
        }
        resp->String(full_path);
    });

    // This handler will add a new router for /user/groups.
    // Exact routes are resolved before param routes, regardless of the order they were defined.
    // Routes starting with /user/groups are never interpreted as /user/{name}/... routes
    svr.GET("/user/groups", [](HttpReq *req, HttpResp *resp)
    {
        resp->String(req->full_path());
    });

    if (svr.start(8888) == 0)
    {
        getchar();
        svr.stop();
    } else
    {
        fprintf(stderr, "Cannot start server");
        exit(1);
    }
    return 0;
}

Querystring parameters

#include "wfrest/HttpServer.h"
using namespace wfrest;

int main()
{
    HttpServer svr;

    // The request responds to a url matching:  /query_list?username=chanchann&password=yyy
    svr.GET("/query_list", [](HttpReq *req, HttpResp *resp)
    {
        std::unordered_map<std::string, std::string> query_list = req->query_list();
        for(auto& query : query_list)
        {
            fprintf(stderr, "%s : %s\n", query.first.c_str(), query.second.c_str());
        }
    });

    // The request responds to a url matching:  /query?username=chanchann&password=yyy
    svr.GET("/query", [](HttpReq *req, HttpResp *resp)
    {
        std::string user_name = req->query("username");
        std::string password = req->query("password");
        std::string info = req->query("info"); // no this field
        std::string address = req->default_query("address", "china");
        resp->String(user_name + " " + password + " " + info + " " + address + "\n");
    });

    // The request responds to a url matching:  /query_has?username=chanchann&password=
    // The logic for judging whether a parameter exists is that if the parameter value is empty, the parameter is considered to exist
    // and the parameter does not exist unless the parameter is submitted.
    svr.GET("/query_has", [](HttpReq *req, HttpResp *resp)
    {
        if(req->has_query("password"))
        {
            fprintf(stderr, "has password query\n");
        }
        if(req->has_query("info"))
        {
            fprintf(stderr, "has info query\n");
        }
    });

    if (svr.start(8888) == 0)
    {
        getchar();
        svr.stop();
    } else
    {
        fprintf(stderr, "Cannot start server");
        exit(1);
    }
    return 0;
}

Post Form

#include "wfrest/HttpServer.h"
using namespace wfrest;

int main()
{
    HttpServer svr;

    // Urlencoded Form
    // curl -v http://ip:port/post -H "body-type:application/x-www-form-urlencoded" -d 'user=admin&pswd=123456'
    svr.POST("/post", [](const HttpReq *req, HttpResp *resp)
    {
        if(req->content_type != APPLICATION_URLENCODED)
        {
            resp->set_status(HttpStatusBadRequest);
            return;
        }
        auto& form_kv = req->kv;
        for(auto& kv : form_kv)
        {
            fprintf(stderr, "key %s : vak %s\n", kv.first.c_str(), kv.second.c_str());
        }
    });

    // curl -X POST http://ip:port/form \
    // -F "[email protected]/path/file" \
    // -H "Content-Type: multipart/form-data"
    svr.POST("/form", [](const HttpReq *req, HttpResp *resp)
    {
        if(req->content_type != MULTIPART_FORM_DATA)
        {
            resp->set_status(HttpStatusBadRequest);
            return;
        }
        fprintf(stderr, "123\n");
        auto& form_kv = req->form;
        for(auto & it : form_kv)
        {
            fprintf(stderr, "%s : %s = %s",
                                it.first.c_str(),
                                it.second.body.c_str(),
                                it.second.filename.c_str());
        }
    });

    if (svr.start(8888) == 0)
    {
        getchar();
        svr.stop();
    } else
    {
        fprintf(stderr, "Cannot start server");
        exit(1);
    }
    return 0;
}

Header

#include "wfrest/HttpServer.h"
using namespace wfrest;

int main()
{
    HttpServer svr;

    svr.POST("/post", [](HttpReq *req, HttpResp *resp)
    {
        std::string host = req->header("Host");
        std::string content_type = req->header("Content-Type");
        if(req->has_header("User-Agent"))
        {
            fprintf(stderr, "Has User-Agent...");
        }
        resp->String(host + " " + content_type + "\n");
    });


    if (svr.start(8888) == 0)
    {
        getchar();
        svr.stop();
    } else
    {
        fprintf(stderr, "Cannot start server");
        exit(1);
    }
    return 0;
}

Send File

#include "wfrest/HttpServer.h"
using namespace wfrest;

int main()
{
    HttpServer svr;
    svr.mount("static");

    // single files
    svr.GET("/file1", [](const HttpReq *req, HttpResp *resp)
    {
        resp->File("todo.txt");
    });

    svr.GET("/file2", [](const HttpReq *req, HttpResp *resp)
    {
        resp->File("html/index.html");
    });

    svr.GET("/file3", [](const HttpReq *req, HttpResp *resp)
    {
        resp->File("/html/index.html");
    });

    svr.GET("/file4", [](const HttpReq *req, HttpResp *resp)
    {
        resp->File("todo.txt", 0);
    });

    svr.GET("/file5", [](const HttpReq *req, HttpResp *resp)
    {
        resp->File("todo.txt", 0, 10);
    });

    svr.GET("/file6", [](const HttpReq *req, HttpResp *resp)
    {
        resp->File("todo.txt", 5, 10);
    });

    // multiple files
    svr.GET("/multi_files", [](const HttpReq *req, HttpResp *resp)
    {
        std::vector<std::string> file_list = {"test.txt", "todo.txt", "test1.txt"};
        resp->File(file_list);
    });

    if (svr.start(8888) == 0)
    {
        getchar();
        svr.stop();
    } else
    {
        fprintf(stderr, "Cannot start server");
        exit(1);
    }
    return 0;
}

Save File

#include "wfrest/HttpServer.h"
using namespace wfrest;

int main()
{
    HttpServer svr;

    // curl -v -X POST "ip:port/file_write1" -F "[email protected]" -H "Content-Type: multipart/form-data"
    svr.POST("/file_write1", [](const HttpReq *req, HttpResp *resp)
    {
        std::string body = req->body();   // multipart/form - body has boundary
        resp->Save("test.txt", std::move(body));
    });

    svr.GET("/file_write2", [](const HttpReq *req, HttpResp *resp)
    {
        std::string body = "1234567890987654321";

        resp->Save("test1.txt", std::move(body));
    });

    if (svr.start(8888) == 0)
    {
        getchar();
        svr.stop();
    } else
    {
        fprintf(stderr, "Cannot start server");
        exit(1);
    }
    return 0;
}

Upload Files

#include "wfrest/HttpServer.h"
#include "wfrest/PathUtil.h"
using namespace wfrest;

int main()
{
    HttpServer svr;
    svr.mount("/static");

    // An expriment (Upload a file to parent dir is really dangerous.):
    // curl -v -X POST "ip:port/upload" -F "[email protected]; filename=../demo.txt" -H "Content-Type: multipart/form-data"
    // Then you find the file is store in the parent dir, which is dangerous
    svr.POST("/upload", [](HttpReq *req, HttpResp *resp)
    {
        std::vector<FormData *> files = req->post_files();
        if(files.empty())
        {
            resp->set_status(HttpStatusBadRequest);
        } else
        {
            auto *file = files[0];
            // file->filename SHOULD NOT be trusted. See Content-Disposition on MDN
            // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Disposition#directives
            // The filename is always optional and must not be used blindly by the application:
            // path information should be stripped, and conversion to the server file system rules should be done.
            fprintf(stderr, "filename : %s\n", file->filename.c_str());
            resp->Save(file->filename, std::move(file->body));
        }
    });

    // Here is the right way:
    // curl -v -X POST "ip:port/upload" -F "[email protected]; filename=../demo.txt" -H "Content-Type: multipart/form-data"
    svr.POST("/upload_fix", [](HttpReq *req, HttpResp *resp)
    {
        std::vector<FormData *> files = req->post_files();
        if(files.empty())
        {
            resp->set_status(HttpStatusBadRequest);
        } else
        {
            auto *file = files[0];
            // simple solution to fix the problem above
            // This will restrict the upload file to current directory.
            resp->Save(PathUtil::base(file->filename), std::move(file->body));
        }
    });

    // upload multiple files
    // curl -X POST http://ip:port/upload_multiple \
    // -F "[email protected]" \
    // -F "[email protected]" \
    // -H "Content-Type: multipart/form-data"
    svr.POST("/upload_multiple", [](HttpReq *req, HttpResp *resp)
    {
        std::vector<FormData *> files = req->post_files();
        if(files.empty())
        {
            resp->set_status(HttpStatusBadRequest);
        } else
        {
            for(auto& file : files)
            {
                resp->Save(PathUtil::base(file->filename), std::move(file->body));
            }
        }
    });

    if (svr.start(8888) == 0)
    {
        getchar();
        svr.stop();
    } else
    {
        fprintf(stderr, "Cannot start server");
        exit(1);
    }
    return 0;
}

Json

#include "wfrest/HttpServer.h"
using namespace wfrest;

int main()
{
    HttpServer svr;

    // curl -v http://ip:port/json1
    svr.GET("/json1", [](const HttpReq *req, HttpResp *resp)
    {
        Json json;
        json["test"] = 123;
        json["json"] = "test json";
        resp->Json(json);
    });

    // curl -v http://ip:port/json2
    svr.GET("/json2", [](const HttpReq *req, HttpResp *resp)
    {
        std::string valid_text = R"(
        {
            "numbers": [1, 2, 3]
        }
        )";
        resp->Json(valid_text);
    });

    // curl -v http://ip:port/json3
    svr.GET("/json3", [](const HttpReq *req, HttpResp *resp)
    {
        std::string invalid_text = R"(
        {
            "strings": ["extra", "comma", ]
        }
        )";
        resp->Json(invalid_text);
    });

    // recieve json
    //   curl -X POST http://ip:port/json4
    //   -H 'Content-Type: application/json'
    //   -d '{"login":"my_login","password":"my_password"}'
    svr.POST("/json4", [](const HttpReq *req, HttpResp *resp)
    {
        if(req->content_type != APPLICATION_JSON)
        {
            resp->String("NOT APPLICATION_JSON");
            return;
        }
        fprintf(stderr, "Json : %s", req->json.dump(4).c_str());
    });

    if (svr.start(8888) == 0)
    {
        getchar();
        svr.stop();
    } else
    {
        fprintf(stderr, "Cannot start server");
        exit(1);
    }
    return 0;
}

Computing task

#include "wfrest/HttpServer.h"
using namespace wfrest;

void Fibonacci(int n, HttpResp *resp)
{
    unsigned long long x = 0, y = 1;
    if (n <= 0 || n > 94)
    {
        fprintf(stderr, "invalid parameter");
        return;
    }
    for (int i = 2; i < n; i++)
    {
        y = x + y;
        x = y - x;
    }
    if (n == 1)
        y = 0;
    resp->String("fib(" + std::to_string(n) + ") is : " + std::to_string(y) + "\n");
}

int main()
{
    HttpServer svr;
    // Second parameter means this computing queue id is 1
    // Then this handler become a computing task
    // curl -v http://ip:port/compute_task?num=20
    svr.GET("/compute_task", 1, [](HttpReq *req, HttpResp *resp)
    {
        int num = std::stoi(req->query("num"));
        Fibonacci(num, resp);
    });

    if (svr.start(8888) == 0)
    {
        getchar();
        svr.stop();
    } else
    {
        fprintf(stderr, "Cannot start server");
        exit(1);
    }
    return 0;
}

ServerSeries Interface

#include "wfrest/HttpServer.h"
using namespace wfrest;

int main()
{
    HttpServer svr;

    svr.GET("/series", [](const HttpReq *req, HttpResp *resp, SeriesWork* series)
    {
        auto *timer = WFTaskFactory::create_timer_task(5000000, [](WFTimerTask *) {
            printf("timer task complete(5s).\n");
        });

        series->push_back(timer);
    });

    if (svr.start(8888) == 0)
    {
        getchar();
        svr.stop();
    } else
    {
        fprintf(stderr, "Cannot start server");
        exit(1);
    }
    return 0;
}

How to use logger

#include "wfrest/Logger.h"
using namespace wfrest;

int main()
{
    // set the logger config
    LoggerSettings settings = LOGGER_SETTINGS_DEFAULT;
    settings.level = LogLevel::TRACE;
    settings.log_in_file = true;
    LOGGER(&settings);

    int i = 1;
    LOG_DEBUG << (float)3.14;
    LOG_DEBUG << (const char)'8';
    LOG_DEBUG << &i;
    LOG_DEBUG << wfrest::Fmt("%.3f", 3.1415926);
    LOG_DEBUG << "debug";
    LOG_TRACE << "trace";
    LOG_INFO << "info";
    LOG_WARN << "warning";

    FILE *fp = fopen("/not_exist_file", "rb");
    if (fp == nullptr)
    {
        LOG_SYSERR << "syserr log!";
    }
    LOG_DEBUG  << abc << 123.345 << "chanchan" << '\n'
               << std::string("name");
    return 0;
}

All the configure fields are:

struct LoggerSettings
{
    LogLevel level;    
    bool log_in_console;    
    bool log_in_file;
    const char *file_path;
    const char *file_base_name;
    const char *file_extension;
    uint64_t roll_size;
    std::chrono::seconds flush_interval;
};

Default configure :

static constexpr struct LoggerSettings LOGGER_SETTINGS_DEFAULT =
{
    .level = LogLevel::INFO,
    .log_in_console = true,
    .log_in_file = false,
    .file_path = "./",
    .file_base_name = "wfrest",
    .file_extension = ".log",
    .roll_size = 20 * 1024 * 1024,
    .flush_interval = std::chrono::seconds(3),
};

Sample Output

2021-11-30 22:36:21.422271 822380  [ERROR]  [logger_test.cc:84] No such file or directory (errno=2) syserr log
Issues
  • two test tests failed on Arm64 platform

    two test tests failed on Arm64 platform

    [email protected]:~/workspace/cpprest/wfrest# ./test.sh 
    + BUILD_DIR=./test/build
    + mkdir -p ./test/build
    + cd ./test/build
    + cmake ..
    -- Build wfrest unit test
    -- Configuring done
    -- Generating done
    -- Build files have been written to: /root/workspace/cpprest/wfrest/test/build
    + make
    Consolidate compiler generated dependencies of target router_test
    [  2%] Linking CXX executable router_test
    [  4%] Built target router_test
    [  6%] Building CXX object CMakeFiles/multi_part_test.dir/multi_part_test.cc.o
    [  8%] Linking CXX executable multi_part_test
    [  8%] Built target multi_part_test
    [ 10%] Building CXX object CMakeFiles/StringPiece_feature.dir/StringPiece_feature.cc.o
    [ 12%] Linking CXX executable StringPiece_feature
    [ 12%] Built target StringPiece_feature
    [ 14%] Building CXX object CMakeFiles/RouteTableNode_test.dir/RouteTableNode_test.cc.o
    [ 16%] Linking CXX executable RouteTableNode_test
    [ 16%] Built target RouteTableNode_test
    [ 18%] Building CXX object CMakeFiles/StrUtil_unittest.dir/StrUtil_unittest.cc.o
    [ 20%] Linking CXX executable StrUtil_unittest
    [ 20%] Built target StrUtil_unittest
    [ 22%] Building CXX object CMakeFiles/StringPiece_unittest.dir/StringPiece_unittest.cc.o
    [ 25%] Linking CXX executable StringPiece_unittest
    [ 25%] Built target StringPiece_unittest
    [ 27%] Building CXX object CMakeFiles/Compress_unittest.dir/Compress_unittest.cc.o
    [ 29%] Linking CXX executable Compress_unittest
    [ 29%] Built target Compress_unittest
    [ 31%] Building CXX object CMakeFiles/Router_unittest.dir/Router_unittest.cc.o
    [ 33%] Linking CXX executable Router_unittest
    [ 33%] Built target Router_unittest
    [ 35%] Building CXX object CMakeFiles/base64_unittest.dir/base64_unittest.cc.o
    [ 37%] Linking CXX executable base64_unittest
    [ 37%] Built target base64_unittest
    [ 39%] Building CXX object CMakeFiles/BluePrint_unittest.dir/BluePrint_unittest.cc.o
    [ 41%] Linking CXX executable BluePrint_unittest
    [ 41%] Built target BluePrint_unittest
    [ 43%] Building CXX object CMakeFiles/FileUtil_unittest.dir/FileUtil_unittest.cc.o
    [ 45%] Building CXX object CMakeFiles/FileUtil_unittest.dir/FileTestUtil.cc.o
    [ 47%] Linking CXX executable FileUtil_unittest
    [ 47%] Built target FileUtil_unittest
    [ 50%] Building CXX object CMakeFiles/PathUtil_unittest.dir/PathUtil_unittest.cc.o
    [ 52%] Building CXX object CMakeFiles/PathUtil_unittest.dir/FileTestUtil.cc.o
    [ 54%] Linking CXX executable PathUtil_unittest
    [ 54%] Built target PathUtil_unittest
    [ 56%] Building CXX object CMakeFiles/TimeStamp_unittest.dir/TimeStamp_unittest.cc.o
    [ 58%] Linking CXX executable TimeStamp_unittest
    [ 58%] Built target TimeStamp_unittest
    [ 60%] Building CXX object CMakeFiles/HttpCookie_unittest.dir/HttpCookie_unittest.cc.o
    [ 62%] Linking CXX executable HttpCookie_unittest
    [ 62%] Built target HttpCookie_unittest
    [ 64%] Building CXX object CMakeFiles/RouteTable_unittest.dir/RouteTable_unittest.cc.o
    [ 66%] Linking CXX executable RouteTable_unittest
    [ 66%] Built target RouteTable_unittest
    [ 68%] Building CXX object CMakeFiles/HttpDef_unittest.dir/HttpDef_unittest.cc.o
    [ 70%] Linking CXX executable HttpDef_unittest
    [ 70%] Built target HttpDef_unittest
    [ 72%] Building CXX object CMakeFiles/server_send_unittest.dir/HttpServer/send_unittest.cc.o
    [ 75%] Linking CXX executable server_send_unittest
    [ 75%] Built target server_send_unittest
    [ 77%] Building CXX object CMakeFiles/server_param_unittest.dir/HttpServer/param_unittest.cc.o
    [ 79%] Linking CXX executable server_param_unittest
    [ 79%] Built target server_param_unittest
    [ 81%] Building CXX object CMakeFiles/server_json_unittest.dir/HttpServer/json_unittest.cc.o
    [ 83%] Linking CXX executable server_json_unittest
    [ 83%] Built target server_json_unittest
    [ 85%] Building CXX object CMakeFiles/server_file_unittest.dir/HttpServer/file_unittest.cc.o
    [ 87%] Building CXX object CMakeFiles/server_file_unittest.dir/FileTestUtil.cc.o
    [ 89%] Linking CXX executable server_file_unittest
    [ 89%] Built target server_file_unittest
    [ 91%] Building CXX object CMakeFiles/server_proxy_unittest.dir/HttpServer/proxy_unittest.cc.o
    [ 93%] Linking CXX executable server_proxy_unittest
    [ 93%] Built target server_proxy_unittest
    [ 95%] Building CXX object CMakeFiles/server_static_unittest.dir/HttpServer/static_unittest.cc.o
    [ 97%] Building CXX object CMakeFiles/server_static_unittest.dir/FileTestUtil.cc.o
    [100%] Linking CXX executable server_static_unittest
    [100%] Built target server_static_unittest
    + make test
    Running tests...
    Test project /root/workspace/cpprest/wfrest/test/build
          Start  1: StrUtil_unittest
     1/18 Test  #1: StrUtil_unittest .................   Passed    0.01 sec
          Start  2: StringPiece_unittest
     2/18 Test  #2: StringPiece_unittest .............   Passed    0.01 sec
          Start  3: Compress_unittest
     3/18 Test  #3: Compress_unittest ................   Passed    0.05 sec
          Start  4: Router_unittest
     4/18 Test  #4: Router_unittest ..................   Passed    0.01 sec
          Start  5: base64_unittest
     5/18 Test  #5: base64_unittest ..................   Passed    0.01 sec
          Start  6: BluePrint_unittest
     6/18 Test  #6: BluePrint_unittest ...............   Passed    0.01 sec
          Start  7: FileUtil_unittest
     7/18 Test  #7: FileUtil_unittest ................   Passed    0.01 sec
          Start  8: PathUtil_unittest
     8/18 Test  #8: PathUtil_unittest ................   Passed    0.01 sec
          Start  9: TimeStamp_unittest
     9/18 Test  #9: TimeStamp_unittest ...............***Failed    0.01 sec
          Start 10: HttpCookie_unittest
    10/18 Test #10: HttpCookie_unittest ..............***Failed    0.01 sec
          Start 11: RouteTable_unittest
    11/18 Test #11: RouteTable_unittest ..............   Passed    0.01 sec
          Start 12: HttpDef_unittest
    12/18 Test #12: HttpDef_unittest .................   Passed    0.01 sec
          Start 13: server_send_unittest
    13/18 Test #13: server_send_unittest .............   Passed    0.03 sec
          Start 14: server_param_unittest
    14/18 Test #14: server_param_unittest ............   Passed    0.01 sec
          Start 15: server_json_unittest
    15/18 Test #15: server_json_unittest .............   Passed    0.01 sec
          Start 16: server_file_unittest
    16/18 Test #16: server_file_unittest .............   Passed    0.04 sec
          Start 17: server_proxy_unittest
    17/18 Test #17: server_proxy_unittest ............   Passed    0.01 sec
          Start 18: server_static_unittest
    18/18 Test #18: server_static_unittest ...........   Passed    0.03 sec
    
    89% tests passed, 2 tests failed out of 18
    
    Total Test time (real) =   0.28 sec
    
    The following tests FAILED:
              9 - TimeStamp_unittest (Failed)
             10 - HttpCookie_unittest (Failed)
    Errors while running CTest
    Output from these tests are in: /root/workspace/cpprest/wfrest/test/build/Testing/Temporary/LastTest.log
    Use "--rerun-failed --output-on-failure" to re-run the failed cases verbosely.
    make: *** [Makefile:71: test] Error 8
    
    opened by cnmade 10
  • Segment fault after calling SeriesWork::cancel() in the task.

    Segment fault after calling SeriesWork::cancel() in the task.

    I'm trying to use the SeriesWork feature through the wfrest's interface like what 12_series_interface.cc shown. When I call SeriesWork::cancel() in the HttpServer callback to interrupt the series,the program crash after calling SeriesWork::~Series().

    This error might be caused by Router.cc line 56/59,you call series_of() to get SeriesWork object while it is actually not allocated.

    opened by yuxilao 4
  • Info: wfrest can build on ARM64 and AMD64 , either docker or podman

    Info: wfrest can build on ARM64 and AMD64 , either docker or podman

    Tested docker build wfrest, on platform ubuntu arm64 and amd64, docker and podman both works.

    make[2]: Leaving directory '/home/project/workflow/build.cmake'
    Install the project...
    -- Install configuration: "RelWithDebInfo"
    -- Installing: /usr/local/lib/cmake/workflow/workflow-config.cmake
    -- Installing: /usr/local/lib/cmake/workflow/workflow-config-version.cmake
    -- Installing: /usr/local/include/workflow/DnsRoutine.h
    -- Installing: /usr/local/include/workflow/MapReduce.h
    -- Installing: /usr/local/include/workflow/MapReduce.inl
    -- Installing: /usr/local/include/workflow/ProtocolMessage.h
    -- Installing: /usr/local/include/workflow/http_parser.h
    -- Installing: /usr/local/include/workflow/HttpMessage.h
    -- Installing: /usr/local/include/workflow/HttpUtil.h
    -- Installing: /usr/local/include/workflow/redis_parser.h
    -- Installing: /usr/local/include/workflow/RedisMessage.h
    -- Installing: /usr/local/include/workflow/mysql_stream.h
    -- Installing: /usr/local/include/workflow/MySQLMessage.h
    -- Installing: /usr/local/include/workflow/MySQLMessage.inl
    -- Installing: /usr/local/include/workflow/MySQLResult.h
    -- Installing: /usr/local/include/workflow/MySQLResult.inl
    -- Installing: /usr/local/include/workflow/mysql_parser.h
    -- Installing: /usr/local/include/workflow/mysql_types.h
    -- Installing: /usr/local/include/workflow/mysql_byteorder.h
    -- Installing: /usr/local/include/workflow/SSLWrapper.h
    -- Installing: /usr/local/include/workflow/dns_parser.h
    -- Installing: /usr/local/include/workflow/DnsMessage.h
    -- Installing: /usr/local/include/workflow/DnsUtil.h
    -- Installing: /usr/local/include/workflow/WFServer.h
    -- Installing: /usr/local/include/workflow/WFDnsServer.h
    -- Installing: /usr/local/include/workflow/WFHttpServer.h
    -- Installing: /usr/local/include/workflow/WFRedisServer.h
    -- Installing: /usr/local/include/workflow/WFMySQLServer.h
    -- Installing: /usr/local/include/workflow/WFMySQLConnection.h
    -- Installing: /usr/local/include/workflow/WFDnsClient.h
    -- Installing: /usr/local/include/workflow/DnsCache.h
    -- Installing: /usr/local/include/workflow/WFGlobal.h
    -- Installing: /usr/local/include/workflow/UpstreamManager.h
    -- Installing: /usr/local/include/workflow/RouteManager.h
    -- Installing: /usr/local/include/workflow/EndpointParams.h
    -- Installing: /usr/local/include/workflow/WFFuture.h
    -- Installing: /usr/local/include/workflow/WFFacilities.h
    -- Installing: /usr/local/include/workflow/WFFacilities.inl
    -- Installing: /usr/local/include/workflow/EncodeStream.h
    -- Installing: /usr/local/include/workflow/LRUCache.h
    -- Installing: /usr/local/include/workflow/StringUtil.h
    -- Installing: /usr/local/include/workflow/URIParser.h
    -- Installing: /usr/local/include/workflow/MD5Util.h
    -- Installing: /usr/local/include/workflow/WFConnection.h
    -- Installing: /usr/local/include/workflow/WFTask.h
    -- Installing: /usr/local/include/workflow/WFTask.inl
    -- Installing: /usr/local/include/workflow/WFGraphTask.h
    -- Installing: /usr/local/include/workflow/WFTaskError.h
    -- Installing: /usr/local/include/workflow/WFTaskFactory.h
    -- Installing: /usr/local/include/workflow/WFTaskFactory.inl
    -- Installing: /usr/local/include/workflow/WFAlgoTaskFactory.h
    -- Installing: /usr/local/include/workflow/WFAlgoTaskFactory.inl
    -- Installing: /usr/local/include/workflow/Workflow.h
    -- Installing: /usr/local/include/workflow/WFOperator.h
    -- Installing: /usr/local/include/workflow/WFResourcePool.h
    -- Installing: /usr/local/include/workflow/WFNameService.h
    -- Installing: /usr/local/include/workflow/WFDnsResolver.h
    -- Installing: /usr/local/include/workflow/WFServiceGovernance.h
    -- Installing: /usr/local/include/workflow/UpstreamPolicies.h
    -- Installing: /usr/local/include/workflow/CommRequest.h
    -- Installing: /usr/local/include/workflow/CommScheduler.h
    -- Installing: /usr/local/include/workflow/Communicator.h
    -- Installing: /usr/local/include/workflow/SleepRequest.h
    -- Installing: /usr/local/include/workflow/ExecRequest.h
    -- Installing: /usr/local/include/workflow/IORequest.h
    -- Installing: /usr/local/include/workflow/Executor.h
    -- Installing: /usr/local/include/workflow/list.h
    -- Installing: /usr/local/include/workflow/mpoller.h
    -- Installing: /usr/local/include/workflow/poller.h
    -- Installing: /usr/local/include/workflow/msgqueue.h
    -- Installing: /usr/local/include/workflow/rbtree.h
    -- Installing: /usr/local/include/workflow/SubTask.h
    -- Installing: /usr/local/include/workflow/thrdpool.h
    -- Installing: /usr/local/include/workflow/IOService_linux.h
    -- Installing: /usr/local/share/doc/workflow-0.9.10/README.md
    -- Installing: /usr/local/lib/libworkflow.a
    -- Installing: /usr/local/lib/libworkflow.so
    -- Up-to-date: /usr/local/lib/libworkflow.a
    -- Installing: /usr/local/lib/cmake/workflow/workflow-targets.cmake
    -- Installing: /usr/local/lib/cmake/workflow/workflow-targets-relwithdebinfo.cmake
    make[1]: Leaving directory '/home/project/workflow/build.cmake'
    Cloning into 'wfrest'...
    -- The C compiler identification is GNU 9.3.0
    -- The CXX compiler identification is GNU 9.3.0
    -- Check for working C compiler: /usr/bin/cc
    -- Check for working C compiler: /usr/bin/cc -- works
    -- Detecting C compiler ABI info
    -- Detecting C compiler ABI info - done
    -- Detecting C compile features
    -- Detecting C compile features - done
    -- Check for working CXX compiler: /usr/bin/c++
    -- Check for working CXX compiler: /usr/bin/c++ -- works
    -- Detecting CXX compiler ABI info
    -- Detecting CXX compiler ABI info - done
    -- Detecting CXX compile features
    -- Detecting CXX compile features - done
    -- Build Type: Release
    -- Found OpenSSL: /usr/lib/aarch64-linux-gnu/libcrypto.so (found version "1.1.1f")  
    -- Found ZLIB: /usr/lib/aarch64-linux-gnu/libz.so (found version "1.2.11") 
    -- workflow exists(version >= 0.9.9), not build
    -- CXX_FLAGS = -g -std=c++11 -rdynamic -pthread -fno-exceptions -O2 -DNDEBUG
    -- lib/cmake/wfrest
    -- Configuring done
    -- Generating done
    -- Build files have been written to: /home/project/wfrest/build
    Scanning dependencies of target wfrest
    [  4%] Building CXX object wfrest/CMakeFiles/wfrest.dir/StrUtil.cc.o
    [  8%] Building CXX object wfrest/CMakeFiles/wfrest.dir/HttpMsg.cc.o
    [ 13%] Building CXX object wfrest/CMakeFiles/wfrest.dir/Router.cc.o
    [ 17%] Building CXX object wfrest/CMakeFiles/wfrest.dir/RouteTable.cc.o
    [ 21%] Building CXX object wfrest/CMakeFiles/wfrest.dir/UriUtil.cc.o
    [ 26%] Building CXX object wfrest/CMakeFiles/wfrest.dir/HttpDef.cc.o
    [ 30%] Building CXX object wfrest/CMakeFiles/wfrest.dir/HttpFile.cc.o
    [ 39%] Building C object wfrest/CMakeFiles/wfrest.dir/MultiPartParser.c.o
    [ 43%] Building CXX object wfrest/CMakeFiles/wfrest.dir/HttpContent.cc.o
    [ 47%] Building CXX object wfrest/CMakeFiles/wfrest.dir/PathUtil.cc.o
    [ 34%] Building CXX object wfrest/CMakeFiles/wfrest.dir/HttpServerTask.cc.o
    [ 52%] Building CXX object wfrest/CMakeFiles/wfrest.dir/HttpServer.cc.o
    [ 56%] Building CXX object wfrest/CMakeFiles/wfrest.dir/Timestamp.cc.o
    [ 60%] Building CXX object wfrest/CMakeFiles/wfrest.dir/SysInfo.cc.o
    [ 65%] Building CXX object wfrest/CMakeFiles/wfrest.dir/Compress.cc.o
    [ 69%] Building CXX object wfrest/CMakeFiles/wfrest.dir/BluePrint.cc.o
    [ 73%] Building CXX object wfrest/CMakeFiles/wfrest.dir/base64.cc.o
    [ 78%] Building CXX object wfrest/CMakeFiles/wfrest.dir/ErrorCode.cc.o
    [ 82%] Building CXX object wfrest/CMakeFiles/wfrest.dir/FileUtil.cc.o
    [ 91%] Building CXX object wfrest/CMakeFiles/wfrest.dir/MysqlUtil.cc.o
    [ 91%] Building CXX object wfrest/CMakeFiles/wfrest.dir/HttpCookie.cc.o
    [ 95%] Building CXX object wfrest/CMakeFiles/wfrest.dir/Aspect.cc.o
    [100%] Linking CXX static library ../lib/libwfrest.a
    [100%] Built target wfrest
    [100%] Built target wfrest
    Install the project...
    -- Install configuration: "Release"
    -- Installing: /usr/local/lib/cmake/wfrest/wfrest-config-version.cmake
    -- Installing: /usr/local/lib/cmake/wfrest/wfrest-config.cmake
    -- Installing: /usr/local/lib/libwfrest.a
    -- Installing: /usr/local/lib/cmake/wfrest/wfrest-targets.cmake
    -- Installing: /usr/local/lib/cmake/wfrest/wfrest-targets-release.cmake
    -- Installing: /usr/local/include/wfrest/AopUtil.h
    -- Installing: /usr/local/include/wfrest/Aspect.h
    -- Installing: /usr/local/include/wfrest/BluePrint.h
    -- Installing: /usr/local/include/wfrest/Compress.h
    -- Installing: /usr/local/include/wfrest/Copyable.h
    -- Installing: /usr/local/include/wfrest/ErrorCode.h
    -- Installing: /usr/local/include/wfrest/FileUtil.h
    -- Installing: /usr/local/include/wfrest/HttpContent.h
    -- Installing: /usr/local/include/wfrest/HttpCookie.h
    -- Installing: /usr/local/include/wfrest/HttpDef.h
    -- Installing: /usr/local/include/wfrest/HttpFile.h
    -- Installing: /usr/local/include/wfrest/HttpMsg.h
    -- Installing: /usr/local/include/wfrest/HttpServer.h
    -- Installing: /usr/local/include/wfrest/HttpServerTask.h
    -- Installing: /usr/local/include/wfrest/Macro.h
    -- Installing: /usr/local/include/wfrest/MultiPartParser.h
    -- Installing: /usr/local/include/wfrest/MysqlUtil.h
    -- Installing: /usr/local/include/wfrest/Noncopyable.h
    -- Installing: /usr/local/include/wfrest/PathUtil.h
    -- Installing: /usr/local/include/wfrest/RouteTable.h
    -- Installing: /usr/local/include/wfrest/Router.h
    -- Installing: /usr/local/include/wfrest/StrUtil.h
    -- Installing: /usr/local/include/wfrest/StringPiece.h
    -- Installing: /usr/local/include/wfrest/SysInfo.h
    -- Installing: /usr/local/include/wfrest/Timestamp.h
    -- Installing: /usr/local/include/wfrest/UriUtil.h
    -- Installing: /usr/local/include/wfrest/VerbHandler.h
    -- Installing: /usr/local/include/wfrest/base64.h
    -- Installing: /usr/local/include/wfrest/json.hpp
    -- Installing: /usr/local/include/wfrest/json_fwd.hpp
    -- Installing: /usr/local/include/wfrest/BluePrint.inl
    -- Installing: /usr/local/lib/cmake/wfrest/FindBrotli.cmake
    STEP 6: COMMIT wfrest
    --> 21f71b2f0a8
    Successfully tagged localhost/wfrest:latest
    21f71b2f0a8bc5d1d8c3ca6dd4b2b15093eff3f409f9ebdc7ca87848ba6719ea
    
    opened by cnmade 3
  • Bug of code in readme

    Bug of code in readme

    Please make sure that you have tested the code before put them into the README doc.

    • Such as no defined varable for abc
    • Missing semicolon

    BTW, in order to build the example you provided, there maybe need some compiler flags to be set such LD_LIBRARY_PATH, or linking specify library, such as -lworkflow.

    opened by chunyang-wen 3
  • bug : 相同路径,动词会被覆盖

    bug : 相同路径,动词会被覆盖

    相同路径,不同动词,前面的动词会被覆盖掉,但打印路径,接收到的还是发出的动词

    具体可以看下面的例子

    svr.PUT("/account", [](const HttpReq *req, HttpResp *resp)
    {
        fprintf(stderr, "put account\n");
        resp->String("put verb");
    });
    
    svr.DELETE("/account", [](const HttpReq *req, HttpResp *resp)
    {
        fprintf(stderr, "delete account\n");
        resp->String("delete verb");
    });
    
    svr.POST("/account", [](const HttpReq *req, HttpResp *resp)
    {
        fprintf(stderr, "post account\n");
        resp->String("post verb");
    });
    

    按顺序发送PUT、DELETE、POST请求,server输出如下:

    post account
    [WFREST] 2022-04-06 13:54:23 | 200 | ip_addr | PUT | "/account" | -- 
    post account
    [WFREST] 2022-04-06 13:54:32 | 200 | ip_addr | DELETE | "/account" | -- 
    post account
    [WFREST] 2022-04-06 13:54:36 | 200 | ip_addr | POST | "/account" | --
    

    且client收到的消息均为

    post verb
    

    (英文写不好,为了表达清晰,还是用中文)

    opened by cuncinc 2
  • Plz do not install workflow automatically

    Plz do not install workflow automatically

    I think it is not good to install workflow automatically at build time.

    Try to prompt people how to install that library when it's not found.

    Or, install it in CMAKE_BUILD_DIRECTORY ( currently /usr/local ) maybe a good way.

    opened by joelcho 2
  • I suggest not to apply byte-to-byte comparison to string

    I suggest not to apply byte-to-byte comparison to string

    In class StringPiece, the string piece (I prefer another term ``string slice'' which is widely used in development community) is compared byte to byte by memcmp. However, a byte-to-byte comparison is only applicable to single-byte character set such as US-ASCII and Western Latin Character Set (for western European languages). If URL is encoded in other character sets, the matching result may be wrong.

    Take UTF-8 as an example. The letter with accent mark é can be encoded in two ways: the first way is the codepoint U+00E9, hence its UTF-8 is \xc3\xa9; the second way is e (U+0065) followed by ◌́ (U+0301), hence its UTF-8 is \x65\xcc\x81. Although their bytes are different, they are the exactly same character (formally, glyph in Unicode). But StringPiece simply recognise them as distinct characters.

    To correctly match URL that is encoded in UTF-8, canonical equivalence must be applied, not byte-to-byte comparison. To simplify the matching of UTF-8 string, I highly recommend integrating International Components for Unicode (ICU) in your project. ICU is a mature, widely used set of C/C++ and Java libraries providing Unicode and Globalization support for software applications.

    opened by weihe0 0
  • question: wfrest support http2 or grpc?

    question: wfrest support http2 or grpc?

    Did wfrest support http2 or grpc? How about add some example show the ability to run http2 server/client, grpc server/client. even a hello world just fine.

    opened by cnmade 3
A REST API in C, yeah, C...

A REST API that fetches custom data from École 42 users, written in C. (Challenge from 42Labs) Constructed with: Mongoose Mjson Org-mode MongoDB Atlas

Henrique Rocha 3 Jun 14, 2022
🌱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++ 5.5k Jun 27, 2022
Various utilities such as WebServer, JSON, WebSocket server, REST framework

DumaisLib This is a library containing several utilities for some projects of Patrick Dumais. Previously, the libraries were all individual but it bec

Patrick Dumais 25 Feb 22, 2022
C++ library for creating an embedded Rest HTTP server (and more)

The libhttpserver reference manual Tl;dr libhttpserver is a C++ library for building high performance RESTful web servers. libhttpserver is built upon

Sebastiano Merlino 660 Jun 20, 2022
C++ client for making HTTP/REST requests

REST client for C++ About This is a simple REST client for C++. It wraps libcurl for HTTP requests. Usage restclient-cpp provides two ways of interact

Daniel Schauenberg 1.4k Jun 21, 2022
A C++ async HTTP client library to use in asynchronous applications while communicating with REST services.

libashttp An asynchronous HTTP library using Boost.ASIO as the backend. This project is licensed under: Usage Here is a example usage which is taken f

Tolga Hoşgör 51 Dec 19, 2021
Modern C++ REST Client library

Introduction to the restc-cpp C++ library The magic that takes the pain out of accessing JSON API's from C++ What it does: It formulates a HTTP reques

Jarle Aase 473 Jun 20, 2022
HTTP/HTTPS REST Client C Library

https_client HTTP/HTTPS REST Client C Library This library is a tiny https client library. it use only small memory(default read buffer size(H_READ_SI

HISONA 94 Jun 1, 2022
Mongoose Embedded Web Server Library - a multi-protocol embedded networking library with TCP/UDP, HTTP, WebSocket, MQTT built-in protocols, async DNS resolver, and non-blocking API.

Mongoose - Embedded Web Server / Embedded Networking Library Mongoose is a networking library for C/C++. It implements event-driven non-blocking APIs

Cesanta Software 8.5k Jun 29, 2022
An asynchronous web framework for C++ built on top of Qt

!!! I can no longer maintain this project. If you're interessed, please contact me and I can move the projetct to you !!! Tufão - an asynchronous web

Vinícius dos Santos Oliveira 542 Jun 14, 2022
Drogon: A C++14/17 based HTTP web application framework running on Linux/macOS/Unix/Windows

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

An Tao 7.5k Jun 29, 2022
Lightweight Python Web framework

fly Python lightweight web application framework. Event driven architecture. Usable as Web server and Application server. Lightweight and fast. Since

tatsuya.s 17 Dec 18, 2021
The Telegram Bot API provides an HTTP API for creating Telegram Bots.

The Telegram Bot API provides an HTTP API for creating Telegram Bots.

Telegram Library 1.6k Jun 25, 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 Jun 30, 2022
Simple, secure & standards compliant web server for the most demanding of applications

Simple, secure[1] & standards compliant[2] web server for the most demanding[3] of applications. Read more... ?? Optimized security Being meticulously

uNetworking AB 13.9k Jun 27, 2022
C Hypertext Library - A library for writing web applications in C

CHL C Hypertext Library - A library for writing web applications in C #include <chl/chl.h> int main() { chl_set_default_headers(); chl_print_header

null 272 Jun 20, 2022
When you need a web server in a hurry.

darkhttpd https://unix4lyfe.org/darkhttpd/ When you need a web server in a hurry. Features: Simple to set up: Single binary, no other files, no instal

Emil Mikulic 800 Jun 24, 2022
web server that will print hello world on the screen only for linux users

a simple http server side lib only for linux users Note: This lib is currently under development you can check the source code and even use it but dn'

notaweeb 11 Mar 14, 2021
Ultra-lightweight web browser based on Qt Ultralight webview, powered by Ultralight HTML renderer

Qt Ultralight Browser This is an ultra-lightweight web browser powered by the Ultralight web engine embedded in Qt 5 app as a custom webview widget -

niu tech 30 Jun 14, 2022