Add the setCustomStatusCode method

This commit is contained in:
an-tao 2021-06-01 19:30:21 +08:00
parent c6b65485e1
commit b654e35e51
5 changed files with 172 additions and 64 deletions

View File

@ -105,6 +105,11 @@ class DROGON_EXPORT HttpResponse
/// Set the status code of the response.
virtual void setStatusCode(HttpStatusCode code) = 0;
void setCustomStatusCode(int code, string_view message = string_view{})
{
setCustomStatusCode(code, message.data(), message.length());
}
/// Get the creation timestamp of the response.
virtual const trantor::Date &creationDate() const = 0;
const trantor::Date &getCreationDate() const
@ -391,6 +396,9 @@ class DROGON_EXPORT HttpResponse
virtual void setContentTypeCodeAndCustomString(ContentType type,
const char *typeString,
size_t typeStringLength) = 0;
virtual void setCustomStatusCode(int code,
const char *message,
size_t messageLength) = 0;
};
template <>
inline HttpResponsePtr toResponse<const Json::Value &>(const Json::Value &pJson)

View File

@ -19,10 +19,11 @@ namespace drogon
{
enum HttpStatusCode
{
// rfc2616-6.1.1
kUnknown = 0,
k100Continue = 100,
k101SwitchingProtocols = 101,
k102Processing = 102,
k103EarlyHints = 103,
k200OK = 200,
k201Created = 201,
k202Accepted = 202,
@ -30,12 +31,16 @@ enum HttpStatusCode
k204NoContent = 204,
k205ResetContent = 205,
k206PartialContent = 206,
k207MultiStatus = 207,
k208AlreadyReported = 208,
k226IMUsed = 226,
k300MultipleChoices = 300,
k301MovedPermanently = 301,
k302Found = 302,
k303SeeOther = 303,
k304NotModified = 304,
k305UseProxy = 305,
k306Unused = 306,
k307TemporaryRedirect = 307,
k308PermanentRedirect = 308,
k400BadRequest = 400,
@ -58,6 +63,9 @@ enum HttpStatusCode
k417ExpectationFailed = 417,
k418ImATeapot = 418,
k421MisdirectedRequest = 421,
k422UnprocessableEntity = 422,
k423Locked = 423,
k424FailedDependency = 424,
k425TooEarly = 425,
k426UpgradeRequired = 426,
k428PreconditionRequired = 428,
@ -70,7 +78,11 @@ enum HttpStatusCode
k503ServiceUnavailable = 503,
k504GatewayTimeout = 504,
k505HTTPVersionNotSupported = 505,
k506VariantAlsoNegotiates = 506,
k507InsufficientStorage = 507,
k508LoopDetected = 508,
k510NotExtended = 510,
k511NetworkAuthenticationRequired = 511
};
enum class Version

View File

@ -19,7 +19,7 @@
#include <drogon/IOThreadStorage.h>
#include <fstream>
#include <memory>
#include <stdio.h>
#include <cstdio>
#include <sys/stat.h>
#include <trantor/utils/Logger.h>
#ifdef _WIN32
@ -159,8 +159,7 @@ HttpResponsePtr HttpResponse::newNotFoundResponse()
{
if (HttpAppFrameworkImpl::instance().isUsingCustomErrorHandler())
{
auto resp = app().getCustomErrorHandler()(k404NotFound);
return resp;
return app().getCustomErrorHandler()(k404NotFound);
}
HttpViewData data;
data.insert("version", drogon::getVersion());
@ -245,8 +244,8 @@ HttpResponsePtr HttpResponse::newFileResponse(
}
auto resp = std::make_shared<HttpResponseImpl>();
std::streambuf *pbuf = infile.rdbuf();
std::streamsize filesize = pbuf->pubseekoff(0, infile.end);
pbuf->pubseekoff(0, infile.beg); // rewind
std::streamsize filesize = pbuf->pubseekoff(0, std::ifstream::end);
pbuf->pubseekoff(0, std::ifstream::beg); // rewind
if (HttpAppFrameworkImpl::instance().useSendfile() && filesize > 1024 * 200)
// TODO : Is 200k an appropriate value? Or set it to be configurable
{
@ -295,17 +294,37 @@ void HttpResponseImpl::makeHeaderString(trantor::MsgBuffer &buffer)
int len{0};
if (version_ == Version::kHttp11)
{
len = snprintf(buffer.beginWrite(),
buffer.writableBytes(),
"HTTP/1.1 %d ",
statusCode_);
if (customStatusCode_ >= 0)
{
len = snprintf(buffer.beginWrite(),
buffer.writableBytes(),
"HTTP/1.1 %d ",
customStatusCode_);
}
else
{
len = snprintf(buffer.beginWrite(),
buffer.writableBytes(),
"HTTP/1.1 %d ",
statusCode_);
}
}
else
{
len = snprintf(buffer.beginWrite(),
buffer.writableBytes(),
"HTTP/1.0 %d ",
statusCode_);
if (customStatusCode_ >= 0)
{
len = snprintf(buffer.beginWrite(),
buffer.writableBytes(),
"HTTP/1.0 %d ",
customStatusCode_);
}
else
{
len = snprintf(buffer.beginWrite(),
buffer.writableBytes(),
"HTTP/1.0 %d ",
statusCode_);
}
}
buffer.hasWritten(len);
@ -326,7 +345,9 @@ void HttpResponseImpl::makeHeaderString(trantor::MsgBuffer &buffer)
}
else
{
struct stat filestat;
struct stat filestat
{
};
if (stat(sendfileName_.data(), &filestat) < 0)
{
LOG_SYSERR << sendfileName_ << " stat error";
@ -385,7 +406,7 @@ void HttpResponseImpl::renderToBuffer(trantor::MsgBuffer &buffer)
}
// output cookies
if (cookies_.size() > 0)
if (!cookies_.empty())
{
for (auto it = cookies_.begin(); it != cookies_.end(); ++it)
{
@ -457,7 +478,7 @@ std::shared_ptr<trantor::MsgBuffer> HttpResponseImpl::renderToBuffer()
}
// output cookies
if (cookies_.size() > 0)
if (!cookies_.empty())
{
for (auto it = cookies_.begin(); it != cookies_.end(); ++it)
{
@ -506,7 +527,7 @@ std::shared_ptr<trantor::MsgBuffer> HttpResponseImpl::
}
// output cookies
if (cookies_.size() > 0)
if (!cookies_.empty())
{
for (auto it = cookies_.begin(); it != cookies_.end(); ++it)
{
@ -698,10 +719,6 @@ void HttpResponseImpl::parseJson() const
}
}
HttpResponseImpl::~HttpResponseImpl()
{
}
bool HttpResponseImpl::shouldBeCompressed() const
{
if (!sendfileName_.empty() ||

View File

@ -47,27 +47,27 @@ class DROGON_EXPORT HttpResponseImpl : public HttpResponse
contentTypeString_(webContentTypeToString(type))
{
}
virtual void setPassThrough(bool flag) override
void setPassThrough(bool flag) override
{
passThrough_ = flag;
}
virtual HttpStatusCode statusCode() const override
HttpStatusCode statusCode() const override
{
return statusCode_;
}
virtual const trantor::Date &creationDate() const override
const trantor::Date &creationDate() const override
{
return creationDate_;
}
virtual void setStatusCode(HttpStatusCode code) override
void setStatusCode(HttpStatusCode code) override
{
statusCode_ = code;
setStatusMessage(statusCodeToString(code));
}
virtual void setVersion(const Version v) override
void setVersion(const Version v) override
{
version_ = v;
if (version_ == Version::kHttp10)
@ -76,42 +76,42 @@ class DROGON_EXPORT HttpResponseImpl : public HttpResponse
}
}
virtual Version version() const override
Version version() const override
{
return version_;
}
virtual void setCloseConnection(bool on) override
void setCloseConnection(bool on) override
{
closeConnection_ = on;
}
virtual bool ifCloseConnection() const override
bool ifCloseConnection() const override
{
return closeConnection_;
}
virtual void setContentTypeCode(ContentType type) override
void setContentTypeCode(ContentType type) override
{
contentType_ = type;
setContentType(webContentTypeToString(type));
flagForParsingContentType_ = true;
}
// virtual void setContentTypeCodeAndCharacterSet(ContentType type, const
// void setContentTypeCodeAndCharacterSet(ContentType type, const
// std::string &charSet = "utf-8") override
// {
// contentType_ = type;
// setContentType(webContentTypeAndCharsetToString(type, charSet));
// }
virtual ContentType contentType() const override
ContentType contentType() const override
{
if (!flagForParsingContentType_)
{
flagForParsingContentType_ = true;
auto &contentTypeString = getHeaderBy("content-type");
if (contentTypeString == "")
if (contentTypeString.empty())
{
contentType_ = CT_NONE;
}
@ -133,20 +133,19 @@ class DROGON_EXPORT HttpResponseImpl : public HttpResponse
return contentType_;
}
virtual const std::string &getHeader(std::string key) const override
const std::string &getHeader(std::string key) const override
{
transform(key.begin(), key.end(), key.begin(), ::tolower);
return getHeaderBy(key);
}
virtual void removeHeader(std::string key) override
void removeHeader(std::string key) override
{
transform(key.begin(), key.end(), key.begin(), ::tolower);
removeHeaderBy(key);
}
virtual const std::unordered_map<std::string, std::string> &headers()
const override
const std::unordered_map<std::string, std::string> &headers() const override
{
return headers_;
}
@ -168,14 +167,14 @@ class DROGON_EXPORT HttpResponseImpl : public HttpResponse
headers_.erase(lowerKey);
}
virtual void addHeader(std::string field, const std::string &value) override
void addHeader(std::string field, const std::string &value) override
{
fullHeaderString_.reset();
transform(field.begin(), field.end(), field.begin(), ::tolower);
headers_[std::move(field)] = value;
}
virtual void addHeader(std::string field, std::string &&value) override
void addHeader(std::string field, std::string &&value) override
{
fullHeaderString_.reset();
transform(field.begin(), field.end(), field.begin(), ::tolower);
@ -184,23 +183,22 @@ class DROGON_EXPORT HttpResponseImpl : public HttpResponse
void addHeader(const char *start, const char *colon, const char *end);
virtual void addCookie(const std::string &key,
const std::string &value) override
void addCookie(const std::string &key, const std::string &value) override
{
cookies_[key] = Cookie(key, value);
}
virtual void addCookie(const Cookie &cookie) override
void addCookie(const Cookie &cookie) override
{
cookies_[cookie.key()] = cookie;
}
virtual void addCookie(Cookie &&cookie) override
void addCookie(Cookie &&cookie) override
{
cookies_[cookie.key()] = std::move(cookie);
}
virtual const Cookie &getCookie(const std::string &key) const override
const Cookie &getCookie(const std::string &key) const override
{
static const Cookie defaultCookie;
auto it = cookies_.find(key);
@ -211,18 +209,17 @@ class DROGON_EXPORT HttpResponseImpl : public HttpResponse
return defaultCookie;
}
virtual const std::unordered_map<std::string, Cookie> &cookies()
const override
const std::unordered_map<std::string, Cookie> &cookies() const override
{
return cookies_;
}
virtual void removeCookie(const std::string &key) override
void removeCookie(const std::string &key) override
{
cookies_.erase(key);
}
virtual void setBody(const std::string &body) override
void setBody(const std::string &body) override
{
bodyPtr_ = std::make_shared<HttpMessageStringBody>(body);
if (passThrough_)
@ -230,7 +227,7 @@ class DROGON_EXPORT HttpResponseImpl : public HttpResponse
addHeader("content-length", std::to_string(bodyPtr_->length()));
}
}
virtual void setBody(std::string &&body) override
void setBody(std::string &&body) override
{
bodyPtr_ = std::make_shared<HttpMessageStringBody>(std::move(body));
if (passThrough_)
@ -246,9 +243,9 @@ class DROGON_EXPORT HttpResponseImpl : public HttpResponse
std::shared_ptr<trantor::MsgBuffer> renderToBuffer();
void renderToBuffer(trantor::MsgBuffer &buffer);
std::shared_ptr<trantor::MsgBuffer> renderHeaderForHeadMethod();
virtual void clear() override;
void clear() override;
virtual void setExpiredTime(ssize_t expiredTime) override
void setExpiredTime(ssize_t expiredTime) override
{
expriedTime_ = expiredTime;
datePos_ = std::string::npos;
@ -258,12 +255,12 @@ class DROGON_EXPORT HttpResponseImpl : public HttpResponse
}
}
virtual ssize_t expiredTime() const override
ssize_t expiredTime() const override
{
return expriedTime_;
}
virtual const char *getBodyData() const override
const char *getBodyData() const override
{
if (!flagForSerializingJson_ && jsonPtr_)
{
@ -275,7 +272,7 @@ class DROGON_EXPORT HttpResponseImpl : public HttpResponse
}
return bodyPtr_->data();
}
virtual size_t getBodyLength() const override
size_t getBodyLength() const override
{
if (bodyPtr_)
return bodyPtr_->length();
@ -284,7 +281,7 @@ class DROGON_EXPORT HttpResponseImpl : public HttpResponse
void swap(HttpResponseImpl &that) noexcept;
void parseJson() const;
virtual const std::shared_ptr<Json::Value> &jsonObject() const override
const std::shared_ptr<Json::Value> &jsonObject() const override
{
// Not multi-thread safe but good, because we basically call this
// function in a single thread
@ -295,9 +292,9 @@ class DROGON_EXPORT HttpResponseImpl : public HttpResponse
}
return jsonPtr_;
}
virtual const std::string &getJsonError() const override
const std::string &getJsonError() const override
{
const static std::string none{""};
const static std::string none;
if (jsonParsingErrorPtr_)
return *jsonParsingErrorPtr_;
return none;
@ -356,13 +353,13 @@ class DROGON_EXPORT HttpResponseImpl : public HttpResponse
}
}
#endif
~HttpResponseImpl();
~HttpResponseImpl() override = default;
protected:
void makeHeaderString(trantor::MsgBuffer &headerString);
private:
virtual void setBody(const char *body, size_t len) override
void setBody(const char *body, size_t len) override
{
bodyPtr_ = std::make_shared<HttpMessageStringViewBody>(body, len);
if (passThrough_)
@ -370,19 +367,28 @@ class DROGON_EXPORT HttpResponseImpl : public HttpResponse
addHeader("content-length", std::to_string(bodyPtr_->length()));
}
}
virtual void setContentTypeCodeAndCustomString(
ContentType type,
const char *typeString,
size_t typeStringLength) override
void setContentTypeCodeAndCustomString(ContentType type,
const char *typeString,
size_t typeStringLength) override
{
contentType_ = type;
flagForParsingContentType_ = true;
setContentType(string_view{typeString, typeStringLength});
}
void setCustomStatusCode(int code,
const char *message,
size_t messageLength) override
{
assert(code >= 0);
customStatusCode_ = code;
statusMessage_ = string_view{message, messageLength};
}
std::unordered_map<std::string, std::string> headers_;
std::unordered_map<std::string, Cookie> cookies_;
int customStatusCode_{-1};
HttpStatusCode statusCode_{kUnknown};
string_view statusMessage_;

View File

@ -186,6 +186,16 @@ const string_view &statusCodeToString(int code)
static string_view sv = "Switching Protocols";
return sv;
}
case 102:
{
static string_view sv = "Processing";
return sv;
}
case 103:
{
static string_view sv = "Early Hints";
return sv;
}
case 200:
{
static string_view sv = "OK";
@ -221,6 +231,21 @@ const string_view &statusCodeToString(int code)
static string_view sv = "Partial Content";
return sv;
}
case 207:
{
static string_view sv = "Multi-Status";
return sv;
}
case 208:
{
static string_view sv = "Already Reported";
return sv;
}
case 226:
{
static string_view sv = "IM Used";
return sv;
}
case 300:
{
static string_view sv = "Multiple Choices";
@ -251,6 +276,11 @@ const string_view &statusCodeToString(int code)
static string_view sv = "Use Proxy";
return sv;
}
case 306:
{
static string_view sv = "(Unused)";
return sv;
}
case 307:
{
static string_view sv = "Temporary Redirect";
@ -361,6 +391,21 @@ const string_view &statusCodeToString(int code)
static string_view sv = "Misdirected Request";
return sv;
}
case 422:
{
static string_view sv = "Unprocessable Entity";
return sv;
}
case 423:
{
static string_view sv = "Locked";
return sv;
}
case 424:
{
static string_view sv = "Failed Dependency";
return sv;
}
case 425:
{
static string_view sv = "Too Early";
@ -421,11 +466,31 @@ const string_view &statusCodeToString(int code)
static string_view sv = "HTTP Version Not Supported";
return sv;
}
case 506:
{
static string_view sv = "Variant Also Negotiates";
return sv;
}
case 507:
{
static string_view sv = "Insufficient Storage";
return sv;
}
case 508:
{
static string_view sv = "Loop Detected";
return sv;
}
case 510:
{
static string_view sv = "Not Extended";
return sv;
}
case 511:
{
static string_view sv = "Network Authentication Required";
return sv;
}
default:
if (code >= 100 && code < 200)
{