diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index f8c9fd77..68288c6c 100755 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -21,7 +21,8 @@ add_dependencies(webapp drogon_ctl) AUX_SOURCE_DIRECTORY(client_example DIR_CLIENT) AUX_SOURCE_DIRECTORY(benchmark DIR_BENCHMARK) +AUX_SOURCE_DIRECTORY(simple_example_test DIR_TEST) add_executable(client ${DIR_CLIENT}) add_executable(benchmark ${DIR_BENCHMARK}) - +add_executable(webapp_test ${DIR_TEST}) \ No newline at end of file diff --git a/examples/simple_example_test/main.cc b/examples/simple_example_test/main.cc new file mode 100644 index 00000000..6fe572f6 --- /dev/null +++ b/examples/simple_example_test/main.cc @@ -0,0 +1,416 @@ +/** + * + * test.cc + * An Tao + * + * Copyright 2018, An Tao. All rights reserved. + * https://github.com/an-tao/drogon + * Use of this source code is governed by a MIT license + * that can be found in the License file. + * + * Drogon + * + */ + +//Make a http client to test the example server app; + +#include +#include +#define RESET "\033[0m" +#define RED "\033[31m" /* Red */ +#define GREEN "\033[32m" /* Green */ + +using namespace drogon; +void outputGood(const HttpRequestPtr &req) +{ + static int i = 0; + static std::mutex mtx; + { + std::lock_guard lock(mtx); + i++; + std::cout << i << GREEN << '\t' << "Good" << '\t' << RED << req->methodString() + << " " << req->path() << RESET << std::endl; + } +} +int main() +{ + auto client = HttpClient::newHttpClient("http://127.0.0.1:8080"); + /// 1 Get / + auto req = HttpRequest::newHttpRequest(); + req->setMethod(drogon::Get); + req->setPath("/"); + client->sendRequest(req, [=](ReqResult result, const HttpResponsePtr &resp) { + if (result == ReqResult::Ok) + { + //LOG_DEBUG << resp->getBody(); + if (resp->getBody() == "

Hello, world!

") + { + outputGood(req); + } + else + { + LOG_ERROR << "Error!"; + exit(1); + } + } + else + { + LOG_ERROR << "Error!"; + exit(1); + } + }); + /// 2. Get /slow to test simple controller, session and filter (cookie is not supported by HttpClient now) + req = HttpRequest::newHttpRequest(); + req->setMethod(drogon::Get); + req->setPath("/slow"); + client->sendRequest(req, [=](ReqResult result, const HttpResponsePtr &resp) { + if (result == ReqResult::Ok) + { + //LOG_DEBUG << resp->getBody(); + if (resp->getBody() == "

Hello, world!

") + { + outputGood(req); + } + else + { + LOG_ERROR << "Error!"; + exit(1); + } + } + else + { + LOG_ERROR << "Error!"; + exit(1); + } + }); + /// 3. Post to /tpost to test Http Method constraint + req = HttpRequest::newHttpRequest(); + req->setMethod(drogon::Get); + req->setPath("/tpost"); + client->sendRequest(req, [=](ReqResult result, const HttpResponsePtr &resp) { + if (result == ReqResult::Ok) + { + //LOG_DEBUG << resp->getBody(); + if (resp->statusCode() == HttpResponse::k405MethodNotAllowed) + { + outputGood(req); + } + else + { + LOG_ERROR << "Error!"; + exit(1); + } + } + else + { + LOG_ERROR << "Error!"; + exit(1); + } + }); + + req = HttpRequest::newHttpRequest(); + req->setMethod(drogon::Post); + req->setPath("/tpost"); + client->sendRequest(req, [=](ReqResult result, const HttpResponsePtr &resp) { + if (result == ReqResult::Ok) + { + if (resp->getBody() == "

Hello, world!

") + { + outputGood(req); + } + else + { + LOG_ERROR << "Error!"; + exit(1); + } + } + else + { + LOG_ERROR << "Error!"; + exit(1); + } + }); + + /// 4. Test HttpController + req = HttpRequest::newHttpRequest(); + req->setMethod(drogon::Post); + req->setPath("/api/v1/apitest"); + client->sendRequest(req, [=](ReqResult result, const HttpResponsePtr &resp) { + if (result == ReqResult::Ok) + { + if (resp->getBody() == "ROOT Post!!!") + { + outputGood(req); + } + else + { + LOG_DEBUG << resp->getBody(); + LOG_ERROR << "Error!"; + exit(1); + } + } + else + { + LOG_ERROR << "Error!"; + exit(1); + } + }); + + req = HttpRequest::newHttpRequest(); + req->setMethod(drogon::Get); + req->setPath("/api/v1/apitest"); + client->sendRequest(req, [=](ReqResult result, const HttpResponsePtr &resp) { + if (result == ReqResult::Ok) + { + if (resp->getBody() == "ROOT Get!!!") + { + outputGood(req); + } + else + { + LOG_DEBUG << resp->getBody(); + LOG_ERROR << "Error!"; + exit(1); + } + } + else + { + LOG_ERROR << "Error!"; + exit(1); + } + }); + + req = HttpRequest::newHttpRequest(); + req->setMethod(drogon::Get); + req->setPath("/api/v1/apitest/get/abc/123"); + client->sendRequest(req, [=](ReqResult result, const HttpResponsePtr &resp) { + if (result == ReqResult::Ok) + { + if (resp->getBody().find("p1\n 123") != std::string::npos && + resp->getBody().find("p2\n abc") != std::string::npos) + { + outputGood(req); + } + else + { + LOG_DEBUG << resp->getBody(); + LOG_ERROR << "Error!"; + exit(1); + } + } + else + { + LOG_ERROR << "Error!"; + exit(1); + } + }); + + req = HttpRequest::newHttpRequest(); + req->setMethod(drogon::Get); + req->setPath("/api/v1/apitest/3.14/List?P2=1234"); + client->sendRequest(req, [=](ReqResult result, const HttpResponsePtr &resp) { + if (result == ReqResult::Ok) + { + if (resp->getBody().find("p1\n 3.140000") != std::string::npos && + resp->getBody().find("p2\n 1234") != std::string::npos) + { + outputGood(req); + } + else + { + LOG_DEBUG << resp->getBody(); + LOG_ERROR << "Error!"; + exit(1); + } + } + else + { + LOG_ERROR << "Error!"; + exit(1); + } + }); + + req = HttpRequest::newHttpRequest(); + req->setMethod(drogon::Get); + req->setPath("/api/v1/apitest/static"); + client->sendRequest(req, [=](ReqResult result, const HttpResponsePtr &resp) { + if (result == ReqResult::Ok) + { + if (resp->getBody() == "staticApi,hello!!") + { + outputGood(req); + } + else + { + LOG_DEBUG << resp->getBody(); + LOG_ERROR << "Error!"; + exit(1); + } + } + else + { + LOG_ERROR << "Error!"; + exit(1); + } + }); + + app().loop()->runAfter(0.5, [=]() mutable { + req = HttpRequest::newHttpRequest(); + req->setMethod(drogon::Post); + req->setPath("/api/v1/apitest/static"); + client->sendRequest(req, [=](ReqResult result, const HttpResponsePtr &resp) { + if (result == ReqResult::Ok) + { + if (resp->getBody() == "staticApi,hello!!") + { + outputGood(req); + } + else + { + LOG_DEBUG << resp->getBody(); + LOG_ERROR << "Error!"; + exit(1); + } + } + else + { + LOG_ERROR << "Error!"; + exit(1); + } + }); + }); + + req = HttpRequest::newHttpRequest(); + req->setMethod(drogon::Get); + req->setPath("/api/v1/apitest/get/111"); + client->sendRequest(req, [=](ReqResult result, const HttpResponsePtr &resp) { + if (result == ReqResult::Ok) + { + if (resp->getBody().length() == 5123) + { + outputGood(req); + } + else + { + //LOG_DEBUG << resp->getBody(); + LOG_ERROR << "Error!"; + exit(1); + } + } + else + { + LOG_ERROR << "Error!"; + exit(1); + } + }); + + /// Test gzip + req = HttpRequest::newHttpRequest(); + req->setMethod(drogon::Get); + req->addHeader("accept-encoding", "gzip"); + req->setPath("/api/v1/apitest/get/111"); + client->sendRequest(req, [=](ReqResult result, const HttpResponsePtr &resp) { + if (result == ReqResult::Ok) + { + if (resp->getBody().length() == 1754) + { + outputGood(req); + } + else + { + LOG_DEBUG << resp->getBody().length(); + LOG_ERROR << "Error!"; + exit(1); + } + } + else + { + LOG_ERROR << "Error!"; + exit(1); + } + }); + + /// Test static function + req = HttpRequest::newHttpRequest(); + req->setMethod(drogon::Get); + req->setPath("/api/v1/handle11/11/22/?p3=33&p4=44"); + client->sendRequest(req, [=](ReqResult result, const HttpResponsePtr &resp) { + if (result == ReqResult::Ok) + { + if (resp->getBody().find("int p1\n 11") != std::string::npos && + resp->getBody().find("int p4\n 44") != std::string::npos && + resp->getBody().find("string p2\n 22") != std::string::npos && + resp->getBody().find("string p3\n 33") != std::string::npos) + { + outputGood(req); + } + else + { + LOG_DEBUG << resp->getBody(); + LOG_ERROR << "Error!"; + exit(1); + } + } + else + { + LOG_ERROR << "Error!"; + exit(1); + } + }); + + /// Test lambda + req = HttpRequest::newHttpRequest(); + req->setMethod(drogon::Get); + req->setPath("/api/v1/handle2/111/222"); + client->sendRequest(req, [=](ReqResult result, const HttpResponsePtr &resp) { + if (result == ReqResult::Ok) + { + if (resp->getBody().find("a\n 111") != std::string::npos && + resp->getBody().find("b\n 222.000000") != std::string::npos) + { + outputGood(req); + } + else + { + LOG_DEBUG << resp->getBody(); + LOG_ERROR << "Error!"; + exit(1); + } + } + else + { + LOG_ERROR << "Error!"; + exit(1); + } + }); + + /// Test std::bind and std::function + req = HttpRequest::newHttpRequest(); + req->setMethod(drogon::Get); + req->setPath("/api/v1/handle4/444/333/111"); + client->sendRequest(req, [=](ReqResult result, const HttpResponsePtr &resp) { + if (result == ReqResult::Ok) + { + if (resp->getBody().find("int p1\n 111") != std::string::npos && + resp->getBody().find("int p4\n 444") != std::string::npos && + resp->getBody().find("string p3\n 333") != std::string::npos && + resp->getBody().find("string p2\n ") != std::string::npos) + { + outputGood(req); + } + else + { + LOG_DEBUG << resp->getBody(); + LOG_ERROR << "Error!"; + exit(1); + } + } + else + { + LOG_ERROR << "Error!"; + exit(1); + } + }); + + app().run(); +} \ No newline at end of file diff --git a/lib/inc/drogon/HttpRequest.h b/lib/inc/drogon/HttpRequest.h index 85a1cd6f..f281649c 100755 --- a/lib/inc/drogon/HttpRequest.h +++ b/lib/inc/drogon/HttpRequest.h @@ -55,6 +55,9 @@ class HttpRequest virtual const std::string &getHeader(const std::string &field, const std::string &defaultVal = std::string()) const = 0; virtual const std::string &getHeader(std::string &&field, const std::string &defaultVal = std::string()) const = 0; + /// Set the header string identified by the @param field + virtual void addHeader(const std::string &field, const std::string &value) = 0; + /// Get the cookie string identified by the @param field virtual const std::string &getCookie(const std::string &field, const std::string &defaultVal = std::string()) const = 0; diff --git a/lib/src/HttpRequestImpl.h b/lib/src/HttpRequestImpl.h index 0a6d33f4..59ea3d8a 100755 --- a/lib/src/HttpRequestImpl.h +++ b/lib/src/HttpRequestImpl.h @@ -334,7 +334,7 @@ class HttpRequestImpl : public HttpRequest { _content = content; } - void addHeader(const std::string &key, const std::string &value) + virtual void addHeader(const std::string &key, const std::string &value) override { _headers[key] = value; }