ClickHouse/dbms/src/Server/HTTPHandler.cpp

186 lines
5.9 KiB
C++
Raw Normal View History

2012-03-09 04:45:27 +00:00
#include <iomanip>
2012-03-09 03:06:09 +00:00
#include <Poco/URI.h>
2012-03-09 03:56:12 +00:00
#include <Poco/NumberParser.h>
2012-03-09 03:06:09 +00:00
2012-03-09 04:45:27 +00:00
#include <statdaemons/Stopwatch.h>
2012-03-09 03:06:09 +00:00
#include <DB/Core/ErrorCodes.h>
#include <DB/IO/ReadBufferFromIStream.h>
2012-03-09 06:36:29 +00:00
#include <DB/IO/ReadBufferFromString.h>
#include <DB/IO/ConcatReadBuffer.h>
2012-03-09 15:46:52 +00:00
#include <DB/IO/CompressedReadBuffer.h>
#include <DB/IO/CompressedWriteBuffer.h>
#include <DB/IO/WriteBufferFromHTTPServerResponse.h>
2012-03-09 03:06:09 +00:00
#include <DB/IO/WriteBufferFromString.h>
#include <DB/IO/WriteHelpers.h>
2012-03-09 04:45:27 +00:00
#include <DB/DataStreams/IProfilingBlockInputStream.h>
2012-03-09 03:06:09 +00:00
#include <DB/Interpreters/executeQuery.h>
2012-03-09 15:46:52 +00:00
#include "HTTPHandler.h"
2012-03-09 03:06:09 +00:00
namespace DB
{
2012-03-09 06:36:29 +00:00
/// Позволяет получать параметры URL даже если запрос POST.
2012-03-09 03:06:09 +00:00
struct HTMLForm : public Poco::Net::HTMLForm
{
HTMLForm(Poco::Net::HTTPRequest & request)
{
Poco::URI uri(request.getURI());
std::istringstream istr(uri.getRawQuery());
readUrl(istr);
}
};
void HTTPHandler::processQuery(Poco::Net::NameValueCollection & params, Poco::Net::HTTPServerResponse & response, std::istream & istr)
2012-03-09 03:06:09 +00:00
{
BlockInputStreamPtr query_plan;
2012-03-09 06:36:29 +00:00
/** Часть запроса может быть передана в параметре query, а часть - POST-ом.
* В таком случае, считается, что запрос - параметр query, затем перевод строки, а затем - данные POST-а.
*/
std::string query_param = params.get("query", "");
if (!query_param.empty())
query_param += '\n';
ReadBufferFromString in_param(query_param);
2012-03-09 15:46:52 +00:00
SharedPtr<ReadBuffer> in_post = new ReadBufferFromIStream(istr);
SharedPtr<ReadBuffer> in_post_maybe_compressed;
/// Если указано decompress, то будем разжимать то, что передано POST-ом.
if (0 != Poco::NumberParser::parseUnsigned(params.get("decompress", "0")))
in_post_maybe_compressed = new CompressedReadBuffer(*in_post);
else
in_post_maybe_compressed = in_post;
ConcatReadBuffer in(in_param, *in_post_maybe_compressed);
2012-03-09 06:36:29 +00:00
2012-03-09 15:46:52 +00:00
/// Если указано compress, то будем сжимать результат.
SharedPtr<WriteBuffer> out = new WriteBufferFromHTTPServerResponse(response);
2012-03-09 15:46:52 +00:00
SharedPtr<WriteBuffer> out_maybe_compressed;
if (0 != Poco::NumberParser::parseUnsigned(params.get("compress", "0")))
out_maybe_compressed = new CompressedWriteBuffer(*out);
else
out_maybe_compressed = out;
2012-03-09 03:06:09 +00:00
Context context = server.global_context;
2012-08-02 17:33:31 +00:00
context.setGlobalContext(server.global_context);
2012-03-09 03:06:09 +00:00
2012-03-09 03:56:12 +00:00
/// Некоторые настройки могут быть переопределены в запросе.
2012-08-02 17:33:31 +00:00
Settings new_settings = context.getSettings();
2012-03-09 03:56:12 +00:00
if (params.has("asynchronous"))
2012-08-02 17:33:31 +00:00
new_settings.asynchronous = 0 != Poco::NumberParser::parseUnsigned(params.get("asynchronous"));
2012-03-09 03:56:12 +00:00
if (params.has("max_block_size"))
2012-08-02 17:33:31 +00:00
new_settings.max_block_size = Poco::NumberParser::parseUnsigned(params.get("max_block_size"));
2012-03-09 03:56:12 +00:00
if (params.has("max_query_size"))
2012-08-02 17:33:31 +00:00
new_settings.max_query_size = Poco::NumberParser::parseUnsigned(params.get("max_query_size"));
2012-03-09 03:56:12 +00:00
if (params.has("max_threads"))
2012-08-02 17:33:31 +00:00
new_settings.max_threads = Poco::NumberParser::parseUnsigned(params.get("max_threads"));
2012-07-10 20:21:29 +00:00
if (params.has("database"))
2012-08-02 17:33:31 +00:00
context.setCurrentDatabase(params.get("database"));
context.setSettings(new_settings);
2012-03-09 03:56:12 +00:00
2012-03-09 04:45:27 +00:00
Stopwatch watch;
2012-03-09 15:46:52 +00:00
executeQuery(in, *out_maybe_compressed, context, query_plan);
2012-03-09 04:45:27 +00:00
watch.stop();
2012-03-09 03:06:09 +00:00
if (query_plan)
{
std::stringstream log_str;
2012-06-25 05:07:34 +00:00
log_str << "Query pipeline:\n";
2012-03-09 03:06:09 +00:00
query_plan->dumpTree(log_str);
LOG_DEBUG(log, log_str.str());
2012-03-09 04:45:27 +00:00
/// Выведем информацию о том, сколько считано строк и байт.
size_t rows = 0;
size_t bytes = 0;
2012-08-23 23:49:28 +00:00
query_plan->getLeafRowsBytes(rows, bytes);
2012-03-09 04:45:27 +00:00
if (rows != 0)
{
LOG_INFO(log, std::fixed << std::setprecision(3)
2012-07-23 06:19:17 +00:00
<< "Read " << rows << " rows, " << bytes / 1048576.0 << " MiB in " << watch.elapsedSeconds() << " sec., "
<< static_cast<size_t>(rows / watch.elapsedSeconds()) << " rows/sec., " << bytes / 1048576.0 / watch.elapsedSeconds() << " MiB/sec.");
2012-03-09 04:45:27 +00:00
}
2012-03-09 03:06:09 +00:00
}
}
2012-03-09 15:46:52 +00:00
void HTTPHandler::handleRequest(Poco::Net::HTTPServerRequest & request, Poco::Net::HTTPServerResponse & response)
2012-03-09 03:06:09 +00:00
{
2012-06-25 05:07:34 +00:00
bool is_browser = false;
if (request.has("Accept"))
{
String accept = request.get("Accept");
if (0 == strncmp(accept.c_str(), "text/html", strlen("text/html")))
is_browser = true;
}
if (is_browser)
response.setContentType("text/plain; charset=UTF-8");
2012-03-09 03:06:09 +00:00
try
{
LOG_TRACE(log, "Request URI: " << request.getURI());
HTMLForm params(request);
std::istream & istr = request.stream();
processQuery(params, response, istr);
2012-03-09 03:06:09 +00:00
LOG_INFO(log, "Done processing query");
}
catch (DB::Exception & e)
{
response.setStatusAndReason(Poco::Net::HTTPResponse::HTTP_INTERNAL_SERVER_ERROR);
std::ostream & ostr = response.send();
std::stringstream s;
s << "Code: " << e.code()
<< ", e.displayText() = " << e.displayText() << ", e.what() = " << e.what();
ostr << s.str() << std::endl;
LOG_ERROR(log, s.str());
}
2012-03-09 03:06:09 +00:00
catch (Poco::Exception & e)
{
response.setStatusAndReason(Poco::Net::HTTPResponse::HTTP_INTERNAL_SERVER_ERROR);
std::ostream & ostr = response.send();
2012-03-09 03:06:09 +00:00
std::stringstream s;
s << "Code: " << ErrorCodes::POCO_EXCEPTION << ", e.code() = " << e.code()
<< ", e.displayText() = " << e.displayText() << ", e.what() = " << e.what();
2012-03-09 03:06:09 +00:00
ostr << s.str() << std::endl;
LOG_ERROR(log, s.str());
}
catch (std::exception & e)
{
response.setStatusAndReason(Poco::Net::HTTPResponse::HTTP_INTERNAL_SERVER_ERROR);
std::ostream & ostr = response.send();
2012-03-09 03:06:09 +00:00
std::stringstream s;
s << "Code: " << ErrorCodes::STD_EXCEPTION << ". " << e.what();
ostr << s.str() << std::endl;
LOG_ERROR(log, s.str());
}
catch (...)
{
response.setStatusAndReason(Poco::Net::HTTPResponse::HTTP_INTERNAL_SERVER_ERROR);
std::ostream & ostr = response.send();
2012-03-09 03:06:09 +00:00
std::stringstream s;
s << "Code: " << ErrorCodes::UNKNOWN_EXCEPTION << ". Unknown exception.";
ostr << s.str() << std::endl;
LOG_ERROR(log, s.str());
}
}
}