- New dto/InternalDto.hpp with JsonErrorDto, WsEntityEventDto, WsPresenceUpdateDto, WsClientMsgDto. - JsonErrorHandler: now takes a shared ObjectMapper (DI). Body built via writeToString on JsonErrorDto. Closes the audit's concrete bug where status.description was embedded raw — a Status with a `"`/`\\` in the description previously emitted invalid JSON. - AuthInterceptor: takes an optional ObjectMapper ctor arg (defaults to a fresh mapper). makeForbidden's `msg` is now serialised via JsonErrorDto + ObjectMapper, so a `"` in a forbidden-reason no longer breaks the response envelope. - Hub: process-wide sharedMapper() with optional setObjectMapper() override. buildPresenceMsg / notifyBooking / notifyPerson all go through ObjectMapper-emitted DTOs. User-supplied IDs / property IDs / usernames containing `"`/`\\`/control chars are now escaped. - Listener: jsonStr/jsonInt regex parsers gone. handleMessage parses inbound frames via ObjectMapper::readFromString into WsClientMsgDto. Malformed JSON / nested objects / escaped quotes — previously silent corruption — now produce a clean drop of the frame. - test/test_json_serialization.cpp: 4 cases pinning the round-trip behaviour (special chars in usernames, IDs, status.description, and malformed-input rejection). Bump to 0.4.0 — ctor signatures changed (additive defaults, but the behaviour of the JSON envelopes is now governed by ObjectMapper). Closes #6 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
62 lines
2.2 KiB
C++
62 lines
2.2 KiB
C++
#ifndef HANDLER_JSON_ERROR_HANDLER_HPP
|
|
#define HANDLER_JSON_ERROR_HANDLER_HPP
|
|
|
|
#include "oatpp/web/server/handler/ErrorHandler.hpp"
|
|
#include "oatpp/web/protocol/http/outgoing/ResponseFactory.hpp"
|
|
#include "oatpp/parser/json/mapping/ObjectMapper.hpp"
|
|
|
|
#include "../dto/InternalDto.hpp"
|
|
|
|
namespace oatpp_authkit {
|
|
|
|
/**
|
|
* @brief Custom error handler that returns JSON error responses.
|
|
*
|
|
* Replaces oatpp's default plain-text error handler so that
|
|
* OATPP_ASSERT_HTTP errors are returned as JSON objects matching the
|
|
* `JsonErrorDto` schema: `{"status": "...", "code": N, "message": "..."}`.
|
|
*
|
|
* Routing through `ObjectMapper` (DI'd) replaces the previous hand-rolled
|
|
* concatenation that embedded `status.description` raw — see #6.
|
|
*/
|
|
class JsonErrorHandler : public oatpp::web::server::handler::ErrorHandler {
|
|
private:
|
|
std::shared_ptr<oatpp::data::mapping::ObjectMapper> m_mapper;
|
|
|
|
public:
|
|
|
|
/**
|
|
* @param mapper Shared JSON object mapper. Pass nullptr for a
|
|
* handler-owned default mapper (back-compat path).
|
|
*/
|
|
explicit JsonErrorHandler(std::shared_ptr<oatpp::data::mapping::ObjectMapper> mapper = nullptr)
|
|
: m_mapper(mapper ? mapper : oatpp::parser::json::mapping::ObjectMapper::createShared()) {}
|
|
|
|
std::shared_ptr<oatpp::web::protocol::http::outgoing::Response>
|
|
handleError(const oatpp::web::protocol::http::Status& status,
|
|
const oatpp::String& message,
|
|
const Headers& headers) override
|
|
{
|
|
auto dto = dto::JsonErrorDto::createShared();
|
|
dto->status = oatpp::String(std::string(status.description));
|
|
dto->code = status.code;
|
|
dto->message = message ? message : oatpp::String("");
|
|
|
|
oatpp::String json = m_mapper->writeToString(dto);
|
|
|
|
auto response = oatpp::web::protocol::http::outgoing::ResponseFactory::createResponse(
|
|
status, json
|
|
);
|
|
response->putHeader("Content-Type", "application/json");
|
|
|
|
for (const auto& pair : headers.getAll()) {
|
|
response->putHeader(pair.first.toString(), pair.second.toString());
|
|
}
|
|
|
|
return response;
|
|
}
|
|
};
|
|
|
|
} // namespace oatpp_authkit
|
|
|
|
#endif // HANDLER_JSON_ERROR_HANDLER_HPP
|