Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix http exception codes. #60252

Merged
merged 2 commits into from Feb 22, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
51 changes: 26 additions & 25 deletions src/Server/HTTPHandler.cpp
Expand Up @@ -884,6 +884,9 @@ void HTTPHandler::processQuery(
{
if (settings.http_write_exception_in_output_format && output_format.supportsWritingException())
{
ExecutionStatus status = ExecutionStatus::fromCurrentException("", false);
devcrafter marked this conversation as resolved.
Show resolved Hide resolved
formatExceptionForClient(status.code, request, response, used_output);

output_format.setException(getCurrentExceptionMessage(false));
output_format.finalize();
used_output.exception_is_written = true;
Expand Down Expand Up @@ -916,31 +919,7 @@ void HTTPHandler::trySendExceptionToClient(
const std::string & s, int exception_code, HTTPServerRequest & request, HTTPServerResponse & response, Output & used_output)
try
{
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 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
&& !request.getStream().eof())
{
request.getStream().ignoreAll();
}

if (exception_code == ErrorCodes::REQUIRED_PASSWORD)
{
response.requireAuthentication("ClickHouse server HTTP API");
}
else
{
response.setStatusAndReason(exceptionCodeToHTTPStatus(exception_code));
}
formatExceptionForClient(exception_code, request, response, used_output);

if (!used_output.out_holder && !used_output.exception_is_written)
{
Expand Down Expand Up @@ -1001,6 +980,28 @@ catch (...)
}
}

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 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 && !request.getStream().eof())
{
request.getStream().ignoreAll();
}

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)
{
Expand Down
6 changes: 6 additions & 0 deletions src/Server/HTTPHandler.h
Expand Up @@ -148,6 +148,12 @@ class HTTPHandler : public HTTPRequestHandler
HTTPServerResponse & response,
Output & used_output);

void formatExceptionForClient(
int exception_code,
HTTPServerRequest & request,
HTTPServerResponse & response,
Output & used_output);

static void pushDelayedResults(Output & used_output);
};

Expand Down
@@ -1,25 +1,47 @@
SELECT missing column WITH default_format=JSON
404NotFound
Content-Type:application/json;charset=UTF-8
X-ClickHouse-Ex---tion-Code:47
"exception":"Code:47.

INSERT WITH default_format=JSON
Content-Type:application/json;charset=UTF-8
"exception":"Code:62.
501NotImplemented
Content-Type:application/json;charset=UTF-8
X-ClickHouse-Ex---tion-Code:48
"exception":"Code:48.

INSERT WITH default_format=XML
Content-Type:application/xml;charset=UTF-8
<exception>Code:62.DB::Ex---tion:
501NotImplemented
Content-Type:application/xml;charset=UTF-8
X-ClickHouse-Ex---tion-Code:48
<exception>Code:48.DB::Ex---tion:

INSERT WITH default_format=BADFORMAT
Content-Type:text/plain;charset=UTF-8
X-ClickHouse-Ex---tion-Code:62
Code:62.DB::Ex---tion:
501NotImplemented
Content-Type:text/plain;charset=UTF-8
X-ClickHouse-Ex---tion-Code:48
Code:48.DB::Ex---tion:

SELECT missing column WITH X-ClickHouse-Format: JSON
404NotFound
Content-Type:application/json;charset=UTF-8
X-ClickHouse-Ex---tion-Code:47
"exception":"Code:47.

INSERT WITH X-ClickHouse-Format: JSON
Content-Type:application/json;charset=UTF-8
"exception":"Code:62.
501NotImplemented
Content-Type:application/json;charset=UTF-8
X-ClickHouse-Ex---tion-Code:48
"exception":"Code:48.

INSERT WITH X-ClickHouse-Format: XML
Content-Type:application/xml;charset=UTF-8
<exception>Code:62.DB::Ex---tion:
501NotImplemented
Content-Type:application/xml;charset=UTF-8
X-ClickHouse-Ex---tion-Code:48
<exception>Code:48.DB::Ex---tion:

INSERT WITH X-ClickHouse-Format: BADFORMAT
Content-Type:text/plain;charset=UTF-8
X-ClickHouse-Ex---tion-Code:62
Code:62.DB::Ex---tion:
501NotImplemented
Content-Type:text/plain;charset=UTF-8
X-ClickHouse-Ex---tion-Code:48
Code:48.DB::Ex---tion:
Expand Up @@ -6,28 +6,44 @@ CUR_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)

CH_URL="$CLICKHOUSE_URL&http_write_exception_in_output_format=1"

echo "SELECT missing column WITH default_format=JSON"
echo "SELECT x FROM system.numbers LIMIT 1;"\
| ${CLICKHOUSE_CURL} -sS "${CH_URL}&default_format=JSON" -i --data-binary @- \
| grep 'HTTP/1.1\|xception\|Content-Type' | sed 's/Exception/Ex---tion/;s/HTTP\/1.1//;s/\r//' | awk '{ print $1 $2 $3 }'
echo ""
echo "INSERT WITH default_format=JSON"
echo "INSERT INTO system.numbers Select * from numbers(10);" \
| ${CLICKHOUSE_CURL} -sS "${CH_URL}&default_format=JSON" -i | grep 'xception\|Content-Type' | sed 's/Exception/Ex---tion/' | awk '{ print $1 $2 $3 }'
| ${CLICKHOUSE_CURL} -sS "${CH_URL}&default_format=JSON" -i --data-binary @- \
| grep 'HTTP/1.1\|xception\|Content-Type' | sed 's/Exception/Ex---tion/;s/HTTP\/1.1//;s/\r//' | awk '{ print $1 $2 $3 }'
echo ""
echo "INSERT WITH default_format=XML"
echo "INSERT INTO system.numbers Select * from numbers(10);" \
| ${CLICKHOUSE_CURL} -sS "${CH_URL}&default_format=XML" -i | grep 'xception\|Content-Type' | sed 's/Exception/Ex---tion/' | awk '{ print $1 $2 $3 }'
| ${CLICKHOUSE_CURL} -sS "${CH_URL}&default_format=XML" -i --data-binary @- \
| grep 'HTTP/1.1\|xception\|Content-Type' | sed 's/Exception/Ex---tion/;s/HTTP\/1.1//;s/\r//' | awk '{ print $1 $2 $3 }'
echo ""
echo "INSERT WITH default_format=BADFORMAT"
echo "INSERT INTO system.numbers Select * from numbers(10);" \
| ${CLICKHOUSE_CURL} -sS "${CH_URL}&default_format=BADFORMAT" -i | grep 'xception\|Content-Type' | sed 's/Exception/Ex---tion/' | awk '{ print $1 $2 $3 }'
| ${CLICKHOUSE_CURL} -sS "${CH_URL}&default_format=BADFORMAT" -i --data-binary @- \
| grep 'HTTP/1.1\|xception\|Content-Type' | sed 's/Exception/Ex---tion/;s/HTTP\/1.1//;s/\r//' | awk '{ print $1 $2 $3 }'


echo ""
echo "SELECT missing column WITH X-ClickHouse-Format: JSON"
echo "SELECT x FROM system.numbers LIMIT 1;"\
| ${CLICKHOUSE_CURL} -sS "${CH_URL}" -H 'X-ClickHouse-Format: JSON' -i --data-binary @- \
| grep 'HTTP/1.1\|xception\|Content-Type' | sed 's/Exception/Ex---tion/;s/HTTP\/1.1//;s/\r//' | awk '{ print $1 $2 $3 }'
echo ""
echo "INSERT WITH X-ClickHouse-Format: JSON"
echo "INSERT INTO system.numbers Select * from numbers(10);" \
| ${CLICKHOUSE_CURL} -sS "${CH_URL}" -H 'X-ClickHouse-Format: JSON' -i | grep 'xception\|Content-Type' | sed 's/Exception/Ex---tion/' | awk '{ print $1 $2 $3 }'
| ${CLICKHOUSE_CURL} -sS "${CH_URL}" -H 'X-ClickHouse-Format: JSON' -i --data-binary @- \
| grep 'HTTP/1.1\|xception\|Content-Type' | sed 's/Exception/Ex---tion/;s/HTTP\/1.1//;s/\r//' | awk '{ print $1 $2 $3 }'
echo ""
echo "INSERT WITH X-ClickHouse-Format: XML"
echo "INSERT INTO system.numbers Select * from numbers(10);" \
| ${CLICKHOUSE_CURL} -sS "${CH_URL}" -H 'X-ClickHouse-Format: XML' -i | grep 'xception\|Content-Type' | sed 's/Exception/Ex---tion/' | awk '{ print $1 $2 $3 }'
| ${CLICKHOUSE_CURL} -sS "${CH_URL}" -H 'X-ClickHouse-Format: XML' -i --data-binary @- \
| grep 'HTTP/1.1\|xception\|Content-Type' | sed 's/Exception/Ex---tion/;s/HTTP\/1.1//;s/\r//' | awk '{ print $1 $2 $3 }'
echo ""
echo "INSERT WITH X-ClickHouse-Format: BADFORMAT"
echo "INSERT INTO system.numbers Select * from numbers(10);" \
| ${CLICKHOUSE_CURL} -sS "${CH_URL}" -H 'X-ClickHouse-Format: BADFORMAT' -i | grep 'xception\|Content-Type' | sed 's/Exception/Ex---tion/' | awk '{ print $1 $2 $3 }'
| ${CLICKHOUSE_CURL} -sS "${CH_URL}" -H 'X-ClickHouse-Format: BADFORMAT' -i --data-binary @- \
| grep 'HTTP/1.1\|xception\|Content-Type' | sed 's/Exception/Ex---tion/;s/HTTP\/1.1//;s/\r//' | awk '{ print $1 $2 $3 }'