Better client error handling, better url mapping

This commit is contained in:
lganzzzo 2018-06-27 01:42:02 +03:00
parent 204e8cce2a
commit 248452893a
15 changed files with 109 additions and 71 deletions

View File

@ -57,11 +57,11 @@ public:
: oatpp::data::mapping::type::ObjectWrapper<oatpp::base::StrBuffer, __class::String>(oatpp::base::StrBuffer::createShared(size))
{}
String(const void* data, v_int32 size, bool copyAsOwnData = true)
String(const char* data, v_int32 size, bool copyAsOwnData = true)
: oatpp::data::mapping::type::ObjectWrapper<oatpp::base::StrBuffer, __class::String>(oatpp::base::StrBuffer::createShared(data, size, copyAsOwnData))
{}
String(const void* data1, v_int32 size1, const void* data2, v_int32 size2)
String(const char* data1, v_int32 size1, const char* data2, v_int32 size2)
: oatpp::data::mapping::type::ObjectWrapper<oatpp::base::StrBuffer, __class::String>(oatpp::base::StrBuffer::createSharedConcatenated(data1, size1, data2, size2))
{}

View File

@ -277,7 +277,7 @@ namespace oatpp { namespace parser {
if(len > 0){
auto str = oatpp::String(&m_data[ipos], len, true);
auto str = oatpp::String((const char*)&m_data[ipos], len, true);
v_int32 result = atoi((const char*)str->getData());
if(negative){
@ -455,7 +455,7 @@ namespace oatpp { namespace parser {
if(m_data[m_pos] == escapeChar){
m_pos++;
}else if(m_data[m_pos] == closeChar){
oatpp::String result = oatpp::String(&m_data[ipos], m_pos - ipos, saveAsOwnData);
oatpp::String result = oatpp::String((const char*)&m_data[ipos], m_pos - ipos, saveAsOwnData);
m_pos++;
return result;
}
@ -488,7 +488,7 @@ namespace oatpp { namespace parser {
}else{
if(ipos < m_pos){
return oatpp::String(&m_data[ipos], m_pos - ipos, saveAsOwnData);
return oatpp::String((const char*)&m_data[ipos], m_pos - ipos, saveAsOwnData);
}else{
m_error = ERROR_NAME_EXPECTED;
return nullptr;
@ -499,7 +499,7 @@ namespace oatpp { namespace parser {
}
if(ipos < m_pos){
return oatpp::String(&m_data[ipos], m_pos - ipos, saveAsOwnData);
return oatpp::String((const char*)&m_data[ipos], m_pos - ipos, saveAsOwnData);
}else{
m_error = ERROR_NAME_EXPECTED;
return nullptr;

View File

@ -69,7 +69,7 @@ public:
if(end == -1){
end = m_caret.m_pos;
}
return oatpp::String(&m_caret.m_data[m_start], end - m_start, saveAsOwnData);
return oatpp::String((const char*)&m_caret.m_data[m_start], end - m_start, saveAsOwnData);
}
oatpp::String toString(){

View File

@ -64,7 +64,7 @@ namespace oatpp { namespace utils { namespace conversion {
v_char8 buff [100];
v_int32 size = int32ToCharSequence(value, &buff[0]);
if(size > 0){
return oatpp::String(&buff[0], size, true);
return oatpp::String((const char*)&buff[0], size, true);
}
return oatpp::String::empty();
}
@ -73,7 +73,7 @@ namespace oatpp { namespace utils { namespace conversion {
v_char8 buff [100];
v_int32 size = int64ToCharSequence(value, &buff[0]);
if(size > 0){
return oatpp::String(&buff[0], size, true);
return oatpp::String((const char*)&buff[0], size, true);
}
return oatpp::String::empty();
}
@ -132,7 +132,7 @@ namespace oatpp { namespace utils { namespace conversion {
v_char8 buff [100];
v_int32 size = float32ToCharSequence(value, &buff[0]);
if(size > 0){
return oatpp::String(&buff[0], size, true);
return oatpp::String((const char*)&buff[0], size, true);
}
return oatpp::String::empty();
}
@ -141,16 +141,16 @@ namespace oatpp { namespace utils { namespace conversion {
v_char8 buff [100];
v_int32 size = float32ToCharSequence(value, &buff[0]);
if(size > 0){
return oatpp::String(&buff[0], size, true);
return oatpp::String((const char*)&buff[0], size, true);
}
return oatpp::String::empty();
}
oatpp::String boolToStr(bool value) {
if(value){
return oatpp::String((p_char8)"true", 4, false);
return oatpp::String("true", 4, false);
} else {
return oatpp::String((p_char8)"false", 5, false);
return oatpp::String("false", 5, false);
}
}

View File

@ -60,7 +60,7 @@ namespace oatpp { namespace utils { namespace conversion {
v_char8 buff [100];
v_int32 size = primitiveToCharSequence(value, &buff[0], pattern);
if(size > 0){
return oatpp::String(&buff[0], size, true);
return oatpp::String((const char*)&buff[0], size, true);
}
return oatpp::String::empty();
}

View File

@ -66,7 +66,7 @@ Connection::Library::v_size Connection::read(void *buff, Library::v_size count){
return ERROR_IO_WAIT_RETRY; // For async io. In case socket is non_blocking
} else if(e == EINTR) {
return ERROR_IO_RETRY;
} else if(e == EPIPE) {
} else if(e == ECONNRESET) {
return ERROR_IO_PIPE;
} else {
//OATPP_LOGD("Connection", "write errno=%d", e);

View File

@ -204,7 +204,7 @@ oatpp::String Utils::escapeString(p_char8 data, v_int32 size) {
v_int32 safeSize;
v_int32 escapedSize = calcEscapedStringSize(data, size, safeSize);
if(escapedSize == size) {
return String(data, size, true);
return String((const char*)data, size, true);
}
auto result = String(escapedSize);
v_int32 i = 0;

View File

@ -78,10 +78,10 @@ void ApiClient::formatPath(oatpp::data::stream::OutputStream* stream,
if(seg.type == PathSegment::SEG_PATH) {
stream->write(seg.text.data(), seg.text.size());
} else {
auto key = oatpp::String((p_char8) seg.text.data(), (v_int32) seg.text.length(), false);
auto key = oatpp::String(seg.text.data(), (v_int32) seg.text.length(), false);
auto& param = params->get(key, oatpp::data::mapping::type::AbstractObjectWrapper::empty());
if(!param){
OATPP_LOGD(TAG, "Path parameter '%s' not provided in the api call", (const char*) seg.text.c_str());
OATPP_LOGD(TAG, "Path parameter '%s' not provided in the api call", seg.text.c_str());
throw std::runtime_error("[oatpp::web::client::ApiClient]: Path parameter missing");
}
auto value = oatpp::utils::conversion::primitiveToStr(param);

View File

@ -46,14 +46,11 @@ HttpRequestExecutor::execute(const String& method,
const std::shared_ptr<Headers>& headers,
const std::shared_ptr<Body>& body) {
//auto stream = oatpp::data::stream::ChunkedBuffer::createShared();
//stream << "/" << path;
//ENV::log("HTTP_EXECUTOR", "Execute: '%s'", (const char*) stream->toStringAsString()->getData());
auto connection = m_connectionProvider->getConnection();
if(!connection){
return nullptr; // TODO ERROR HERE
throw RequestExecutionError(RequestExecutionError::ERROR_CODE_CANT_CONNECT,
"[oatpp::web::client::HttpRequestExecutor::execute()]: ConnectionProvider failed to provide Connection");
}
auto request = oatpp::web::protocol::http::outgoing::Request::createShared(method, path, headers, body);
@ -65,41 +62,37 @@ HttpRequestExecutor::execute(const String& method,
request->send(upStream);
upStream->flush();
//auto upStream = oatpp::data::stream::ChunkedBuffer::createShared();
//request->send(upStream);
//ENV::log("request", "request:'%s'\n", (const char*) upStream->toStringAsString()->getData());
//upStream->flushToStream(connection);
auto readCount = connection->read(ioBuffer->getData(), ioBuffer->getSize());
//((p_char8) ioBuffer->getData())[readCount] = 0;
//ENV::log("asd", "response='%s'", (const char*) ioBuffer->getData());
if(readCount > 0) {
oatpp::parser::ParsingCaret caret((p_char8) ioBuffer->getData(), ioBuffer->getSize());
auto line = protocol::http::Protocol::parseResponseStartingLine(caret);
if(!line){
return nullptr; // TODO ERROR HERE
}
oatpp::web::protocol::http::Status error;
auto headers = protocol::http::Protocol::parseHeaders(caret, error);
if(error.code != 0){
return nullptr; // TODO ERROR HERE
}
auto bodyStream = oatpp::data::stream::InputStreamBufferedProxy::createShared(connection,
ioBuffer,
caret.getPosition(),
(v_int32) readCount);
return Response::createShared(line->statusCode, line->description, headers, bodyStream);
if(readCount == 0) {
throw RequestExecutionError(RequestExecutionError::ERROR_CODE_NO_RESPONSE,
"[oatpp::web::client::HttpRequestExecutor::execute()]: No response from server");
} else if(readCount < 0) {
throw RequestExecutionError(RequestExecutionError::ERROR_CODE_CANT_READ_RESPONSE,
"[oatpp::web::client::HttpRequestExecutor::execute()]: Failed to read response. Check out the RequestExecutionError::getReadErrorCode() for more information", (v_int32) readCount);
}
oatpp::parser::ParsingCaret caret((p_char8) ioBuffer->getData(), ioBuffer->getSize());
auto line = protocol::http::Protocol::parseResponseStartingLine(caret);
if(!line){
throw RequestExecutionError(RequestExecutionError::ERROR_CODE_CANT_PARSE_STARTING_LINE,
"[oatpp::web::client::HttpRequestExecutor::execute()]: Failed to parse response. Invalid starting line");
}
return nullptr;
oatpp::web::protocol::http::Status error;
auto responseHeaders = protocol::http::Protocol::parseHeaders(caret, error);
if(error.code != 0){
throw RequestExecutionError(RequestExecutionError::ERROR_CODE_CANT_PARSE_HEADERS,
"[oatpp::web::client::HttpRequestExecutor::execute()]: Failed to parse response. Invalid headers section");
}
auto bodyStream = oatpp::data::stream::InputStreamBufferedProxy::createShared(connection,
ioBuffer,
caret.getPosition(),
(v_int32) readCount);
return Response::createShared(line->statusCode, line->description, responseHeaders, bodyStream);
}

View File

@ -44,6 +44,9 @@ public:
return std::shared_ptr<HttpRequestExecutor>(new HttpRequestExecutor(connectionProvider));
}
/**
* throws RequestExecutionError
*/
std::shared_ptr<Response> execute(const String& method,
const String& path,
const std::shared_ptr<Headers>& headers,

View File

@ -41,6 +41,48 @@ public:
typedef oatpp::web::protocol::http::outgoing::Body Body;
public:
typedef Action (oatpp::async::AbstractCoroutine::*AsyncCallback)(const std::shared_ptr<Response>&);
public:
class RequestExecutionError : public std::runtime_error {
public:
constexpr static const v_int32 ERROR_CODE_CANT_CONNECT = 1;
constexpr static const v_int32 ERROR_CODE_CANT_PARSE_STARTING_LINE = 2;
constexpr static const v_int32 ERROR_CODE_CANT_PARSE_HEADERS = 3;
constexpr static const v_int32 ERROR_CODE_CANT_READ_RESPONSE = 4;
constexpr static const v_int32 ERROR_CODE_NO_RESPONSE = 5;
private:
v_int32 m_errorCode;
v_int32 m_readErrorCode;
const char* m_message;
public:
RequestExecutionError(v_int32 errorCode, const char* message, v_int32 readErrorCode = 0)
:std::runtime_error(message)
, m_errorCode(errorCode)
, m_message(message)
, m_readErrorCode(readErrorCode)
{}
v_int32 getErrorCode() const {
return m_errorCode;
}
const char* getMessage() const {
return m_message;
}
/**
* This value is valid if errorCode == ERROR_CODE_CANT_READ_RESPONSE
* For more information about the read error you get check out:
* - oatpp::data::stream::IOStream for possible error codes
* - implementation of Connection provided by your ConnectionProvider for implementation-specific behaviour
*/
v_int32 getReadErrorCode() const {
return m_readErrorCode;
}
};
public:
virtual std::shared_ptr<Response> execute(const String& method,

View File

@ -77,7 +77,7 @@ HttpProcessor::processRequest(HttpRouter* router,
auto route = router->getRoute(line->method, line->path);
if(!route.isNull()) {
if(route) {
oatpp::web::protocol::http::Status error;
auto headers = protocol::http::Protocol::parseHeaders(caret, error);
@ -143,7 +143,7 @@ HttpProcessor::Coroutine::Action HttpProcessor::Coroutine::parseRequest(v_int32
m_currentRoute = m_router->getRoute(line->method, line->path);
if(m_currentRoute.isNull()) {
if(!m_currentRoute) {
m_currentResponse = m_errorHandler->handleError(protocol::http::Status::CODE_404, "Current url has no mapping");
return yieldTo(&HttpProcessor::Coroutine::onResponseFormed);
}

View File

@ -72,7 +72,7 @@ TYPE NAME = __request;
#define OATPP_MACRO_API_CONTROLLER_HEADER_0(TYPE, NAME, PARAM_LIST) \
auto __param_str_val_##NAME = __request->getHeader(#NAME); \
if(__param_str_val_##NAME.isNull()){ \
if(!__param_str_val_##NAME){ \
return ApiController::handleError(Status::CODE_400, "Missing HEADER parameter '" #NAME "'"); \
} \
bool __param_validation_check_##NAME; \
@ -83,7 +83,7 @@ if(!__param_validation_check_##NAME){ \
#define OATPP_MACRO_API_CONTROLLER_HEADER_1(TYPE, NAME, PARAM_LIST) \
auto __param_str_val_##NAME = __request->getHeader(OATPP_MACRO_FIRSTARG PARAM_LIST); \
if(__param_str_val_##NAME.isNull()){ \
if(!__param_str_val_##NAME){ \
return ApiController::handleError(Status::CODE_400, \
oatpp::String("Missing HEADER parameter '") + OATPP_MACRO_FIRSTARG PARAM_LIST + "'"); \
} \
@ -126,7 +126,7 @@ OATPP_MACRO_API_CONTROLLER_HEADER_INFO_CHOOSER_EXP(TYPE, NAME, PARAM_LIST, OATPP
#define OATPP_MACRO_API_CONTROLLER_PATH_0(TYPE, NAME, PARAM_LIST) \
auto __param_str_val_##NAME = __request->getPathVariable(#NAME); \
if(__param_str_val_##NAME.isNull()){ \
if(!__param_str_val_##NAME){ \
return ApiController::handleError(Status::CODE_400, "Missing PATH parameter '" #NAME "'"); \
} \
bool __param_validation_check_##NAME; \
@ -137,7 +137,7 @@ if(!__param_validation_check_##NAME){ \
#define OATPP_MACRO_API_CONTROLLER_PATH_1(TYPE, NAME, PARAM_LIST) \
auto __param_str_val_##NAME = __request->getPathVariable(OATPP_MACRO_FIRSTARG PARAM_LIST); \
if(__param_str_val_##NAME.isNull()){ \
if(!__param_str_val_##NAME){ \
return ApiController::handleError(Status::CODE_400, \
oatpp::String("Missing PATH parameter '") + OATPP_MACRO_FIRSTARG PARAM_LIST + "'"); \
} \
@ -192,7 +192,7 @@ info->body.type = oatpp::data::mapping::type::__class::String::getType();
#define OATPP_MACRO_API_CONTROLLER_BODY_DTO(TYPE, NAME, PARAM_LIST) \
TYPE NAME; \
__request->readBodyToDto(NAME, getDefaultObjectMapper()); \
if(NAME.isNull()) { \
if(!NAME) { \
return ApiController::handleError(Status::CODE_400, "Missing valid body parameter '" #NAME "'"); \
}

View File

@ -50,7 +50,7 @@ std::shared_ptr<Pattern> Pattern::parse(p_char8 data, v_int32 size){
if(a == '/'){
if(i - lastPos > 0){
auto part = Part::createShared(Part::FUNCTION_CONST, oatpp::String(&data[lastPos], i - lastPos, true));
auto part = Part::createShared(Part::FUNCTION_CONST, oatpp::String((const char*)&data[lastPos], i - lastPos, true));
result->m_parts->pushBack(part);
}
@ -59,7 +59,7 @@ std::shared_ptr<Pattern> Pattern::parse(p_char8 data, v_int32 size){
} else if(a == '*'){
lastPos = i + 1;
if(size > lastPos){
auto part = Part::createShared(Part::FUNCTION_ANY_END, oatpp::String(&data[lastPos], size - lastPos, true));
auto part = Part::createShared(Part::FUNCTION_ANY_END, oatpp::String((const char*)&data[lastPos], size - lastPos, true));
result->m_parts->pushBack(part);
}else{
auto part = Part::createShared(Part::FUNCTION_ANY_END, oatpp::String(0));
@ -75,7 +75,7 @@ std::shared_ptr<Pattern> Pattern::parse(p_char8 data, v_int32 size){
}
if(i > lastPos){
auto part = Part::createShared(Part::FUNCTION_VAR, oatpp::String(&data[lastPos], i - lastPos, true));
auto part = Part::createShared(Part::FUNCTION_VAR, oatpp::String((const char*)&data[lastPos], i - lastPos, true));
result->m_parts->pushBack(part);
}else{
auto part = Part::createShared(Part::FUNCTION_VAR, oatpp::String(0));
@ -91,7 +91,7 @@ std::shared_ptr<Pattern> Pattern::parse(p_char8 data, v_int32 size){
}
if(i - lastPos > 0){
auto part = Part::createShared(Part::FUNCTION_CONST, oatpp::String(&data[lastPos], i - lastPos, true));
auto part = Part::createShared(Part::FUNCTION_CONST, oatpp::String((const char*)&data[lastPos], i - lastPos, true));
result->m_parts->pushBack(part);
}
@ -151,7 +151,7 @@ std::shared_ptr<Pattern::MatchMap> Pattern::match(p_char8 url, v_int32 size){
if(caret.canContinue() && !caret.isAtChar('/')){
if(caret.isAtChar('?') && (curr == nullptr || curr->getData()->function == Part::FUNCTION_ANY_END)) {
tail = oatpp::String(caret.getCurrData(), size - caret.getPosition(), true);
tail = oatpp::String((const char*)caret.getCurrData(), size - caret.getPosition(), true);
return MatchMap::createShared(vars, tail);
}
return nullptr;
@ -159,7 +159,7 @@ std::shared_ptr<Pattern::MatchMap> Pattern::match(p_char8 url, v_int32 size){
}else if(part->function == Part::FUNCTION_ANY_END){
if(size > caret.getPosition()){
tail = oatpp::String(caret.getCurrData(), size - caret.getPosition(), true);
tail = oatpp::String((const char*)caret.getCurrData(), size - caret.getPosition(), true);
}
return MatchMap::createShared(vars, tail);
}else if(part->function == Part::FUNCTION_VAR){
@ -172,14 +172,14 @@ std::shared_ptr<Pattern::MatchMap> Pattern::match(p_char8 url, v_int32 size){
v_char8 a = findSysChar(caret);
if(a == '?') {
if(curr == nullptr || curr->getData()->function == Part::FUNCTION_ANY_END) {
vars->put(oatpp::String(part->text.get(), true), label.toString());
tail = oatpp::String(caret.getCurrData(), size - caret.getPosition(), true);
vars->put(oatpp::String(part->text), label.toString());
tail = oatpp::String((const char*)caret.getCurrData(), size - caret.getPosition(), true);
return MatchMap::createShared(vars, tail);
}
caret.findChar('/');
}
vars->put(oatpp::String(part->text.get(), true), label.toString());
vars->put(oatpp::String(part->text), label.toString());
}

View File

@ -69,8 +69,8 @@ public:
return m_subscriber->processUrlAsync(parentCoroutine, callback, param);
}
bool isNull() const {
return m_subscriber == nullptr;
explicit operator bool() const {
return m_subscriber != nullptr;
}
std::shared_ptr<Pattern::MatchMap> matchMap;