mirror of
https://github.com/oatpp/oatpp.git
synced 2025-01-30 16:59:30 +08:00
better error handling for HeadersReader
This commit is contained in:
parent
645666dbf9
commit
3a8fecee3d
@ -124,6 +124,8 @@ add_library(oatpp
|
||||
web/client/HttpRequestExecutor.hpp
|
||||
web/client/RequestExecutor.cpp
|
||||
web/client/RequestExecutor.hpp
|
||||
web/protocol/CommunicationError.cpp
|
||||
web/protocol/CommunicationError.hpp
|
||||
web/protocol/http/Http.cpp
|
||||
web/protocol/http/Http.hpp
|
||||
web/protocol/http/incoming/BodyDecoder.cpp
|
||||
@ -162,8 +164,6 @@ add_library(oatpp
|
||||
web/server/handler/Interceptor.hpp
|
||||
web/server/HttpConnectionHandler.cpp
|
||||
web/server/HttpConnectionHandler.hpp
|
||||
web/server/HttpError.cpp
|
||||
web/server/HttpError.hpp
|
||||
web/server/HttpProcessor.cpp
|
||||
web/server/HttpProcessor.hpp
|
||||
web/server/HttpRouter.cpp
|
||||
|
@ -129,7 +129,11 @@ public:
|
||||
}
|
||||
|
||||
void close() {
|
||||
std::lock_guard<std::mutex> lock(m_mutex);
|
||||
m_open = false;
|
||||
m_mutex.unlock();
|
||||
m_conditionRead.notify_one();
|
||||
m_conditionWrite.notify_one();
|
||||
}
|
||||
|
||||
};
|
||||
|
@ -52,7 +52,7 @@ bool FullTest::onRun() {
|
||||
auto serverConnectionProvider = oatpp::network::virtual_::server::ConnectionProvider::createShared(interface);
|
||||
auto clientConnectionProvider = oatpp::network::virtual_::client::ConnectionProvider::createShared(interface);
|
||||
|
||||
serverConnectionProvider->setSocketMaxAvailableToReadWrtie(20, -1);
|
||||
serverConnectionProvider->setSocketMaxAvailableToReadWrtie(1, 10);
|
||||
|
||||
auto objectMapper = oatpp::parser::json::mapping::ObjectMapper::createShared();
|
||||
|
||||
@ -72,9 +72,13 @@ bool FullTest::onRun() {
|
||||
|
||||
for(v_int32 i = 0; i < 1; i ++) {
|
||||
|
||||
auto response = client->getRoot();
|
||||
auto text = response->readBodyToString();
|
||||
OATPP_LOGD("client", "body='%s'", text->c_str());
|
||||
try {
|
||||
auto response = client->getRoot();
|
||||
auto text = response->readBodyToString();
|
||||
OATPP_LOGD("client", "body='%s'", text->c_str());
|
||||
} catch(std::runtime_error e) {
|
||||
OATPP_LOGD("client", "error='%s'", e.what());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
@ -107,14 +107,19 @@ HttpRequestExecutor::execute(const String& method,
|
||||
upStream->flush();
|
||||
|
||||
oatpp::web::protocol::http::incoming::ResponseHeadersReader headerReader(ioBuffer->getData(), ioBuffer->getSize(), 4096);
|
||||
oatpp::web::protocol::http::Status error;
|
||||
oatpp::web::protocol::http::HttpError::Info error;
|
||||
const auto& result = headerReader.readHeaders(connection, error);
|
||||
|
||||
if(error.code != 0) {
|
||||
if(error.status.code != 0) {
|
||||
throw RequestExecutionError(RequestExecutionError::ERROR_CODE_CANT_PARSE_STARTING_LINE,
|
||||
"[oatpp::web::client::HttpRequestExecutor::execute()]: Failed to parse response. Invalid response headers");
|
||||
}
|
||||
|
||||
if(error.ioStatus < 0) {
|
||||
throw RequestExecutionError(RequestExecutionError::ERROR_CODE_CANT_PARSE_STARTING_LINE,
|
||||
"[oatpp::web::client::HttpRequestExecutor::execute()]: Failed to read response.");
|
||||
}
|
||||
|
||||
auto bodyStream = oatpp::data::stream::InputStreamBufferedProxy::createShared(connection,
|
||||
ioBuffer,
|
||||
result.bufferPosStart,
|
||||
|
@ -22,4 +22,22 @@
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
#include "HttpError.hpp"
|
||||
#include "CommunicationError.hpp"
|
||||
|
||||
namespace oatpp { namespace web { namespace protocol {
|
||||
|
||||
CommunicationError::CommunicationError(oatpp::os::io::Library::v_size ioStatus, const oatpp::String& message)
|
||||
:std::runtime_error(message->std_str())
|
||||
, m_ioStatus(ioStatus)
|
||||
, m_message(message)
|
||||
{}
|
||||
|
||||
oatpp::os::io::Library::v_size CommunicationError::getIOStatus() {
|
||||
return m_ioStatus;
|
||||
}
|
||||
|
||||
oatpp::String& CommunicationError::getMessage(){
|
||||
return m_message;
|
||||
}
|
||||
|
||||
}}}
|
@ -22,40 +22,61 @@
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef oatpp_web_server_HttpError_hpp
|
||||
#define oatpp_web_server_HttpError_hpp
|
||||
#ifndef oatpp_web_protocol_CommunicationError_hpp
|
||||
#define oatpp_web_protocol_CommunicationError_hpp
|
||||
|
||||
#include "oatpp/web/protocol/http/Http.hpp"
|
||||
#include "oatpp/core/Types.hpp"
|
||||
#include "oatpp/core/os/io/Library.hpp"
|
||||
|
||||
namespace oatpp { namespace web { namespace server {
|
||||
namespace oatpp { namespace web { namespace protocol {
|
||||
|
||||
class HttpError : public std::runtime_error {
|
||||
class CommunicationError : public std::runtime_error {
|
||||
private:
|
||||
oatpp::web::protocol::http::Status m_status;
|
||||
oatpp::os::io::Library::v_size m_ioStatus;
|
||||
oatpp::String m_message;
|
||||
public:
|
||||
|
||||
HttpError(const oatpp::web::protocol::http::Status& status,
|
||||
const oatpp::String& message)
|
||||
:std::runtime_error(status.description)
|
||||
, m_status(status)
|
||||
, m_message(message)
|
||||
CommunicationError(oatpp::os::io::Library::v_size ioStatus, const oatpp::String& message);
|
||||
oatpp::os::io::Library::v_size getIOStatus();
|
||||
oatpp::String& getMessage();
|
||||
|
||||
};
|
||||
|
||||
template<class Status>
|
||||
class ProtocolError : public CommunicationError {
|
||||
public:
|
||||
|
||||
struct Info {
|
||||
|
||||
Info()
|
||||
: ioStatus(0)
|
||||
{}
|
||||
|
||||
Info(oatpp::os::io::Library::v_size pIOStatus, const Status& pStatus)
|
||||
: ioStatus(pIOStatus)
|
||||
, status(pStatus)
|
||||
{}
|
||||
|
||||
oatpp::os::io::Library::v_size ioStatus;
|
||||
Status status;
|
||||
|
||||
};
|
||||
|
||||
private:
|
||||
Info m_info;
|
||||
public:
|
||||
|
||||
ProtocolError(const Info& info, const oatpp::String& message)
|
||||
: CommunicationError(info.ioStatus, message)
|
||||
, m_info(info)
|
||||
{}
|
||||
|
||||
oatpp::web::protocol::http::Status getStatus() {
|
||||
return m_status;
|
||||
}
|
||||
|
||||
oatpp::String& getMessage(){
|
||||
return m_message;
|
||||
Info getInfo() {
|
||||
return m_info;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
#define OATPP_ASSERT_HTTP(COND, STATUS, MESSAGE) \
|
||||
if(!(COND)) { throw oatpp::web::server::HttpError(STATUS, MESSAGE); }
|
||||
|
||||
}}}
|
||||
|
||||
#endif /* oatpp_web_server_HttpError_hpp */
|
||||
#endif /* oatpp_web_protocol_CommunicationError_hpp */
|
@ -22,11 +22,13 @@
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef oatpp_network_http_Protocol_hpp
|
||||
#define oatpp_network_http_Protocol_hpp
|
||||
#ifndef oatpp_web_protocol_http_Http_hpp
|
||||
#define oatpp_web_protocol_http_Http_hpp
|
||||
|
||||
#include "oatpp/network/Connection.hpp"
|
||||
|
||||
#include "oatpp/web/protocol/CommunicationError.hpp"
|
||||
|
||||
#include "oatpp/core/parser/ParsingCaret.hpp"
|
||||
#include "oatpp/core/data/share/MemoryLabel.hpp"
|
||||
#include "oatpp/core/data/stream/Delegate.hpp"
|
||||
@ -130,6 +132,22 @@ public:
|
||||
|
||||
};
|
||||
|
||||
class HttpError : public protocol::ProtocolError<Status> {
|
||||
public:
|
||||
|
||||
HttpError(const Info& info, const oatpp::String& message)
|
||||
: protocol::ProtocolError<Status>(info, message)
|
||||
{}
|
||||
|
||||
HttpError(const Status& status, const oatpp::String& message)
|
||||
: protocol::ProtocolError<Status>(Info(0, status), message)
|
||||
{}
|
||||
|
||||
};
|
||||
|
||||
#define OATPP_ASSERT_HTTP(COND, STATUS, MESSAGE) \
|
||||
if(!(COND)) { throw oatpp::web::protocol::http::HttpError(STATUS, MESSAGE); }
|
||||
|
||||
class Header {
|
||||
public:
|
||||
class Value {
|
||||
@ -287,4 +305,4 @@ namespace std {
|
||||
};
|
||||
}
|
||||
|
||||
#endif /* oatpp_network_http_Protocol_hpp */
|
||||
#endif /* oatpp_web_protocol_http_Http_hpp */
|
||||
|
@ -73,14 +73,14 @@ os::io::Library::v_size RequestHeadersReader::readHeadersSection(const std::shar
|
||||
}
|
||||
|
||||
RequestHeadersReader::Result RequestHeadersReader::readHeaders(const std::shared_ptr<oatpp::data::stream::IOStream>& connection,
|
||||
http::Status& error) {
|
||||
http::HttpError::Info& error) {
|
||||
|
||||
RequestHeadersReader::Result result;
|
||||
|
||||
oatpp::data::stream::ChunkedBuffer buffer;
|
||||
auto res = readHeadersSection(connection, &buffer, result);
|
||||
error.ioStatus = readHeadersSection(connection, &buffer, result);
|
||||
|
||||
if(res > 0) {
|
||||
if(error.ioStatus > 0) {
|
||||
auto headersText = buffer.toString();
|
||||
oatpp::parser::ParsingCaret caret (headersText);
|
||||
http::Status status;
|
||||
|
@ -62,7 +62,7 @@ public:
|
||||
, m_maxHeadersSize(maxHeadersSize)
|
||||
{}
|
||||
|
||||
Result readHeaders(const std::shared_ptr<oatpp::data::stream::IOStream>& connection, http::Status& error);
|
||||
Result readHeaders(const std::shared_ptr<oatpp::data::stream::IOStream>& connection, http::HttpError::Info& error);
|
||||
Action readHeadersAsync(oatpp::async::AbstractCoroutine* parentCoroutine,
|
||||
AsyncCallback callback,
|
||||
const std::shared_ptr<oatpp::data::stream::IOStream>& connection);
|
||||
|
@ -73,14 +73,14 @@ os::io::Library::v_size ResponseHeadersReader::readHeadersSection(const std::sha
|
||||
}
|
||||
|
||||
ResponseHeadersReader::Result ResponseHeadersReader::readHeaders(const std::shared_ptr<oatpp::data::stream::IOStream>& connection,
|
||||
http::Status& error) {
|
||||
http::HttpError::Info& error) {
|
||||
|
||||
Result result;
|
||||
|
||||
oatpp::data::stream::ChunkedBuffer buffer;
|
||||
auto res = readHeadersSection(connection, &buffer, result);
|
||||
error.ioStatus = readHeadersSection(connection, &buffer, result);
|
||||
|
||||
if(res > 0) {
|
||||
if(error.ioStatus > 0) {
|
||||
auto headersText = buffer.toString();
|
||||
oatpp::parser::ParsingCaret caret (headersText);
|
||||
http::Status status;
|
||||
|
@ -62,7 +62,7 @@ public:
|
||||
, m_maxHeadersSize(maxHeadersSize)
|
||||
{}
|
||||
|
||||
Result readHeaders(const std::shared_ptr<oatpp::data::stream::IOStream>& connection, http::Status& error);
|
||||
Result readHeaders(const std::shared_ptr<oatpp::data::stream::IOStream>& connection, http::HttpError::Info& error);
|
||||
Action readHeadersAsync(oatpp::async::AbstractCoroutine* parentCoroutine,
|
||||
AsyncCallback callback,
|
||||
const std::shared_ptr<oatpp::data::stream::IOStream>& connection);
|
||||
|
@ -26,6 +26,11 @@
|
||||
|
||||
namespace oatpp { namespace web { namespace protocol { namespace http { namespace outgoing {
|
||||
|
||||
bool CommunicationUtils::headerEqualsCI_FAST(const oatpp::data::share::MemoryLabel& headerValue, const char* value) {
|
||||
v_int32 size = (v_int32) std::strlen(value);
|
||||
return size == headerValue.getSize() && oatpp::base::StrBuffer::equalsCI_FAST(headerValue.getData(), value, size);
|
||||
}
|
||||
|
||||
bool CommunicationUtils::considerConnectionKeepAlive(const std::shared_ptr<protocol::http::incoming::Request>& request,
|
||||
const std::shared_ptr<protocol::http::outgoing::Response>& response){
|
||||
|
||||
@ -34,13 +39,12 @@ bool CommunicationUtils::considerConnectionKeepAlive(const std::shared_ptr<proto
|
||||
/* Set keep-alive to value specified in the client's request, if no Connection header present in response. */
|
||||
/* Set keep-alive to value specified in response otherwise */
|
||||
auto it = request->headers.find(Header::CONNECTION);
|
||||
if(it != request->headers.end() && oatpp::base::StrBuffer::equalsCI_FAST((const char*) it->second.getData(), Header::Value::CONNECTION_KEEP_ALIVE)) {
|
||||
if(it != request->headers.end() && headerEqualsCI_FAST(it->second, Header::Value::CONNECTION_KEEP_ALIVE)) {
|
||||
if(response->putHeaderIfNotExists(Header::CONNECTION, it->second)){
|
||||
return true;
|
||||
} else {
|
||||
auto outKeepAlive = response->getHeaders().find(Header::CONNECTION);
|
||||
return (outKeepAlive != response->getHeaders().end() &&
|
||||
oatpp::base::StrBuffer::equalsCI_FAST((const char*)outKeepAlive->second.getData(), Header::Value::CONNECTION_KEEP_ALIVE));
|
||||
return (outKeepAlive != response->getHeaders().end() && headerEqualsCI_FAST(outKeepAlive->second, Header::Value::CONNECTION_KEEP_ALIVE));
|
||||
}
|
||||
}
|
||||
|
||||
@ -48,11 +52,10 @@ bool CommunicationUtils::considerConnectionKeepAlive(const std::shared_ptr<proto
|
||||
/* Set HTTP/1.1 default Connection header value (Keep-Alive), if no Connection header present in response. */
|
||||
/* Set keep-alive to value specified in response otherwise */
|
||||
auto& protocol = request->startingLine.protocol;
|
||||
if(protocol.getData() != nullptr && oatpp::base::StrBuffer::equalsCI_FAST((const char*) protocol.getData(), "HTTP/1.1")) {
|
||||
if(protocol.getData() != nullptr && headerEqualsCI_FAST(protocol, "HTTP/1.1")) {
|
||||
if(!response->putHeaderIfNotExists(Header::CONNECTION, Header::Value::CONNECTION_KEEP_ALIVE)) {
|
||||
auto outKeepAlive = response->getHeaders().find(Header::CONNECTION);
|
||||
return (outKeepAlive != response->getHeaders().end() &&
|
||||
oatpp::base::StrBuffer::equalsCI_FAST((const char*) outKeepAlive->second.getData(), Header::Value::CONNECTION_KEEP_ALIVE));
|
||||
return (outKeepAlive != response->getHeaders().end() && headerEqualsCI_FAST(outKeepAlive->second, Header::Value::CONNECTION_KEEP_ALIVE));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@ -64,8 +67,7 @@ bool CommunicationUtils::considerConnectionKeepAlive(const std::shared_ptr<proto
|
||||
/* Set keep-alive to value specified in response otherwise */
|
||||
if(!response->putHeaderIfNotExists(Header::CONNECTION, Header::Value::CONNECTION_CLOSE)) {
|
||||
auto outKeepAlive = response->getHeaders().find(Header::CONNECTION);
|
||||
return (outKeepAlive != response->getHeaders().end() &&
|
||||
oatpp::base::StrBuffer::equalsCI_FAST((const char*)outKeepAlive->second.getData(), Header::Value::CONNECTION_KEEP_ALIVE));
|
||||
return (outKeepAlive != response->getHeaders().end() && headerEqualsCI_FAST(outKeepAlive->second, Header::Value::CONNECTION_KEEP_ALIVE));
|
||||
}
|
||||
|
||||
return false;
|
||||
|
@ -31,6 +31,8 @@
|
||||
namespace oatpp { namespace web { namespace protocol { namespace http { namespace outgoing {
|
||||
|
||||
class CommunicationUtils {
|
||||
private:
|
||||
static bool headerEqualsCI_FAST(const oatpp::data::share::MemoryLabel& headerValue, const char* value);
|
||||
public:
|
||||
|
||||
/**
|
||||
|
@ -28,7 +28,6 @@
|
||||
|
||||
#include "oatpp/web/protocol/http/incoming/Request.hpp"
|
||||
#include "oatpp/web/protocol/http/Http.hpp"
|
||||
#include "oatpp/web/server/HttpError.hpp"
|
||||
|
||||
#include "oatpp/network/Connection.hpp"
|
||||
#include "oatpp/test/Checker.hpp"
|
||||
|
@ -23,7 +23,6 @@
|
||||
***************************************************************************/
|
||||
|
||||
#include "./HttpConnectionHandler.hpp"
|
||||
#include "./HttpError.hpp"
|
||||
|
||||
#include "oatpp/web/protocol/http/outgoing/ChunkedBufferBody.hpp"
|
||||
#include "oatpp/web/protocol/http/incoming/Request.hpp"
|
||||
|
@ -23,7 +23,6 @@
|
||||
***************************************************************************/
|
||||
|
||||
#include "HttpProcessor.hpp"
|
||||
#include "./HttpError.hpp"
|
||||
|
||||
#include "oatpp/web/protocol/http/outgoing/CommunicationUtils.hpp"
|
||||
|
||||
@ -43,11 +42,16 @@ HttpProcessor::processRequest(HttpRouter* router,
|
||||
bool& keepAlive) {
|
||||
|
||||
RequestHeadersReader headersReader(buffer, bufferSize, 4096);
|
||||
oatpp::web::protocol::http::Status error;
|
||||
oatpp::web::protocol::http::HttpError::Info error;
|
||||
auto headersReadResult = headersReader.readHeaders(connection, error);
|
||||
|
||||
if(error.code != 0) {
|
||||
return errorHandler->handleError(error, "Invalid request headers");
|
||||
if(error.status.code != 0) {
|
||||
return errorHandler->handleError(error.status, "Invalid request headers");
|
||||
}
|
||||
|
||||
if(error.ioStatus < 0) {
|
||||
keepAlive = false;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto route = router->getRoute(headersReadResult.startingLine.method.toString(), headersReadResult.startingLine.path.toString());
|
||||
@ -78,8 +82,8 @@ HttpProcessor::processRequest(HttpRouter* router,
|
||||
if(!response) {
|
||||
response = route.processUrl(request);
|
||||
}
|
||||
} catch (HttpError& error) {
|
||||
return errorHandler->handleError(error.getStatus(), error.getMessage());
|
||||
} catch (oatpp::web::protocol::http::HttpError& error) {
|
||||
return errorHandler->handleError(error.getInfo().status, error.getMessage());
|
||||
} catch (std::exception& error) {
|
||||
return errorHandler->handleError(protocol::http::Status::CODE_500, error.what());
|
||||
} catch (...) {
|
||||
@ -175,8 +179,8 @@ HttpProcessor::Coroutine::Action HttpProcessor::Coroutine::handleError(const oat
|
||||
if (error.isExceptionThrown) {
|
||||
try{
|
||||
throw;
|
||||
} catch (HttpError& error) {
|
||||
m_currentResponse = m_errorHandler->handleError(error.getStatus(), error.getMessage());
|
||||
} catch (oatpp::web::protocol::http::HttpError& error) {
|
||||
m_currentResponse = m_errorHandler->handleError(error.getInfo().status, error.getMessage());
|
||||
} catch (std::exception& error) {
|
||||
m_currentResponse = m_errorHandler->handleError(protocol::http::Status::CODE_500, error.what());
|
||||
} catch (...) {
|
||||
|
@ -51,7 +51,7 @@ std::shared_ptr<ApiController::OutgoingResponse> ApiController::handleError(cons
|
||||
if(m_errorHandler) {
|
||||
return m_errorHandler->handleError(status, message);
|
||||
}
|
||||
throw oatpp::web::server::HttpError(status, message);
|
||||
throw oatpp::web::protocol::http::HttpError(status, message);
|
||||
}
|
||||
|
||||
void ApiController::setErrorHandler(const std::shared_ptr<handler::ErrorHandler>& errorHandler){
|
||||
|
@ -27,7 +27,6 @@
|
||||
|
||||
#include "./Endpoint.hpp"
|
||||
|
||||
#include "oatpp/web/server/HttpError.hpp"
|
||||
#include "oatpp/web/server/handler/ErrorHandler.hpp"
|
||||
#include "oatpp/web/server/HttpConnectionHandler.hpp"
|
||||
#include "oatpp/web/url/mapping/Router.hpp"
|
||||
|
Loading…
Reference in New Issue
Block a user