Add sending customized http requests to drogon_ctl (#2186)

This commit is contained in:
fantasy-peak 2024-10-17 10:47:04 +08:00 committed by GitHub
parent 3fce70b535
commit ca2210331d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 152 additions and 4 deletions

View File

@ -19,6 +19,10 @@
#include <memory> #include <memory>
#include <iomanip> #include <iomanip>
#include <cstdlib> #include <cstdlib>
#include <json/json.h>
#include <fstream>
#include <string>
#include <unordered_map>
#ifndef _WIN32 #ifndef _WIN32
#include <unistd.h> #include <unistd.h>
#endif #endif
@ -33,9 +37,10 @@ std::string press::detail()
" -t num number of threads(default : 1)\n" " -t num number of threads(default : 1)\n"
" -c num concurrent connections(default : 1)\n" " -c num concurrent connections(default : 1)\n"
" -k disable SSL certificate validation(default: enable)\n" " -k disable SSL certificate validation(default: enable)\n"
" -f customize http request json file(default: disenable)\n"
" -q no progress indication(default: show)\n\n" " -q no progress indication(default: show)\n\n"
"example: drogon_ctl press -n 10000 -c 100 -t 4 -q " "example: drogon_ctl press -n 10000 -c 100 -t 4 -q "
"http://localhost:8080/index.html\n"; "http://localhost:8080/index.html -f ./http_request.json\n";
} }
void outputErrorAndExit(const std::string_view &err) void outputErrorAndExit(const std::string_view &err)
@ -151,6 +156,24 @@ void press::handleCommand(std::vector<std::string> &parameters)
continue; continue;
} }
} }
else if (param.find("-f") == 0)
{
if (param == "-f")
{
++iter;
if (iter == parameters.end())
{
outputErrorAndExit("No http request json file!");
}
httpRequestJsonFile_ = *iter;
continue;
}
else
{
httpRequestJsonFile_ = param.substr(2);
continue;
}
}
else if (param == "-k") else if (param == "-k")
{ {
certValidation_ = false; certValidation_ = false;
@ -190,6 +213,118 @@ void press::handleCommand(std::vector<std::string> &parameters)
path_ = url_.substr(posOfPath); path_ = url_.substr(posOfPath);
} }
} }
/*
http_request.json
{
"method": "POST",
"header": {
"token": "e2e9d0fe-dd14-4eaf-8ac1-0997730a805d"
},
"body": {
"passwd": "123456",
"account": "10001"
}
}
*/
if (!httpRequestJsonFile_.empty())
{
Json::Value httpRequestJson;
std::ifstream httpRequestFile(httpRequestJsonFile_,
std::ifstream::binary);
if (!httpRequestFile.is_open())
{
outputErrorAndExit(std::string{"No "} + httpRequestJsonFile_);
}
httpRequestFile >> httpRequestJson;
if (!httpRequestJson.isMember("method"))
{
outputErrorAndExit("No contain method");
}
auto methodStr = httpRequestJson["method"].asString();
std::transform(methodStr.begin(),
methodStr.end(),
methodStr.begin(),
::toupper);
auto toHttpMethod = [&]() -> drogon::HttpMethod {
if (methodStr == "GET")
{
return drogon::HttpMethod::Get;
}
else if (methodStr == "POST")
{
return drogon::HttpMethod::Post;
}
else if (methodStr == "HEAD")
{
return drogon::HttpMethod::Head;
}
else if (methodStr == "PUT")
{
return drogon::HttpMethod::Put;
}
else if (methodStr == "DELETE")
{
return drogon::HttpMethod::Delete;
}
else if (methodStr == "OPTIONS")
{
return drogon::HttpMethod::Options;
}
else if (methodStr == "PATCH")
{
return drogon::HttpMethod::Patch;
}
else
{
outputErrorAndExit("invalid method");
}
return drogon::HttpMethod::Get;
};
std::unordered_map<std::string, std::string> header;
if (httpRequestJson.isMember("header"))
{
auto &jsonValue = httpRequestJson["header"];
for (const auto &key : jsonValue.getMemberNames())
{
if (jsonValue[key].isString())
{
header[key] = jsonValue[key].asString();
}
else
{
header[key] = jsonValue[key].toStyledString();
}
}
}
std::string body;
if (httpRequestJson.isMember("body"))
{
Json::FastWriter fastWriter;
body = fastWriter.write(httpRequestJson["body"]);
}
createHttpRequestFunc_ = [this,
method = toHttpMethod(),
body = std::move(body),
header =
std::move(header)]() -> HttpRequestPtr {
auto request = HttpRequest::newHttpRequest();
request->setPath(path_);
request->setMethod(method);
for (const auto &[field, val] : header)
request->addHeader(field, val);
if (!body.empty())
request->setBody(body);
return request;
};
}
// std::cout << "host=" << host_ << std::endl; // std::cout << "host=" << host_ << std::endl;
// std::cout << "path=" << path_ << std::endl; // std::cout << "path=" << path_ << std::endl;
doTesting(); doTesting();
@ -232,9 +367,19 @@ void press::sendRequest(const HttpClientPtr &client)
{ {
return; return;
} }
auto request = HttpRequest::newHttpRequest();
HttpRequestPtr request;
if (createHttpRequestFunc_)
{
request = createHttpRequestFunc_();
}
else
{
request = HttpRequest::newHttpRequest();
request->setPath(path_); request->setPath(path_);
request->setMethod(Get); request->setMethod(Get);
}
// std::cout << "send!" << std::endl; // std::cout << "send!" << std::endl;
client->sendRequest( client->sendRequest(
request, request,

View File

@ -20,6 +20,7 @@
#include <drogon/HttpClient.h> #include <drogon/HttpClient.h>
#include <trantor/utils/Date.h> #include <trantor/utils/Date.h>
#include <trantor/net/EventLoopThreadPool.h> #include <trantor/net/EventLoopThreadPool.h>
#include <functional>
#include <string> #include <string>
#include <atomic> #include <atomic>
#include <memory> #include <memory>
@ -62,6 +63,8 @@ class press : public DrObject<press>, public CommandHandler
size_t numOfThreads_{1}; size_t numOfThreads_{1};
size_t numOfRequests_{1}; size_t numOfRequests_{1};
size_t numOfConnections_{1}; size_t numOfConnections_{1};
std::string httpRequestJsonFile_;
std::function<HttpRequestPtr()> createHttpRequestFunc_;
bool certValidation_{true}; bool certValidation_{true};
bool processIndication_{true}; bool processIndication_{true};
std::string url_; std::string url_;