diff --git a/lib/inc/drogon/HttpRequest.h b/lib/inc/drogon/HttpRequest.h index 700e9be4..115f0c11 100644 --- a/lib/inc/drogon/HttpRequest.h +++ b/lib/inc/drogon/HttpRequest.h @@ -1,6 +1,6 @@ /** * - * HttpRequest.h + * @file HttpRequest.h * An Tao * * Copyright 2018, An Tao. All rights reserved. @@ -280,14 +280,24 @@ class HttpRequest * string (the part after the question mark in the URI) must be empty, * otherwise the method returns an empty shared_ptr object. */ - virtual const std::shared_ptr jsonObject() const = 0; + virtual const std::shared_ptr &jsonObject() const = 0; /// Get the Json object of the request - const std::shared_ptr getJsonObject() const + const std::shared_ptr &getJsonObject() const { return jsonObject(); } + /** + * @brief Get the error message of parsing the JSON body received from peer. + * This method usually is called after getting a empty shared_ptr object + * by the getJsonObject() method. + * + * @return const std::string& The error message. An empty string is returned + * when no error occurs. + */ + virtual const std::string &getJsonError() const = 0; + /// Get the content type virtual ContentType contentType() const = 0; ContentType getContentType() const diff --git a/lib/inc/drogon/HttpResponse.h b/lib/inc/drogon/HttpResponse.h index 9e6912e0..ed9c79bf 100644 --- a/lib/inc/drogon/HttpResponse.h +++ b/lib/inc/drogon/HttpResponse.h @@ -276,12 +276,22 @@ class HttpResponse /// Get the json object from the server response. /// If the response is not in json format, then a empty shared_ptr is /// retured. - virtual const std::shared_ptr jsonObject() const = 0; - const std::shared_ptr getJsonObject() const + virtual const std::shared_ptr &jsonObject() const = 0; + const std::shared_ptr &getJsonObject() const { return jsonObject(); } + /** + * @brief Get the error message of parsing the JSON body received from peer. + * This method usually is called after getting a empty shared_ptr object + * by the getJsonObject() method. + * + * @return const std::string& The error message. An empty string is returned + * when no error occurs. + */ + virtual const std::string &getJsonError() const = 0; + /** * @brief Set the reponse object to the pass-through mode or not. It's not * by default when a new response object is created. diff --git a/lib/src/HttpRequestImpl.cc b/lib/src/HttpRequestImpl.cc index f13ee255..c38d514e 100644 --- a/lib/src/HttpRequestImpl.cc +++ b/lib/src/HttpRequestImpl.cc @@ -1,6 +1,6 @@ /** * - * HttpRequestImpl.cc + * @file HttpRequestImpl.cc * An Tao * * Copyright 2018, An Tao. All rights reserved. @@ -46,11 +46,19 @@ void HttpRequestImpl::parseJson() const { LOG_ERROR << errs; jsonPtr_.reset(); + jsonParsingErrorPtr_ = + std::make_unique(std::move(errs)); + } + else + { + jsonParsingErrorPtr_.reset(); } } else { jsonPtr_.reset(); + jsonParsingErrorPtr_ = + std::make_unique("content type error"); } } void HttpRequestImpl::parseParameters() const @@ -412,7 +420,7 @@ void HttpRequestImpl::addHeader(const char *start, case 6: if (field == "expect") { - expect_ = value; + expectPtr_ = std::make_unique(value); } break; case 10: @@ -506,12 +514,13 @@ void HttpRequestImpl::swap(HttpRequestImpl &that) noexcept swap(local_, that.local_); swap(creationDate_, that.creationDate_); swap(content_, that.content_); - swap(expect_, that.expect_); + swap(expectPtr_, that.expectPtr_); swap(contentType_, that.contentType_); swap(contentTypeString_, that.contentTypeString_); swap(keepAlive_, that.keepAlive_); swap(loop_, that.loop_); swap(flagForParsingContentType_, that.flagForParsingContentType_); + swap(jsonParsingErrorPtr_, that.jsonParsingErrorPtr_); } const char *HttpRequestImpl::methodString() const diff --git a/lib/src/HttpRequestImpl.h b/lib/src/HttpRequestImpl.h index 857e457c..2c976279 100644 --- a/lib/src/HttpRequestImpl.h +++ b/lib/src/HttpRequestImpl.h @@ -1,6 +1,6 @@ /** * - * HttpRequestImpl.h + * @file HttpRequestImpl.h * An Tao * * Copyright 2018, An Tao. All rights reserved. @@ -58,12 +58,13 @@ class HttpRequestImpl : public HttpRequest sessionPtr_.reset(); attributesPtr_.reset(); cacheFilePtr_.reset(); - expect_.clear(); + expectPtr_.reset(); content_.clear(); contentType_ = CT_TEXT_PLAIN; flagForParsingContentType_ = false; contentTypeString_.clear(); keepAlive_ = true; + jsonParsingErrorPtr_.reset(); } trantor::EventLoop *getLoop() { @@ -351,7 +352,7 @@ class HttpRequestImpl : public HttpRequest return attributesPtr_; } - virtual const std::shared_ptr jsonObject() const override + virtual const std::shared_ptr &jsonObject() const override { // Not multi-thread safe but good, because we basically call this // function in a single thread @@ -427,7 +428,10 @@ class HttpRequestImpl : public HttpRequest } const std::string &expect() const { - return expect_; + const static std::string none{""}; + if (expectPtr_) + return *expectPtr_; + return none; } bool keepAlive() const { @@ -437,6 +441,13 @@ class HttpRequestImpl : public HttpRequest { return isOnSecureConnection_; } + virtual const std::string &getJsonError() const override + { + const static std::string none{""}; + if (jsonParsingErrorPtr_) + return *jsonParsingErrorPtr_; + return none; + } ~HttpRequestImpl(); @@ -482,7 +493,8 @@ class HttpRequestImpl : public HttpRequest trantor::InetAddress local_; trantor::Date creationDate_; std::unique_ptr cacheFilePtr_; - std::string expect_; + mutable std::unique_ptr jsonParsingErrorPtr_; + std::unique_ptr expectPtr_; bool keepAlive_{true}; bool isOnSecureConnection_{false}; bool passThrough_{false}; diff --git a/lib/src/HttpResponseImpl.cc b/lib/src/HttpResponseImpl.cc index 1df87474..fc37eb83 100644 --- a/lib/src/HttpResponseImpl.cc +++ b/lib/src/HttpResponseImpl.cc @@ -591,6 +591,7 @@ void HttpResponseImpl::swap(HttpResponseImpl &that) noexcept fullHeaderString_.swap(that.fullHeaderString_); httpString_.swap(that.httpString_); swap(datePos_, that.datePos_); + swap(jsonParsingErrorPtr_, that.jsonParsingErrorPtr_); } void HttpResponseImpl::clear() @@ -599,6 +600,7 @@ void HttpResponseImpl::clear() version_ = Version::kHttp11; statusMessage_ = string_view{}; fullHeaderString_.reset(); + jsonParsingErrorPtr_.reset(); sendfileName_.clear(); headers_.clear(); cookies_.clear(); @@ -628,11 +630,19 @@ void HttpResponseImpl::parseJson() const LOG_ERROR << errs; LOG_ERROR << "body: " << bodyPtr_->getString(); jsonPtr_.reset(); + jsonParsingErrorPtr_ = + std::make_shared(std::move(errs)); + } + else + { + jsonParsingErrorPtr_.reset(); } } else { jsonPtr_.reset(); + jsonParsingErrorPtr_ = + std::make_shared("empty response body"); } } diff --git a/lib/src/HttpResponseImpl.h b/lib/src/HttpResponseImpl.h index fc219d64..4326cc73 100644 --- a/lib/src/HttpResponseImpl.h +++ b/lib/src/HttpResponseImpl.h @@ -291,7 +291,7 @@ class HttpResponseImpl : public HttpResponse void swap(HttpResponseImpl &that) noexcept; void parseJson() const; - virtual const std::shared_ptr jsonObject() const override + virtual const std::shared_ptr &jsonObject() const override { // Not multi-thread safe but good, because we basically call this // function in a single thread @@ -302,6 +302,13 @@ class HttpResponseImpl : public HttpResponse } return jsonPtr_; } + virtual const std::string &getJsonError() const override + { + const static std::string none{""}; + if (jsonParsingErrorPtr_) + return *jsonParsingErrorPtr_; + return none; + } void setJsonObject(const Json::Value &pJson) { flagForParsingJson_ = true; @@ -396,6 +403,7 @@ class HttpResponseImpl : public HttpResponse mutable bool flagForSerializingJson_{true}; mutable ContentType contentType_{CT_TEXT_PLAIN}; mutable bool flagForParsingContentType_{false}; + mutable std::shared_ptr jsonParsingErrorPtr_; string_view contentTypeString_{ "Content-Type: text/html; charset=utf-8\r\n"}; bool passThrough_{false};