Merge pull request #75 from an-tao/dev

Adapt ipv6
This commit is contained in:
An Tao 2019-03-14 09:11:38 +08:00 committed by GitHub
commit 8d6a1ed643
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 93 additions and 142 deletions

View File

@ -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);

View File

@ -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();

View File

@ -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.

View File

@ -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

View File

@ -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;

View File

@ -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)

View File

@ -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())
{

View File

@ -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;

View File

@ -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)

View File

@ -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;