diff --git a/dbms/programs/server/InterserverIOHTTPHandler.cpp b/dbms/programs/server/InterserverIOHTTPHandler.cpp index 94095365b6a..27e4c7041c4 100644 --- a/dbms/programs/server/InterserverIOHTTPHandler.cpp +++ b/dbms/programs/server/InterserverIOHTTPHandler.cpp @@ -1,17 +1,16 @@ +#include "InterserverIOHTTPHandler.h" + #include #include #include - #include - #include #include #include #include #include #include - -#include "InterserverIOHTTPHandler.h" +#include "IServer.h" namespace DB { @@ -50,7 +49,7 @@ std::pair InterserverIOHTTPHandler::checkAuthentication(Poco::Net: return {"", true}; } -void InterserverIOHTTPHandler::processQuery(Poco::Net::HTTPServerRequest & request, Poco::Net::HTTPServerResponse & response) +void InterserverIOHTTPHandler::processQuery(Poco::Net::HTTPServerRequest & request, Poco::Net::HTTPServerResponse & response, Output & used_output) { HTMLForm params(request); @@ -61,24 +60,17 @@ void InterserverIOHTTPHandler::processQuery(Poco::Net::HTTPServerRequest & reque ReadBufferFromIStream body(request.stream()); - const auto & config = server.config(); - unsigned keep_alive_timeout = config.getUInt("keep_alive_timeout", 10); - - WriteBufferFromHTTPServerResponse out(request, response, keep_alive_timeout); - auto endpoint = server.context().getInterserverIOHandler().getEndpoint(endpoint_name); if (compress) { - CompressedWriteBuffer compressed_out(out); + CompressedWriteBuffer compressed_out(*used_output.out.get()); endpoint->processQuery(params, body, compressed_out, response); } else { - endpoint->processQuery(params, body, out, response); + endpoint->processQuery(params, body, *used_output.out.get(), response); } - - out.finalize(); } @@ -90,30 +82,30 @@ void InterserverIOHTTPHandler::handleRequest(Poco::Net::HTTPServerRequest & requ if (request.getVersion() == Poco::Net::HTTPServerRequest::HTTP_1_1) response.setChunkedTransferEncoding(true); + Output used_output; + const auto & config = server.config(); + unsigned keep_alive_timeout = config.getUInt("keep_alive_timeout", 10); + used_output.out = std::make_shared(request, response, keep_alive_timeout); + try { - if (auto [msg, success] = checkAuthentication(request); success) + if (auto [message, success] = checkAuthentication(request); success) { - processQuery(request, response); + processQuery(request, response, used_output); LOG_INFO(log, "Done processing query"); } else { response.setStatusAndReason(Poco::Net::HTTPServerResponse::HTTP_UNAUTHORIZED); if (!response.sent()) - response.send() << msg << std::endl; + writeString(message, *used_output.out); LOG_WARNING(log, "Query processing failed request: '" << request.getURI() << "' authentification failed"); } } catch (Exception & e) { - if (e.code() == ErrorCodes::TOO_MANY_SIMULTANEOUS_QUERIES) - { - if (!response.sent()) - response.send(); return; - } response.setStatusAndReason(Poco::Net::HTTPResponse::HTTP_INTERNAL_SERVER_ERROR); @@ -122,7 +114,7 @@ void InterserverIOHTTPHandler::handleRequest(Poco::Net::HTTPServerRequest & requ std::string message = getCurrentExceptionMessage(is_real_error); if (!response.sent()) - response.send() << message << std::endl; + writeString(message, *used_output.out); if (is_real_error) LOG_ERROR(log, message); @@ -134,7 +126,8 @@ void InterserverIOHTTPHandler::handleRequest(Poco::Net::HTTPServerRequest & requ response.setStatusAndReason(Poco::Net::HTTPResponse::HTTP_INTERNAL_SERVER_ERROR); std::string message = getCurrentExceptionMessage(false); if (!response.sent()) - response.send() << message << std::endl; + writeString(message, *used_output.out); + LOG_ERROR(log, message); } } diff --git a/dbms/programs/server/InterserverIOHTTPHandler.h b/dbms/programs/server/InterserverIOHTTPHandler.h index fbaf432d4f9..8dc1962664c 100644 --- a/dbms/programs/server/InterserverIOHTTPHandler.h +++ b/dbms/programs/server/InterserverIOHTTPHandler.h @@ -1,12 +1,10 @@ #pragma once +#include #include #include - #include -#include "IServer.h" - namespace CurrentMetrics { @@ -16,6 +14,9 @@ namespace CurrentMetrics namespace DB { +class IServer; +class WriteBufferFromHTTPServerResponse; + class InterserverIOHTTPHandler : public Poco::Net::HTTPRequestHandler { public: @@ -28,12 +29,17 @@ public: void handleRequest(Poco::Net::HTTPServerRequest & request, Poco::Net::HTTPServerResponse & response) override; private: + struct Output + { + std::shared_ptr out; + }; + IServer & server; Poco::Logger * log; CurrentMetrics::Increment metric_increment{CurrentMetrics::InterserverConnection}; - void processQuery(Poco::Net::HTTPServerRequest & request, Poco::Net::HTTPServerResponse & response); + void processQuery(Poco::Net::HTTPServerRequest & request, Poco::Net::HTTPServerResponse & response, Output & used_output); std::pair checkAuthentication(Poco::Net::HTTPServerRequest & request) const; }; diff --git a/dbms/tests/queries/0_stateless/00942_dataparts_500.reference b/dbms/tests/queries/0_stateless/00942_dataparts_500.reference new file mode 100644 index 00000000000..e6a7bd76965 --- /dev/null +++ b/dbms/tests/queries/0_stateless/00942_dataparts_500.reference @@ -0,0 +1 @@ +< HTTP/1.1 500 Internal Server Error diff --git a/dbms/tests/queries/0_stateless/00942_dataparts_500.sh b/dbms/tests/queries/0_stateless/00942_dataparts_500.sh new file mode 100755 index 00000000000..cccd1b8695d --- /dev/null +++ b/dbms/tests/queries/0_stateless/00942_dataparts_500.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash + +# Test fix for issue #5066 + +CURDIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd) +. $CURDIR/../shell_config.sh + +${CLICKHOUSE_CURL} -vvv "${CLICKHOUSE_URL_INTERSERVER}?endpoint=DataPartsExchange%3A%2Fclickhouse%2Ftables%2F01-01%2Fvisits%2Freplicas%2Fsome.server.com&part=0&compress=false" 2>&1 | grep -F "< HTTP/1.1 500 Internal Server Error" diff --git a/dbms/tests/queries/shell_config.sh b/dbms/tests/queries/shell_config.sh index af222fc9531..7126a99b348 100644 --- a/dbms/tests/queries/shell_config.sh +++ b/dbms/tests/queries/shell_config.sh @@ -41,6 +41,10 @@ export CLICKHOUSE_PORT_HTTP_PROTO=${CLICKHOUSE_PORT_HTTP_PROTO:="http"} export CLICKHOUSE_URL=${CLICKHOUSE_URL:="${CLICKHOUSE_PORT_HTTP_PROTO}://${CLICKHOUSE_HOST}:${CLICKHOUSE_PORT_HTTP}/"} export CLICKHOUSE_URL_HTTPS=${CLICKHOUSE_URL_HTTPS:="https://${CLICKHOUSE_HOST}:${CLICKHOUSE_PORT_HTTPS}/"} export CLICKHOUSE_URL_PARAMS=${CLICKHOUSE_URL_PARAMS:="${CLICKHOUSE_URL}?database=${CLICKHOUSE_DATABASE}"} +export CLICKHOUSE_PORT_INTERSERVER=${CLICKHOUSE_PORT_INTERSERVER:=`${CLICKHOUSE_EXTRACT_CONFIG} --try --key=interserver_http_port 2>/dev/null`} 2>/dev/null +export CLICKHOUSE_PORT_INTERSERVER=${CLICKHOUSE_PORT_INTERSERVER:="9009"} +export CLICKHOUSE_URL_INTERSERVER=${CLICKHOUSE_URL_INTERSERVER:="${CLICKHOUSE_PORT_HTTP_PROTO}://${CLICKHOUSE_HOST}:${CLICKHOUSE_PORT_INTERSERVER}/"} + export CLICKHOUSE_CURL_COMMAND=${CLICKHOUSE_CURL_COMMAND:="curl"} export CLICKHOUSE_CURL=${CLICKHOUSE_CURL:="${CLICKHOUSE_CURL_COMMAND} --max-time 10"} export CLICKHOUSE_TMP=${CLICKHOUSE_TMP:="."}