mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-11-26 09:32:01 +00:00
Move function HTTPHandler::formatExceptionForClient() to a separate header in order to reuse it.
This commit is contained in:
parent
49b982747a
commit
ecfe6fddcf
80
src/Server/HTTP/sendExceptionToHTTPClient.cpp
Normal file
80
src/Server/HTTP/sendExceptionToHTTPClient.cpp
Normal file
@ -0,0 +1,80 @@
|
||||
#include <Server/HTTP/sendExceptionToHTTPClient.h>
|
||||
|
||||
#include <Server/HTTP/HTTPServerRequest.h>
|
||||
#include <Server/HTTP/WriteBufferFromHTTPServerResponse.h>
|
||||
#include <Server/HTTP/exceptionCodeToHTTPStatus.h>
|
||||
|
||||
|
||||
namespace DB
|
||||
{
|
||||
|
||||
namespace ErrorCodes
|
||||
{
|
||||
extern const int HTTP_LENGTH_REQUIRED;
|
||||
extern const int REQUIRED_PASSWORD;
|
||||
}
|
||||
|
||||
|
||||
void sendExceptionToHTTPClient(
|
||||
const String & exception_message,
|
||||
int exception_code,
|
||||
HTTPServerRequest & request,
|
||||
HTTPServerResponse & response,
|
||||
WriteBufferFromHTTPServerResponse * out,
|
||||
LoggerPtr log)
|
||||
{
|
||||
setHTTPResponseStatusAndHeadersForException(exception_code, request, response, out, log);
|
||||
|
||||
if (!out)
|
||||
{
|
||||
/// If nothing was sent yet.
|
||||
WriteBufferFromHTTPServerResponse out_for_message{response, request.getMethod() == HTTPRequest::HTTP_HEAD, DEFAULT_HTTP_KEEP_ALIVE_TIMEOUT};
|
||||
|
||||
out_for_message.writeln(exception_message);
|
||||
out_for_message.finalize();
|
||||
}
|
||||
else
|
||||
{
|
||||
/// If buffer has data, and that data wasn't sent yet, then no need to send that data
|
||||
bool data_sent = (out->count() != out->offset());
|
||||
|
||||
if (!data_sent)
|
||||
out->position() = out->buffer().begin();
|
||||
|
||||
out->writeln(exception_message);
|
||||
out->finalize();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void setHTTPResponseStatusAndHeadersForException(
|
||||
int exception_code, HTTPServerRequest & request, HTTPServerResponse & response, WriteBufferFromHTTPServerResponse * out, LoggerPtr log)
|
||||
{
|
||||
if (out)
|
||||
out->setExceptionCode(exception_code);
|
||||
else
|
||||
response.set("X-ClickHouse-Exception-Code", toString<int>(exception_code));
|
||||
|
||||
/// If HTTP method is POST and Keep-Alive is turned on, we should try to read the whole request body
|
||||
/// to avoid reading part of the current request body in the next request.
|
||||
if (request.getMethod() == Poco::Net::HTTPRequest::HTTP_POST && response.getKeepAlive()
|
||||
&& exception_code != ErrorCodes::HTTP_LENGTH_REQUIRED)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!request.getStream().eof())
|
||||
request.getStream().ignoreAll();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
tryLogCurrentException(log, "Cannot read remaining request body during exception handling");
|
||||
response.setKeepAlive(false);
|
||||
}
|
||||
}
|
||||
|
||||
if (exception_code == ErrorCodes::REQUIRED_PASSWORD)
|
||||
response.requireAuthentication("ClickHouse server HTTP API");
|
||||
else
|
||||
response.setStatusAndReason(exceptionCodeToHTTPStatus(exception_code));
|
||||
}
|
||||
}
|
27
src/Server/HTTP/sendExceptionToHTTPClient.h
Normal file
27
src/Server/HTTP/sendExceptionToHTTPClient.h
Normal file
@ -0,0 +1,27 @@
|
||||
#pragma once
|
||||
|
||||
#include <Common/logger_useful.h>
|
||||
#include <base/types.h>
|
||||
|
||||
|
||||
namespace DB
|
||||
{
|
||||
class HTTPServerRequest;
|
||||
class HTTPServerResponse;
|
||||
class WriteBufferFromHTTPServerResponse;
|
||||
|
||||
/// Sends an exception to HTTP client. This function doesn't handle its own exceptions so it needs to be wrapped in try-catch.
|
||||
/// Argument `out` may be either created from `response` or be nullptr (if it wasn't created before the exception).
|
||||
void sendExceptionToHTTPClient(
|
||||
const String & exception_message,
|
||||
int exception_code,
|
||||
HTTPServerRequest & request,
|
||||
HTTPServerResponse & response,
|
||||
WriteBufferFromHTTPServerResponse * out,
|
||||
LoggerPtr log);
|
||||
|
||||
/// Sets "X-ClickHouse-Exception-Code" header and the correspondent HTTP status in the response for an exception.
|
||||
/// This is a part of what sendExceptionToHTTPClient() does.
|
||||
void setHTTPResponseStatusAndHeadersForException(
|
||||
int exception_code, HTTPServerRequest & request, HTTPServerResponse & response, WriteBufferFromHTTPServerResponse * out, LoggerPtr log);
|
||||
}
|
@ -33,7 +33,7 @@
|
||||
#include <base/scope_guard.h>
|
||||
#include <Server/HTTP/HTTPResponse.h>
|
||||
#include <Server/HTTP/authenticateUserByHTTP.h>
|
||||
#include <Server/HTTP/exceptionCodeToHTTPStatus.h>
|
||||
#include <Server/HTTP/sendExceptionToHTTPClient.h>
|
||||
#include <Server/HTTP/setReadOnlyIfHTTPMethodIdempotent.h>
|
||||
#include <boost/container/flat_set.hpp>
|
||||
|
||||
@ -60,8 +60,6 @@ namespace ErrorCodes
|
||||
|
||||
extern const int NO_ELEMENTS_IN_CONFIG;
|
||||
|
||||
extern const int REQUIRED_PASSWORD;
|
||||
|
||||
extern const int INVALID_SESSION_TIMEOUT;
|
||||
extern const int HTTP_LENGTH_REQUIRED;
|
||||
}
|
||||
@ -519,7 +517,7 @@ void HTTPHandler::processQuery(
|
||||
{
|
||||
bool with_stacktrace = (params.getParsed<bool>("stacktrace", false) && server.config().getBool("enable_http_stacktrace", true));
|
||||
ExecutionStatus status = ExecutionStatus::fromCurrentException("", with_stacktrace);
|
||||
formatExceptionForClient(status.code, request, response, used_output);
|
||||
setHTTPResponseStatusAndHeadersForException(status.code, request, response, used_output.out_holder.get(), log);
|
||||
current_output_format.setException(status.message);
|
||||
current_output_format.finalize();
|
||||
used_output.exception_is_written = true;
|
||||
@ -553,7 +551,7 @@ void HTTPHandler::trySendExceptionToClient(
|
||||
const std::string & s, int exception_code, HTTPServerRequest & request, HTTPServerResponse & response, Output & used_output)
|
||||
try
|
||||
{
|
||||
formatExceptionForClient(exception_code, request, response, used_output);
|
||||
setHTTPResponseStatusAndHeadersForException(exception_code, request, response, used_output.out_holder.get(), log);
|
||||
|
||||
if (!used_output.out_holder && !used_output.exception_is_written)
|
||||
{
|
||||
@ -615,38 +613,6 @@ catch (...)
|
||||
used_output.cancel();
|
||||
}
|
||||
|
||||
void HTTPHandler::formatExceptionForClient(int exception_code, HTTPServerRequest & request, HTTPServerResponse & response, Output & used_output)
|
||||
{
|
||||
if (used_output.out_holder)
|
||||
used_output.out_holder->setExceptionCode(exception_code);
|
||||
else
|
||||
response.set("X-ClickHouse-Exception-Code", toString<int>(exception_code));
|
||||
|
||||
/// FIXME: make sure that no one else is reading from the same stream at the moment.
|
||||
|
||||
/// If HTTP method is POST and Keep-Alive is turned on, we should try to read the whole request body
|
||||
/// to avoid reading part of the current request body in the next request.
|
||||
if (request.getMethod() == Poco::Net::HTTPRequest::HTTP_POST && response.getKeepAlive()
|
||||
&& exception_code != ErrorCodes::HTTP_LENGTH_REQUIRED)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!request.getStream().eof())
|
||||
request.getStream().ignoreAll();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
tryLogCurrentException(log, "Cannot read remaining request body during exception handling");
|
||||
response.setKeepAlive(false);
|
||||
}
|
||||
}
|
||||
|
||||
if (exception_code == ErrorCodes::REQUIRED_PASSWORD)
|
||||
response.requireAuthentication("ClickHouse server HTTP API");
|
||||
else
|
||||
response.setStatusAndReason(exceptionCodeToHTTPStatus(exception_code));
|
||||
}
|
||||
|
||||
void HTTPHandler::handleRequest(HTTPServerRequest & request, HTTPServerResponse & response, const ProfileEvents::Event & write_event)
|
||||
{
|
||||
setThreadName("HTTPHandler");
|
||||
|
@ -173,12 +173,6 @@ private:
|
||||
HTTPServerResponse & response,
|
||||
Output & used_output);
|
||||
|
||||
void formatExceptionForClient(
|
||||
int exception_code,
|
||||
HTTPServerRequest & request,
|
||||
HTTPServerResponse & response,
|
||||
Output & used_output);
|
||||
|
||||
static void pushDelayedResults(Output & used_output);
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user