Optimize response caching

This commit is contained in:
antao 2018-10-13 21:49:37 +08:00
parent 74e46d9b02
commit 0a3d27a5b0
7 changed files with 1121 additions and 1074 deletions

1
.gitignore vendored
View File

@ -39,3 +39,4 @@ lib/inc/drogon/config.h
Doxyfile
html/
latex/
.vscode

View File

@ -136,5 +136,3 @@ install(FILES ${drogon_util_headers}
DESTINATION include/drogon/utils)
install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/lib/inc/drogon/version.h"
DESTINATION include/drogon)
#target_link_libraries(drogon trantor pthread)

View File

@ -6,141 +6,140 @@
#include <string>
using namespace drogon;
class A:public DrObjectBase
class A : public DrObjectBase
{
public:
void handle(const HttpRequestPtr& req,
const std::function<void (const HttpResponsePtr &)>&callback,
int p1,const std::string &p2,const std::string &p3,int p4) const
public:
void handle(const HttpRequestPtr &req,
const std::function<void(const HttpResponsePtr &)> &callback,
int p1, const std::string &p2, const std::string &p3, int p4) const
{
HttpViewData data;
data.insert("title",std::string("ApiTest::get"));
std::map<std::string,std::string> para;
para["int p1"]=std::to_string(p1);
para["string p2"]=p2;
para["string p3"]=p3;
para["int p4"]=std::to_string(p4);
data.insert("title", std::string("ApiTest::get"));
std::map<std::string, std::string> para;
para["int p1"] = std::to_string(p1);
para["string p2"] = p2;
para["string p3"] = p3;
para["int p4"] = std::to_string(p4);
data.insert("parameters",para);
auto res=HttpResponse::newHttpViewResponse("ListParaView",data);
data.insert("parameters", para);
auto res = HttpResponse::newHttpViewResponse("ListParaView", data);
callback(res);
}
static void staticHandle(const HttpRequestPtr& req,
const std::function<void (const HttpResponsePtr &)>&callback,
int p1,const std::string &p2,const std::string &p3,int p4)
static void staticHandle(const HttpRequestPtr &req,
const std::function<void(const HttpResponsePtr &)> &callback,
int p1, const std::string &p2, const std::string &p3, int p4)
{
HttpViewData data;
data.insert("title",std::string("ApiTest::get"));
std::map<std::string,std::string> para;
para["int p1"]=std::to_string(p1);
para["string p2"]=p2;
para["string p3"]=p3;
para["int p4"]=std::to_string(p4);
data.insert("title", std::string("ApiTest::get"));
std::map<std::string, std::string> para;
para["int p1"] = std::to_string(p1);
para["string p2"] = p2;
para["string p3"] = p3;
para["int p4"] = std::to_string(p4);
data.insert("parameters",para);
auto res=HttpResponse::newHttpViewResponse("ListParaView",data);
data.insert("parameters", para);
auto res = HttpResponse::newHttpViewResponse("ListParaView", data);
callback(res);
}
};
class B:public DrObjectBase
class B : public DrObjectBase
{
public:
void operator ()(const HttpRequestPtr& req,const std::function<void (const HttpResponsePtr &)>&callback,int p1,int p2)
public:
void operator()(const HttpRequestPtr &req, const std::function<void(const HttpResponsePtr &)> &callback, int p1, int p2)
{
HttpViewData data;
data.insert("title",std::string("ApiTest::get"));
std::map<std::string,std::string> para;
para["p1"]=std::to_string(p1);
para["p2"]=std::to_string(p2);
data.insert("parameters",para);
auto res=HttpResponse::newHttpViewResponse("ListParaView",data);
data.insert("title", std::string("ApiTest::get"));
std::map<std::string, std::string> para;
para["p1"] = std::to_string(p1);
para["p2"] = std::to_string(p2);
data.insert("parameters", para);
auto res = HttpResponse::newHttpViewResponse("ListParaView", data);
callback(res);
}
};
namespace api
{
namespace v1
namespace v1
{
class Test : public HttpApiController<Test>
{
public:
METHOD_LIST_BEGIN
METHOD_ADD(Test::get, "get/{2}/{1}", "drogon::GetFilter"); //path will be /api/v1/test/get/{arg2}/{arg1}
METHOD_ADD(Test::list, "/{2}/info", "drogon::GetFilter"); //path will be /api/v1/test/{arg2}/info
METHOD_LIST_END
void get(const HttpRequestPtr &req, const std::function<void(const HttpResponsePtr &)> &callback, int p1, int p2) const
{
class Test:public HttpApiController<Test>
{
public:
METHOD_LIST_BEGIN
METHOD_ADD(Test::get,"get/{2}/{1}","drogon::GetFilter");//path will be /api/v1/test/get/{arg2}/{arg1}
METHOD_ADD(Test::list,"/{2}/info","drogon::GetFilter");//path will be /api/v1/test/{arg2}/info
METHOD_LIST_END
void get(const HttpRequestPtr& req,const std::function<void (const HttpResponsePtr &)>&callback,int p1,int p2) const
{
HttpViewData data;
data.insert("title",std::string("ApiTest::get"));
std::map<std::string,std::string> para;
para["p1"]=std::to_string(p1);
para["p2"]=std::to_string(p2);
data.insert("parameters",para);
auto res=HttpResponse::newHttpViewResponse("ListParaView",data);
callback(res);
}
void list(const HttpRequestPtr& req,const std::function<void (const HttpResponsePtr &)>&callback,int p1,int p2) const
{
HttpViewData data;
data.insert("title",std::string("ApiTest::get"));
std::map<std::string,std::string> para;
para["p1"]=std::to_string(p1);
para["p2"]=std::to_string(p2);
data.insert("parameters",para);
auto res=HttpResponse::newHttpViewResponse("ListParaView",data);
callback(res);
}
};
HttpViewData data;
data.insert("title", std::string("ApiTest::get"));
std::map<std::string, std::string> para;
para["p1"] = std::to_string(p1);
para["p2"] = std::to_string(p2);
data.insert("parameters", para);
auto res = HttpResponse::newHttpViewResponse("ListParaView", data);
callback(res);
}
}
void list(const HttpRequestPtr &req, const std::function<void(const HttpResponsePtr &)> &callback, int p1, int p2) const
{
HttpViewData data;
data.insert("title", std::string("ApiTest::get"));
std::map<std::string, std::string> para;
para["p1"] = std::to_string(p1);
para["p2"] = std::to_string(p2);
data.insert("parameters", para);
auto res = HttpResponse::newHttpViewResponse("ListParaView", data);
callback(res);
}
};
} // namespace v1
} // namespace api
using namespace std::placeholders;
int main()
{
std::cout<<banner<<std::endl;
std::cout << banner << std::endl;
// drogon::HttpAppFramework::instance().addListener("0.0.0.0",12345);
drogon::HttpAppFramework::instance().addListener("0.0.0.0",8080);
//#ifdef USE_OPENSSL
// //https
// drogon::HttpAppFramework::instance().setSSLFiles("server.pem","server.pem");
// drogon::HttpAppFramework::instance().addListener("0.0.0.0",4430,true);
// drogon::HttpAppFramework::instance().addListener("0.0.0.0",4431,true);
//#endif
// drogon::HttpAppFramework::instance().addListener("0.0.0.0",12345);
drogon::HttpAppFramework::instance().addListener("0.0.0.0", 8080);
//#ifdef USE_OPENSSL
// //https
// drogon::HttpAppFramework::instance().setSSLFiles("server.pem","server.pem");
// drogon::HttpAppFramework::instance().addListener("0.0.0.0",4430,true);
// drogon::HttpAppFramework::instance().addListener("0.0.0.0",4431,true);
//#endif
drogon::HttpAppFramework::instance().setThreadNum(4);
// trantor::Logger::setLogLevel(trantor::Logger::TRACE);
// trantor::Logger::setLogLevel(trantor::Logger::TRACE);
//class function
drogon::HttpAppFramework::registerHttpApiMethod("/api/v1/handle1/{1}/{2}/?p3={3}&p4={4}",&A::handle);
drogon::HttpAppFramework::registerHttpApiMethod("/api/v1/handle11/{1}/{2}/?p3={3}&p4={4}",&A::staticHandle);
drogon::HttpAppFramework::registerHttpApiMethod("/api/v1/handle1/{1}/{2}/?p3={3}&p4={4}", &A::handle);
drogon::HttpAppFramework::registerHttpApiMethod("/api/v1/handle11/{1}/{2}/?p3={3}&p4={4}", &A::staticHandle);
//lambda example
drogon::HttpAppFramework::registerHttpApiMethod("/api/v1/handle2/{1}/{2}",[](const HttpRequestPtr&req,const std::function<void (const HttpResponsePtr &)>&callback,int a,float b){
LOG_DEBUG<<"int a="<<a;
LOG_DEBUG<<"float b="<<b;
drogon::HttpAppFramework::registerHttpApiMethod("/api/v1/handle2/{1}/{2}", [](const HttpRequestPtr &req, const std::function<void(const HttpResponsePtr &)> &callback, int a, float b) {
LOG_DEBUG << "int a=" << a;
LOG_DEBUG << "float b=" << b;
HttpViewData data;
data.insert("title",std::string("ApiTest::get"));
std::map<std::string,std::string> para;
para["a"]=std::to_string(a);
para["b"]=std::to_string(b);
data.insert("parameters",para);
auto res=HttpResponse::newHttpViewResponse("ListParaView",data);
data.insert("title", std::string("ApiTest::get"));
std::map<std::string, std::string> para;
para["a"] = std::to_string(a);
para["b"] = std::to_string(b);
data.insert("parameters", para);
auto res = HttpResponse::newHttpViewResponse("ListParaView", data);
callback(res);
});
B b;
//functor example
drogon::HttpAppFramework::registerHttpApiMethod("/api/v1/handle3/{1}/{2}",b);
drogon::HttpAppFramework::registerHttpApiMethod("/api/v1/handle3/{1}/{2}", b);
A tmp;
std::function<void(const HttpRequestPtr&,const std::function<void (const HttpResponsePtr &)>&,int,const std::string &,const std::string &,int)>
func=std::bind(&A::handle,&tmp,_1,_2,_3,_4,_5,_6);
std::function<void(const HttpRequestPtr &, const std::function<void(const HttpResponsePtr &)> &, int, const std::string &, const std::string &, int)>
func = std::bind(&A::handle, &tmp, _1, _2, _3, _4, _5, _6);
//api example for std::function
drogon::HttpAppFramework::registerHttpApiMethod("/api/v1/handle4/{4}/{3}/{1}",func);
drogon::HttpAppFramework::registerHttpApiMethod("/api/v1/handle4/{4}/{3}/{1}", func);
drogon::HttpAppFramework::instance().setDocumentRoot("./");
drogon::HttpAppFramework::instance().enableSession(1200);
drogon::HttpAppFramework::instance().enableSession(60);
//start app framework
//drogon::HttpAppFramework::instance().enableDynamicViewsLoading({"/tmp/views"});
drogon::HttpAppFramework::instance().loadConfigFile("../../config.json.example");
// drogon::HttpAppFramework::instance().loadConfigFile("../../config.json.example");
drogon::HttpAppFramework::instance().run();
}

File diff suppressed because it is too large Load Diff

View File

@ -42,7 +42,7 @@ HttpResponsePtr HttpResponse::newHttpResponse()
HttpResponsePtr HttpResponse::newHttpJsonResponse(const Json::Value &data)
{
auto res=std::make_shared<HttpResponseImpl>();
auto res = std::make_shared<HttpResponseImpl>();
res->setStatusCode(HttpResponse::k200OK);
res->setContentTypeCode(CT_APPLICATION_JSON);
Json::StreamWriterBuilder builder;
@ -54,8 +54,8 @@ HttpResponsePtr HttpResponse::newHttpJsonResponse(const Json::Value &data)
HttpResponsePtr HttpResponse::newNotFoundResponse()
{
HttpViewData data;
data.insert("version",getVersion());
auto res=HttpResponse::newHttpViewResponse("NotFound",data);
data.insert("version", getVersion());
auto res = HttpResponse::newHttpViewResponse("NotFound", data);
res->setStatusCode(HttpResponse::k404NotFound);
//res->setCloseConnection(true);
@ -63,291 +63,302 @@ HttpResponsePtr HttpResponse::newNotFoundResponse()
}
HttpResponsePtr HttpResponse::newLocationRedirectResponse(const std::string &path)
{
auto res=std::make_shared<HttpResponseImpl>();
auto res = std::make_shared<HttpResponseImpl>();
res->setStatusCode(HttpResponse::k302Found);
res->redirect(path.c_str());
return res;
}
HttpResponsePtr HttpResponse::newHttpViewResponse(const std::string &viewName,const HttpViewData& data)
HttpResponsePtr HttpResponse::newHttpViewResponse(const std::string &viewName, const HttpViewData &data)
{
return HttpViewBase::genHttpResponse(viewName,data);
return HttpViewBase::genHttpResponse(viewName, data);
}
const std::string HttpResponseImpl::web_content_type_and_charset_to_string(uint8_t contenttype,const std::string &charSet)
const std::string HttpResponseImpl::web_content_type_and_charset_to_string(uint8_t contenttype, const std::string &charSet)
{
switch(contenttype) {
case CT_TEXT_HTML:
return "text/html; charset="+charSet;
switch (contenttype)
{
case CT_TEXT_HTML:
return "text/html; charset=" + charSet;
case CT_APPLICATION_XML:
return "application/xml; charset="+charSet;
case CT_APPLICATION_XML:
return "application/xml; charset=" + charSet;
case CT_APPLICATION_JSON:
return "application/json; charset="+charSet;
case CT_APPLICATION_JSON:
return "application/json; charset=" + charSet;
case CT_APPLICATION_X_JAVASCRIPT:
return "application/x-javascript; charset="+charSet;
case CT_APPLICATION_X_JAVASCRIPT:
return "application/x-javascript; charset=" + charSet;
case CT_TEXT_CSS:
return "text/css; charset="+charSet;
case CT_TEXT_CSS:
return "text/css; charset=" + charSet;
case CT_TEXT_XML:
return "text/xml; charset="+charSet;
case CT_TEXT_XML:
return "text/xml; charset=" + charSet;
case CT_TEXT_XSL:
return "text/xsl; charset="+charSet;
case CT_TEXT_XSL:
return "text/xsl; charset=" + charSet;
case CT_APPLICATION_OCTET_STREAM:
return "application/octet-stream";
case CT_APPLICATION_OCTET_STREAM:
return "application/octet-stream";
case CT_IMAGE_SVG_XML:
return "image/svg+xml";
case CT_IMAGE_SVG_XML:
return "image/svg+xml";
case CT_APPLICATION_X_FONT_TRUETYPE:
return "application/x-font-truetype";
case CT_APPLICATION_X_FONT_TRUETYPE:
return "application/x-font-truetype";
case CT_APPLICATION_X_FONT_OPENTYPE:
return "application/x-font-opentype";
case CT_APPLICATION_X_FONT_OPENTYPE:
return "application/x-font-opentype";
case CT_APPLICATION_FONT_WOFF:
return "application/font-woff";
case CT_APPLICATION_FONT_WOFF:
return "application/font-woff";
case CT_APPLICATION_FONT_WOFF2:
return "application/font-woff2";
case CT_APPLICATION_FONT_WOFF2:
return "application/font-woff2";
case CT_APPLICATION_VND_MS_FONTOBJ:
return "application/vnd.ms-fontobject";
case CT_APPLICATION_VND_MS_FONTOBJ:
return "application/vnd.ms-fontobject";
case CT_IMAGE_PNG:
return "image/png";
case CT_IMAGE_PNG:
return "image/png";
case CT_IMAGE_JPG:
return "image/jpeg";
case CT_IMAGE_JPG:
return "image/jpeg";
case CT_IMAGE_GIF:
return "image/gif";
case CT_IMAGE_GIF:
return "image/gif";
case CT_IMAGE_XICON:
return "image/x-icon";
case CT_IMAGE_XICON:
return "image/x-icon";
case CT_IMAGE_BMP:
return "image/bmp";
case CT_IMAGE_BMP:
return "image/bmp";
case CT_IMAGE_ICNS:
return "image/icns";
case CT_IMAGE_ICNS:
return "image/icns";
default:
case CT_TEXT_PLAIN:
return "text/plain; charset="+charSet;
default:
case CT_TEXT_PLAIN:
return "text/plain; charset=" + charSet;
}
}
std::string HttpResponseImpl::web_content_type_to_string(uint8_t contenttype)
{
switch(contenttype) {
case CT_TEXT_HTML:
return "text/html; charset=utf-8";
switch (contenttype)
{
case CT_TEXT_HTML:
return "text/html; charset=utf-8";
case CT_APPLICATION_XML:
return "application/xml; charset=utf-8";
case CT_APPLICATION_XML:
return "application/xml; charset=utf-8";
case CT_APPLICATION_JSON:
return "application/json; charset=utf-8";
case CT_APPLICATION_JSON:
return "application/json; charset=utf-8";
case CT_APPLICATION_X_JAVASCRIPT:
return "application/x-javascript; charset=utf-8";
case CT_APPLICATION_X_JAVASCRIPT:
return "application/x-javascript; charset=utf-8";
case CT_TEXT_CSS:
return "text/css; charset=utf-8";
case CT_TEXT_CSS:
return "text/css; charset=utf-8";
case CT_TEXT_XML:
return "text/xml; charset=utf-8";
case CT_TEXT_XML:
return "text/xml; charset=utf-8";
case CT_TEXT_XSL:
return "text/xsl; charset=utf-8";
case CT_TEXT_XSL:
return "text/xsl; charset=utf-8";
case CT_APPLICATION_OCTET_STREAM:
return "application/octet-stream";
case CT_APPLICATION_OCTET_STREAM:
return "application/octet-stream";
case CT_IMAGE_SVG_XML:
return "image/svg+xml";
case CT_IMAGE_SVG_XML:
return "image/svg+xml";
case CT_APPLICATION_X_FONT_TRUETYPE:
return "application/x-font-truetype";
case CT_APPLICATION_X_FONT_TRUETYPE:
return "application/x-font-truetype";
case CT_APPLICATION_X_FONT_OPENTYPE:
return "application/x-font-opentype";
case CT_APPLICATION_X_FONT_OPENTYPE:
return "application/x-font-opentype";
case CT_APPLICATION_FONT_WOFF:
return "application/font-woff";
case CT_APPLICATION_FONT_WOFF:
return "application/font-woff";
case CT_APPLICATION_FONT_WOFF2:
return "application/font-woff2";
case CT_APPLICATION_FONT_WOFF2:
return "application/font-woff2";
case CT_APPLICATION_VND_MS_FONTOBJ:
return "application/vnd.ms-fontobject";
case CT_APPLICATION_VND_MS_FONTOBJ:
return "application/vnd.ms-fontobject";
case CT_IMAGE_PNG:
return "image/png";
case CT_IMAGE_PNG:
return "image/png";
case CT_IMAGE_JPG:
return "image/jpeg";
case CT_IMAGE_JPG:
return "image/jpeg";
case CT_IMAGE_GIF:
return "image/gif";
case CT_IMAGE_GIF:
return "image/gif";
case CT_IMAGE_XICON:
return "image/x-icon";
case CT_IMAGE_XICON:
return "image/x-icon";
case CT_IMAGE_BMP:
return "image/bmp";
case CT_IMAGE_BMP:
return "image/bmp";
case CT_IMAGE_ICNS:
return "image/icns";
case CT_IMAGE_ICNS:
return "image/icns";
default:
case CT_TEXT_PLAIN:
return "text/plain; charset=utf-8";
default:
case CT_TEXT_PLAIN:
return "text/plain; charset=utf-8";
}
}
std::string HttpResponseImpl::web_response_code_to_string(int code)
{
switch(code) {
case 100:
return "Continue";
case 101:
return "Switching Protocols";
case 200:
return "OK";
case 201:
return "Created";
case 202:
return "Accepted";
case 203:
return "Non-Authoritative Information";
case 204:
return "No Content";
case 205:
return "Reset Content";
case 206:
return "Partial Content";
case 300:
return "Multiple Choices";
case 301:
return "Moved Permanently";
case 302:
return "Found";
case 303:
return "See Other";
case 304:
return "Not Modified";
case 305:
return "Use Proxy";
case 307:
return "Temporary Redirect";
case 400:
switch (code)
{
case 100:
return "Continue";
case 101:
return "Switching Protocols";
case 200:
return "OK";
case 201:
return "Created";
case 202:
return "Accepted";
case 203:
return "Non-Authoritative Information";
case 204:
return "No Content";
case 205:
return "Reset Content";
case 206:
return "Partial Content";
case 300:
return "Multiple Choices";
case 301:
return "Moved Permanently";
case 302:
return "Found";
case 303:
return "See Other";
case 304:
return "Not Modified";
case 305:
return "Use Proxy";
case 307:
return "Temporary Redirect";
case 400:
return "Bad Request";
case 401:
return "Unauthorized";
case 402:
return "Payment Required";
case 403:
return "Forbidden";
case 404:
return "Not Found";
case 405:
return "Method Not Allowed";
case 406:
return "Not Acceptable";
case 407:
return "Proxy Authentication Required";
case 408:
return "Request Time-out";
case 409:
return "Conflict";
case 410:
return "Gone";
case 411:
return "Length Required";
case 412:
return "Precondition Failed";
case 413:
return "Request Entity Too Large";
case 414:
return "Request-URI Too Large";
case 415:
return "Unsupported Media Type";
case 416:
return "Requested range not satisfiable";
case 417:
return "Expectation Failed";
case 500:
return "Internal Server Error";
case 501:
return "Not Implemented";
case 502:
return "Bad Gateway";
case 503:
return "Service Unavailable";
case 504:
return "Gateway Time-out";
case 505:
return "HTTP Version not supported";
default:
if (code >= 100 && code < 200)
return "Informational";
if (code >= 200 && code < 300)
return "Successful";
if (code >= 300 && code < 400)
return "Redirection";
if (code >= 400 && code < 500)
return "Bad Request";
case 401:
return "Unauthorized";
case 402:
return "Payment Required";
case 403:
return "Forbidden";
case 404:
return "Not Found";
case 405:
return "Method Not Allowed";
case 406:
return "Not Acceptable";
case 407:
return "Proxy Authentication Required";
case 408:
return "Request Time-out";
case 409:
return "Conflict";
case 410:
return "Gone";
case 411:
return "Length Required";
case 412:
return "Precondition Failed";
case 413:
return "Request Entity Too Large";
case 414:
return "Request-URI Too Large";
case 415:
return "Unsupported Media Type";
case 416:
return "Requested range not satisfiable";
case 417:
return "Expectation Failed";
case 500:
return "Internal Server Error";
case 501:
return "Not Implemented";
case 502:
return "Bad Gateway";
case 503:
return "Service Unavailable";
case 504:
return "Gateway Time-out";
case 505:
return "HTTP Version not supported";
default:
if(code >= 100 && code < 200)
return "Informational";
if(code >= 200 && code < 300)
return "Successful";
if (code >= 500 && code < 600)
return "Server Error";
if(code >= 300 && code < 400)
return "Redirection";
if(code >= 400 && code < 500)
return "Bad Request";
if(code >= 500 && code < 600)
return "Server Error";
return "Undefined Error";
return "Undefined Error";
}
}
void HttpResponseImpl::makeHeaderString(MsgBuffer* output) const
void HttpResponseImpl::makeHeaderString(MsgBuffer *output) const
{
char buf[64];
snprintf(buf, sizeof buf, "HTTP/1.1 %d ", _statusCode);
output->append(buf);
output->append(_statusMessage);
output->append("\r\n");
if (_sendfileName.empty()) {
if (_sendfileName.empty())
{
snprintf(buf, sizeof buf, "Content-Length: %lu\r\n", _body.size());
} else {
}
else
{
struct stat filestat;
if (stat(_sendfileName.c_str(), &filestat) < 0) {
if (stat(_sendfileName.c_str(), &filestat) < 0)
{
LOG_SYSERR << _sendfileName << " stat error";
return;
}
#ifdef __linux__
snprintf(buf, sizeof buf, "Content-Length: %ld\r\n",filestat.st_size);
snprintf(buf, sizeof buf, "Content-Length: %ld\r\n", filestat.st_size);
#else
snprintf(buf, sizeof buf, "Content-Length: %lld\r\n", filestat.st_size);
#endif
}
output->append(buf);
if (_headers.find("Connection") == _headers.end()) {
if (_closeConnection) {
if (_headers.find("Connection") == _headers.end())
{
if (_closeConnection)
{
output->append("Connection: close\r\n");
} else {
}
else
{
//output->append("Connection: Keep-Alive\r\n");
}
}
for (auto it = _headers.begin();
it != _headers.end();
++it) {
++it)
{
output->append(it->first);
output->append(": ");
output->append(it->second);
@ -357,24 +368,24 @@ void HttpResponseImpl::makeHeaderString(MsgBuffer* output) const
output->append("Server: drogon/");
output->append(drogon::getVersion());
output->append("\r\n");
if(_expriedTime>=0)
_fullHeaderString=std::string(output->peek(),output->readableBytes());
}
void HttpResponseImpl::appendToBuffer(MsgBuffer* output) const {
if(_fullHeaderString.empty())
void HttpResponseImpl::appendToBuffer(MsgBuffer *output) const
{
if (!_fullHeaderString)
{
makeHeaderString(output);
}
else
{
output->append(_fullHeaderString);
output->append(*_fullHeaderString);
}
//output cookies
if(_cookies.size() > 0) {
for(auto it = _cookies.begin(); it != _cookies.end(); it++) {
if (_cookies.size() > 0)
{
for (auto it = _cookies.begin(); it != _cookies.end(); it++)
{
output->append(it->second.cookieString());
}
@ -385,7 +396,6 @@ void HttpResponseImpl::appendToBuffer(MsgBuffer* output) const {
output->append(getHttpFullDate(trantor::Date::date()));
output->append("\r\n\r\n");
LOG_TRACE<<"reponse(no body):"<<output->peek();
output->append(_body);
LOG_TRACE << "reponse(no body):" << output->peek();
output->append(_body);
}

View File

@ -8,7 +8,6 @@
//
// This is a public header file, it must only include public header files.
//taken from muduo and modified
/**
@ -25,8 +24,6 @@
*
*/
#pragma once
#include <drogon/HttpResponse.h>
@ -36,305 +33,321 @@
#include <drogon/utils/Utilities.h>
#include <map>
#include <string>
#include <memory>
using namespace trantor;
namespace drogon
{
class HttpResponseImpl:public HttpResponse
class HttpResponseImpl : public HttpResponse
{
friend class HttpContext;
public:
explicit HttpResponseImpl()
: _statusCode(kUnknown),
_closeConnection(false),
_left_body_length(0),
_current_chunk_length(0)
{
friend class HttpContext;
public:
}
virtual HttpStatusCode statusCode() override
{
return _statusCode;
}
virtual void setStatusCode(HttpStatusCode code) override
{
_statusCode = code;
setStatusMessage(web_response_code_to_string(code));
}
explicit HttpResponseImpl()
: _statusCode(kUnknown),
_closeConnection(false),
_left_body_length(0),
_current_chunk_length(0)
{
virtual void setStatusCode(HttpStatusCode code, const std::string &status_message) override
{
_statusCode = code;
setStatusMessage(status_message);
}
}
virtual HttpStatusCode statusCode() override
{
return _statusCode;
}
virtual void setStatusCode(HttpStatusCode code) override
{
_statusCode = code;
setStatusMessage(web_response_code_to_string(code));
}
virtual void setVersion(const Version v) override
{
_v = v;
}
virtual void setStatusCode(HttpStatusCode code, const std::string& status_message) override
{
_statusCode = code;
setStatusMessage(status_message);
}
virtual void setCloseConnection(bool on) override
{
_closeConnection = on;
}
virtual void setVersion(const Version v) override
{
_v = v;
}
virtual bool closeConnection() const override
{
return _closeConnection;
}
virtual void setContentTypeCode(uint8_t type) override
{
_contentType = type;
setContentType(web_content_type_to_string(type));
}
virtual void setCloseConnection(bool on) override
{
_closeConnection = on;
}
virtual void setContentTypeCodeAndCharacterSet(uint8_t type, const std::string charSet = "utf-8") override
{
_contentType = type;
setContentType(web_content_type_and_charset_to_string(type, charSet));
}
virtual bool closeConnection() const override
{
return _closeConnection;
}
virtual uint8_t getContentTypeCode() override
{
return _contentType;
}
// virtual uint8_t contentTypeCode() override
// {
// return _contentType;
// }
virtual void setContentTypeCode(uint8_t type) override
virtual std::string getHeader(const std::string &key) const override
{
auto field = key;
transform(field.begin(), field.end(), field.begin(), ::tolower);
auto iter = _headers.find(field);
if (iter == _headers.end())
{
_contentType=type;
setContentType(web_content_type_to_string(type));
return "";
}
else
{
return iter->second;
}
}
virtual void addHeader(const std::string &key, const std::string &value) override
{
_fullHeaderString.reset();
auto field = key;
transform(field.begin(), field.end(), field.begin(), ::tolower);
_headers[field] = value;
}
virtual void setContentTypeCodeAndCharacterSet(uint8_t type,const std::string charSet="utf-8") override
{
_contentType=type;
setContentType(web_content_type_and_charset_to_string(type,charSet));
}
virtual void addHeader(const std::string &key, std::string &&value) override
{
_fullHeaderString.reset();
auto field = key;
transform(field.begin(), field.end(), field.begin(), ::tolower);
_headers[field] = std::move(value);
}
virtual uint8_t getContentTypeCode() override
virtual void addHeader(const char *start, const char *colon, const char *end) override
{
_fullHeaderString.reset();
std::string field(start, colon);
transform(field.begin(), field.end(), field.begin(), ::tolower);
++colon;
while (colon < end && isspace(*colon))
{
return _contentType;
}
// virtual uint8_t contentTypeCode() override
// {
// return _contentType;
// }
virtual std::string getHeader(const std::string& key) const override
{
auto field=key;
transform(field.begin(), field.end(), field.begin(), ::tolower);
auto iter=_headers.find(field);
if(iter == _headers.end())
{
return "";
}
else
{
return iter->second;
}
}
virtual void addHeader(const std::string& key, const std::string& value) override
{
auto field=key;
transform(field.begin(), field.end(), field.begin(), ::tolower);
_headers[field] = value;
}
virtual void addHeader(const std::string& key, std::string&& value) override
{
auto field=key;
transform(field.begin(), field.end(), field.begin(), ::tolower);
_headers[field] = std::move(value);
}
virtual void addHeader(const char* start, const char* colon, const char* end) override
{
std::string field(start, colon);
transform(field.begin(), field.end(), field.begin(), ::tolower);
++colon;
while (colon < end && isspace(*colon)) {
++colon;
}
std::string value(colon, end);
while (!value.empty() && isspace(value[value.size() - 1])) {
value.resize(value.size() - 1);
}
_headers[field] = value;
}
std::string value(colon, end);
while (!value.empty() && isspace(value[value.size() - 1]))
{
value.resize(value.size() - 1);
}
_headers[field] = value;
//FIXME:reponse cookie should be "Set-Cookie:...."
if(field == "cookie") {
//LOG_INFO<<"cookies!!!:"<<value;
std::string::size_type pos;
while((pos = value.find(";")) != std::string::npos) {
std::string coo = value.substr(0, pos);
auto epos = coo.find("=");
if(epos != std::string::npos) {
std::string cookie_name = coo.substr(0, epos);
std::string::size_type cpos=0;
while(cpos<cookie_name.length()&&isspace(cookie_name[cpos]))
cpos++;
cookie_name=cookie_name.substr(cpos);
std::string cookie_value = coo.substr(epos + 1);
_cookies.insert(std::make_pair(cookie_name,Cookie(cookie_name,cookie_value)));
}
value=value.substr(pos+1);
}
if(value.length()>0)
{
std::string &coo = value;
auto epos = coo.find("=");
if(epos != std::string::npos) {
std::string cookie_name = coo.substr(0, epos);
std::string::size_type cpos=0;
while(cpos<cookie_name.length()&&isspace(cookie_name[cpos]))
cpos++;
cookie_name=cookie_name.substr(cpos);
std::string cookie_value = coo.substr(epos + 1);
_cookies.insert(std::make_pair(cookie_name,Cookie(cookie_name,cookie_value)));
}
}
}
}
virtual void addCookie(const std::string& key, const std::string& value) override
//FIXME:reponse cookie should be "Set-Cookie:...."
if (field == "cookie")
{
_cookies.insert(std::make_pair(key,Cookie(key,value)));
}
virtual void addCookie(const Cookie &cookie) override
{
_cookies.insert(std::make_pair(cookie.key(),cookie));
}
virtual void removeCookie(const std::string& key) override
{
_cookies.erase(key);
}
virtual void setBody(const std::string& body) override
{
_body = body;
}
virtual void setBody(std::string&& body) override
{
_body = std::move(body);
}
virtual void redirect(const std::string& url) override
{
_headers["Location"] = url;
}
void appendToBuffer(MsgBuffer* output) const;
virtual void clear() override
{
_statusCode = kUnknown;
_v = kHttp11;
_statusMessage.clear();
_fullHeaderString.clear();
_headers.clear();
_cookies.clear();
_body.clear();
_left_body_length = 0;
_current_chunk_length = 0;
}
virtual void setExpiredTime(ssize_t expiredTime) override
{
_expriedTime=expiredTime;
}
virtual ssize_t expiredTime() const override {return _expriedTime;}
// void setReceiveTime(trantor::Date t)
// {
// receiveTime_ = t;
// }
virtual const std::string & getBody() const override
{
return _body;
}
virtual std::string & getBody() override
{
return _body;
}
void swap(HttpResponseImpl &that)
{
_headers.swap(that._headers);
_cookies.swap(that._cookies);
std::swap(_statusCode,that._statusCode);
std::swap(_v,that._v);
_statusMessage.swap(that._statusMessage);
std::swap(_closeConnection,that._closeConnection);
_body.swap(that._body);
std::swap(_left_body_length,that._left_body_length);
std::swap(_current_chunk_length,that._current_chunk_length);
std::swap(_contentType,that._contentType);
_jsonPtr.swap(that._jsonPtr);
_fullHeaderString.swap(that._fullHeaderString);
}
void parseJson() const
{
//parse json data in reponse
_jsonPtr=std::make_shared<Json::Value>();
Json::CharReaderBuilder builder;
builder["collectComments"] = false;
JSONCPP_STRING errs;
std::unique_ptr<Json::CharReader> reader(builder.newCharReader());
if (!reader->parse(_body.data(), _body.data() + _body.size(), _jsonPtr.get() , &errs))
//LOG_INFO<<"cookies!!!:"<<value;
std::string::size_type pos;
while ((pos = value.find(";")) != std::string::npos)
{
LOG_ERROR<<errs;
_jsonPtr.reset();
std::string coo = value.substr(0, pos);
auto epos = coo.find("=");
if (epos != std::string::npos)
{
std::string cookie_name = coo.substr(0, epos);
std::string::size_type cpos = 0;
while (cpos < cookie_name.length() && isspace(cookie_name[cpos]))
cpos++;
cookie_name = cookie_name.substr(cpos);
std::string cookie_value = coo.substr(epos + 1);
_cookies.insert(std::make_pair(cookie_name, Cookie(cookie_name, cookie_value)));
}
value = value.substr(pos + 1);
}
if (value.length() > 0)
{
std::string &coo = value;
auto epos = coo.find("=");
if (epos != std::string::npos)
{
std::string cookie_name = coo.substr(0, epos);
std::string::size_type cpos = 0;
while (cpos < cookie_name.length() && isspace(cookie_name[cpos]))
cpos++;
cookie_name = cookie_name.substr(cpos);
std::string cookie_value = coo.substr(epos + 1);
_cookies.insert(std::make_pair(cookie_name, Cookie(cookie_name, cookie_value)));
}
}
}
virtual const std::shared_ptr<Json::Value> getJsonObject() const override
}
virtual void addCookie(const std::string &key, const std::string &value) override
{
_cookies.insert(std::make_pair(key, Cookie(key, value)));
}
virtual void addCookie(const Cookie &cookie) override
{
_cookies.insert(std::make_pair(cookie.key(), cookie));
}
virtual void removeCookie(const std::string &key) override
{
_cookies.erase(key);
}
virtual void setBody(const std::string &body) override
{
_body = body;
}
virtual void setBody(std::string &&body) override
{
_body = std::move(body);
}
virtual void redirect(const std::string &url) override
{
_headers["Location"] = url;
}
void appendToBuffer(MsgBuffer *output) const;
virtual void clear() override
{
_statusCode = kUnknown;
_v = kHttp11;
_statusMessage.clear();
_fullHeaderString.reset();
_headers.clear();
_cookies.clear();
_body.clear();
_left_body_length = 0;
_current_chunk_length = 0;
}
virtual void setExpiredTime(ssize_t expiredTime) override
{
_expriedTime = expiredTime;
}
virtual ssize_t expiredTime() const override { return _expriedTime; }
// void setReceiveTime(trantor::Date t)
// {
// receiveTime_ = t;
// }
virtual const std::string &getBody() const override
{
return _body;
}
virtual std::string &getBody() override
{
return _body;
}
void swap(HttpResponseImpl &that)
{
_headers.swap(that._headers);
_cookies.swap(that._cookies);
std::swap(_statusCode, that._statusCode);
std::swap(_v, that._v);
_statusMessage.swap(that._statusMessage);
std::swap(_closeConnection, that._closeConnection);
_body.swap(that._body);
std::swap(_left_body_length, that._left_body_length);
std::swap(_current_chunk_length, that._current_chunk_length);
std::swap(_contentType, that._contentType);
_jsonPtr.swap(that._jsonPtr);
_fullHeaderString.swap(that._fullHeaderString);
}
void parseJson() const
{
//parse json data in reponse
_jsonPtr = std::make_shared<Json::Value>();
Json::CharReaderBuilder builder;
builder["collectComments"] = false;
JSONCPP_STRING errs;
std::unique_ptr<Json::CharReader> reader(builder.newCharReader());
if (!reader->parse(_body.data(), _body.data() + _body.size(), _jsonPtr.get(), &errs))
{
if(!_jsonPtr){
parseJson();
}
return _jsonPtr;
LOG_ERROR << errs;
_jsonPtr.reset();
}
const std::string &sendfileName() const {
return _sendfileName;
}
void setSendfile(const std::string &filename){
_sendfileName=filename;
}
protected:
static std::string web_content_type_to_string(uint8_t contenttype);
static const std::string web_content_type_and_charset_to_string(uint8_t contenttype,
const std::string &charSet);
static std::string web_response_code_to_string(int code);
void makeHeaderString(MsgBuffer* output) const;
private:
std::map<std::string, std::string> _headers;
std::map<std::string, Cookie> _cookies;
HttpStatusCode _statusCode;
// FIXME: add http version
Version _v;
std::string _statusMessage;
bool _closeConnection;
std::string _body;
size_t _left_body_length;
size_t _current_chunk_length;
uint8_t _contentType=CT_TEXT_HTML;
ssize_t _expriedTime=-1;
std::string _sendfileName;
mutable std::shared_ptr<Json::Value> _jsonPtr;
mutable std::string _fullHeaderString;
//trantor::Date receiveTime_;
void setContentType(const std::string& contentType)
}
virtual const std::shared_ptr<Json::Value> getJsonObject() const override
{
if (!_jsonPtr)
{
addHeader("Content-Type", contentType);
parseJson();
}
void setContentType(std::string && contentType)
{
addHeader("Content-Type", std::move(contentType));
}
void setStatusMessage(const std::string& message)
{
_statusMessage = message;
}
void setStatusMessage(std::string && message)
{
_statusMessage = std::move(message);
}
};
typedef std::shared_ptr<HttpResponseImpl> HttpResponseImplPtr;
}
return _jsonPtr;
}
const std::string &sendfileName() const
{
return _sendfileName;
}
void setSendfile(const std::string &filename)
{
_sendfileName = filename;
}
void makeHeaderString()
{
trantor::MsgBuffer buf;
makeHeaderString(&buf);
_fullHeaderString = std::make_shared<std::string>(buf.peek(), buf.readableBytes());
}
protected:
static std::string web_content_type_to_string(uint8_t contenttype);
static const std::string web_content_type_and_charset_to_string(uint8_t contenttype,
const std::string &charSet);
static std::string web_response_code_to_string(int code);
void makeHeaderString(MsgBuffer *output) const;
private:
std::map<std::string, std::string> _headers;
std::map<std::string, Cookie> _cookies;
HttpStatusCode _statusCode;
// FIXME: add http version
Version _v;
std::string _statusMessage;
bool _closeConnection;
std::string _body;
size_t _left_body_length;
size_t _current_chunk_length;
uint8_t _contentType = CT_TEXT_HTML;
ssize_t _expriedTime = -1;
std::string _sendfileName;
mutable std::shared_ptr<Json::Value> _jsonPtr;
std::shared_ptr<std::string> _fullHeaderString;
//trantor::Date receiveTime_;
void setContentType(const std::string &contentType)
{
addHeader("Content-Type", contentType);
}
void setContentType(std::string &&contentType)
{
addHeader("Content-Type", std::move(contentType));
}
void setStatusMessage(const std::string &message)
{
_statusMessage = message;
}
void setStatusMessage(std::string &&message)
{
_statusMessage = std::move(message);
}
};
typedef std::shared_ptr<HttpResponseImpl> HttpResponseImplPtr;
} // namespace drogon

View File

@ -35,41 +35,39 @@ using namespace std::placeholders;
using namespace drogon;
using namespace trantor;
static void defaultHttpAsyncCallback(const HttpRequestPtr&,const std::function<void(const HttpResponsePtr & resp)> & callback)
static void defaultHttpAsyncCallback(const HttpRequestPtr &, const std::function<void(const HttpResponsePtr &resp)> &callback)
{
auto resp=HttpResponse::newNotFoundResponse();
auto resp = HttpResponse::newNotFoundResponse();
resp->setCloseConnection(true);
callback(resp);
}
static void defaultWebSockAsyncCallback(const HttpRequestPtr&,
const std::function<void( const HttpResponsePtr & resp)> & callback,
const WebSocketConnectionPtr& wsConnPtr)
static void defaultWebSockAsyncCallback(const HttpRequestPtr &,
const std::function<void(const HttpResponsePtr &resp)> &callback,
const WebSocketConnectionPtr &wsConnPtr)
{
auto resp=HttpResponse::newNotFoundResponse();
auto resp = HttpResponse::newNotFoundResponse();
resp->setCloseConnection(true);
callback(resp);
}
static void defaultConnectionCallback(const trantor::TcpConnectionPtr & conn)
static void defaultConnectionCallback(const trantor::TcpConnectionPtr &conn)
{
return;
}
HttpServer::HttpServer(EventLoop* loop,
const InetAddress& listenAddr,
const std::string& name)
: server_(loop, listenAddr, name.c_str()),
httpAsyncCallback_(defaultHttpAsyncCallback),
newWebsocketCallback_(defaultWebSockAsyncCallback),
_connectionCallback(defaultConnectionCallback)
HttpServer::HttpServer(EventLoop *loop,
const InetAddress &listenAddr,
const std::string &name)
: server_(loop, listenAddr, name.c_str()),
httpAsyncCallback_(defaultHttpAsyncCallback),
newWebsocketCallback_(defaultWebSockAsyncCallback),
_connectionCallback(defaultConnectionCallback)
{
server_.setConnectionCallback(
std::bind(&HttpServer::onConnection, this, _1));
std::bind(&HttpServer::onConnection, this, _1));
server_.setRecvMessageCallback(
std::bind(&HttpServer::onMessage, this, _1, _2));
std::bind(&HttpServer::onMessage, this, _1, _2));
}
HttpServer::~HttpServer()
@ -83,18 +81,19 @@ void HttpServer::start()
server_.start();
}
void HttpServer::onConnection(const TcpConnectionPtr& conn)
void HttpServer::onConnection(const TcpConnectionPtr &conn)
{
if (conn->connected()) {
if (conn->connected())
{
conn->setContext(HttpContext(conn));
}
else if(conn->disconnected())
else if (conn->disconnected())
{
LOG_TRACE<<"conn disconnected!";
HttpContext* context = any_cast<HttpContext>(conn->getMutableContext());
LOG_TRACE << "conn disconnected!";
HttpContext *context = any_cast<HttpContext>(conn->getMutableContext());
// LOG_INFO << "###:" << string(buf->peek(), buf->readableBytes());
if(context->webSocketConn())
if (context->webSocketConn())
{
disconnectWebsocketCallback_(context->webSocketConn());
}
@ -103,107 +102,113 @@ void HttpServer::onConnection(const TcpConnectionPtr& conn)
_connectionCallback(conn);
}
void HttpServer::onMessage(const TcpConnectionPtr& conn,
MsgBuffer* buf)
void HttpServer::onMessage(const TcpConnectionPtr &conn,
MsgBuffer *buf)
{
HttpContext* context = any_cast<HttpContext>(conn->getMutableContext());
HttpContext *context = any_cast<HttpContext>(conn->getMutableContext());
// LOG_INFO << "###:" << string(buf->peek(), buf->readableBytes());
if(context->webSocketConn())
if (context->webSocketConn())
{
//websocket payload,we shouldn't parse it
webSocketMessageCallback_(context->webSocketConn(),buf);
webSocketMessageCallback_(context->webSocketConn(), buf);
return;
}
if (!context->parseRequest(buf)) {
if (!context->parseRequest(buf))
{
conn->send("HTTP/1.1 400 Bad Request\r\n\r\n");
//conn->shutdown();
}
if (context->gotAll()) {
if (context->gotAll())
{
context->requestImpl()->parsePremeter();
context->requestImpl()->setPeerAddr(conn->peerAddr());
context->requestImpl()->setLocalAddr(conn->localAddr());
context->requestImpl()->setReceiveDate(trantor::Date::date());
if(context->firstReq()&&isWebSocket(conn,context->request()))
if (context->firstReq() && isWebSocket(conn, context->request()))
{
auto wsConn=std::make_shared<WebSocketConnectionImpl>(conn);
newWebsocketCallback_(context->request(),[=](const HttpResponsePtr &resp) mutable
{
if(resp->statusCode()==HttpResponse::k101SwitchingProtocols)
auto wsConn = std::make_shared<WebSocketConnectionImpl>(conn);
newWebsocketCallback_(context->request(), [=](const HttpResponsePtr &resp) mutable {
if (resp->statusCode() == HttpResponse::k101SwitchingProtocols)
{
context->setWebsockConnection(wsConn);
}
MsgBuffer buffer;
std::dynamic_pointer_cast<HttpResponseImpl>(resp)->appendToBuffer(&buffer);
conn->send(std::move(buffer));
},wsConn);
},
wsConn);
}
else
onRequest(conn, context->request());
context->reset();
}
}
bool HttpServer::isWebSocket(const TcpConnectionPtr& conn, const HttpRequestPtr& req)
bool HttpServer::isWebSocket(const TcpConnectionPtr &conn, const HttpRequestPtr &req)
{
if(req->getHeader("Connection")=="Upgrade"&&
req->getHeader("Upgrade")=="websocket")
if (req->getHeader("Connection") == "Upgrade" &&
req->getHeader("Upgrade") == "websocket")
{
LOG_TRACE<<"new websocket request";
LOG_TRACE << "new websocket request";
return true;
}
return false;
}
void HttpServer::onRequest(const TcpConnectionPtr& conn, const HttpRequestPtr& req)
void HttpServer::onRequest(const TcpConnectionPtr &conn, const HttpRequestPtr &req)
{
const std::string& connection = req->getHeader("Connection");
const std::string &connection = req->getHeader("Connection");
bool _close = connection == "close" ||
(req->getVersion() == HttpRequestImpl::kHttp10 && connection != "Keep-Alive");
bool _isHeadMethod=(req->method()==HttpRequest::kHead);
if(_isHeadMethod)
bool _isHeadMethod = (req->method() == HttpRequest::kHead);
if (_isHeadMethod)
{
req->setMethod(HttpRequest::kGet);
}
HttpContext* context = any_cast<HttpContext>(conn->getMutableContext());
HttpContext *context = any_cast<HttpContext>(conn->getMutableContext());
//request will be received in same thread,so we don't need mutex;
context->pushRquestToPipeLine(req);
httpAsyncCallback_(req, [ = ](const HttpResponsePtr &response) {
if(!response)
httpAsyncCallback_(req, [=](const HttpResponsePtr &response) {
if (!response)
return;
response->setCloseConnection(_close);
//if the request method is HEAD,remove the body of response(rfc2616-9.4)
if(_isHeadMethod)
if (_isHeadMethod)
response->setBody(std::string());
auto & sendfileName=std::dynamic_pointer_cast<HttpResponseImpl>(response)->sendfileName();
if(sendfileName.empty()&&
response->getContentTypeCode()<CT_APPLICATION_OCTET_STREAM&&
response->getBody().length()>1024&&
req->getHeader("Accept-Encoding").find("gzip")!=std::string::npos&&
response->getHeader("Content-Encoding")=="")
auto &sendfileName = std::dynamic_pointer_cast<HttpResponseImpl>(response)->sendfileName();
auto newResp = response;
if (sendfileName.empty() &&
response->getContentTypeCode() < CT_APPLICATION_OCTET_STREAM &&
response->getBody().length() > 1024 &&
req->getHeader("Accept-Encoding").find("gzip") != std::string::npos &&
response->getHeader("Content-Encoding") == "")
{
//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)
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)
{
if(zlen>0)
if (zlen > 0)
{
response->setBody(std::string(zbuf,zlen));
response->addHeader("Content-Encoding","gzip");
if (response->expiredTime() >= 0)
{
//cached response,we need to make a clone
newResp = std::make_shared<HttpResponseImpl>(*std::dynamic_pointer_cast<HttpResponseImpl>(response));
}
newResp->setBody(std::string(zbuf, zlen));
newResp->addHeader("Content-Encoding", "gzip");
}
else
{
LOG_ERROR<<"gzip got 0 length result";
LOG_ERROR << "gzip got 0 length result";
}
}
delete [] zbuf;
delete[] zbuf;
}
{
/*
@ -214,42 +219,43 @@ void HttpServer::onRequest(const TcpConnectionPtr& conn, const HttpRequestPtr& r
* rfc2616-8.1.1.2
*/
std::lock_guard<std::mutex> guard(context->getPipeLineMutex());
if(context->getFirstRequest()==req)
if (context->getFirstRequest() == req)
{
context->popFirstRequest();
sendResponse(conn,response);
while(1)
sendResponse(conn, newResp);
while (1)
{
auto resp=context->getFirstResponse();
if(resp)
auto resp = context->getFirstResponse();
if (resp)
{
context->popFirstRequest();
sendResponse(conn,resp);
} else
sendResponse(conn, resp);
}
else
return;
}
}
else
{
//some earlier requests are waiting for responses;
context->pushResponseToPipeLine(req,response);
context->pushResponseToPipeLine(req, newResp);
}
}
});
}
void HttpServer::sendResponse(const TcpConnectionPtr& conn,
void HttpServer::sendResponse(const TcpConnectionPtr &conn,
const HttpResponsePtr &response)
{
MsgBuffer buf;
std::dynamic_pointer_cast<HttpResponseImpl>(response)->appendToBuffer(&buf);
conn->send(std::move(buf));
auto & sendfileName=std::dynamic_pointer_cast<HttpResponseImpl>(response)->sendfileName();
if(!sendfileName.empty())
auto &sendfileName = std::dynamic_pointer_cast<HttpResponseImpl>(response)->sendfileName();
if (!sendfileName.empty())
{
conn->sendFile(sendfileName.c_str());
}
if (response->closeConnection()) {
if (response->closeConnection())
{
conn->shutdown();
}
}