ClickHouse/src/Server/InterserverIOHTTPHandler.cpp

157 lines
4.7 KiB
C++
Raw Normal View History

#include <Server/InterserverIOHTTPHandler.h>
#include <Server/IServer.h>
2018-12-28 18:15:26 +00:00
#include <Compression/CompressedWriteBuffer.h>
#include <IO/ReadBufferFromIStream.h>
#include <Interpreters/Context.h>
#include <Interpreters/InterserverIOHandler.h>
#include <Server/HTTP/HTMLForm.h>
#include <Server/HTTP/WriteBufferFromHTTPServerResponse.h>
#include <Common/setThreadName.h>
2021-10-02 07:13:14 +00:00
#include <base/logger_useful.h>
#include <Poco/Net/HTTPBasicCredentials.h>
#include <Poco/Util/LayeredConfiguration.h>
2014-03-21 13:42:14 +00:00
namespace DB
{
2016-01-12 02:21:15 +00:00
namespace ErrorCodes
{
extern const int ABORTED;
2018-03-09 23:23:15 +00:00
extern const int TOO_MANY_SIMULTANEOUS_QUERIES;
2016-01-12 02:21:15 +00:00
}
std::pair<String, bool> InterserverIOHTTPHandler::checkAuthentication(HTTPServerRequest & request) const
2014-03-21 13:42:14 +00:00
{
auto server_credentials = server.context()->getInterserverCredentials();
2021-04-06 13:56:14 +00:00
if (server_credentials)
{
if (!request.hasCredentials())
2021-04-07 13:59:18 +00:00
return server_credentials->isValidUser("", "");
2021-04-06 13:56:14 +00:00
String scheme, info;
request.getCredentials(scheme, info);
2021-04-06 13:56:14 +00:00
if (scheme != "Basic")
return {"Server requires HTTP Basic authentication but client provides another method", false};
2021-04-06 13:56:14 +00:00
Poco::Net::HTTPBasicCredentials credentials(info);
2021-04-07 13:59:18 +00:00
return server_credentials->isValidUser(credentials.getUsername(), credentials.getPassword());
2021-04-06 13:56:14 +00:00
}
else if (request.hasCredentials())
{
return {"Client requires HTTP Basic authentication, but server doesn't provide it", false};
}
return {"", true};
}
void InterserverIOHTTPHandler::processQuery(HTTPServerRequest & request, HTTPServerResponse & response, Output & used_output)
{
2021-06-16 14:33:14 +00:00
HTMLForm params(server.context()->getSettingsRef(), request);
2020-05-23 22:24:01 +00:00
LOG_TRACE(log, "Request URI: {}", request.getURI());
String endpoint_name = params.get("endpoint");
bool compress = params.get("compress") == "true";
2014-03-21 13:42:14 +00:00
auto & body = request.getStream();
2016-03-01 17:47:53 +00:00
auto endpoint = server.context()->getInterserverIOHandler().getEndpoint(endpoint_name);
2020-01-14 14:27:48 +00:00
/// Locked for read while query processing
std::shared_lock lock(endpoint->rwlock);
if (endpoint->blocker.isCancelled())
throw Exception("Transferring part to replica was cancelled", ErrorCodes::ABORTED);
2014-03-21 13:42:14 +00:00
if (compress)
{
2020-03-09 03:38:43 +00:00
CompressedWriteBuffer compressed_out(*used_output.out);
endpoint->processQuery(params, body, compressed_out, response);
}
else
{
2020-03-09 03:38:43 +00:00
endpoint->processQuery(params, body, *used_output.out, response);
}
2014-03-21 13:42:14 +00:00
}
void InterserverIOHTTPHandler::handleRequest(HTTPServerRequest & request, HTTPServerResponse & response)
2014-03-21 13:42:14 +00:00
{
2018-08-31 00:59:48 +00:00
setThreadName("IntersrvHandler");
/// In order to work keep-alive.
if (request.getVersion() == 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<WriteBufferFromHTTPServerResponse>(
response, request.getMethod() == Poco::Net::HTTPRequest::HTTP_HEAD, keep_alive_timeout);
auto write_response = [&](const std::string & message)
{
if (response.sent())
return;
auto & out = *used_output.out;
try
{
writeString(message, out);
out.finalize();
}
catch (...)
{
tryLogCurrentException(log);
out.finalize();
}
};
try
{
2021-04-06 13:42:38 +00:00
if (auto [message, success] = checkAuthentication(request); success)
{
processQuery(request, response, used_output);
Fix uncaught exception in InterserverIOHTTPHandler There was one more uncaught exception case [1]: 2021.03.19 18:11:00.845632 [ 17469 ] {} <Debug> InterserverIOHTTPHandler: Done processing query ... 2021.03.19 18:11:31.698961 [ 80145 ] {} <Fatal> BaseDaemon: ######################################## 2021.03.19 18:11:31.699903 [ 80145 ] {} <Fatal> BaseDaemon: (version 21.4.1.6293 (official build), build id: 859E400E1C65C4702FE491420741DD8B58190002) (from thread 17469) (no query) Received signal Aborted (6) 2021.03.19 18:11:32.614075 [ 80145 ] {} <Fatal> BaseDaemon: 8. ./obj-x86_64-linux-gnu/../contrib/libcxxabi/src/cxa_handlers.cpp:89: std::terminate() @ 0x21e9b3a2 in /usr/bin/clickhouse 2021.03.19 18:11:43.831215 [ 80145 ] {} <Fatal> BaseDaemon: 10. ./obj-x86_64-linux-gnu/../src/Server/HTTP/WriteBufferFromHTTPServerResponse.cpp:201: ? @ 0x1be77038 in /usr/bin/clickhouse 2021.03.19 18:11:44.743193 [ 80145 ] {} <Fatal> BaseDaemon: 11. ./obj-x86_64-linux-gnu/../contrib/libcxx/include/memory:892: std::__1::allocator<DB::WriteBufferFromHTTPServerResponse>::destroy(DB::WriteBufferFromHTTPServerResponse*) @ 0x1bddd7c9 in /usr/bin/clickhouse 2021.03.19 18:11:45.283905 [ 80145 ] {} <Fatal> BaseDaemon: 12. ./obj-x86_64-linux-gnu/../contrib/libcxx/include/__memory/allocator_traits.h:541: void std::__1::allocator_traits<std::__1::allocator<DB::WriteBufferFromHTTPServerResponse> >::__destroy<DB::WriteBufferFromHTTPServerResponse>(std::__1::integral_constant<bool, true>, std::__1::allocator<DB::WriteBufferFromHTTPServerResponse>&, DB::WriteBufferFromHTTPServerResponse*) @ 0x1bddd79d in /usr/bin/clickhouse 2021.03.19 18:11:45.805233 [ 80145 ] {} <Fatal> BaseDaemon: 13. ./obj-x86_64-linux-gnu/../contrib/libcxx/include/__memory/allocator_traits.h:487: void std::__1::allocator_traits<std::__1::allocator<DB::WriteBufferFromHTTPServerResponse> >::destroy<DB::WriteBufferFromHTTPServerResponse>(std::__1::allocator<DB::WriteBufferFromHTTPServerResponse>&, DB::WriteBufferFromHTTPServerResponse*) @ 0x1bddd76d in /usr/bin/clickhouse 2021.03.19 18:11:46.351371 [ 80145 ] {} <Fatal> BaseDaemon: 14. ./obj-x86_64-linux-gnu/../contrib/libcxx/include/memory:2611: std::__1::__shared_ptr_emplace<DB::WriteBufferFromHTTPServerResponse, std::__1::allocator<DB::WriteBufferFromHTTPServerResponse> >::__on_zero_shared() @ 0x1bddd525 in /usr/bin/clickhouse 2021.03.19 18:11:46.579263 [ 80145 ] {} <Fatal> BaseDaemon: 15. ./obj-x86_64-linux-gnu/../contrib/libcxx/include/memory:2476: std::__1::__shared_count::__release_shared() @ 0x119490ed in /usr/bin/clickhouse 2021.03.19 18:11:46.790912 [ 80145 ] {} <Fatal> BaseDaemon: 16. ./obj-x86_64-linux-gnu/../contrib/libcxx/include/memory:2517: std::__1::__shared_weak_count::__release_shared() @ 0x1194908f in /usr/bin/clickhouse 2021.03.19 18:11:47.277990 [ 80145 ] {} <Fatal> BaseDaemon: 17. ./obj-x86_64-linux-gnu/../contrib/libcxx/include/memory:3213: std::__1::shared_ptr<DB::WriteBufferFromHTTPServerResponse>::~shared_ptr() @ 0x1bdd75fc in /usr/bin/clickhouse 2021.03.19 18:11:47.649213 [ 80145 ] {} <Fatal> BaseDaemon: 18. ./obj-x86_64-linux-gnu/../src/Server/InterserverIOHTTPHandler.h:34: DB::InterserverIOHTTPHandler::Output::~Output() @ 0x1bdf6bd5 in /usr/bin/clickhouse 2021.03.19 18:11:47.921556 [ 80145 ] {} <Fatal> BaseDaemon: 19. ./obj-x86_64-linux-gnu/../src/Server/InterserverIOHTTPHandler.cpp:154: DB::InterserverIOHTTPHandler::handleRequest(DB::HTTPServerRequest&, DB::HTTPServerResponse&) @ 0x1bdf653f in /usr/bin/clickhouse [1]: https://clickhouse-test-reports.s3.yandex.net/0/78c56b891383288cf3a893139e796fc87476412e/stress_test_(debug).html Since in case of no errors during processing we should call finalize, to ensure that it will not be called from dtor. Fixes: #22046 Fixes: #22067
2021-03-25 20:41:03 +00:00
used_output.out->finalize();
2020-10-10 17:47:34 +00:00
LOG_DEBUG(log, "Done processing query");
}
else
{
response.setStatusAndReason(HTTPServerResponse::HTTP_UNAUTHORIZED);
write_response(message);
2020-05-23 22:24:01 +00:00
LOG_WARNING(log, "Query processing failed request: '{}' authentication failed", request.getURI());
}
}
catch (Exception & e)
{
2018-03-09 23:23:15 +00:00
if (e.code() == ErrorCodes::TOO_MANY_SIMULTANEOUS_QUERIES)
return;
response.setStatusAndReason(Poco::Net::HTTPResponse::HTTP_INTERNAL_SERVER_ERROR);
/// Sending to remote server was cancelled due to server shutdown or drop table.
bool is_real_error = e.code() != ErrorCodes::ABORTED;
std::string message = getCurrentExceptionMessage(is_real_error);
write_response(message);
if (is_real_error)
2020-05-23 22:24:01 +00:00
LOG_ERROR(log, message);
else
2020-05-23 22:24:01 +00:00
LOG_INFO(log, message);
}
catch (...)
{
response.setStatusAndReason(Poco::Net::HTTPResponse::HTTP_INTERNAL_SERVER_ERROR);
std::string message = getCurrentExceptionMessage(false);
write_response(message);
2020-05-23 22:24:01 +00:00
LOG_ERROR(log, message);
}
2014-03-21 13:42:14 +00:00
}
}