зеркало из https://github.com/microsoft/CCF.git
Clear headers on error during handler execution (#5122)
This commit is contained in:
Родитель
158bf42106
Коммит
159f9b1dbc
|
@ -137,6 +137,7 @@ namespace ccf
|
||||||
{
|
{
|
||||||
set_response_header(kv.first, kv.second);
|
set_response_header(kv.first, kv.second);
|
||||||
}
|
}
|
||||||
|
virtual void clear_response_headers() = 0;
|
||||||
|
|
||||||
virtual void set_response_trailer(
|
virtual void set_response_trailer(
|
||||||
const std::string_view& name, const std::string_view& value) = 0;
|
const std::string_view& name, const std::string_view& value) = 0;
|
||||||
|
|
|
@ -250,6 +250,11 @@ namespace http
|
||||||
response_headers[std::string(name)] = value;
|
response_headers[std::string(name)] = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual void clear_response_headers() override
|
||||||
|
{
|
||||||
|
response_headers.clear();
|
||||||
|
}
|
||||||
|
|
||||||
virtual void set_response_trailer(
|
virtual void set_response_trailer(
|
||||||
const std::string_view& name, const std::string_view& value) override
|
const std::string_view& name, const std::string_view& value) override
|
||||||
{
|
{
|
||||||
|
|
|
@ -517,6 +517,7 @@ namespace ccf
|
||||||
ctx->get_request_verb().c_str(),
|
ctx->get_request_verb().c_str(),
|
||||||
ctx->get_request_path());
|
ctx->get_request_path());
|
||||||
|
|
||||||
|
ctx->clear_response_headers();
|
||||||
ctx->set_error(
|
ctx->set_error(
|
||||||
HTTP_STATUS_INTERNAL_SERVER_ERROR,
|
HTTP_STATUS_INTERNAL_SERVER_ERROR,
|
||||||
ccf::errors::InternalError,
|
ccf::errors::InternalError,
|
||||||
|
@ -566,6 +567,7 @@ namespace ccf
|
||||||
catch (const std::exception& e)
|
catch (const std::exception& e)
|
||||||
{
|
{
|
||||||
// run default handler to set transaction id in header
|
// run default handler to set transaction id in header
|
||||||
|
ctx->clear_response_headers();
|
||||||
ccf::endpoints::default_locally_committed_func(
|
ccf::endpoints::default_locally_committed_func(
|
||||||
args, tx_id.value());
|
args, tx_id.value());
|
||||||
ctx->set_error(
|
ctx->set_error(
|
||||||
|
@ -578,6 +580,7 @@ namespace ccf
|
||||||
catch (...)
|
catch (...)
|
||||||
{
|
{
|
||||||
// run default handler to set transaction id in header
|
// run default handler to set transaction id in header
|
||||||
|
ctx->clear_response_headers();
|
||||||
ccf::endpoints::default_locally_committed_func(
|
ccf::endpoints::default_locally_committed_func(
|
||||||
args, tx_id.value());
|
args, tx_id.value());
|
||||||
ctx->set_error(
|
ctx->set_error(
|
||||||
|
@ -605,6 +608,7 @@ namespace ccf
|
||||||
|
|
||||||
case kv::CommitResult::FAIL_NO_REPLICATE:
|
case kv::CommitResult::FAIL_NO_REPLICATE:
|
||||||
{
|
{
|
||||||
|
ctx->clear_response_headers();
|
||||||
ctx->set_error(
|
ctx->set_error(
|
||||||
HTTP_STATUS_SERVICE_UNAVAILABLE,
|
HTTP_STATUS_SERVICE_UNAVAILABLE,
|
||||||
ccf::errors::TransactionReplicationFailed,
|
ccf::errors::TransactionReplicationFailed,
|
||||||
|
@ -624,12 +628,14 @@ namespace ccf
|
||||||
}
|
}
|
||||||
catch (RpcException& e)
|
catch (RpcException& e)
|
||||||
{
|
{
|
||||||
|
ctx->clear_response_headers();
|
||||||
ctx->set_error(std::move(e.error));
|
ctx->set_error(std::move(e.error));
|
||||||
update_metrics(ctx);
|
update_metrics(ctx);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
catch (const JsonParseError& e)
|
catch (const JsonParseError& e)
|
||||||
{
|
{
|
||||||
|
ctx->clear_response_headers();
|
||||||
ctx->set_error(
|
ctx->set_error(
|
||||||
HTTP_STATUS_BAD_REQUEST, ccf::errors::InvalidInput, e.describe());
|
HTTP_STATUS_BAD_REQUEST, ccf::errors::InvalidInput, e.describe());
|
||||||
update_metrics(ctx);
|
update_metrics(ctx);
|
||||||
|
@ -637,6 +643,7 @@ namespace ccf
|
||||||
}
|
}
|
||||||
catch (const nlohmann::json::exception& e)
|
catch (const nlohmann::json::exception& e)
|
||||||
{
|
{
|
||||||
|
ctx->clear_response_headers();
|
||||||
ctx->set_error(
|
ctx->set_error(
|
||||||
HTTP_STATUS_BAD_REQUEST, ccf::errors::InvalidInput, e.what());
|
HTTP_STATUS_BAD_REQUEST, ccf::errors::InvalidInput, e.what());
|
||||||
update_metrics(ctx);
|
update_metrics(ctx);
|
||||||
|
@ -653,6 +660,7 @@ namespace ccf
|
||||||
}
|
}
|
||||||
catch (const std::exception& e)
|
catch (const std::exception& e)
|
||||||
{
|
{
|
||||||
|
ctx->clear_response_headers();
|
||||||
ctx->set_error(
|
ctx->set_error(
|
||||||
HTTP_STATUS_INTERNAL_SERVER_ERROR,
|
HTTP_STATUS_INTERNAL_SERVER_ERROR,
|
||||||
ccf::errors::InternalError,
|
ccf::errors::InternalError,
|
||||||
|
@ -662,6 +670,7 @@ namespace ccf
|
||||||
}
|
}
|
||||||
} // end of while loop
|
} // end of while loop
|
||||||
|
|
||||||
|
ctx->clear_response_headers();
|
||||||
ctx->set_error(
|
ctx->set_error(
|
||||||
HTTP_STATUS_SERVICE_UNAVAILABLE,
|
HTTP_STATUS_SERVICE_UNAVAILABLE,
|
||||||
ccf::errors::TransactionCommitAttemptsExceedLimit,
|
ccf::errors::TransactionCommitAttemptsExceedLimit,
|
||||||
|
@ -669,6 +678,7 @@ namespace ccf
|
||||||
"Transaction continued to conflict after {} attempts. Retry "
|
"Transaction continued to conflict after {} attempts. Retry "
|
||||||
"later.",
|
"later.",
|
||||||
max_attempts));
|
max_attempts));
|
||||||
|
update_metrics(ctx);
|
||||||
static constexpr size_t retry_after_seconds = 3;
|
static constexpr size_t retry_after_seconds = 3;
|
||||||
ctx->set_response_header(http::headers::RETRY_AFTER, retry_after_seconds);
|
ctx->set_response_header(http::headers::RETRY_AFTER, retry_after_seconds);
|
||||||
|
|
||||||
|
|
|
@ -1491,6 +1491,7 @@ class TestConflictFrontend : public BaseTestFrontend
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
using Values = kv::Map<size_t, size_t>;
|
using Values = kv::Map<size_t, size_t>;
|
||||||
|
size_t execution_count = 0;
|
||||||
|
|
||||||
TestConflictFrontend(kv::Store& tables) : BaseTestFrontend(tables)
|
TestConflictFrontend(kv::Store& tables) : BaseTestFrontend(tables)
|
||||||
{
|
{
|
||||||
|
@ -1502,8 +1503,6 @@ public:
|
||||||
.value()); // This header only exists in the context of
|
.value()); // This header only exists in the context of
|
||||||
// this test
|
// this test
|
||||||
|
|
||||||
static size_t execution_count = 0;
|
|
||||||
|
|
||||||
auto conflict_map = ctx.tx.template rw<Values>("test_values_conflict");
|
auto conflict_map = ctx.tx.template rw<Values>("test_values_conflict");
|
||||||
conflict_map->get(0); // Record a read dependency
|
conflict_map->get(0); // Record a read dependency
|
||||||
|
|
||||||
|
@ -1547,6 +1546,7 @@ TEST_CASE("Retry on conflict")
|
||||||
|
|
||||||
INFO("Does not reach execution limit");
|
INFO("Does not reach execution limit");
|
||||||
{
|
{
|
||||||
|
frontend.execution_count = 0;
|
||||||
size_t retry_count = ccf_max_attempts - 1;
|
size_t retry_count = ccf_max_attempts - 1;
|
||||||
req.set_header("test-retry-count", fmt::format("{}", retry_count));
|
req.set_header("test-retry-count", fmt::format("{}", retry_count));
|
||||||
auto serialized_call = req.build_request();
|
auto serialized_call = req.build_request();
|
||||||
|
@ -1564,6 +1564,7 @@ TEST_CASE("Retry on conflict")
|
||||||
|
|
||||||
INFO("Reaches execution limit");
|
INFO("Reaches execution limit");
|
||||||
{
|
{
|
||||||
|
frontend.execution_count = 0;
|
||||||
size_t retry_count = ccf_max_attempts + 1;
|
size_t retry_count = ccf_max_attempts + 1;
|
||||||
req.set_header("test-retry-count", fmt::format("{}", retry_count));
|
req.set_header("test-retry-count", fmt::format("{}", retry_count));
|
||||||
auto serialized_call = req.build_request();
|
auto serialized_call = req.build_request();
|
||||||
|
@ -1573,10 +1574,10 @@ TEST_CASE("Retry on conflict")
|
||||||
auto response = parse_response(rpc_ctx->serialise_response());
|
auto response = parse_response(rpc_ctx->serialise_response());
|
||||||
CHECK(response.status == HTTP_STATUS_SERVICE_UNAVAILABLE);
|
CHECK(response.status == HTTP_STATUS_SERVICE_UNAVAILABLE);
|
||||||
|
|
||||||
CHECK(response.headers["test-has-conflicted"] == "true");
|
// Response headers are cleared on error
|
||||||
CHECK(
|
CHECK(
|
||||||
response.headers["test-execution-count"] ==
|
response.headers.find("test-has-conflicted") == response.headers.end());
|
||||||
fmt::format("{}", ccf_max_attempts));
|
CHECK(frontend.execution_count == ccf_max_attempts);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Загрузка…
Ссылка в новой задаче