Merge pull request #40 from an-tao/dev

Support http request in json format
This commit is contained in:
An Tao 2019-01-22 23:11:54 +08:00 committed by GitHub
commit 4e7714e5e9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
24 changed files with 562 additions and 331 deletions

View File

@ -22,6 +22,6 @@ void {{className}}::doFilter(const HttpRequestPtr &req,
}
//Check failed
auto res = drogon::HttpResponse::newHttpResponse();
res->setStatusCode(HttpResponse::k500InternalServerError);
res->setStatusCode(k500InternalServerError);
fcb(res);
}

View File

@ -32,6 +32,6 @@ void Attachment::upload(const HttpRequestPtr &req,
file.saveAs("../xxx");
}
auto resp = HttpResponse::newHttpResponse();
resp->setStatusCode(HttpResponse::k200OK);
resp->setStatusCode(k200OK);
callback(resp);
}

View File

@ -350,3 +350,19 @@ void ApiTest::get2(const HttpRequestPtr &req, const std::function<void(const Htt
res->setExpiredTime(0);
callback(res);
}
void ApiTest::jsonTest(const HttpRequestPtr &req, const std::function<void(const HttpResponsePtr &)> &callback)
{
auto json = req->getJsonObject();
Json::Value ret;
if(json)
{
ret["result"] = "ok";
}
else
{
ret["result"] = "bad";
}
auto resp = HttpResponse::newHttpJsonResponse(ret);
callback(resp);
}

View File

@ -16,6 +16,7 @@ class ApiTest : public drogon::HttpController<ApiTest>
METHOD_ADD(ApiTest::your_method_name, "/{1}/List?P2={2}", Get); //path will be /api/v1/apitest/{arg1}/list
METHOD_ADD(ApiTest::staticApi, "/static", Get, Post);
METHOD_ADD(ApiTest::get2, "/get/{1}", Get);
METHOD_ADD(ApiTest::jsonTest, "/json", Post);
METHOD_LIST_END
//your declaration of processing function maybe like this:
void get(const HttpRequestPtr &req, const std::function<void(const HttpResponsePtr &)> &callback, int p1, std::string &&p2);
@ -24,6 +25,7 @@ class ApiTest : public drogon::HttpController<ApiTest>
void get2(const HttpRequestPtr &req, const std::function<void(const HttpResponsePtr &)> &callback, std::string &&p1);
void rootGet(const HttpRequestPtr &req, const std::function<void(const HttpResponsePtr &)> &callback);
void rootPost(const HttpRequestPtr &req, const std::function<void(const HttpResponsePtr &)> &callback);
void jsonTest(const HttpRequestPtr &req, const std::function<void(const HttpResponsePtr &)> &callback);
};
} // namespace v1
} // namespace api

View File

@ -35,8 +35,35 @@ void outputGood(const HttpRequestPtr &req)
}
void doTest(const HttpClientPtr &client)
{
/// Post json
Json::Value json;
json["request"] = "json";
auto req = HttpRequest::newHttpJsonRequest(json);
req->setMethod(drogon::Post);
req->setPath("/api/v1/apitest/json");
client->sendRequest(req, [=](ReqResult result, const HttpResponsePtr &resp) {
if (result == ReqResult::Ok)
{
auto ret = resp->getJsonObject();
if (ret && (*ret)["result"].asString() == "ok")
{
outputGood(req);
}
else
{
LOG_DEBUG << resp->getBody();
LOG_ERROR << "Error!";
exit(1);
}
}
else
{
LOG_ERROR << "Error!";
exit(1);
}
});
/// 1 Get /
auto req = HttpRequest::newHttpRequest();
req = HttpRequest::newHttpRequest();
req->setMethod(drogon::Get);
req->setPath("/");
client->sendRequest(req, [=](ReqResult result, const HttpResponsePtr &resp) {
@ -91,7 +118,7 @@ void doTest(const HttpClientPtr &client)
if (result == ReqResult::Ok)
{
//LOG_DEBUG << resp->getBody();
if (resp->statusCode() == HttpResponse::k405MethodNotAllowed)
if (resp->statusCode() == k405MethodNotAllowed)
{
outputGood(req);
}
@ -444,7 +471,7 @@ void doTest(const HttpClientPtr &client)
client->sendRequest(req, [=](ReqResult result, const HttpResponsePtr &resp) {
if (result == ReqResult::Ok)
{
if (resp->statusCode() == HttpResponse::k403Forbidden)
if (resp->statusCode() == k403Forbidden)
{
outputGood(req);
}
@ -461,6 +488,7 @@ void doTest(const HttpClientPtr &client)
exit(1);
}
});
}
int main()
@ -468,7 +496,7 @@ int main()
trantor::EventLoopThread loop[2];
loop[0].run();
loop[1].run();
// for (int i = 0; i < 100;i++)
// for (int i = 0; i < 100;i++)
{
auto client = HttpClient::newHttpClient("http://127.0.0.1:8848", loop[0].getLoop());
doTest(client);

View File

@ -14,6 +14,7 @@
#pragma once
#include <drogon/HttpTypes.h>
#include <drogon/Session.h>
#include <trantor/net/InetAddress.h>
#include <trantor/utils/Date.h>
@ -21,19 +22,13 @@
#include <unordered_map>
#include <string>
#include <memory>
namespace drogon
{
class HttpRequest;
typedef std::shared_ptr<HttpRequest> HttpRequestPtr;
enum HttpMethod
{
Get = 0,
Post,
Head,
Put,
Delete,
Invalid
};
/// Abstract class for webapp developer to get or set the Http request;
class HttpRequest
@ -111,8 +106,14 @@ class HttpRequest
/// Set the parameter of the request
virtual void setParameter(const std::string &key, const std::string &value) = 0;
/// Set or get the content type
virtual void setContentTypeCode(ContentType type) = 0;
virtual void setContentTypeCodeAndCharacterSet(ContentType type, const std::string &charSet = "utf-8") = 0;
virtual ContentType getContentTypeCode() = 0;
/// Create a request object.
static HttpRequestPtr newHttpRequest();
static HttpRequestPtr newHttpJsonRequest(const Json::Value &data);
virtual ~HttpRequest() {}
};

View File

@ -15,33 +15,11 @@
#include <drogon/HttpViewData.h>
#include <drogon/Cookie.h>
#include <drogon/HttpTypes.h>
#include <json/json.h>
#include <string>
#include <memory>
using std::string;
#define CT_APPLICATION_JSON 1
#define CT_TEXT_PLAIN 2
#define CT_TEXT_HTML 3
#define CT_APPLICATION_X_JAVASCRIPT 4
#define CT_TEXT_CSS 5
#define CT_TEXT_XML 6
#define CT_APPLICATION_XML 7
#define CT_TEXT_XSL 8
#define CT_APPLICATION_OCTET_STREAM 9
#define CT_APPLICATION_X_FONT_TRUETYPE 10
#define CT_APPLICATION_X_FONT_OPENTYPE 11
#define CT_APPLICATION_FONT_WOFF 12
#define CT_APPLICATION_FONT_WOFF2 13
#define CT_APPLICATION_VND_MS_FONTOBJ 14
#define CT_IMAGE_SVG_XML 15
#define CT_IMAGE_PNG 16
#define CT_IMAGE_JPG 17
#define CT_IMAGE_GIF 18
#define CT_IMAGE_XICON 19
#define CT_IMAGE_ICNS 20
#define CT_IMAGE_BMP 21
namespace drogon
{
/// Abstract class for webapp developer to get or set the Http response;
@ -50,58 +28,6 @@ typedef std::shared_ptr<HttpResponse> HttpResponsePtr;
class HttpResponse
{
public:
enum HttpStatusCode
{
//rfc2616-6.1.1
kUnknown = 0,
k100Continue = 100,
k101SwitchingProtocols = 101,
k200OK = 200,
k201Created = 201,
k202Accepted = 202,
k203NonAuthoritativeInformation = 203,
k204NoContent = 204,
k205ResetContent = 205,
k206PartialContent = 206,
k300MultipleChoices = 300,
k301MovedPermanently = 301,
k302Found = 302,
k303SeeOther = 303,
k304NotModified = 304,
k305UseProxy = 305,
k307TemporaryRedirect = 307,
k400BadRequest = 400,
k401Unauthorized = 401,
k402PaymentRequired = 402,
k403Forbidden = 403,
k404NotFound = 404,
k405MethodNotAllowed = 405,
k406NotAcceptable = 406,
k407ProxyAuthenticationRequired = 407,
k408RequestTimeout = 408,
k409Conflict = 409,
k410Gone = 410,
k411LengthRequired = 411,
k412PreconditionFailed = 412,
k413RequestEntityTooLarge = 413,
k414RequestURITooLarge = 414,
k415UnsupportedMediaType = 415,
k416Requestedrangenotsatisfiable = 416,
k417ExpectationFailed = 417,
k500InternalServerError = 500,
k501NotImplemented = 501,
k502BadGateway = 502,
k503ServiceUnavailable = 503,
k504GatewayTimeout = 504,
k505HTTPVersionnotsupported = 505,
};
enum Version
{
kHttp10,
kHttp11
};
explicit HttpResponse()
{
}
@ -120,11 +46,11 @@ class HttpResponse
virtual bool closeConnection() const = 0;
virtual void setContentTypeCode(uint8_t type) = 0;
virtual void setContentTypeCode(ContentType type) = 0;
virtual void setContentTypeCodeAndCharacterSet(uint8_t type, const std::string &charSet = "utf-8") = 0;
virtual void setContentTypeCodeAndCharacterSet(ContentType type, const std::string &charSet = "utf-8") = 0;
virtual uint8_t getContentTypeCode() = 0;
virtual ContentType getContentTypeCode() = 0;
virtual const std::string &getHeader(const std::string &key, const std::string &defaultVal = std::string()) const = 0;

106
lib/inc/drogon/HttpTypes.h Normal file
View File

@ -0,0 +1,106 @@
/**
* HttpTypes.h
* An Tao
*
* Copyright 2018, An Tao. All rights reserved.
* https://github.com/an-tao/drogon
* Use of this source code is governed by a MIT license
* that can be found in the License file.
*
* Drogon
*
*/
#pragma once
namespace drogon
{
enum HttpStatusCode
{
//rfc2616-6.1.1
kUnknown = 0,
k100Continue = 100,
k101SwitchingProtocols = 101,
k200OK = 200,
k201Created = 201,
k202Accepted = 202,
k203NonAuthoritativeInformation = 203,
k204NoContent = 204,
k205ResetContent = 205,
k206PartialContent = 206,
k300MultipleChoices = 300,
k301MovedPermanently = 301,
k302Found = 302,
k303SeeOther = 303,
k304NotModified = 304,
k305UseProxy = 305,
k307TemporaryRedirect = 307,
k400BadRequest = 400,
k401Unauthorized = 401,
k402PaymentRequired = 402,
k403Forbidden = 403,
k404NotFound = 404,
k405MethodNotAllowed = 405,
k406NotAcceptable = 406,
k407ProxyAuthenticationRequired = 407,
k408RequestTimeout = 408,
k409Conflict = 409,
k410Gone = 410,
k411LengthRequired = 411,
k412PreconditionFailed = 412,
k413RequestEntityTooLarge = 413,
k414RequestURITooLarge = 414,
k415UnsupportedMediaType = 415,
k416Requestedrangenotsatisfiable = 416,
k417ExpectationFailed = 417,
k500InternalServerError = 500,
k501NotImplemented = 501,
k502BadGateway = 502,
k503ServiceUnavailable = 503,
k504GatewayTimeout = 504,
k505HTTPVersionnotsupported = 505,
};
enum Version
{
kHttp10,
kHttp11
};
enum ContentType
{
CT_APPLICATION_JSON = 0,
CT_TEXT_PLAIN,
CT_TEXT_HTML,
CT_APPLICATION_X_JAVASCRIPT,
CT_TEXT_CSS,
CT_TEXT_XML,
CT_APPLICATION_XML,
CT_TEXT_XSL,
CT_APPLICATION_OCTET_STREAM,
CT_APPLICATION_X_FONT_TRUETYPE,
CT_APPLICATION_X_FONT_OPENTYPE,
CT_APPLICATION_FONT_WOFF,
CT_APPLICATION_FONT_WOFF2,
CT_APPLICATION_VND_MS_FONTOBJ,
CT_IMAGE_SVG_XML,
CT_IMAGE_PNG,
CT_IMAGE_JPG,
CT_IMAGE_GIF,
CT_IMAGE_XICON,
CT_IMAGE_ICNS,
CT_IMAGE_BMP
};
enum HttpMethod
{
Get = 0,
Post,
Head,
Put,
Delete,
Invalid
};
} // namespace drogon

View File

@ -13,6 +13,7 @@
*/
#include "HttpRequestImpl.h"
#include "HttpUtils.h"
#include <drogon/utils/Utilities.h>
#include <drogon/FileUpload.h>
#include <drogon/HttpAppFramework.h>

View File

@ -15,6 +15,7 @@
#include "HttpAppFrameworkImpl.h"
#include "ConfigLoader.h"
#include "HttpServer.h"
#include <drogon/HttpTypes.h>
#include <drogon/utils/Utilities.h>
#include <drogon/DrClassMap.h>
#include <drogon/HttpRequest.h>
@ -642,7 +643,7 @@ void HttpAppFrameworkImpl::onAsyncRequest(const HttpRequestImplPtr &req, std::fu
{
//Downloading files from the parent folder is forbidden.
auto resp = HttpResponse::newHttpResponse();
resp->setStatusCode(HttpResponse::k403Forbidden);
resp->setStatusCode(k403Forbidden);
callback(resp);
return;
}
@ -670,7 +671,7 @@ void HttpAppFrameworkImpl::onAsyncRequest(const HttpRequestImplPtr &req, std::fu
{
if (std::dynamic_pointer_cast<HttpResponseImpl>(cachedResp)->getHeaderBy("last-modified") == req->getHeaderBy("if-modified-since"))
{
resp->setStatusCode(HttpResponse::k304NotModified);
resp->setStatusCode(k304NotModified);
if (needSetJsessionid)
{
resp->addCookie("JSESSIONID", sessionId);
@ -696,7 +697,7 @@ void HttpAppFrameworkImpl::onAsyncRequest(const HttpRequestImplPtr &req, std::fu
if (modiStr == timeStr && !modiStr.empty())
{
LOG_TRACE << "not Modified!";
resp->setStatusCode(HttpResponse::k304NotModified);
resp->setStatusCode(k304NotModified);
if (needSetJsessionid)
{
resp->addCookie("JSESSIONID", sessionId);
@ -798,7 +799,7 @@ void HttpAppFrameworkImpl::readSendFile(const std::string &filePath, const HttpR
if (!infile)
{
resp->setStatusCode(HttpResponse::k404NotFound);
resp->setStatusCode(k404NotFound);
resp->setCloseConnection(true);
return;
}
@ -822,7 +823,7 @@ void HttpAppFrameworkImpl::readSendFile(const std::string &filePath, const HttpR
resp->setBody(std::move(str));
}
resp->setStatusCode(HttpResponse::k200OK);
resp->setStatusCode(k200OK);
//cache the response for 5 seconds by default

View File

@ -103,6 +103,13 @@ void HttpClientImpl::sendRequestInLoop(const drogon::HttpRequestPtr &req,
const drogon::HttpReqCallback &callback)
{
_loop->assertInLoopThread();
req->addHeader("Connection", "Keep-Alive");
// req->addHeader("Accept", "*/*");
if (!_domain.empty())
{
req->addHeader("Host", _domain);
}
req->addHeader("User-Agent", "DrogonClient");
if (!_tcpClient)
{
@ -230,7 +237,7 @@ void HttpClientImpl::onRecvMessage(const trantor::TcpConnectionPtr &connPtr, tra
resp->parseJson();
}
if (resp->getHeaderBy("content-encoding")=="gzip")
if (resp->getHeaderBy("content-encoding") == "gzip")
{
resp->gunzip();
}

View File

@ -163,7 +163,7 @@ void HttpControllersRouter::route(const HttpRequestImplPtr &req,
{
//Invalid Http Method
auto res = drogon::HttpResponse::newHttpResponse();
res->setStatusCode(HttpResponse::k405MethodNotAllowed);
res->setStatusCode(k405MethodNotAllowed);
callback(res);
return;
}

View File

@ -13,14 +13,14 @@
*/
#include "HttpRequestImpl.h"
#include <iostream>
using namespace drogon;
void HttpRequestImpl::parseParameter()
{
const std::string &input = query();
if(input.empty())
if (input.empty())
return;
std::string type = getHeaderBy("content-type");
std::transform(type.begin(), type.end(), type.begin(), tolower);
@ -113,7 +113,7 @@ void HttpRequestImpl::appendToBuffer(MsgBuffer *output) const
return;
}
if (_path.size() != 0)
if (!_path.empty())
{
output->append(_path);
}
@ -122,17 +122,31 @@ void HttpRequestImpl::appendToBuffer(MsgBuffer *output) const
output->append("/");
}
if (_parameters.size() != 0)
std::string content;
if (!_parameters.empty())
{
output->append("?");
for (auto const &p : _parameters)
{
output->append(p.first);
output->append("=");
output->append(p.second);
output->append("&");
content.append(p.first);
content.append("=");
content.append(p.second);
content.append("&");
}
content.resize(content.length() - 1);
///TODO: URL code?
if (_method == Get || _method == Delete)
{
output->append("?");
output->append(content);
content.clear();
}
else if (_contentType == CT_APPLICATION_JSON)
{
///Can't set parameters in content in this case
LOG_ERROR << "You can't set parameters in the query string when the request content type is JSON and http method is POST or PUT";
LOG_ERROR << "Please put these parameters in the path or the json string";
content.clear();
}
output->unwrite(1);
}
output->append(" ");
@ -150,6 +164,20 @@ void HttpRequestImpl::appendToBuffer(MsgBuffer *output) const
}
output->append("\r\n");
assert(!(!content.empty() && !_content.empty()));
if (!content.empty() || !_content.empty())
{
char buf[64];
snprintf(buf, sizeof buf, "Content-Length: %lu\r\n", static_cast<long unsigned int>(content.length() + _content.length()));
output->append(buf);
if (_headers.find("Content-Type") == _headers.end())
{
output->append("Content-Type: ");
output->append(webContentTypeToString(_contentType));
output->append("\r\n");
}
}
for (auto it = _headers.begin(); it != _headers.end(); ++it)
{
output->append(it->first);
@ -172,9 +200,70 @@ void HttpRequestImpl::appendToBuffer(MsgBuffer *output) const
}
output->append("\r\n");
//LOG_INFO<<"request(no body):"<<output->peek();
output->append(_content);
if (!content.empty())
output->append(content);
if (!_content.empty())
output->append(_content);
//LOG_INFO << output->peek();
}
void HttpRequestImpl::addHeader(const char *start, const char *colon, const char *end)
{
std::string field(start, colon);
//field name is case-insensitive.so we transform it to lower;(rfc2616-4.2)
std::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);
}
if (field == "cookie")
{
LOG_TRACE << "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[std::move(cookie_name)] = std::move(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[std::move(cookie_name)] = std::move(cookie_value);
}
}
}
else
{
_headers[std::move(field)] = std::move(value);
}
}
HttpRequestPtr HttpRequest::newHttpRequest()
@ -184,3 +273,16 @@ HttpRequestPtr HttpRequest::newHttpRequest()
req->setVersion(drogon::HttpRequest::kHttp11);
return req;
}
HttpRequestPtr HttpRequest::newHttpJsonRequest(const Json::Value &data)
{
auto req = std::make_shared<HttpRequestImpl>();
req->setMethod(drogon::Get);
req->setVersion(drogon::HttpRequest::kHttp11);
req->_contentType = CT_APPLICATION_JSON;
Json::StreamWriterBuilder builder;
builder["commentStyle"] = "None";
builder["indentation"] = "";
req->setContent(writeString(builder, data));
return req;
}

View File

@ -14,8 +14,10 @@
#pragma once
#include "HttpUtils.h"
#include <drogon/utils/Utilities.h>
#include <drogon/HttpRequest.h>
#include <drogon/HttpResponse.h>
#include <trantor/utils/NonCopyable.h>
#include <trantor/utils/Logger.h>
@ -26,14 +28,18 @@
#include <stdio.h>
#include <algorithm>
#include <string>
using std::string;
using namespace trantor;
namespace drogon
{
class HttpRequestImpl : public HttpRequest
{
public:
friend class HttpRequestParser;
HttpRequestImpl()
: _method(Invalid),
_version(kUnknown),
@ -50,7 +56,9 @@ class HttpRequestImpl : public HttpRequest
{
return _version;
}
void parseParameter();
bool setMethod(const char *start, const char *end)
{
@ -137,6 +145,7 @@ class HttpRequestImpl : public HttpRequest
{
_path = urlDecode(start, end);
}
virtual void setPath(const std::string &path) override
{
_path = path;
@ -146,6 +155,7 @@ class HttpRequestImpl : public HttpRequest
{
return _parameters;
}
const std::string &path() const override
{
return _path;
@ -155,6 +165,7 @@ class HttpRequestImpl : public HttpRequest
{
_query.assign(start, end);
}
void setQuery(const std::string &query)
{
_query = query;
@ -182,84 +193,33 @@ class HttpRequestImpl : public HttpRequest
{
return _peer;
}
virtual const trantor::InetAddress &localAddr() const override
{
return _local;
}
virtual const trantor::Date &receiveDate() const override
{
return _date;
}
void setReceiveDate(const trantor::Date &date)
{
_date = date;
}
void setPeerAddr(const trantor::InetAddress &peer)
{
_peer = peer;
}
void setLocalAddr(const trantor::InetAddress &local)
{
_local = local;
}
void addHeader(const char *start, const char *colon, const char *end)
{
std::string field(start, colon);
//field name is case-insensitive.so we transform it to lower;(rfc2616-4.2)
std::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);
}
if (field == "cookie")
{
LOG_TRACE << "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[std::move(cookie_name)] = std::move(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[std::move(cookie_name)] = std::move(cookie_value);
}
}
}
else
{
_headers[std::move(field)] = std::move(value);
}
}
void addHeader(const char *start, const char *colon, const char *end);
const std::string &getHeader(const std::string &field, const std::string &defaultVal = std::string()) const override
{
@ -293,6 +253,7 @@ class HttpRequestImpl : public HttpRequest
}
return defaultVal;
}
const std::unordered_map<std::string, std::string> &headers() const override
{
return _headers;
@ -302,14 +263,17 @@ class HttpRequestImpl : public HttpRequest
{
return _cookies;
}
virtual void setParameter(const std::string &key, const std::string &value) override
{
_parameters[key] = value;
}
const std::string &getContent() const
{
return _content;
}
void swap(HttpRequestImpl &that)
{
std::swap(_method, that._method);
@ -334,10 +298,12 @@ class HttpRequestImpl : public HttpRequest
{
_content = content;
}
virtual void addHeader(const std::string &key, const std::string &value) override
{
_headers[key] = value;
}
void addCookie(const std::string &key, const std::string &value)
{
_cookies[key] = value;
@ -360,7 +326,35 @@ class HttpRequestImpl : public HttpRequest
return _jsonPtr;
}
virtual void setContentTypeCode(ContentType type) override
{
_contentType = type;
setContentType(webContentTypeToString(type));
}
virtual void setContentTypeCodeAndCharacterSet(ContentType type, const std::string &charSet = "utf-8") override
{
_contentType = type;
setContentType(webContentTypeAndCharsetToString(type, charSet));
}
virtual ContentType getContentTypeCode() override
{
return _contentType;
}
private:
friend class HttpRequest;
void setContentType(const std::string &contentType)
{
addHeader("Content-Type", contentType);
}
void setContentType(std::string &&contentType)
{
addHeader("Content-Type", std::move(contentType));
}
HttpMethod _method;
Version _version;
std::string _path;
@ -375,6 +369,7 @@ class HttpRequestImpl : public HttpRequest
trantor::InetAddress _peer;
trantor::InetAddress _local;
trantor::Date _date;
ContentType _contentType = CT_TEXT_PLAIN;
protected:
std::string _content;
@ -382,4 +377,5 @@ class HttpRequestImpl : public HttpRequest
};
typedef std::shared_ptr<HttpRequestImpl> HttpRequestImplPtr;
} // namespace drogon

View File

@ -12,6 +12,7 @@
*
*/
#include <drogon/HttpTypes.h>
#include <trantor/utils/MsgBuffer.h>
#include <trantor/utils/Logger.h>
#include "HttpRequestParser.h"
@ -130,7 +131,7 @@ bool HttpRequestParser::parseRequest(MsgBuffer *buf)
if (connPtr)
{
auto resp = HttpResponse::newHttpResponse();
resp->setStatusCode(HttpResponse::k100Continue);
resp->setStatusCode(k100Continue);
auto httpString = std::dynamic_pointer_cast<HttpResponseImpl>(resp)->renderToString();
connPtr->send(httpString);
}
@ -142,7 +143,7 @@ bool HttpRequestParser::parseRequest(MsgBuffer *buf)
if (connPtr)
{
auto resp = HttpResponse::newHttpResponse();
resp->setStatusCode(HttpResponse::k417ExpectationFailed);
resp->setStatusCode(k417ExpectationFailed);
MsgBuffer buffer;
auto httpString = std::dynamic_pointer_cast<HttpResponseImpl>(resp)->renderToString();
connPtr->send(httpString);

View File

@ -28,7 +28,7 @@ using namespace drogon;
HttpResponsePtr HttpResponse::newHttpResponse()
{
auto res = std::make_shared<HttpResponseImpl>();
res->setStatusCode(HttpResponse::k200OK);
res->setStatusCode(k200OK);
res->setContentTypeCode(CT_TEXT_HTML);
return res;
}
@ -36,7 +36,7 @@ HttpResponsePtr HttpResponse::newHttpResponse()
HttpResponsePtr HttpResponse::newHttpJsonResponse(const Json::Value &data)
{
auto res = std::make_shared<HttpResponseImpl>();
res->setStatusCode(HttpResponse::k200OK);
res->setStatusCode(k200OK);
res->setContentTypeCode(CT_APPLICATION_JSON);
Json::StreamWriterBuilder builder;
builder["commentStyle"] = "None";
@ -49,7 +49,7 @@ HttpResponsePtr HttpResponse::newNotFoundResponse()
HttpViewData data;
data.insert("version", getVersion());
auto res = HttpResponse::newHttpViewResponse("NotFound", data);
res->setStatusCode(HttpResponse::k404NotFound);
res->setStatusCode(k404NotFound);
//res->setCloseConnection(true);
return res;
@ -57,7 +57,7 @@ HttpResponsePtr HttpResponse::newNotFoundResponse()
HttpResponsePtr HttpResponse::newLocationRedirectResponse(const std::string &path)
{
auto res = std::make_shared<HttpResponseImpl>();
res->setStatusCode(HttpResponse::k302Found);
res->setStatusCode(k302Found);
res->redirect(path.c_str());
return res;
}
@ -66,144 +66,6 @@ HttpResponsePtr HttpResponse::newHttpViewResponse(const std::string &viewName, c
{
return HttpViewBase::genHttpResponse(viewName, data);
}
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;
case CT_APPLICATION_XML:
return "application/xml; charset=" + charSet;
case CT_APPLICATION_JSON:
return "application/json; 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_XML:
return "text/xml; charset=" + charSet;
case CT_TEXT_XSL:
return "text/xsl; charset=" + charSet;
case CT_APPLICATION_OCTET_STREAM:
return "application/octet-stream";
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_OPENTYPE:
return "application/x-font-opentype";
case CT_APPLICATION_FONT_WOFF:
return "application/font-woff";
case CT_APPLICATION_FONT_WOFF2:
return "application/font-woff2";
case CT_APPLICATION_VND_MS_FONTOBJ:
return "application/vnd.ms-fontobject";
case CT_IMAGE_PNG:
return "image/png";
case CT_IMAGE_JPG:
return "image/jpeg";
case CT_IMAGE_GIF:
return "image/gif";
case CT_IMAGE_XICON:
return "image/x-icon";
case CT_IMAGE_BMP:
return "image/bmp";
case CT_IMAGE_ICNS:
return "image/icns";
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";
case CT_APPLICATION_XML:
return "application/xml; 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_TEXT_CSS:
return "text/css; 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_APPLICATION_OCTET_STREAM:
return "application/octet-stream";
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_OPENTYPE:
return "application/x-font-opentype";
case CT_APPLICATION_FONT_WOFF:
return "application/font-woff";
case CT_APPLICATION_FONT_WOFF2:
return "application/font-woff2";
case CT_APPLICATION_VND_MS_FONTOBJ:
return "application/vnd.ms-fontobject";
case CT_IMAGE_PNG:
return "image/png";
case CT_IMAGE_JPG:
return "image/jpeg";
case CT_IMAGE_GIF:
return "image/gif";
case CT_IMAGE_XICON:
return "image/x-icon";
case CT_IMAGE_BMP:
return "image/bmp";
case CT_IMAGE_ICNS:
return "image/icns";
default:
case CT_TEXT_PLAIN:
return "text/plain; charset=utf-8";
}
}
std::string HttpResponseImpl::web_response_code_to_string(int code)
{

View File

@ -14,6 +14,7 @@
#pragma once
#include "HttpUtils.h"
#include <drogon/HttpResponse.h>
#include <trantor/utils/MsgBuffer.h>
#include <trantor/net/InetAddress.h>
@ -79,19 +80,19 @@ class HttpResponseImpl : public HttpResponse
return _closeConnection;
}
virtual void setContentTypeCode(uint8_t type) override
virtual void setContentTypeCode(ContentType type) override
{
_contentType = type;
setContentType(web_content_type_to_string(type));
setContentType(webContentTypeToString(type));
}
virtual void setContentTypeCodeAndCharacterSet(uint8_t type, const std::string &charSet = "utf-8") override
virtual void setContentTypeCodeAndCharacterSet(ContentType type, const std::string &charSet = "utf-8") override
{
_contentType = type;
setContentType(web_content_type_and_charset_to_string(type, charSet));
setContentType(webContentTypeAndCharsetToString(type, charSet));
}
virtual uint8_t getContentTypeCode() override
virtual ContentType getContentTypeCode() override
{
return _contentType;
}
@ -360,12 +361,8 @@ class HttpResponseImpl : public HttpResponse
}
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(const std::shared_ptr<std::string> &headerStringPtr) const;
private:
@ -381,7 +378,7 @@ class HttpResponseImpl : public HttpResponse
size_t _currentChunkLength;
std::shared_ptr<std::string> _bodyPtr;
uint8_t _contentType = CT_TEXT_HTML;
ContentType _contentType = CT_TEXT_HTML;
ssize_t _expriedTime = -1;
std::string _sendfileName;

View File

@ -33,11 +33,11 @@ bool HttpResponseParser::processResponseLine(const char *begin, const char *end)
LOG_TRACE << *(space - 1);
if (*(space - 1) == '1')
{
_response->setVersion(HttpResponse::kHttp11);
_response->setVersion(kHttp11);
}
else if (*(space - 1) == '0')
{
_response->setVersion(HttpResponse::kHttp10);
_response->setVersion(kHttp10);
}
else
{
@ -53,7 +53,7 @@ bool HttpResponseParser::processResponseLine(const char *begin, const char *end)
std::string status_message(space + 1, end - space - 1);
LOG_TRACE << status_code << " " << status_message;
auto code = atoi(status_code.c_str());
_response->setStatusCode(HttpResponse::HttpStatusCode(code), status_message);
_response->setStatusCode(HttpStatusCode(code), status_message);
return true;
}

View File

@ -122,7 +122,7 @@ void HttpServer::onMessage(const TcpConnectionPtr &conn,
auto wsConn = std::make_shared<WebSocketConnectionImpl>(conn);
_newWebsocketCallback(requestParser->request(),
[=](const HttpResponsePtr &resp) mutable {
if (resp->statusCode() == HttpResponse::k101SwitchingProtocols)
if (resp->statusCode() == k101SwitchingProtocols)
{
requestParser->setWebsockConnection(wsConn);
}

View File

@ -82,7 +82,7 @@ void HttpSimpleControllersRouter::route(const HttpRequestImplPtr &req,
{
//Invalid Http Method
auto res = drogon::HttpResponse::newHttpResponse();
res->setStatusCode(HttpResponse::k405MethodNotAllowed);
res->setStatusCode(k405MethodNotAllowed);
callback(res);
return;
}

160
lib/src/HttpUtils.cc Normal file
View File

@ -0,0 +1,160 @@
/**
*
* HttpUtils.h
* An Tao
*
* Copyright 2018, An Tao. All rights reserved.
* https://github.com/an-tao/drogon
* Use of this source code is governed by a MIT license
* that can be found in the License file.
*
* Drogon
*
*/
#include "HttpUtils.h"
namespace drogon
{
std::string webContentTypeAndCharsetToString(ContentType contenttype, const std::string &charSet)
{
switch (contenttype)
{
case CT_TEXT_HTML:
return "text/html; charset=" + charSet;
case CT_APPLICATION_XML:
return "application/xml; charset=" + charSet;
case CT_APPLICATION_JSON:
return "application/json; 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_XML:
return "text/xml; charset=" + charSet;
case CT_TEXT_XSL:
return "text/xsl; charset=" + charSet;
case CT_APPLICATION_OCTET_STREAM:
return "application/octet-stream";
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_OPENTYPE:
return "application/x-font-opentype";
case CT_APPLICATION_FONT_WOFF:
return "application/font-woff";
case CT_APPLICATION_FONT_WOFF2:
return "application/font-woff2";
case CT_APPLICATION_VND_MS_FONTOBJ:
return "application/vnd.ms-fontobject";
case CT_IMAGE_PNG:
return "image/png";
case CT_IMAGE_JPG:
return "image/jpeg";
case CT_IMAGE_GIF:
return "image/gif";
case CT_IMAGE_XICON:
return "image/x-icon";
case CT_IMAGE_BMP:
return "image/bmp";
case CT_IMAGE_ICNS:
return "image/icns";
default:
case CT_TEXT_PLAIN:
return "text/plain; charset=" + charSet;
}
}
std::string webContentTypeToString(ContentType contenttype)
{
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_JSON:
return "application/json; 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_XML:
return "text/xml; charset=utf-8";
case CT_TEXT_XSL:
return "text/xsl; charset=utf-8";
case CT_APPLICATION_OCTET_STREAM:
return "application/octet-stream";
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_OPENTYPE:
return "application/x-font-opentype";
case CT_APPLICATION_FONT_WOFF:
return "application/font-woff";
case CT_APPLICATION_FONT_WOFF2:
return "application/font-woff2";
case CT_APPLICATION_VND_MS_FONTOBJ:
return "application/vnd.ms-fontobject";
case CT_IMAGE_PNG:
return "image/png";
case CT_IMAGE_JPG:
return "image/jpeg";
case CT_IMAGE_GIF:
return "image/gif";
case CT_IMAGE_XICON:
return "image/x-icon";
case CT_IMAGE_BMP:
return "image/bmp";
case CT_IMAGE_ICNS:
return "image/icns";
default:
case CT_TEXT_PLAIN:
return "text/plain; charset=utf-8";
}
}
}

25
lib/src/HttpUtils.h Normal file
View File

@ -0,0 +1,25 @@
/**
*
* HttpUtils.h
* An Tao
*
* Copyright 2018, An Tao. All rights reserved.
* https://github.com/an-tao/drogon
* Use of this source code is governed by a MIT license
* that can be found in the License file.
*
* Drogon
*
*/
#pragma once
#include <string>
#include <drogon/HttpTypes.h>
namespace drogon
{
std::string webContentTypeToString(ContentType contenttype);
std::string webContentTypeAndCharsetToString(ContentType contenttype, const std::string &charSet);
} // namespace drogon

View File

@ -35,7 +35,7 @@ HttpResponsePtr HttpViewBase::genHttpResponse(std::string viewName, const HttpVi
if (templ)
{
auto res = HttpResponse::newHttpResponse();
res->setStatusCode(HttpResponse::k200OK);
res->setStatusCode(k200OK);
res->setContentTypeCode(CT_TEXT_HTML);
res->setBody(templ->genText(data));
return res;

View File

@ -90,7 +90,7 @@ void WebsocketControllersRouter::doControllerHandler(const WebSocketControllerBa
SHA1(reinterpret_cast<const unsigned char *>(wsKey.c_str()), wsKey.length(), accKey);
auto base64Key = base64Encode(accKey, SHA_DIGEST_LENGTH);
auto resp = HttpResponse::newHttpResponse();
resp->setStatusCode(HttpResponse::k101SwitchingProtocols);
resp->setStatusCode(k101SwitchingProtocols);
resp->addHeader("Upgrade", "websocket");
resp->addHeader("Connection", "Upgrade");
resp->addHeader("Sec-WebSocket-Accept", base64Key);