2021-02-19 12:51:26 +00:00
|
|
|
#include <Server/InterserverIOHTTPHandler.h>
|
|
|
|
|
|
|
|
#include <Server/IServer.h>
|
2019-05-20 17:04:36 +00:00
|
|
|
|
2018-12-28 18:15:26 +00:00
|
|
|
#include <Compression/CompressedWriteBuffer.h>
|
2017-04-01 09:19:00 +00:00
|
|
|
#include <IO/ReadBufferFromIStream.h>
|
2020-12-10 22:05:02 +00:00
|
|
|
#include <Interpreters/Context.h>
|
2021-02-19 12:51:26 +00:00
|
|
|
#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>
|
2021-02-19 12:51:26 +00:00
|
|
|
|
|
|
|
#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
|
|
|
|
{
|
2017-04-01 07:20:54 +00:00
|
|
|
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
|
|
|
}
|
|
|
|
|
2021-02-19 12:51:26 +00:00
|
|
|
std::pair<String, bool> InterserverIOHTTPHandler::checkAuthentication(HTTPServerRequest & request) const
|
2014-03-21 13:42:14 +00:00
|
|
|
{
|
2021-04-10 23:33:54 +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("", "");
|
2018-07-26 15:10:57 +00:00
|
|
|
|
2021-04-06 13:56:14 +00:00
|
|
|
String scheme, info;
|
|
|
|
request.getCredentials(scheme, info);
|
2018-07-26 15:10:57 +00:00
|
|
|
|
2021-04-06 13:56:14 +00:00
|
|
|
if (scheme != "Basic")
|
|
|
|
return {"Server requires HTTP Basic authentication but client provides another method", false};
|
2018-07-26 15:10:57 +00:00
|
|
|
|
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};
|
2018-07-26 15:10:57 +00:00
|
|
|
}
|
|
|
|
|
2021-02-19 12:51:26 +00:00
|
|
|
void InterserverIOHTTPHandler::processQuery(HTTPServerRequest & request, HTTPServerResponse & response, Output & used_output)
|
2018-07-26 15:10:57 +00:00
|
|
|
{
|
2021-06-16 14:33:14 +00:00
|
|
|
HTMLForm params(server.context()->getSettingsRef(), request);
|
2018-07-26 15:10:57 +00:00
|
|
|
|
2020-05-23 22:24:01 +00:00
|
|
|
LOG_TRACE(log, "Request URI: {}", request.getURI());
|
2018-07-26 15:10:57 +00:00
|
|
|
|
2017-04-01 07:20:54 +00:00
|
|
|
String endpoint_name = params.get("endpoint");
|
|
|
|
bool compress = params.get("compress") == "true";
|
2014-03-21 13:42:14 +00:00
|
|
|
|
2021-02-19 12:51:26 +00:00
|
|
|
auto & body = request.getStream();
|
2016-03-01 17:47:53 +00:00
|
|
|
|
2021-04-10 23:33:54 +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
|
|
|
|
2017-04-01 07:20:54 +00:00
|
|
|
if (compress)
|
|
|
|
{
|
2020-03-09 03:38:43 +00:00
|
|
|
CompressedWriteBuffer compressed_out(*used_output.out);
|
2017-04-06 13:03:23 +00:00
|
|
|
endpoint->processQuery(params, body, compressed_out, response);
|
2017-04-01 07:20:54 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2020-03-09 03:38:43 +00:00
|
|
|
endpoint->processQuery(params, body, *used_output.out, response);
|
2017-04-01 07:20:54 +00:00
|
|
|
}
|
2014-03-21 13:42:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-02-19 12:51:26 +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");
|
|
|
|
|
2017-04-01 07:20:54 +00:00
|
|
|
/// In order to work keep-alive.
|
2021-02-19 12:51:26 +00:00
|
|
|
if (request.getVersion() == HTTPServerRequest::HTTP_1_1)
|
2017-04-01 07:20:54 +00:00
|
|
|
response.setChunkedTransferEncoding(true);
|
|
|
|
|
2019-05-20 17:04:36 +00:00
|
|
|
Output used_output;
|
|
|
|
const auto & config = server.config();
|
|
|
|
unsigned keep_alive_timeout = config.getUInt("keep_alive_timeout", 10);
|
2021-02-19 12:51:26 +00:00
|
|
|
used_output.out = std::make_shared<WriteBufferFromHTTPServerResponse>(
|
|
|
|
response, request.getMethod() == Poco::Net::HTTPRequest::HTTP_HEAD, keep_alive_timeout);
|
2019-05-20 17:04:36 +00:00
|
|
|
|
2021-02-20 05:28:47 +00:00
|
|
|
auto write_response = [&](const std::string & message)
|
|
|
|
{
|
|
|
|
if (response.sent())
|
|
|
|
return;
|
|
|
|
|
|
|
|
auto & out = *used_output.out;
|
|
|
|
try
|
|
|
|
{
|
|
|
|
writeString(message, out);
|
|
|
|
out.finalize();
|
|
|
|
}
|
|
|
|
catch (...)
|
|
|
|
{
|
2021-03-25 20:41:03 +00:00
|
|
|
tryLogCurrentException(log);
|
2021-02-20 05:28:47 +00:00
|
|
|
out.finalize();
|
|
|
|
}
|
|
|
|
};
|
2019-05-20 17:04:36 +00:00
|
|
|
|
2017-04-01 07:20:54 +00:00
|
|
|
try
|
|
|
|
{
|
2021-04-06 13:42:38 +00:00
|
|
|
if (auto [message, success] = checkAuthentication(request); success)
|
2018-07-26 15:10:57 +00:00
|
|
|
{
|
2019-05-20 17:04:36 +00:00
|
|
|
processQuery(request, response, used_output);
|
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");
|
2018-07-26 15:10:57 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2021-02-19 12:51:26 +00:00
|
|
|
response.setStatusAndReason(HTTPServerResponse::HTTP_UNAUTHORIZED);
|
2021-02-20 05:28:47 +00:00
|
|
|
write_response(message);
|
2020-05-23 22:24:01 +00:00
|
|
|
LOG_WARNING(log, "Query processing failed request: '{}' authentication failed", request.getURI());
|
2018-07-26 15:10:57 +00:00
|
|
|
}
|
2017-04-01 07:20:54 +00:00
|
|
|
}
|
|
|
|
catch (Exception & e)
|
|
|
|
{
|
2018-03-09 23:23:15 +00:00
|
|
|
if (e.code() == ErrorCodes::TOO_MANY_SIMULTANEOUS_QUERIES)
|
2017-04-06 13:03:23 +00:00
|
|
|
return;
|
|
|
|
|
2017-04-01 07:20:54 +00:00
|
|
|
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);
|
2021-02-20 05:28:47 +00:00
|
|
|
write_response(message);
|
2017-04-01 07:20:54 +00:00
|
|
|
|
|
|
|
if (is_real_error)
|
2020-05-23 22:24:01 +00:00
|
|
|
LOG_ERROR(log, message);
|
2017-04-01 07:20:54 +00:00
|
|
|
else
|
2020-05-23 22:24:01 +00:00
|
|
|
LOG_INFO(log, message);
|
2017-04-01 07:20:54 +00:00
|
|
|
}
|
|
|
|
catch (...)
|
|
|
|
{
|
|
|
|
response.setStatusAndReason(Poco::Net::HTTPResponse::HTTP_INTERNAL_SERVER_ERROR);
|
|
|
|
std::string message = getCurrentExceptionMessage(false);
|
2021-02-20 05:28:47 +00:00
|
|
|
write_response(message);
|
2019-05-20 17:04:36 +00:00
|
|
|
|
2020-05-23 22:24:01 +00:00
|
|
|
LOG_ERROR(log, message);
|
2017-04-01 07:20:54 +00:00
|
|
|
}
|
2014-03-21 13:42:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
}
|