The c++ async micro web framework for building web applications based on workflow
- wfrest: C++ Web Framework REST API
For more information, you can first see discussions:
https://github.com/chanchann/wfrest/discussions
git clone https://github.com/sogou/workflow.git
cd wfrest
mkdir build && cd build
cmake ..
make -j
make install
Use dockerfile
docker build -t wfrest .
Or you can Pull from DockerHub
docker pull shiyuyi/wfrest
#include "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)
{
resp->String("Hello world\n", 12);
});
// 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;
}
#include "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;
}
#include "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;
}
#include "HttpServer.h"
using namespace wfrest;
int main()
{
HttpServer svr;
// Urlencoded Form
// curl -v http://ip:port/post -H "content-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 "file=@/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.content.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;
}
#include "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;
}
#include "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;
}
#include "HttpServer.h"
using namespace wfrest;
int main()
{
HttpServer svr;
// curl -v -X POST "ip:port/file_write1" -F "file=@filename" -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 content = "1234567890987654321";
resp->Save("test1.txt", std::move(content));
});
if (svr.start(8888) == 0)
{
getchar();
svr.stop();
} else
{
fprintf(stderr, "Cannot start server");
exit(1);
}
return 0;
}
#include "HttpServer.h"
#include "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->content));
}
});
// 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->content));
}
});
// upload multiple files
// curl -X POST http://ip:port/upload_multiple \
// -F "file1=@file1" \
// -F "file2=@file2" \
// -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->content));
}
}
});
if (svr.start(8888) == 0)
{
getchar();
svr.stop();
} else
{
fprintf(stderr, "Cannot start server");
exit(1);
}
return 0;
}
#include "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;
}