mirror of
https://gitee.com/an-tao/drogon.git
synced 2024-12-02 11:47:56 +08:00
commit
8d6a1ed643
@ -98,10 +98,12 @@ int main()
|
||||
{
|
||||
|
||||
std::cout << banner << std::endl;
|
||||
app().addListener("0.0.0.0", 8848);
|
||||
app().addListener("::1", 8848);
|
||||
//app().addListener("0.0.0.0", 8848);
|
||||
#ifdef USE_OPENSSL
|
||||
//https
|
||||
//https
|
||||
drogon::HttpAppFramework::instance().setSSLFiles("server.pem", "server.pem");
|
||||
//drogon::HttpAppFramework::instance().addListener("::1", 8849, true);
|
||||
drogon::HttpAppFramework::instance().addListener("0.0.0.0", 8849, true);
|
||||
#endif
|
||||
//app().setThreadNum(4);
|
||||
|
@ -50,10 +50,35 @@ void outputGood(const HttpRequestPtr &req, bool isHttps)
|
||||
}
|
||||
void doTest(const HttpClientPtr &client, std::promise<int> &pro, bool isHttps = false)
|
||||
{
|
||||
/// Test gzip
|
||||
auto 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() == 5123)
|
||||
{
|
||||
outputGood(req, isHttps);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_DEBUG << resp->getBody().length();
|
||||
LOG_ERROR << "Error!";
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_ERROR << "Error!";
|
||||
exit(1);
|
||||
}
|
||||
});
|
||||
/// Post json
|
||||
Json::Value json;
|
||||
json["request"] = "json";
|
||||
auto req = HttpRequest::newHttpJsonRequest(json);
|
||||
req = HttpRequest::newHttpJsonRequest(json);
|
||||
req->setMethod(drogon::Post);
|
||||
req->setPath("/api/v1/apitest/json");
|
||||
client->sendRequest(req, [=](ReqResult result, const HttpResponsePtr &resp) {
|
||||
@ -346,32 +371,6 @@ void doTest(const HttpClientPtr &client, std::promise<int> &pro, bool isHttps =
|
||||
}
|
||||
});
|
||||
|
||||
/// 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() == 5123)
|
||||
{
|
||||
outputGood(req, isHttps);
|
||||
}
|
||||
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);
|
||||
@ -629,11 +628,11 @@ int main(int argc, char *argv[])
|
||||
do
|
||||
{
|
||||
std::promise<int> pro1;
|
||||
auto client = HttpClient::newHttpClient("http://127.0.0.1:8848", loop[0].getLoop());
|
||||
auto client = HttpClient::newHttpClient("::1", 8848, false, loop[0].getLoop());
|
||||
doTest(client, pro1);
|
||||
#ifdef USE_OPENSSL
|
||||
std::promise<int> pro2;
|
||||
auto sslClient = HttpClient::newHttpClient("https://127.0.0.1:8849", loop[1].getLoop());
|
||||
auto sslClient = HttpClient::newHttpClient("127.0.0.1", 8849, true, loop[1].getLoop());
|
||||
doTest(sslClient, pro2, true);
|
||||
auto f2 = pro2.get_future();
|
||||
f2.get();
|
||||
|
@ -68,6 +68,8 @@ class HttpClient : public trantor::NonCopyable
|
||||
* If the loop parameter is set to nullptr, the client
|
||||
* uses the HttpAppFramework's event loop, otherwise it
|
||||
* runs in the loop identified by the parameter.
|
||||
*
|
||||
* Note: The @param ip support for both ipv4 and ipv6 address
|
||||
*/
|
||||
static HttpClientPtr newHttpClient(const std::string &ip,
|
||||
uint16_t port,
|
||||
@ -85,6 +87,9 @@ class HttpClient : public trantor::NonCopyable
|
||||
* https://127.0.0.1:8080/
|
||||
* http://127.0.0.1
|
||||
*
|
||||
* The @param hostString must be prefixed by 'http://' or 'https://'
|
||||
* and doesn't support for ipv6 address if the host is in ip format
|
||||
*
|
||||
* If the loop parameter is set to nullptr, the client
|
||||
* uses the HttpAppFramework's event loop, otherwise it
|
||||
* runs in the loop identified by the parameter.
|
||||
|
@ -65,10 +65,7 @@ std::string urlEncode(const std::string &str);
|
||||
* @param zdata: Data after compressing or before decompressing
|
||||
* @param nzdata: Data length after compressing or before decompressing
|
||||
*/
|
||||
int gzipCompress(const char *data, const size_t ndata,
|
||||
char *zdata, size_t *nzdata);
|
||||
int gzipDecompress(const char *zdata, const size_t nzdata,
|
||||
char *data, size_t *ndata);
|
||||
std::shared_ptr<std::string> gzipCompress(const char *data, const size_t ndata);
|
||||
std::shared_ptr<std::string> gzipDecompress(const std::shared_ptr<std::string> &compressedData);
|
||||
|
||||
/// Get the http full date string
|
||||
|
@ -293,8 +293,11 @@ void HttpAppFrameworkImpl::run()
|
||||
ioLoops.push_back(loopThreadPtr->getLoop());
|
||||
for (auto const &listener : _listeners)
|
||||
{
|
||||
auto ip = std::get<0>(listener);
|
||||
bool isIpv6 = ip.find(":") == std::string::npos ? false : true;
|
||||
auto serverPtr = std::make_shared<HttpServer>(loopThreadPtr->getLoop(),
|
||||
InetAddress(std::get<0>(listener), std::get<1>(listener)), "drogon");
|
||||
InetAddress(ip, std::get<1>(listener), isIpv6),
|
||||
"drogon");
|
||||
if (std::get<2>(listener))
|
||||
{
|
||||
//enable ssl;
|
||||
@ -327,8 +330,11 @@ void HttpAppFrameworkImpl::run()
|
||||
auto loopThreadPtr = std::make_shared<EventLoopThread>("DrogonListeningLoop");
|
||||
loopThreadPtr->run();
|
||||
loopThreads.push_back(loopThreadPtr);
|
||||
auto ip = std::get<0>(listener);
|
||||
bool isIpv6 = ip.find(":") == std::string::npos ? false : true;
|
||||
auto serverPtr = std::make_shared<HttpServer>(loopThreadPtr->getLoop(),
|
||||
InetAddress(std::get<0>(listener), std::get<1>(listener)), "drogon");
|
||||
InetAddress(ip, std::get<1>(listener), isIpv6),
|
||||
"drogon");
|
||||
if (std::get<2>(listener))
|
||||
{
|
||||
//enable ssl;
|
||||
|
@ -122,7 +122,21 @@ void HttpClientImpl::sendRequestInLoop(const drogon::HttpRequestPtr &req,
|
||||
|
||||
if (!_tcpClient)
|
||||
{
|
||||
if (_server.ipNetEndian() == 0 &&
|
||||
bool hasIpv6Address = false;
|
||||
if (_server.isIpV6())
|
||||
{
|
||||
auto ipaddr = _server.ip6NetEndian();
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
if (ipaddr[i] != 0)
|
||||
{
|
||||
hasIpv6Address = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (_server.ipNetEndian() == 0 && !hasIpv6Address &&
|
||||
!_domain.empty() &&
|
||||
_server.portNetEndian() != 0)
|
||||
{
|
||||
@ -136,7 +150,8 @@ void HttpClientImpl::sendRequestInLoop(const drogon::HttpRequestPtr &req,
|
||||
}
|
||||
LOG_TRACE << "dns:domain=" << _domain << ";ip=" << _server.toIp();
|
||||
}
|
||||
if (_server.ipNetEndian() != 0 && _server.portNetEndian() != 0)
|
||||
|
||||
if ((_server.ipNetEndian() != 0 || hasIpv6Address) && _server.portNetEndian() != 0)
|
||||
{
|
||||
LOG_TRACE << "New TcpClient," << _server.toIpPort();
|
||||
_tcpClient = std::make_shared<trantor::TcpClient>(_loop, _server, "httpClient");
|
||||
@ -288,7 +303,8 @@ void HttpClientImpl::onRecvMessage(const trantor::TcpConnectionPtr &connPtr, tra
|
||||
|
||||
HttpClientPtr HttpClient::newHttpClient(const std::string &ip, uint16_t port, bool useSSL, trantor::EventLoop *loop)
|
||||
{
|
||||
return std::make_shared<HttpClientImpl>(loop == nullptr ? drogon::app().loop() : loop, trantor::InetAddress(ip, port), useSSL);
|
||||
bool isIpv6 = ip.find(":") == std::string::npos ? false : true;
|
||||
return std::make_shared<HttpClientImpl>(loop == nullptr ? drogon::app().loop() : loop, trantor::InetAddress(ip, port, isIpv6), useSSL);
|
||||
}
|
||||
|
||||
HttpClientPtr HttpClient::newHttpClient(const std::string &hostString, trantor::EventLoop *loop)
|
||||
|
@ -308,21 +308,21 @@ void HttpServer::onRequest(const TcpConnectionPtr &conn, const HttpRequestImplPt
|
||||
{
|
||||
//use gzip
|
||||
LOG_TRACE << "Use gzip to compress the body";
|
||||
char *zbuf = new char[response->getBody().length()];
|
||||
size_t zlen = response->getBody().length();
|
||||
if (gzipCompress(response->getBody().data(),
|
||||
response->getBody().length(),
|
||||
zbuf, &zlen) >= 0)
|
||||
auto strCompress = gzipCompress(response->getBody().data(),
|
||||
response->getBody().length());
|
||||
if (strCompress)
|
||||
{
|
||||
if (zlen > 0)
|
||||
{
|
||||
LOG_TRACE << "length after compressing:" << zlen;
|
||||
if (response->expiredTime() >= 0)
|
||||
{
|
||||
//cached response,we need to make a clone
|
||||
newResp = std::make_shared<HttpResponseImpl>(*std::dynamic_pointer_cast<HttpResponseImpl>(response));
|
||||
newResp->setExpiredTime(-1);
|
||||
}
|
||||
newResp->setBody(std::string(zbuf, zlen));
|
||||
newResp->setBody(std::move(*strCompress));
|
||||
newResp->addHeader("Content-Encoding", "gzip");
|
||||
}
|
||||
else
|
||||
@ -330,7 +330,6 @@ void HttpServer::onRequest(const TcpConnectionPtr &conn, const HttpRequestImplPt
|
||||
LOG_ERROR << "gzip got 0 length result";
|
||||
}
|
||||
}
|
||||
delete[] zbuf;
|
||||
}
|
||||
if (conn->getLoop()->isInLoopThread())
|
||||
{
|
||||
|
@ -19,7 +19,8 @@ void LocalHostFilter::doFilter(const HttpRequestPtr &req,
|
||||
const FilterCallback &fcb,
|
||||
const FilterChainCallback &fccb)
|
||||
{
|
||||
if (req->peerAddr().toIp() == "127.0.0.1")
|
||||
|
||||
if (req->peerAddr().isLoopbackIp())
|
||||
{
|
||||
fccb();
|
||||
return;
|
||||
|
@ -516,98 +516,28 @@ std::string urlDecode(const char *begin, const char *end)
|
||||
}
|
||||
|
||||
/* Compress gzip data */
|
||||
/* data 原数据 ndata 原数据长度 zdata 压缩后数据 nzdata 压缩后长度 */
|
||||
|
||||
int gzipCompress(const char *data, const size_t ndata,
|
||||
char *zdata, size_t *nzdata)
|
||||
std::shared_ptr<std::string> gzipCompress(const char *data, const size_t ndata)
|
||||
{
|
||||
|
||||
z_stream c_stream;
|
||||
|
||||
z_stream strm = {0};
|
||||
if (data && ndata > 0)
|
||||
{
|
||||
c_stream.zalloc = NULL;
|
||||
c_stream.zfree = NULL;
|
||||
c_stream.opaque = NULL;
|
||||
//只有设置为MAX_WBITS + 16才能在在压缩文本中带header和trailer
|
||||
if (deflateInit2(&c_stream, Z_DEFAULT_COMPRESSION, Z_DEFLATED,
|
||||
if (deflateInit2(&strm, Z_DEFAULT_COMPRESSION, Z_DEFLATED,
|
||||
MAX_WBITS + 16, 8, Z_DEFAULT_STRATEGY) != Z_OK)
|
||||
return -1;
|
||||
c_stream.next_in = (Bytef *)data;
|
||||
c_stream.avail_in = ndata;
|
||||
c_stream.next_out = (Bytef *)zdata;
|
||||
c_stream.avail_out = *nzdata;
|
||||
while (c_stream.avail_in != 0 && c_stream.total_out < *nzdata)
|
||||
{
|
||||
if (deflate(&c_stream, Z_NO_FLUSH) != Z_OK)
|
||||
{
|
||||
LOG_ERROR << "compress err:" << c_stream.msg;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
if (c_stream.avail_in != 0)
|
||||
return c_stream.avail_in;
|
||||
for (;;)
|
||||
{
|
||||
int err = 0;
|
||||
if ((err = deflate(&c_stream, Z_FINISH)) == Z_STREAM_END)
|
||||
break;
|
||||
if (err != Z_OK)
|
||||
return -1;
|
||||
}
|
||||
if (deflateEnd(&c_stream) != Z_OK)
|
||||
return -1;
|
||||
*nzdata = c_stream.total_out;
|
||||
return 0;
|
||||
return nullptr;
|
||||
auto outstr = std::make_shared<std::string>();
|
||||
outstr->resize(compressBound(ndata));
|
||||
strm.next_in = (Bytef *)data;
|
||||
strm.avail_in = ndata;
|
||||
strm.next_out = (Bytef *)outstr->data();
|
||||
strm.avail_out = outstr->length();
|
||||
if (deflate(&strm, Z_FINISH) != Z_STREAM_END)
|
||||
return nullptr;
|
||||
if (deflateEnd(&strm) != Z_OK)
|
||||
return nullptr;
|
||||
outstr->resize(strm.total_out);
|
||||
return outstr;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Uncompress gzip data */
|
||||
/* zdata 数据 nzdata 原数据长度 data 解压后数据 ndata 解压后长度 */
|
||||
int gzipDecompress(const char *zdata, const size_t nzdata,
|
||||
char *data, size_t *ndata)
|
||||
{
|
||||
z_stream d_stream = {0}; /* decompression stream */
|
||||
static char dummy_head[2] = {
|
||||
0x8 + 0x7 * 0x10,
|
||||
(((0x8 + 0x7 * 0x10) * 0x100 + 30) / 31 * 31) & 0xFF,
|
||||
};
|
||||
d_stream.zalloc = NULL;
|
||||
d_stream.zfree = NULL;
|
||||
d_stream.opaque = NULL;
|
||||
d_stream.next_in = (Bytef *)zdata;
|
||||
d_stream.avail_in = 0;
|
||||
d_stream.next_out = (Bytef *)data;
|
||||
//只有设置为MAX_WBITS + 16才能在解压带header和trailer的文本
|
||||
if (inflateInit2(&d_stream, MAX_WBITS + 16) != Z_OK)
|
||||
return -1;
|
||||
//if(inflateInit2(&d_stream, 47) != Z_OK) return -1;
|
||||
while (d_stream.total_out < *ndata && d_stream.total_in < nzdata)
|
||||
{
|
||||
int err = 0;
|
||||
d_stream.avail_in = d_stream.avail_out = 1; /* force small buffers */
|
||||
if ((err = inflate(&d_stream, Z_NO_FLUSH)) == Z_STREAM_END)
|
||||
break;
|
||||
if (err != Z_OK)
|
||||
{
|
||||
if (err == Z_DATA_ERROR)
|
||||
{
|
||||
d_stream.next_in = (Bytef *)dummy_head;
|
||||
d_stream.avail_in = sizeof(dummy_head);
|
||||
if ((err = inflate(&d_stream, Z_NO_FLUSH)) != Z_OK)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
if (inflateEnd(&d_stream) != Z_OK)
|
||||
return -1;
|
||||
*ndata = d_stream.total_out;
|
||||
return 0;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::shared_ptr<std::string> gzipDecompress(const std::shared_ptr<std::string> &compressedData)
|
||||
|
@ -304,16 +304,12 @@ int main()
|
||||
"mobile\n"
|
||||
"origin\n"
|
||||
"rawpacket";
|
||||
std::string out;
|
||||
out.resize(inStr.length());
|
||||
size_t len = out.length();
|
||||
auto ret=gzipCompress(inStr.c_str(), inStr.length(), (char *)(out.data()), &len);
|
||||
if(ret==0)
|
||||
auto ret=gzipCompress(inStr.c_str(), inStr.length());
|
||||
if(ret)
|
||||
{
|
||||
out.resize(len);
|
||||
std::cout << "origin length=" << inStr.length() << " compressing length=" << out.length() << std::endl;
|
||||
std::cout << "origin length=" << inStr.length() << " compressing length=" << ret->length() << std::endl;
|
||||
|
||||
auto decompressStr = gzipDecompress(std::make_shared<std::string>(out));
|
||||
auto decompressStr = gzipDecompress(ret);
|
||||
if (decompressStr)
|
||||
{
|
||||
std::cout << "decompressing length=" << decompressStr->length() << std::endl;
|
||||
|
Loading…
Reference in New Issue
Block a user