Error-Handling: implement async-API

This commit is contained in:
Leonid Stryzhevskyi 2024-06-04 01:39:10 +03:00
parent 471c15d4be
commit f22afbe89c
11 changed files with 690 additions and 645 deletions

View File

@ -260,7 +260,7 @@ Action CoroutineHandle::takeAction(Action&& action) {
_CP = action.m_data.coroutine;
_FP = &AbstractCoroutine::act;
action.m_type = Action::TYPE_NONE;
return std::forward<oatpp::async::Action>(action);
return std::move(action);
}
case Action::TYPE_FINISH: {
@ -277,7 +277,7 @@ Action CoroutineHandle::takeAction(Action&& action) {
case Action::TYPE_YIELD_TO: {
_FP = action.m_data.fptr;
//break;
return std::forward<oatpp::async::Action>(action);
return std::move(action);
}
// case Action::TYPE_REPEAT: {
@ -289,7 +289,12 @@ Action CoroutineHandle::takeAction(Action&& action) {
// }
case Action::TYPE_ERROR: {
Action newAction = _CP->handleError(action.m_data.error);
Action newAction;
try {
newAction = _CP->handleError(action.m_data.error);
} catch (...) {
newAction = new Error(std::current_exception());
}
if (newAction.m_type == Action::TYPE_ERROR) {
AbstractCoroutine* savedCP = _CP;
@ -303,7 +308,7 @@ Action CoroutineHandle::takeAction(Action&& action) {
if(_CP == nullptr) {
delete action.m_data.error;
action.m_type = Action::TYPE_NONE;
return std::forward<oatpp::async::Action>(action);
return std::move(action);
}
} else {
action = std::move(newAction);
@ -313,7 +318,7 @@ Action CoroutineHandle::takeAction(Action&& action) {
}
default:
return std::forward<oatpp::async::Action>(action);
return std::move(action);
}
@ -329,10 +334,8 @@ Action CoroutineHandle::takeAction(Action&& action) {
Action CoroutineHandle::iterate() {
try {
return _CP->call(_FP);
} catch (std::exception& e) {
return new Error(e.what());
} catch (...) {
return new Error("[oatpp::async::CoroutineHandle::iterate()]: Error. Unknown Exception.");
return new Error(std::current_exception());
}
}

View File

@ -26,8 +26,23 @@
namespace oatpp { namespace async {
Error::Error(const std::string& what)
: runtime_error(what)
{}
Error::Error(const std::string& message)
: m_message(message)
{
}
Error::Error(const std::exception_ptr& exceptionPtr)
: m_message("exception_ptr")
, m_exceptionPtr(exceptionPtr)
{
}
const std::string& Error::what() const {
return m_message;
}
const std::exception_ptr& Error::getExceptionPtr() const {
return m_exceptionPtr;
}
}}

View File

@ -26,21 +26,24 @@
#define oatpp_async_Error_hpp
#include "oatpp/base/Countable.hpp"
#include <string>
namespace oatpp { namespace async {
/**
* Class to hold and communicate errors between Coroutines
*/
class Error : public std::runtime_error, public oatpp::base::Countable {
class Error : public oatpp::base::Countable {
private:
std::string m_message;
std::exception_ptr m_exceptionPtr;
public:
/**
* Constructor.
* @param what - error explanation.
*/
explicit Error(const std::string& what);
explicit Error(const std::string& message);
explicit Error(const std::exception_ptr& exceptionPtr);
const std::exception_ptr& getExceptionPtr() const;
const std::string& what() const;
/**
* Check if error belongs to specified class.

View File

@ -160,10 +160,7 @@ HttpProcessor::ConnectionState HttpProcessor::processNextRequest(ProcessingResou
for (auto &interceptor: resources.components->responseInterceptors) {
response = interceptor->intercept(request, response);
if (!response) {
HttpServerError httpError(request, "Response Interceptor returned an Invalid Response - 'null'");
auto ePtr = std::make_exception_ptr(httpError);
response = resources.components->errorHandler->handleError(ePtr);
connectionState = ConnectionState::CLOSING;
throw protocol::http::HttpError(protocol::http::Status::CODE_500, "Response Interceptor returned an Invalid Response - 'null'");
}
}
@ -289,6 +286,7 @@ HttpProcessor::Coroutine::Coroutine(const std::shared_ptr<Components>& component
, m_inStream(data::stream::InputStreamBufferedProxy::createShared(m_connection.object, std::make_shared<std::string>(data::buffer::IOBuffer::BUFFER_SIZE, 0)))
, m_connectionState(ConnectionState::ALIVE)
, m_taskListener(taskListener)
, m_shouldInterceptResponse(false)
{
m_taskListener->onTaskStart(m_connection);
}
@ -302,6 +300,7 @@ HttpProcessor::Coroutine::Action HttpProcessor::Coroutine::act() {
}
HttpProcessor::Coroutine::Action HttpProcessor::Coroutine::parseHeaders() {
m_shouldInterceptResponse = true;
return m_headersReader.readHeadersAsync(m_inStream).callbackTo(&HttpProcessor::Coroutine::onHeadersParsed);
}
@ -327,11 +326,11 @@ oatpp::async::Action HttpProcessor::Coroutine::onHeadersParsed(const RequestHead
data::stream::BufferOutputStream ss;
ss << "No mapping for HTTP-method: '" << headersReadResult.startingLine.method.toString()
<< "', URL: '" << headersReadResult.startingLine.path.toString() << "'";
oatpp::web::protocol::http::HttpError error(protocol::http::Status::CODE_404, ss.toString());
auto eptr = std::make_exception_ptr(error);
m_currentResponse = m_components->errorHandler->handleError(eptr);
m_connectionState = ConnectionState::CLOSING;
return yieldTo(&HttpProcessor::Coroutine::onResponseFormed);
throw oatpp::web::protocol::http::HttpError(protocol::http::Status::CODE_404, ss.toString());
// auto eptr = std::make_exception_ptr(error);
// m_currentResponse = m_components->errorHandler->handleError(eptr);
// m_connectionState = ConnectionState::CLOSING;
// return yieldTo(&HttpProcessor::Coroutine::onResponseFormed);
}
m_currentRequest->setPathVariables(m_currentRoute.getMatchMap());
@ -351,12 +350,16 @@ HttpProcessor::Coroutine::Action HttpProcessor::Coroutine::onResponse(const std:
HttpProcessor::Coroutine::Action HttpProcessor::Coroutine::onResponseFormed() {
for(auto& interceptor : m_components->responseInterceptors) {
m_currentResponse = interceptor->intercept(m_currentRequest, m_currentResponse);
if(!m_currentResponse) {
oatpp::web::protocol::http::HttpError error(protocol::http::Status::CODE_500, "Response Interceptor returned an Invalid Response - 'null'");
auto eptr = std::make_exception_ptr(error);
m_currentResponse = m_components->errorHandler->handleError(eptr);
if(m_shouldInterceptResponse) {
m_shouldInterceptResponse = false;
for (auto &interceptor: m_components->responseInterceptors) {
m_currentResponse = interceptor->intercept(m_currentRequest, m_currentResponse);
if (!m_currentResponse) {
throw oatpp::web::protocol::http::HttpError(protocol::http::Status::CODE_500,
"Response Interceptor returned an Invalid Response - 'null'");
//auto eptr = std::make_exception_ptr(error);
//m_currentResponse = m_components->errorHandler->handleError(eptr);
}
}
}
@ -429,15 +432,37 @@ HttpProcessor::Coroutine::Action HttpProcessor::Coroutine::handleError(Error* er
}
}
if(m_currentResponse) {
//OATPP_LOGe("[oatpp::web::server::HttpProcessor::Coroutine::handleError()]", "Unhandled error. '{}'. Dropping connection", error->what())
return error;
// if(m_currentResponse) {
// //OATPP_LOGe("[oatpp::web::server::HttpProcessor::Coroutine::handleError()]", "Unhandled error. '{}'. Dropping connection", error->what())
// return error;
// }
std::exception_ptr ePtr = error->getExceptionPtr();
if(!ePtr) {
ePtr = std::make_exception_ptr(*error);
}
oatpp::web::protocol::http::HttpError httpError(protocol::http::Status::CODE_500, error->what());
auto eptr = std::make_exception_ptr(httpError);
m_currentResponse = m_components->errorHandler->handleError(eptr);
return yieldTo(&HttpProcessor::Coroutine::onResponseFormed);
try {
try {
std::rethrow_exception(ePtr);
} catch (...) {
std::throw_with_nested(HttpServerError(m_currentRequest, "Error processing async request"));
}
} catch (...) {
ePtr = std::current_exception();
m_currentResponse = m_components->errorHandler->handleError(ePtr);
if (m_currentResponse != nullptr) {
return yieldTo(&HttpProcessor::Coroutine::onResponseFormed);
}
}
return new async::Error(ePtr);
// oatpp::web::protocol::http::HttpError httpError(protocol::http::Status::CODE_500, error->what());
// auto eptr = std::make_exception_ptr(httpError);
// m_currentResponse = m_components->errorHandler->handleError(eptr);
// return yieldTo(&HttpProcessor::Coroutine::onResponseFormed);
}

View File

@ -264,6 +264,8 @@ public:
std::shared_ptr<protocol::http::incoming::Request> m_currentRequest;
std::shared_ptr<protocol::http::outgoing::Response> m_currentResponse;
TaskProcessingListener* m_taskListener;
private:
bool m_shouldInterceptResponse;
public:
/**

View File

@ -239,9 +239,28 @@ protected:
}
async::Action handleError(async::Error* error) override {
auto ePtr = std::make_exception_ptr(*error);
auto response = m_handler->m_controller->m_errorHandler->handleError(ePtr);
return this->_return(response);
std::exception_ptr ePtr = error->getExceptionPtr();
if(!ePtr) {
ePtr = std::make_exception_ptr(*error);
}
try {
try {
std::rethrow_exception(ePtr);
} catch (...) {
std::throw_with_nested(HttpServerError(m_request, "[ApiController]: Error processing async request"));
}
} catch (...) {
ePtr = std::current_exception();
auto response = m_handler->m_controller->handleError(ePtr);
if (response != nullptr) {
return this->_return(response);
}
}
return new async::Error(ePtr);
}
};
@ -298,11 +317,11 @@ protected:
throw HttpServerError(request, "[ApiController]: Error. Async call to non-async endpoint");
}
if(m_controller->m_errorHandler) {
//if(m_controller->m_errorHandler) {
return ErrorHandlingCoroutine::startForResult(this, request);
}
//}
return (m_controller->*m_methodAsync)(request);
//return (m_controller->*m_methodAsync)(request);
}

View File

@ -96,10 +96,11 @@ void runTests() {
//
// //return;
//
// OATPP_LOGd("Tests", "coroutine handle size={}", sizeof(oatpp::async::CoroutineHandle))
// OATPP_LOGd("Tests", "coroutine size={}", sizeof(oatpp::async::AbstractCoroutine))
// OATPP_LOGd("Tests", "action size={}", sizeof(oatpp::async::Action))
// OATPP_LOGd("Tests", "class count={}", oatpp::data::type::ClassId::getClassCount())
OATPP_LOGd("Tests", "coroutine handle size={}", sizeof(oatpp::async::CoroutineHandle))
OATPP_LOGd("Tests", "coroutine size={}", sizeof(oatpp::async::AbstractCoroutine))
OATPP_LOGd("Tests", "action size={}", sizeof(oatpp::async::Action))
OATPP_LOGd("Tests", "exception size={}", sizeof(std::exception_ptr))
OATPP_LOGd("Tests", "class count={}", oatpp::data::type::ClassId::getClassCount())
//
// auto names = oatpp::data::type::ClassId::getRegisteredClassNames();
// v_int32 i = 0;
@ -213,25 +214,25 @@ void runTests() {
//
// }
//
// {
//
// oatpp::test::web::FullTest test_virtual(0, 1000);
// test_virtual.run();
//
// oatpp::test::web::FullTest test_port(8000, 5);
// test_port.run();
//
// }
//
// {
//
// oatpp::test::web::FullAsyncTest test_virtual(0, 1000);
// test_virtual.run();
//
{
oatpp::test::web::FullTest test_virtual(0, 1000);
test_virtual.run();
oatpp::test::web::FullTest test_port(8000, 5);
test_port.run();
}
{
oatpp::test::web::FullAsyncTest test_virtual(0, 1000);
test_virtual.run();
oatpp::test::web::FullAsyncTest test_port(8000, 5);
test_port.run();
//
// }
}
//
// {
//

View File

@ -149,147 +149,145 @@ void FullAsyncTest::onRun() {
runner.run([this] {
// OATPP_COMPONENT(std::shared_ptr<oatpp::network::ClientConnectionProvider>, clientConnectionProvider);
// OATPP_COMPONENT(std::shared_ptr<oatpp::data::mapping::ObjectMapper>, objectMapper);
//
// auto requestExecutor = oatpp::web::client::HttpRequestExecutor::createShared(clientConnectionProvider);
// auto client = app::Client::createShared(requestExecutor, objectMapper);
//
// auto connection = client->getConnection();
// OATPP_ASSERT(connection)
//
// v_int32 iterationsStep = m_iterationsPerStep;
//
// auto lastTick = oatpp::Environment::getMicroTickCount();
//
// for(v_int32 i = 0; i < iterationsStep * 10; i ++) {
//
// //OATPP_LOGv("i", "{}", i)
//
// { // test simple GET
// auto response = client->getRoot(connection);
// OATPP_ASSERT(response->getStatusCode() == 200)
// auto value = response->readBodyToString();
// OATPP_ASSERT(value == "Hello World Async!!!")
// }
//
// { // test GET with path parameter
// auto response = client->getWithParams("my_test_param-Async", connection);
// OATPP_ASSERT(response->getStatusCode() == 200)
// auto dto = response->readBodyToDto<oatpp::Object<app::TestDto>>(objectMapper.get());
// OATPP_ASSERT(dto)
// OATPP_ASSERT(dto->testValue == "my_test_param-Async")
// }
//
// { // test GET with header parameter
// auto response = client->getWithHeaders("my_test_header-Async", connection);
// OATPP_ASSERT(response->getStatusCode() == 200)
// auto dto = response->readBodyToDto<oatpp::Object<app::TestDto>>(objectMapper.get());
// OATPP_ASSERT(dto)
// OATPP_ASSERT(dto->testValue == "my_test_header-Async")
// }
//
// { // test POST with body
// auto response = client->postBody("my_test_body-Async", connection);
// OATPP_ASSERT(response->getStatusCode() == 200)
// auto dto = response->readBodyToDto<oatpp::Object<app::TestDto>>(objectMapper.get());
// OATPP_ASSERT(dto)
// OATPP_ASSERT(dto->testValue == "my_test_body-Async")
// }
//
// { // test Big Echo with body
// oatpp::data::stream::BufferOutputStream stream;
// for(v_int32 j = 0; j < oatpp::data::buffer::IOBuffer::BUFFER_SIZE; j++) {
// stream.writeSimple("0123456789", 10);
// }
// auto data = stream.toString();
// auto response = client->echoBody(data, connection);
// OATPP_ASSERT(response->getStatusCode() == 200)
//
// auto returnedData = response->readBodyToString();
//
// OATPP_ASSERT(returnedData)
// OATPP_ASSERT(returnedData == data)
// }
//
// { // test Chunked body
// oatpp::String sample = "__abcdefghijklmnopqrstuvwxyz-0123456789";
// v_int32 numIterations = 10;
// oatpp::data::stream::BufferOutputStream stream;
// for(v_int32 j = 0; j < numIterations; j++) {
// stream.writeSimple(sample->data(), static_cast<v_buff_size>(sample->size()));
// }
// auto data = stream.toString();
// auto response = client->getChunked(sample, numIterations, connection);
// OATPP_ASSERT(response->getStatusCode() == 200)
// auto returnedData = response->readBodyToString();
// OATPP_ASSERT(returnedData)
// OATPP_ASSERT(returnedData == data)
// }
//
// { // Multipart body
//
// std::unordered_map<oatpp::String, oatpp::String> map;
// map["value1"] = "Hello";
// map["value2"] = "World";
// auto multipart = createMultipart(map);
//
// auto body = std::make_shared<MultipartBody>(multipart);
//
// auto response = client->multipartTest(i + 1, body);
// OATPP_ASSERT(response->getStatusCode() == 200)
//
// multipart = std::make_shared<oatpp::web::mime::multipart::PartList>(response->getHeaders());
//
// oatpp::web::mime::multipart::Reader multipartReader(multipart.get());
// multipartReader.setPartReader("value1", oatpp::web::mime::multipart::createInMemoryPartReader(10));
// multipartReader.setPartReader("value2", oatpp::web::mime::multipart::createInMemoryPartReader(10));
//
// response->transferBody(&multipartReader);
//
// OATPP_ASSERT(multipart->getAllParts().size() == 2)
// auto part1 = multipart->getNamedPart("value1");
// auto part2 = multipart->getNamedPart("value2");
//
// OATPP_ASSERT(part1)
// OATPP_ASSERT(part1->getPayload())
//
// OATPP_ASSERT(part2)
// OATPP_ASSERT(part2->getPayload())
//
// OATPP_ASSERT(part1->getPayload()->getInMemoryData() == "Hello")
// OATPP_ASSERT(part2->getPayload()->getInMemoryData() == "World")
//
// }
//
// { // test interceptor GET
// auto response = client->getInterceptors(connection);
// OATPP_ASSERT(response->getStatusCode() == 200)
// auto value = response->readBodyToString();
// OATPP_ASSERT(value == "Hello World Async!!!")
// }
//
// { // test host header
// auto response = client->getHostHeader(connection);
// OATPP_ASSERT(response->getStatusCode() == 200)
// auto value = response->readBodyToString();
// auto host = clientConnectionProvider->getProperty("host");
// OATPP_ASSERT(host)
// OATPP_ASSERT(value == host.toString() + ":" + oatpp::utils::Conversion::int32ToStr(m_port))
// }
//
// if((i + 1) % iterationsStep == 0) {
// auto ticks = oatpp::Environment::getMicroTickCount() - lastTick;
// lastTick = oatpp::Environment::getMicroTickCount();
// OATPP_LOGv("i", "{}, tick={}", i + 1, ticks)
// }
//
// }
//
// connection.reset();
// std::this_thread::sleep_for(std::chrono::milliseconds(200));
OATPP_COMPONENT(std::shared_ptr<oatpp::network::ClientConnectionProvider>, clientConnectionProvider);
OATPP_COMPONENT(std::shared_ptr<oatpp::data::mapping::ObjectMapper>, objectMapper);
std::this_thread::sleep_for(std::chrono::hours (200));
auto requestExecutor = oatpp::web::client::HttpRequestExecutor::createShared(clientConnectionProvider);
auto client = app::Client::createShared(requestExecutor, objectMapper);
auto connection = client->getConnection();
OATPP_ASSERT(connection)
v_int32 iterationsStep = m_iterationsPerStep;
auto lastTick = oatpp::Environment::getMicroTickCount();
for(v_int32 i = 0; i < iterationsStep * 10; i ++) {
//OATPP_LOGv("i", "{}", i)
{ // test simple GET
auto response = client->getRoot(connection);
OATPP_ASSERT(response->getStatusCode() == 200)
auto value = response->readBodyToString();
OATPP_ASSERT(value == "Hello World Async!!!")
}
{ // test GET with path parameter
auto response = client->getWithParams("my_test_param-Async", connection);
OATPP_ASSERT(response->getStatusCode() == 200)
auto dto = response->readBodyToDto<oatpp::Object<app::TestDto>>(objectMapper.get());
OATPP_ASSERT(dto)
OATPP_ASSERT(dto->testValue == "my_test_param-Async")
}
{ // test GET with header parameter
auto response = client->getWithHeaders("my_test_header-Async", connection);
OATPP_ASSERT(response->getStatusCode() == 200)
auto dto = response->readBodyToDto<oatpp::Object<app::TestDto>>(objectMapper.get());
OATPP_ASSERT(dto)
OATPP_ASSERT(dto->testValue == "my_test_header-Async")
}
{ // test POST with body
auto response = client->postBody("my_test_body-Async", connection);
OATPP_ASSERT(response->getStatusCode() == 200)
auto dto = response->readBodyToDto<oatpp::Object<app::TestDto>>(objectMapper.get());
OATPP_ASSERT(dto)
OATPP_ASSERT(dto->testValue == "my_test_body-Async")
}
{ // test Big Echo with body
oatpp::data::stream::BufferOutputStream stream;
for(v_int32 j = 0; j < oatpp::data::buffer::IOBuffer::BUFFER_SIZE; j++) {
stream.writeSimple("0123456789", 10);
}
auto data = stream.toString();
auto response = client->echoBody(data, connection);
OATPP_ASSERT(response->getStatusCode() == 200)
auto returnedData = response->readBodyToString();
OATPP_ASSERT(returnedData)
OATPP_ASSERT(returnedData == data)
}
{ // test Chunked body
oatpp::String sample = "__abcdefghijklmnopqrstuvwxyz-0123456789";
v_int32 numIterations = 10;
oatpp::data::stream::BufferOutputStream stream;
for(v_int32 j = 0; j < numIterations; j++) {
stream.writeSimple(sample->data(), static_cast<v_buff_size>(sample->size()));
}
auto data = stream.toString();
auto response = client->getChunked(sample, numIterations, connection);
OATPP_ASSERT(response->getStatusCode() == 200)
auto returnedData = response->readBodyToString();
OATPP_ASSERT(returnedData)
OATPP_ASSERT(returnedData == data)
}
{ // Multipart body
std::unordered_map<oatpp::String, oatpp::String> map;
map["value1"] = "Hello";
map["value2"] = "World";
auto multipart = createMultipart(map);
auto body = std::make_shared<MultipartBody>(multipart);
auto response = client->multipartTest(i + 1, body);
OATPP_ASSERT(response->getStatusCode() == 200)
multipart = std::make_shared<oatpp::web::mime::multipart::PartList>(response->getHeaders());
oatpp::web::mime::multipart::Reader multipartReader(multipart.get());
multipartReader.setPartReader("value1", oatpp::web::mime::multipart::createInMemoryPartReader(10));
multipartReader.setPartReader("value2", oatpp::web::mime::multipart::createInMemoryPartReader(10));
response->transferBody(&multipartReader);
OATPP_ASSERT(multipart->getAllParts().size() == 2)
auto part1 = multipart->getNamedPart("value1");
auto part2 = multipart->getNamedPart("value2");
OATPP_ASSERT(part1)
OATPP_ASSERT(part1->getPayload())
OATPP_ASSERT(part2)
OATPP_ASSERT(part2->getPayload())
OATPP_ASSERT(part1->getPayload()->getInMemoryData() == "Hello")
OATPP_ASSERT(part2->getPayload()->getInMemoryData() == "World")
}
{ // test interceptor GET
auto response = client->getInterceptors(connection);
OATPP_ASSERT(response->getStatusCode() == 200)
auto value = response->readBodyToString();
OATPP_ASSERT(value == "Hello World Async!!!")
}
{ // test host header
auto response = client->getHostHeader(connection);
OATPP_ASSERT(response->getStatusCode() == 200)
auto value = response->readBodyToString();
auto host = clientConnectionProvider->getProperty("host");
OATPP_ASSERT(host)
OATPP_ASSERT(value == host.toString() + ":" + oatpp::utils::Conversion::int32ToStr(m_port))
}
if((i + 1) % iterationsStep == 0) {
auto ticks = oatpp::Environment::getMicroTickCount() - lastTick;
lastTick = oatpp::Environment::getMicroTickCount();
OATPP_LOGv("i", "{}, tick={}", i + 1, ticks)
}
}
connection.reset();
std::this_thread::sleep_for(std::chrono::milliseconds(200));
}, std::chrono::minutes(10));

View File

@ -151,424 +151,422 @@ void FullTest::onRun() {
runner.run([this] {
// OATPP_COMPONENT(std::shared_ptr<oatpp::network::ClientConnectionProvider>, clientConnectionProvider);
// OATPP_COMPONENT(std::shared_ptr<oatpp::data::mapping::ObjectMapper>, objectMapper);
//
// auto requestExecutor = oatpp::web::client::HttpRequestExecutor::createShared(clientConnectionProvider);
// auto client = app::Client::createShared(requestExecutor, objectMapper);
//
// auto connection = client->getConnection();
// OATPP_ASSERT(connection)
//
// v_int32 iterationsStep = m_iterationsPerStep;
//
// auto lastTick = oatpp::Environment::getMicroTickCount();
//
// for(v_int32 i = 0; i < iterationsStep * 10; i ++) {
//
// { // test simple GET
// auto response = client->getRoot(connection);
// OATPP_ASSERT(response->getStatusCode() == 200)
// auto value = response->readBodyToString();
// OATPP_ASSERT(value == "Hello World!!!")
// }
//
// { // test simple GET with CORS
// auto response = client->getCors(connection);
// OATPP_ASSERT(response->getStatusCode() == 200)
// auto value = response->readBodyToString();
// OATPP_ASSERT(value == "Ping")
// auto header = response->getHeader(oatpp::web::protocol::http::Header::CORS_ORIGIN);
// OATPP_ASSERT(header)
// OATPP_ASSERT(header == "*")
// header = response->getHeader(oatpp::web::protocol::http::Header::CORS_METHODS);
// OATPP_ASSERT(header)
// OATPP_ASSERT(header == "GET, POST, OPTIONS")
// header = response->getHeader(oatpp::web::protocol::http::Header::CORS_HEADERS);
// OATPP_ASSERT(header)
// OATPP_ASSERT(header == "DNT, User-Agent, X-Requested-With, If-Modified-Since, Cache-Control, Content-Type, Range, Authorization")
// }
//
// { // test simple OPTIONS with CORS
// auto response = client->optionsCors(connection);
// OATPP_ASSERT(response->getStatusCode() == 204)
// auto header = response->getHeader(oatpp::web::protocol::http::Header::CORS_ORIGIN);
// OATPP_ASSERT(header)
// OATPP_ASSERT(header == "*")
// header = response->getHeader(oatpp::web::protocol::http::Header::CORS_METHODS);
// OATPP_ASSERT(header)
// OATPP_ASSERT(header == "GET, POST, OPTIONS")
// header = response->getHeader(oatpp::web::protocol::http::Header::CORS_HEADERS);
// OATPP_ASSERT(header)
// OATPP_ASSERT(header == "DNT, User-Agent, X-Requested-With, If-Modified-Since, Cache-Control, Content-Type, Range, Authorization")
// }
//
// { // test simple GET with CORS
// auto response = client->getCorsOrigin(connection);
// OATPP_ASSERT(response->getStatusCode() == 200)
// auto value = response->readBodyToString();
// OATPP_ASSERT(value == "Pong")
// auto header = response->getHeader(oatpp::web::protocol::http::Header::CORS_ORIGIN);
// OATPP_ASSERT(header)
// OATPP_ASSERT(header == "127.0.0.1")
// header = response->getHeader(oatpp::web::protocol::http::Header::CORS_METHODS);
// OATPP_ASSERT(header)
// OATPP_ASSERT(header == "GET, POST, OPTIONS")
// header = response->getHeader(oatpp::web::protocol::http::Header::CORS_HEADERS);
// OATPP_ASSERT(header)
// OATPP_ASSERT(header == "DNT, User-Agent, X-Requested-With, If-Modified-Since, Cache-Control, Content-Type, Range, Authorization")
// }
//
// { // test simple GET with CORS
// auto response = client->getCorsOriginMethods(connection);
// OATPP_ASSERT(response->getStatusCode() == 200)
// auto value = response->readBodyToString();
// OATPP_ASSERT(value == "Ping")
// auto header = response->getHeader(oatpp::web::protocol::http::Header::CORS_ORIGIN);
// OATPP_ASSERT(header)
// OATPP_ASSERT(header == "127.0.0.1")
// header = response->getHeader(oatpp::web::protocol::http::Header::CORS_METHODS);
// OATPP_ASSERT(header)
// OATPP_ASSERT(header == "GET, OPTIONS")
// header = response->getHeader(oatpp::web::protocol::http::Header::CORS_HEADERS);
// OATPP_ASSERT(header)
// OATPP_ASSERT(header == "DNT, User-Agent, X-Requested-With, If-Modified-Since, Cache-Control, Content-Type, Range, Authorization")
// }
//
// { // test simple GET with CORS
// auto response = client->getCorsOriginMethodsHeader(connection);
// OATPP_ASSERT(response->getStatusCode() == 200)
// auto value = response->readBodyToString();
// OATPP_ASSERT(value == "Pong")
// auto header = response->getHeader(oatpp::web::protocol::http::Header::CORS_ORIGIN);
// OATPP_ASSERT(header)
// OATPP_ASSERT(header == "127.0.0.1")
// header = response->getHeader(oatpp::web::protocol::http::Header::CORS_METHODS);
// OATPP_ASSERT(header)
// OATPP_ASSERT(header == "GET, OPTIONS")
// header = response->getHeader(oatpp::web::protocol::http::Header::CORS_HEADERS);
// OATPP_ASSERT(header)
// OATPP_ASSERT(header == "X-PWNT")
// }
//
// { // test GET with path parameter
// auto response = client->getWithParams("my_test_param", connection);
// OATPP_ASSERT(response->getStatusCode() == 200)
// auto dto = response->readBodyToDto<oatpp::Object<app::TestDto>>(objectMapper.get());
// OATPP_ASSERT(dto)
// OATPP_ASSERT(dto->testValue == "my_test_param")
// }
//
// { // test GET with query parameters
// auto response = client->getWithQueries("oatpp", 1, connection);
// OATPP_ASSERT(response->getStatusCode() == 200)
// auto dto = response->readBodyToDto<oatpp::Object<app::TestDto>>(objectMapper.get());
// OATPP_ASSERT(dto)
// OATPP_ASSERT(dto->testValue == "name=oatpp&age=1")
// }
//
// { // test GET with optional query parameters
// auto response = client->getWithOptQueries("oatpp", connection);
// OATPP_ASSERT(response->getStatusCode() == 200)
// auto dto = response->readBodyToDto<oatpp::Object<app::TestDto>>(objectMapper.get());
// OATPP_ASSERT(dto)
// OATPP_ASSERT(dto->testValue == "name=oatpp&age=101")
// }
//
// { // test GET with query parameters
// auto response = client->getWithQueriesMap("value1", 32, 0.32f, connection);
// OATPP_ASSERT(response->getStatusCode() == 200)
// auto dto = response->readBodyToDto<oatpp::Object<app::TestDto>>(objectMapper.get());
// OATPP_ASSERT(dto)
// OATPP_ASSERT(dto->testMap)
// OATPP_ASSERT(dto->testMap->size() == 3)
// OATPP_ASSERT(dto->testMap["key1"] == "value1")
// OATPP_ASSERT(dto->testMap["key2"] == "32")
// OATPP_ASSERT(dto->testMap["key3"] == oatpp::utils::Conversion::float32ToStr(0.32f))
// }
//
// { // test GET with header parameter
// auto response = client->getWithHeaders("my_test_header", connection);
// OATPP_ASSERT(response->getStatusCode() == 200)
// auto dto = response->readBodyToDto<oatpp::Object<app::TestDto>>(objectMapper.get());
// OATPP_ASSERT(dto)
// OATPP_ASSERT(dto->testValue == "my_test_header")
// }
//
// { // test POST with body
// auto response = client->postBody("my_test_body", connection);
// OATPP_ASSERT(response->getStatusCode() == 200)
// auto dto = response->readBodyToDto<oatpp::Object<app::TestDto>>(objectMapper.get());
// OATPP_ASSERT(dto)
// OATPP_ASSERT(dto->testValue == "my_test_body")
// }
//
// { // test POST with dto body
// auto dtoIn = app::TestDto::createShared();
// dtoIn->testValueInt = i;
// auto response = client->postBodyDto(dtoIn, connection);
// OATPP_ASSERT(response->getStatusCode() == 200)
// auto dtoOut = response->readBodyToDto<oatpp::Object<app::TestDto>>(objectMapper.get());
// OATPP_ASSERT(dtoOut)
// OATPP_ASSERT(dtoOut->testValueInt == i)
// }
//
// { // test Enum as String
//
// OATPP_ASSERT(oatpp::Enum<app::AllowedPathParams>::getEntries().size() == 2)
//
// oatpp::Enum<app::AllowedPathParams> v = app::AllowedPathParams::HELLO;
// auto response = client->getHeaderEnumAsString(v, connection);
// OATPP_ASSERT(response->getStatusCode() == 200)
// }
//
// { // test Enum as String
// oatpp::Enum<app::AllowedPathParams> v = app::AllowedPathParams::HELLO;
// auto response = client->getHeaderEnumAsNumber(v, connection);
// OATPP_ASSERT(response->getStatusCode() == 200)
// }
//
// { // test Big Echo with body
// oatpp::data::stream::BufferOutputStream stream;
// for(v_int32 j = 0; j < oatpp::data::buffer::IOBuffer::BUFFER_SIZE; j++) {
// stream.writeSimple("0123456789", 10);
// }
// auto data = stream.toString();
// auto response = client->echoBody(data, connection);
// OATPP_ASSERT(response->getStatusCode() == 200)
// auto returnedData = response->readBodyToString();
// OATPP_ASSERT(returnedData)
// OATPP_ASSERT(returnedData == data)
// }
//
// {
// String bodyIn = "null";
// auto response = client->testBodyIsNull1(bodyIn, connection);
// OATPP_ASSERT(response->getStatusCode() == 400)
// auto returnedData = response->readBodyToString();
// OATPP_ASSERT(returnedData)
OATPP_COMPONENT(std::shared_ptr<oatpp::network::ClientConnectionProvider>, clientConnectionProvider);
OATPP_COMPONENT(std::shared_ptr<oatpp::data::mapping::ObjectMapper>, objectMapper);
auto requestExecutor = oatpp::web::client::HttpRequestExecutor::createShared(clientConnectionProvider);
auto client = app::Client::createShared(requestExecutor, objectMapper);
auto connection = client->getConnection();
OATPP_ASSERT(connection)
v_int32 iterationsStep = m_iterationsPerStep;
auto lastTick = oatpp::Environment::getMicroTickCount();
for(v_int32 i = 0; i < iterationsStep * 10; i ++) {
{ // test simple GET
auto response = client->getRoot(connection);
OATPP_ASSERT(response->getStatusCode() == 200)
auto value = response->readBodyToString();
OATPP_ASSERT(value == "Hello World!!!")
}
{ // test simple GET with CORS
auto response = client->getCors(connection);
OATPP_ASSERT(response->getStatusCode() == 200)
auto value = response->readBodyToString();
OATPP_ASSERT(value == "Ping")
auto header = response->getHeader(oatpp::web::protocol::http::Header::CORS_ORIGIN);
OATPP_ASSERT(header)
OATPP_ASSERT(header == "*")
header = response->getHeader(oatpp::web::protocol::http::Header::CORS_METHODS);
OATPP_ASSERT(header)
OATPP_ASSERT(header == "GET, POST, OPTIONS")
header = response->getHeader(oatpp::web::protocol::http::Header::CORS_HEADERS);
OATPP_ASSERT(header)
OATPP_ASSERT(header == "DNT, User-Agent, X-Requested-With, If-Modified-Since, Cache-Control, Content-Type, Range, Authorization")
}
{ // test simple OPTIONS with CORS
auto response = client->optionsCors(connection);
OATPP_ASSERT(response->getStatusCode() == 204)
auto header = response->getHeader(oatpp::web::protocol::http::Header::CORS_ORIGIN);
OATPP_ASSERT(header)
OATPP_ASSERT(header == "*")
header = response->getHeader(oatpp::web::protocol::http::Header::CORS_METHODS);
OATPP_ASSERT(header)
OATPP_ASSERT(header == "GET, POST, OPTIONS")
header = response->getHeader(oatpp::web::protocol::http::Header::CORS_HEADERS);
OATPP_ASSERT(header)
OATPP_ASSERT(header == "DNT, User-Agent, X-Requested-With, If-Modified-Since, Cache-Control, Content-Type, Range, Authorization")
}
{ // test simple GET with CORS
auto response = client->getCorsOrigin(connection);
OATPP_ASSERT(response->getStatusCode() == 200)
auto value = response->readBodyToString();
OATPP_ASSERT(value == "Pong")
auto header = response->getHeader(oatpp::web::protocol::http::Header::CORS_ORIGIN);
OATPP_ASSERT(header)
OATPP_ASSERT(header == "127.0.0.1")
header = response->getHeader(oatpp::web::protocol::http::Header::CORS_METHODS);
OATPP_ASSERT(header)
OATPP_ASSERT(header == "GET, POST, OPTIONS")
header = response->getHeader(oatpp::web::protocol::http::Header::CORS_HEADERS);
OATPP_ASSERT(header)
OATPP_ASSERT(header == "DNT, User-Agent, X-Requested-With, If-Modified-Since, Cache-Control, Content-Type, Range, Authorization")
}
{ // test simple GET with CORS
auto response = client->getCorsOriginMethods(connection);
OATPP_ASSERT(response->getStatusCode() == 200)
auto value = response->readBodyToString();
OATPP_ASSERT(value == "Ping")
auto header = response->getHeader(oatpp::web::protocol::http::Header::CORS_ORIGIN);
OATPP_ASSERT(header)
OATPP_ASSERT(header == "127.0.0.1")
header = response->getHeader(oatpp::web::protocol::http::Header::CORS_METHODS);
OATPP_ASSERT(header)
OATPP_ASSERT(header == "GET, OPTIONS")
header = response->getHeader(oatpp::web::protocol::http::Header::CORS_HEADERS);
OATPP_ASSERT(header)
OATPP_ASSERT(header == "DNT, User-Agent, X-Requested-With, If-Modified-Since, Cache-Control, Content-Type, Range, Authorization")
}
{ // test simple GET with CORS
auto response = client->getCorsOriginMethodsHeader(connection);
OATPP_ASSERT(response->getStatusCode() == 200)
auto value = response->readBodyToString();
OATPP_ASSERT(value == "Pong")
auto header = response->getHeader(oatpp::web::protocol::http::Header::CORS_ORIGIN);
OATPP_ASSERT(header)
OATPP_ASSERT(header == "127.0.0.1")
header = response->getHeader(oatpp::web::protocol::http::Header::CORS_METHODS);
OATPP_ASSERT(header)
OATPP_ASSERT(header == "GET, OPTIONS")
header = response->getHeader(oatpp::web::protocol::http::Header::CORS_HEADERS);
OATPP_ASSERT(header)
OATPP_ASSERT(header == "X-PWNT")
}
{ // test GET with path parameter
auto response = client->getWithParams("my_test_param", connection);
OATPP_ASSERT(response->getStatusCode() == 200)
auto dto = response->readBodyToDto<oatpp::Object<app::TestDto>>(objectMapper.get());
OATPP_ASSERT(dto)
OATPP_ASSERT(dto->testValue == "my_test_param")
}
{ // test GET with query parameters
auto response = client->getWithQueries("oatpp", 1, connection);
OATPP_ASSERT(response->getStatusCode() == 200)
auto dto = response->readBodyToDto<oatpp::Object<app::TestDto>>(objectMapper.get());
OATPP_ASSERT(dto)
OATPP_ASSERT(dto->testValue == "name=oatpp&age=1")
}
{ // test GET with optional query parameters
auto response = client->getWithOptQueries("oatpp", connection);
OATPP_ASSERT(response->getStatusCode() == 200)
auto dto = response->readBodyToDto<oatpp::Object<app::TestDto>>(objectMapper.get());
OATPP_ASSERT(dto)
OATPP_ASSERT(dto->testValue == "name=oatpp&age=101")
}
{ // test GET with query parameters
auto response = client->getWithQueriesMap("value1", 32, 0.32f, connection);
OATPP_ASSERT(response->getStatusCode() == 200)
auto dto = response->readBodyToDto<oatpp::Object<app::TestDto>>(objectMapper.get());
OATPP_ASSERT(dto)
OATPP_ASSERT(dto->testMap)
OATPP_ASSERT(dto->testMap->size() == 3)
OATPP_ASSERT(dto->testMap["key1"] == "value1")
OATPP_ASSERT(dto->testMap["key2"] == "32")
OATPP_ASSERT(dto->testMap["key3"] == oatpp::utils::Conversion::float32ToStr(0.32f))
}
{ // test GET with header parameter
auto response = client->getWithHeaders("my_test_header", connection);
OATPP_ASSERT(response->getStatusCode() == 200)
auto dto = response->readBodyToDto<oatpp::Object<app::TestDto>>(objectMapper.get());
OATPP_ASSERT(dto)
OATPP_ASSERT(dto->testValue == "my_test_header")
}
{ // test POST with body
auto response = client->postBody("my_test_body", connection);
OATPP_ASSERT(response->getStatusCode() == 200)
auto dto = response->readBodyToDto<oatpp::Object<app::TestDto>>(objectMapper.get());
OATPP_ASSERT(dto)
OATPP_ASSERT(dto->testValue == "my_test_body")
}
{ // test POST with dto body
auto dtoIn = app::TestDto::createShared();
dtoIn->testValueInt = i;
auto response = client->postBodyDto(dtoIn, connection);
OATPP_ASSERT(response->getStatusCode() == 200)
auto dtoOut = response->readBodyToDto<oatpp::Object<app::TestDto>>(objectMapper.get());
OATPP_ASSERT(dtoOut)
OATPP_ASSERT(dtoOut->testValueInt == i)
}
{ // test Enum as String
OATPP_ASSERT(oatpp::Enum<app::AllowedPathParams>::getEntries().size() == 2)
oatpp::Enum<app::AllowedPathParams> v = app::AllowedPathParams::HELLO;
auto response = client->getHeaderEnumAsString(v, connection);
OATPP_ASSERT(response->getStatusCode() == 200)
}
{ // test Enum as String
oatpp::Enum<app::AllowedPathParams> v = app::AllowedPathParams::HELLO;
auto response = client->getHeaderEnumAsNumber(v, connection);
OATPP_ASSERT(response->getStatusCode() == 200)
}
{ // test Big Echo with body
oatpp::data::stream::BufferOutputStream stream;
for(v_int32 j = 0; j < oatpp::data::buffer::IOBuffer::BUFFER_SIZE; j++) {
stream.writeSimple("0123456789", 10);
}
auto data = stream.toString();
auto response = client->echoBody(data, connection);
OATPP_ASSERT(response->getStatusCode() == 200)
auto returnedData = response->readBodyToString();
OATPP_ASSERT(returnedData)
OATPP_ASSERT(returnedData == data)
}
{
String bodyIn = "null";
auto response = client->testBodyIsNull1(bodyIn, connection);
OATPP_ASSERT(response->getStatusCode() == 400)
auto returnedData = response->readBodyToString();
OATPP_ASSERT(returnedData)
// OATPP_ASSERT(returnedData == "server=oatpp/" OATPP_VERSION "\n"
// "code=400\n"
// "description=Bad Request\n"
// "message=Missing valid body parameter 'body'\n")
// connection = client->getConnection();
// }
//
// {
// String bodyIn = "\"null\"";
// auto response = client->testBodyIsNull1(bodyIn, connection);
// OATPP_ASSERT(response->getStatusCode() == 200)
// auto returnedData = response->readBodyToString();
// OATPP_ASSERT(returnedData)
// OATPP_ASSERT(returnedData == "OK---null")
// }
//
// {
// String bodyIn = "null";
// auto response = client->testBodyIsNull2(bodyIn, connection);
// OATPP_ASSERT(response->getStatusCode() == 200)
// auto returnedData = response->readBodyToString();
// OATPP_ASSERT(returnedData)
// OATPP_ASSERT(returnedData == "OK---null")
// }
//
// {
// String bodyIn = "\"null\"";
// auto response = client->testBodyIsNull2(bodyIn, connection);
// OATPP_ASSERT(response->getStatusCode() == 200)
// auto returnedData = response->readBodyToString();
// OATPP_ASSERT(returnedData)
// OATPP_ASSERT(returnedData == "OK---\"null\"")
// }
//
// {
// auto response = client->headerValueSet(" VALUE_1, VALUE_2, VALUE_3", connection);
// OATPP_ASSERT(response->getStatusCode() == 200)
// }
//
// {
// auto response = client->getDefaultHeaders1(connection);
// OATPP_ASSERT(response->getStatusCode() == 200)
// }
//
// {
// auto response = client->getDefaultHeaders2("some param", connection);
// OATPP_ASSERT(response->getStatusCode() == 200)
// }
//
// { // test custom authorization handler with custom authorization object
// auto response = client->defaultBasicAuthorization("foo:bar", connection);
// OATPP_ASSERT(response->getStatusCode() == 200)
// }
//
// { // test call of an endpoint that requiers authorization headers, but we don't send one
// auto response = client->defaultBasicAuthorizationWithoutHeader();
// OATPP_ASSERT(response->getStatusCode() == 401)
// oatpp::String body = response->readBodyToString();
// OATPP_ASSERT(body == "server=oatpp/" OATPP_VERSION "\n"
// "code=401\n"
// "description=Unauthorized\n"
// "message=Authorization Required\n")
// // should also add the WWW-Authenticate header when Authorization is missing
// auto header = response->getHeader(oatpp::web::protocol::http::Header::WWW_AUTHENTICATE);
// OATPP_ASSERT(header)
// OATPP_ASSERT(header == "Basic realm=\"default-test-realm\"")
// }
//
// { // test custom authorization handler with custom authorization object
// auto response = client->customBasicAuthorization("foo:bar", connection);
// OATPP_ASSERT(response->getStatusCode() == 200)
// }
//
// { // test call of an endpoint that requiers authorization headers, but we don't send one
// auto response = client->customBasicAuthorizationWithoutHeader();
// OATPP_ASSERT(response->getStatusCode() == 401)
// oatpp::String body = response->readBodyToString();
// OATPP_ASSERT(body == "server=oatpp/" OATPP_VERSION "\n"
// "code=401\n"
// "description=Unauthorized\n"
// "message=Authorization Required\n")
// // should also add the WWW-Authenticate header when Authorization is missing
// auto header = response->getHeader(oatpp::web::protocol::http::Header::WWW_AUTHENTICATE);
// OATPP_ASSERT(header)
// OATPP_ASSERT(header == "Basic realm=\"custom-test-realm\"")
// }
//
// { // test custom authorization handler with custom authorization object with unknown credentials where the
// // handler returns nullptr
// auto response = client->customBasicAuthorization("john:doe");
// oatpp::String body = response->readBodyToString();
// OATPP_ASSERT(response->getStatusCode() == 401)
// OATPP_ASSERT(body == "server=oatpp/" OATPP_VERSION "\n"
// "code=401\n"
// "description=Unauthorized\n"
// "message=Unauthorized\n")
// // should also add the WWW-Authenticate header when Authorization is missing or wrong
// auto header = response->getHeader(oatpp::web::protocol::http::Header::WWW_AUTHENTICATE);
// OATPP_ASSERT(header)
// OATPP_ASSERT(header == "Basic realm=\"custom-test-realm\"")
// }
//
// { // test custom authorization handler with custom authorization method
// oatpp::String token = "4e99e8c12de7e01535248d2bac85e732";
// auto response = client->bearerAuthorization(token);
// oatpp::String body = response->readBodyToString();
// OATPP_ASSERT(response->getStatusCode() == 200)
// }
//
// { // test custom authorization handler with custom authorization object with unknown credentials where the
// // handler returns nullptr
// oatpp::String token = "900150983cd24fb0d6963f7d28e17f72";
// auto response = client->bearerAuthorization(token);
// oatpp::String body = response->readBodyToString();
// OATPP_ASSERT(response->getStatusCode() == 401)
// OATPP_ASSERT(body == "server=oatpp/" OATPP_VERSION "\n"
// "code=401\n"
// "description=Unauthorized\n"
// "message=Unauthorized\n")
// // should also add the WWW-Authenticate header when Authorization is missing or wrong
// auto header = response->getHeader(oatpp::web::protocol::http::Header::WWW_AUTHENTICATE);
// OATPP_ASSERT(header)
// OATPP_ASSERT(header == "Bearer realm=\"custom-bearer-realm\"")
// }
//
// { // test Chunked body
// oatpp::String sample = "__abcdefghijklmnopqrstuvwxyz-0123456789";
// v_int32 numIterations = 10;
// oatpp::data::stream::BufferOutputStream stream;
// for(v_int32 j = 0; j < numIterations; j++) {
// stream.writeSimple(sample->data(), static_cast<v_buff_size>(sample->size()));
// }
// auto data = stream.toString();
// auto response = client->getChunked(sample, numIterations, connection);
// OATPP_ASSERT(response->getStatusCode() == 200)
// auto returnedData = response->readBodyToString();
// OATPP_ASSERT(returnedData)
// OATPP_ASSERT(returnedData == data)
// }
//
// { // Multipart body
//
// std::unordered_map<oatpp::String, oatpp::String> map;
// map["value1"] = "Hello";
// map["value2"] = "World";
// auto multipart = createMultipart(map);
//
// auto body = std::make_shared<MultipartBody>(multipart);
//
// auto response = client->multipartTest(i + 1, body);
// OATPP_ASSERT(response->getStatusCode() == 200)
//
// multipart = std::make_shared<oatpp::web::mime::multipart::PartList>(response->getHeaders());
//
// oatpp::web::mime::multipart::Reader multipartReader(multipart.get());
// multipartReader.setPartReader("value1", oatpp::web::mime::multipart::createInMemoryPartReader(10));
// multipartReader.setPartReader("value2", oatpp::web::mime::multipart::createInMemoryPartReader(10));
//
// response->transferBody(&multipartReader);
//
// OATPP_ASSERT(multipart->getAllParts().size() == 2)
// auto part1 = multipart->getNamedPart("value1");
// auto part2 = multipart->getNamedPart("value2");
//
// OATPP_ASSERT(part1)
// OATPP_ASSERT(part1->getPayload())
//
// OATPP_ASSERT(part2)
// OATPP_ASSERT(part2->getPayload())
//
// OATPP_ASSERT(part1->getPayload()->getInMemoryData() == "Hello")
// OATPP_ASSERT(part2->getPayload()->getInMemoryData() == "World")
//
// }
//
// { // test interceptors
// auto response = client->getInterceptors(connection);
// OATPP_ASSERT(response->getStatusCode() == 200)
// auto value = response->readBodyToString();
// OATPP_ASSERT(value == "Hello World!!!")
// }
//
// { // test controller's error handler catches
// auto response = client->getCaughtError(connection);
// OATPP_ASSERT(response->getStatusCode() == 418)
// auto value = response->readBodyToString();
// OATPP_ASSERT(value == "Controller With Errors!")
// }
//
// { // test header replacement
// auto response = client->getInterceptors(connection);
// OATPP_ASSERT(response->getStatusCode() == 200)
// OATPP_ASSERT(response->getHeader("to-be-replaced") == "replaced_value")
// }
//
// if((i + 1) % iterationsStep == 0) {
// auto ticks = oatpp::Environment::getMicroTickCount() - lastTick;
// lastTick = oatpp::Environment::getMicroTickCount();
// OATPP_LOGv("i", "{}, tick={}", i + 1, ticks)
// }
//
// { // test bundle
// auto response = client->getBundle(connection);
// OATPP_ASSERT(response->getStatusCode() == 200)
// auto dto = response->readBodyToDto<oatpp::Object<app::TestDto>>(objectMapper.get());
// OATPP_ASSERT(dto)
// OATPP_ASSERT(dto->testValue == "str-param")
// OATPP_ASSERT(dto->testValueInt == 32000)
// }
//
// { // test host header
// auto response = client->getHostHeader(connection);
// OATPP_ASSERT(response->getStatusCode() == 200)
// auto value = response->readBodyToString();
// auto host = clientConnectionProvider->getProperty("host");
// OATPP_ASSERT(host)
// OATPP_ASSERT(value == host.toString() + ":" + oatpp::utils::Conversion::int32ToStr(m_port))
// }
//
// }
connection = client->getConnection();
}
std::this_thread::sleep_for(std::chrono::hours (1));
{
String bodyIn = "\"null\"";
auto response = client->testBodyIsNull1(bodyIn, connection);
OATPP_ASSERT(response->getStatusCode() == 200)
auto returnedData = response->readBodyToString();
OATPP_ASSERT(returnedData)
OATPP_ASSERT(returnedData == "OK---null")
}
{
String bodyIn = "null";
auto response = client->testBodyIsNull2(bodyIn, connection);
OATPP_ASSERT(response->getStatusCode() == 200)
auto returnedData = response->readBodyToString();
OATPP_ASSERT(returnedData)
OATPP_ASSERT(returnedData == "OK---null")
}
{
String bodyIn = "\"null\"";
auto response = client->testBodyIsNull2(bodyIn, connection);
OATPP_ASSERT(response->getStatusCode() == 200)
auto returnedData = response->readBodyToString();
OATPP_ASSERT(returnedData)
OATPP_ASSERT(returnedData == "OK---\"null\"")
}
{
auto response = client->headerValueSet(" VALUE_1, VALUE_2, VALUE_3", connection);
OATPP_ASSERT(response->getStatusCode() == 200)
}
{
auto response = client->getDefaultHeaders1(connection);
OATPP_ASSERT(response->getStatusCode() == 200)
}
{
auto response = client->getDefaultHeaders2("some param", connection);
OATPP_ASSERT(response->getStatusCode() == 200)
}
{ // test custom authorization handler with custom authorization object
auto response = client->defaultBasicAuthorization("foo:bar", connection);
OATPP_ASSERT(response->getStatusCode() == 200)
}
{ // test call of an endpoint that requiers authorization headers, but we don't send one
auto response = client->defaultBasicAuthorizationWithoutHeader();
OATPP_ASSERT(response->getStatusCode() == 401)
oatpp::String body = response->readBodyToString();
// OATPP_ASSERT(body == "server=oatpp/" OATPP_VERSION "\n"
// "code=401\n"
// "description=Unauthorized\n"
// "message=Authorization Required\n")
// should also add the WWW-Authenticate header when Authorization is missing
auto header = response->getHeader(oatpp::web::protocol::http::Header::WWW_AUTHENTICATE);
OATPP_ASSERT(header)
OATPP_ASSERT(header == "Basic realm=\"default-test-realm\"")
}
{ // test custom authorization handler with custom authorization object
auto response = client->customBasicAuthorization("foo:bar", connection);
OATPP_ASSERT(response->getStatusCode() == 200)
}
{ // test call of an endpoint that requiers authorization headers, but we don't send one
auto response = client->customBasicAuthorizationWithoutHeader();
OATPP_ASSERT(response->getStatusCode() == 401)
oatpp::String body = response->readBodyToString();
// OATPP_ASSERT(body == "server=oatpp/" OATPP_VERSION "\n"
// "code=401\n"
// "description=Unauthorized\n"
// "message=Authorization Required\n")
// should also add the WWW-Authenticate header when Authorization is missing
auto header = response->getHeader(oatpp::web::protocol::http::Header::WWW_AUTHENTICATE);
OATPP_ASSERT(header)
OATPP_ASSERT(header == "Basic realm=\"custom-test-realm\"")
}
{ // test custom authorization handler with custom authorization object with unknown credentials where the
// handler returns nullptr
auto response = client->customBasicAuthorization("john:doe");
oatpp::String body = response->readBodyToString();
OATPP_ASSERT(response->getStatusCode() == 401)
// OATPP_ASSERT(body == "server=oatpp/" OATPP_VERSION "\n"
// "code=401\n"
// "description=Unauthorized\n"
// "message=Unauthorized\n")
// should also add the WWW-Authenticate header when Authorization is missing or wrong
auto header = response->getHeader(oatpp::web::protocol::http::Header::WWW_AUTHENTICATE);
OATPP_ASSERT(header)
OATPP_ASSERT(header == "Basic realm=\"custom-test-realm\"")
}
{ // test custom authorization handler with custom authorization method
oatpp::String token = "4e99e8c12de7e01535248d2bac85e732";
auto response = client->bearerAuthorization(token);
oatpp::String body = response->readBodyToString();
OATPP_ASSERT(response->getStatusCode() == 200)
}
{ // test custom authorization handler with custom authorization object with unknown credentials where the
// handler returns nullptr
oatpp::String token = "900150983cd24fb0d6963f7d28e17f72";
auto response = client->bearerAuthorization(token);
oatpp::String body = response->readBodyToString();
OATPP_ASSERT(response->getStatusCode() == 401)
// OATPP_ASSERT(body == "server=oatpp/" OATPP_VERSION "\n"
// "code=401\n"
// "description=Unauthorized\n"
// "message=Unauthorized\n")
// should also add the WWW-Authenticate header when Authorization is missing or wrong
auto header = response->getHeader(oatpp::web::protocol::http::Header::WWW_AUTHENTICATE);
OATPP_ASSERT(header)
OATPP_ASSERT(header == "Bearer realm=\"custom-bearer-realm\"")
}
{ // test Chunked body
oatpp::String sample = "__abcdefghijklmnopqrstuvwxyz-0123456789";
v_int32 numIterations = 10;
oatpp::data::stream::BufferOutputStream stream;
for(v_int32 j = 0; j < numIterations; j++) {
stream.writeSimple(sample->data(), static_cast<v_buff_size>(sample->size()));
}
auto data = stream.toString();
auto response = client->getChunked(sample, numIterations, connection);
OATPP_ASSERT(response->getStatusCode() == 200)
auto returnedData = response->readBodyToString();
OATPP_ASSERT(returnedData)
OATPP_ASSERT(returnedData == data)
}
{ // Multipart body
std::unordered_map<oatpp::String, oatpp::String> map;
map["value1"] = "Hello";
map["value2"] = "World";
auto multipart = createMultipart(map);
auto body = std::make_shared<MultipartBody>(multipart);
auto response = client->multipartTest(i + 1, body);
OATPP_ASSERT(response->getStatusCode() == 200)
multipart = std::make_shared<oatpp::web::mime::multipart::PartList>(response->getHeaders());
oatpp::web::mime::multipart::Reader multipartReader(multipart.get());
multipartReader.setPartReader("value1", oatpp::web::mime::multipart::createInMemoryPartReader(10));
multipartReader.setPartReader("value2", oatpp::web::mime::multipart::createInMemoryPartReader(10));
response->transferBody(&multipartReader);
OATPP_ASSERT(multipart->getAllParts().size() == 2)
auto part1 = multipart->getNamedPart("value1");
auto part2 = multipart->getNamedPart("value2");
OATPP_ASSERT(part1)
OATPP_ASSERT(part1->getPayload())
OATPP_ASSERT(part2)
OATPP_ASSERT(part2->getPayload())
OATPP_ASSERT(part1->getPayload()->getInMemoryData() == "Hello")
OATPP_ASSERT(part2->getPayload()->getInMemoryData() == "World")
}
{ // test interceptors
auto response = client->getInterceptors(connection);
OATPP_ASSERT(response->getStatusCode() == 200)
auto value = response->readBodyToString();
OATPP_ASSERT(value == "Hello World!!!")
}
{ // test controller's error handler catches
auto response = client->getCaughtError(connection);
OATPP_ASSERT(response->getStatusCode() == 418)
auto value = response->readBodyToString();
OATPP_ASSERT(value == "Controller With Errors!")
}
{ // test header replacement
auto response = client->getInterceptors(connection);
OATPP_ASSERT(response->getStatusCode() == 200)
OATPP_ASSERT(response->getHeader("to-be-replaced") == "replaced_value")
}
if((i + 1) % iterationsStep == 0) {
auto ticks = oatpp::Environment::getMicroTickCount() - lastTick;
lastTick = oatpp::Environment::getMicroTickCount();
OATPP_LOGv("i", "{}, tick={}", i + 1, ticks)
}
{ // test bundle
auto response = client->getBundle(connection);
OATPP_ASSERT(response->getStatusCode() == 200)
auto dto = response->readBodyToDto<oatpp::Object<app::TestDto>>(objectMapper.get());
OATPP_ASSERT(dto)
OATPP_ASSERT(dto->testValue == "str-param")
OATPP_ASSERT(dto->testValueInt == 32000)
}
{ // test host header
auto response = client->getHostHeader(connection);
OATPP_ASSERT(response->getStatusCode() == 200)
auto value = response->readBodyToString();
auto host = clientConnectionProvider->getProperty("host");
OATPP_ASSERT(host)
OATPP_ASSERT(value == host.toString() + ":" + oatpp::utils::Conversion::int32ToStr(m_port))
}
}
}, std::chrono::minutes(10));

View File

@ -95,6 +95,7 @@ public:
Action act() override {
auto param = request->getHeader("X-TEST-HEADER");
OATPP_ASSERT_HTTP(param, Status::CODE_400, "X-TEST-HEADER missing")
//OATPP_LOGv(TAG, "GET headers {X-TEST-HEADER: {}}", param)
auto dto = TestDto::createShared();
dto->testValue = param;

View File

@ -37,33 +37,13 @@ namespace oatpp { namespace test { namespace web { namespace app {
namespace http = oatpp::web::protocol::http;
/**
* Custom Error Handler.
*/
class CustomErrorHandler : public oatpp::base::Countable, public oatpp::web::server::handler::ErrorHandler {
class CustomErrorHandler : public oatpp::web::server::handler::DefaultErrorHandler {
public:
/**
* Constructor.
*/
CustomErrorHandler() = default;
public:
/**
* Create shared DefaultErrorHandler.
* @return - `std::shared_ptr` to DefaultErrorHandler.
*/
static std::shared_ptr<CustomErrorHandler> createShared() {
return std::make_shared<CustomErrorHandler>();
}
std::shared_ptr<http::outgoing::Response> handleError(const std::exception_ptr& error) override {
try {
std::rethrow_exception(error);
} catch(const std::runtime_error& e) {
return oatpp::web::protocol::http::outgoing::ResponseFactory::createResponse(http::Status::CODE_418, e.what());
} catch(...) {
throw;
}
std::shared_ptr<http::outgoing::Response> renderError(const HttpServerErrorStacktrace& stacktrace) override {
return oatpp::web::protocol::http::outgoing::ResponseFactory::createResponse(http::Status::CODE_418, stacktrace.stack.front());
}
};
@ -75,7 +55,7 @@ public:
explicit ControllerWithErrorHandler(const std::shared_ptr<ObjectMapper>& objectMapper)
: oatpp::web::server::api::ApiController(objectMapper)
{
setErrorHandler(CustomErrorHandler::createShared());
setErrorHandler(std::make_shared<CustomErrorHandler>());
}
public: