Skip to content

Commit 694800e

Browse files
Parse JSON string in HTTP request body
1 parent 14ed4ef commit 694800e

File tree

3 files changed

+54
-45
lines changed

3 files changed

+54
-45
lines changed

src/proteus/clients/http_internal.cpp

Lines changed: 42 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -543,53 +543,54 @@ drogon::HttpResponsePtr errorHttpResponse(const std::string &error,
543543
return resp;
544544
}
545545

546-
DrogonHttp::DrogonHttp(const drogon::HttpRequestPtr &req,
547-
DrogonCallback callback) {
548-
this->req_ = req;
549-
this->callback_ = std::move(callback);
550-
this->type_ = InterfaceType::kDrogonHttp;
551-
this->json_ = nullptr;
552-
}
553-
554-
void DrogonHttp::setJson() {
546+
std::shared_ptr<Json::Value> parseJson(const drogon::HttpRequest *req) {
555547
#ifdef PROTEUS_ENABLE_LOGGING
556-
const auto &logger = this->getLogger();
548+
Logger logger{Loggers::kServer};
557549
#endif
558-
const auto &json_raw = this->req_->getJsonObject();
559-
560-
// if we fail to get the JSON object, return
561-
if (json_raw == nullptr) {
562-
auto root = std::make_shared<Json::Value>();
563-
std::string errors;
564-
Json::CharReaderBuilder builder;
565-
Json::CharReader *reader = builder.newCharReader();
566-
auto body = this->req_->getBody();
567-
auto body_parsed = z_decompress(body.data(), body.length());
568-
if (body_parsed.empty()) {
569-
this->callback_(errorHttpResponse("Failed attempt to inflate request",
570-
HttpStatusCode::k400BadRequest));
571-
return;
572-
}
573-
bool parsingSuccessful =
574-
reader->parse(body_parsed.data(), body_parsed.data() + body_parsed.size(),
575-
root.get(), &errors);
576-
if (!parsingSuccessful) {
577-
this->callback_(errorHttpResponse("Failed to parse JSON request",
578-
HttpStatusCode::k400BadRequest));
579-
return;
580-
}
581-
PROTEUS_LOG_INFO(logger, "Successfully inflated request");
582-
this->json_ = std::move(root);
583-
} else {
584-
this->json_ = json_raw;
550+
551+
// attempt to get the JSON object directly first
552+
const auto &json_obj = req->getJsonObject();
553+
if (json_obj != nullptr) {
554+
return json_obj;
585555
}
586-
}
587556

588-
size_t DrogonHttp::getInputSize() {
589-
if (this->json_ == nullptr) {
590-
this->setJson();
557+
PROTEUS_LOG_DEBUG(logger, "Failed to get JSON data directly");
558+
559+
// if it's not valid, then we need to attempt to parse the body
560+
auto root = std::make_shared<Json::Value>();
561+
562+
std::string errors;
563+
Json::CharReaderBuilder builder;
564+
Json::CharReader *reader = builder.newCharReader();
565+
auto body = req->getBody();
566+
bool success =
567+
reader->parse(body.data(), body.data() + body.size(), root.get(), &errors);
568+
if (success) {
569+
return root;
570+
}
571+
572+
PROTEUS_LOG_DEBUG(logger, "Failed to interpret body as JSON data");
573+
574+
// if it's still not valid, attempt to uncompress the body and convert to JSON
575+
auto body_decompress = z_decompress(body.data(), body.length());
576+
success = reader->parse(body_decompress.data(),
577+
body_decompress.data() + body_decompress.size(),
578+
root.get(), &errors);
579+
if (success) {
580+
return root;
591581
}
592582

583+
throw std::invalid_argument("Failed to interpret request body as JSON");
584+
}
585+
586+
DrogonHttp::DrogonHttp(const drogon::HttpRequestPtr &req,
587+
DrogonCallback callback)
588+
: req_(req), callback_(std::move(callback)) {
589+
this->type_ = InterfaceType::kDrogonHttp;
590+
this->json_ = parseJson(req.get());
591+
}
592+
593+
size_t DrogonHttp::getInputSize() {
593594
if (!this->json_->isMember("inputs")) {
594595
throw std::invalid_argument("No 'inputs' key present in request");
595596
}

src/proteus/clients/http_internal.hpp

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -106,9 +106,6 @@ class DrogonHttp : public Interface {
106106
void errorHandler(const std::invalid_argument &e) override;
107107

108108
private:
109-
/// parse the request's JSON payload and save it for future use
110-
void setJson();
111-
112109
drogon::HttpRequestPtr req_;
113110
DrogonCallback callback_;
114111
std::shared_ptr<Json::Value> json_;

src/proteus/servers/http_server.cpp

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -258,7 +258,18 @@ void v2::ProteusHttpServer::inferModel(
258258
return;
259259
}
260260

261-
auto request = std::make_unique<DrogonHttp>(req, std::move(callback));
261+
std::unique_ptr<DrogonHttp> request;
262+
try {
263+
request = std::make_unique<DrogonHttp>(req, std::move(callback));
264+
} catch (const std::invalid_argument &e) {
265+
PROTEUS_LOG_INFO(logger_, e.what());
266+
auto resp = errorHttpResponse(e.what(), HttpStatusCode::k400BadRequest);
267+
#ifdef PROTEUS_ENABLE_TRACING
268+
auto context = trace->propagate();
269+
propagate(resp.get(), context);
270+
#endif
271+
callback(resp);
272+
}
262273
#ifdef PROTEUS_ENABLE_METRICS
263274
request->set_time(now);
264275
#endif

0 commit comments

Comments
 (0)