mirror of
https://gitee.com/an-tao/drogon.git
synced 2024-11-29 18:27:43 +08:00
Optimize response caching
This commit is contained in:
parent
74e46d9b02
commit
0a3d27a5b0
1
.gitignore
vendored
1
.gitignore
vendored
@ -39,3 +39,4 @@ lib/inc/drogon/config.h
|
||||
Doxyfile
|
||||
html/
|
||||
latex/
|
||||
.vscode
|
||||
|
@ -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)
|
||||
|
@ -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
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user