2017-02-07 19:45:55 +00:00
|
|
|
#include <Poco/Version.h>
|
|
|
|
#include <Poco/Net/HTTPServerResponse.h>
|
2019-02-10 17:40:52 +00:00
|
|
|
#include <IO/WriteBufferFromHTTPServerResponse.h>
|
2017-04-01 09:19:00 +00:00
|
|
|
#include <IO/WriteBufferFromString.h>
|
|
|
|
#include <IO/HTTPCommon.h>
|
2019-02-10 17:40:52 +00:00
|
|
|
#include <IO/Progress.h>
|
|
|
|
#include <Common/Exception.h>
|
2017-04-01 09:19:00 +00:00
|
|
|
#include <Common/NetException.h>
|
|
|
|
#include <Common/Stopwatch.h>
|
2019-06-24 11:17:15 +00:00
|
|
|
#include <Common/config.h>
|
2019-02-10 17:40:52 +00:00
|
|
|
|
2017-01-30 05:13:58 +00:00
|
|
|
|
|
|
|
namespace DB
|
|
|
|
{
|
|
|
|
|
|
|
|
namespace ErrorCodes
|
|
|
|
{
|
2017-04-01 07:20:54 +00:00
|
|
|
extern const int LOGICAL_ERROR;
|
2017-01-30 05:13:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void WriteBufferFromHTTPServerResponse::startSendHeaders()
|
|
|
|
{
|
2017-04-01 07:20:54 +00:00
|
|
|
if (!headers_started_sending)
|
|
|
|
{
|
|
|
|
headers_started_sending = true;
|
2017-01-30 05:13:58 +00:00
|
|
|
|
2017-04-01 07:20:54 +00:00
|
|
|
if (add_cors_header)
|
|
|
|
response.set("Access-Control-Allow-Origin", "*");
|
2017-01-30 05:13:58 +00:00
|
|
|
|
2017-09-08 11:57:43 +00:00
|
|
|
setResponseDefaultHeaders(response, keep_alive_timeout);
|
2017-01-30 05:13:58 +00:00
|
|
|
|
2019-02-15 11:46:07 +00:00
|
|
|
#if defined(POCO_CLICKHOUSE_PATCH)
|
2017-09-01 21:46:12 +00:00
|
|
|
if (request.getMethod() != Poco::Net::HTTPRequest::HTTP_HEAD)
|
|
|
|
std::tie(response_header_ostr, response_body_ostr) = response.beginSend();
|
2017-02-07 19:45:55 +00:00
|
|
|
#endif
|
2017-04-01 07:20:54 +00:00
|
|
|
}
|
2017-01-30 05:13:58 +00:00
|
|
|
}
|
|
|
|
|
2019-04-26 03:38:39 +00:00
|
|
|
void WriteBufferFromHTTPServerResponse::writeHeaderSummary()
|
2019-04-19 12:14:10 +00:00
|
|
|
{
|
2019-05-13 04:48:09 +00:00
|
|
|
#if defined(POCO_CLICKHOUSE_PATCH)
|
2019-04-19 12:14:10 +00:00
|
|
|
if (headers_finished_sending)
|
|
|
|
return;
|
2019-05-06 06:57:48 +00:00
|
|
|
|
2019-04-19 12:14:10 +00:00
|
|
|
WriteBufferFromOwnString progress_string_writer;
|
|
|
|
accumulated_progress.writeJSON(progress_string_writer);
|
|
|
|
|
2019-05-06 09:09:45 +00:00
|
|
|
if (response_header_ostr)
|
|
|
|
*response_header_ostr << "X-ClickHouse-Summary: " << progress_string_writer.str() << "\r\n" << std::flush;
|
2019-04-26 03:38:39 +00:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void WriteBufferFromHTTPServerResponse::writeHeaderProgress()
|
|
|
|
{
|
2019-05-13 04:48:09 +00:00
|
|
|
#if defined(POCO_CLICKHOUSE_PATCH)
|
2019-04-26 03:38:39 +00:00
|
|
|
if (headers_finished_sending)
|
|
|
|
return;
|
2019-05-06 06:57:48 +00:00
|
|
|
|
2019-04-26 03:38:39 +00:00
|
|
|
WriteBufferFromOwnString progress_string_writer;
|
2019-05-13 04:48:09 +00:00
|
|
|
accumulated_progress.writeJSON(progress_string_writer);
|
2019-04-26 03:38:39 +00:00
|
|
|
|
2019-05-13 05:55:53 +00:00
|
|
|
if (response_header_ostr)
|
|
|
|
*response_header_ostr << "X-ClickHouse-Progress: " << progress_string_writer.str() << "\r\n" << std::flush;
|
2019-04-19 12:14:10 +00:00
|
|
|
#endif
|
|
|
|
}
|
2017-01-30 05:13:58 +00:00
|
|
|
|
|
|
|
void WriteBufferFromHTTPServerResponse::finishSendHeaders()
|
|
|
|
{
|
2017-04-01 07:20:54 +00:00
|
|
|
if (!headers_finished_sending)
|
|
|
|
{
|
2019-04-26 03:38:39 +00:00
|
|
|
writeHeaderSummary();
|
2017-04-01 07:20:54 +00:00
|
|
|
headers_finished_sending = true;
|
2017-01-30 05:13:58 +00:00
|
|
|
|
2017-09-01 21:48:18 +00:00
|
|
|
if (request.getMethod() != Poco::Net::HTTPRequest::HTTP_HEAD)
|
|
|
|
{
|
2019-02-15 11:46:07 +00:00
|
|
|
#if defined(POCO_CLICKHOUSE_PATCH)
|
2017-09-01 21:46:12 +00:00
|
|
|
/// Send end of headers delimiter.
|
|
|
|
if (response_header_ostr)
|
|
|
|
*response_header_ostr << "\r\n" << std::flush;
|
2017-02-07 19:45:55 +00:00
|
|
|
#else
|
2017-09-01 21:46:12 +00:00
|
|
|
/// Newline autosent by response.send()
|
|
|
|
/// if nothing to send in body:
|
|
|
|
if (!response_body_ostr)
|
|
|
|
response_body_ostr = &(response.send());
|
2017-02-07 19:45:55 +00:00
|
|
|
#endif
|
2017-09-01 21:47:37 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2017-09-01 21:46:12 +00:00
|
|
|
if (!response_body_ostr)
|
|
|
|
response_body_ostr = &(response.send());
|
|
|
|
}
|
2017-04-01 07:20:54 +00:00
|
|
|
}
|
2017-01-30 05:13:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void WriteBufferFromHTTPServerResponse::nextImpl()
|
|
|
|
{
|
2017-04-01 07:20:54 +00:00
|
|
|
{
|
2019-01-02 06:44:36 +00:00
|
|
|
std::lock_guard lock(mutex);
|
2017-01-30 05:13:58 +00:00
|
|
|
|
2017-04-01 07:20:54 +00:00
|
|
|
startSendHeaders();
|
2017-01-30 05:13:58 +00:00
|
|
|
|
2017-09-01 21:46:12 +00:00
|
|
|
if (!out && request.getMethod() != Poco::Net::HTTPRequest::HTTP_HEAD)
|
2017-04-01 07:20:54 +00:00
|
|
|
{
|
|
|
|
if (compress)
|
|
|
|
{
|
2020-01-04 07:31:00 +00:00
|
|
|
auto content_encoding_name = toContentEncodingName(compression_method);
|
|
|
|
|
2019-04-09 21:59:44 +00:00
|
|
|
#if defined(POCO_CLICKHOUSE_PATCH)
|
2020-01-04 07:31:00 +00:00
|
|
|
*response_header_ostr << "Content-Encoding: " << content_encoding_name << "\r\n";
|
2019-02-13 21:07:12 +00:00
|
|
|
#else
|
2020-01-04 07:31:00 +00:00
|
|
|
response.set("Content-Encoding", content_encoding_name);
|
2019-06-03 20:27:53 +00:00
|
|
|
#endif
|
2017-04-01 07:20:54 +00:00
|
|
|
}
|
2020-01-04 22:59:08 +00:00
|
|
|
|
2019-02-15 11:46:07 +00:00
|
|
|
#if !defined(POCO_CLICKHOUSE_PATCH)
|
2020-01-04 22:59:08 +00:00
|
|
|
response_body_ostr = &(response.send());
|
2017-02-07 19:45:55 +00:00
|
|
|
#endif
|
2020-01-04 22:59:08 +00:00
|
|
|
|
|
|
|
out = wrapWriteBufferWithCompressionMethod(
|
|
|
|
std::make_unique<WriteBufferFromOStream>(*response_body_ostr),
|
|
|
|
compress ? compression_method : CompressionMethod::None,
|
|
|
|
compression_level,
|
|
|
|
working_buffer.size(),
|
|
|
|
working_buffer.begin());
|
2017-04-01 07:20:54 +00:00
|
|
|
}
|
2017-01-30 05:13:58 +00:00
|
|
|
|
2017-04-01 07:20:54 +00:00
|
|
|
finishSendHeaders();
|
2017-02-07 19:45:55 +00:00
|
|
|
|
2017-04-01 07:20:54 +00:00
|
|
|
}
|
2017-01-30 05:13:58 +00:00
|
|
|
|
2017-09-01 21:49:06 +00:00
|
|
|
if (out)
|
|
|
|
{
|
2017-09-01 21:46:12 +00:00
|
|
|
out->position() = position();
|
|
|
|
out->next();
|
|
|
|
}
|
2017-01-30 05:13:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
WriteBufferFromHTTPServerResponse::WriteBufferFromHTTPServerResponse(
|
2017-09-01 21:46:12 +00:00
|
|
|
Poco::Net::HTTPServerRequest & request_,
|
2017-04-01 07:20:54 +00:00
|
|
|
Poco::Net::HTTPServerResponse & response_,
|
2017-09-08 16:41:35 +00:00
|
|
|
unsigned keep_alive_timeout_,
|
2017-04-01 07:20:54 +00:00
|
|
|
bool compress_,
|
2020-01-04 07:31:00 +00:00
|
|
|
CompressionMethod compression_method_)
|
2020-01-04 22:59:08 +00:00
|
|
|
: BufferWithOwnMemory<WriteBuffer>(DBMS_DEFAULT_BUFFER_SIZE)
|
2017-09-08 11:57:43 +00:00
|
|
|
, request(request_)
|
|
|
|
, response(response_)
|
|
|
|
, keep_alive_timeout(keep_alive_timeout_)
|
|
|
|
, compress(compress_)
|
|
|
|
, compression_method(compression_method_)
|
2017-01-30 05:13:58 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void WriteBufferFromHTTPServerResponse::onProgress(const Progress & progress)
|
|
|
|
{
|
2019-01-02 06:44:36 +00:00
|
|
|
std::lock_guard lock(mutex);
|
2017-01-30 05:13:58 +00:00
|
|
|
|
2017-04-01 07:20:54 +00:00
|
|
|
/// Cannot add new headers if body was started to send.
|
|
|
|
if (headers_finished_sending)
|
|
|
|
return;
|
2017-01-30 05:13:58 +00:00
|
|
|
|
2019-04-26 03:38:39 +00:00
|
|
|
accumulated_progress.incrementPiecewiseAtomically(progress);
|
2017-01-30 05:13:58 +00:00
|
|
|
|
2017-04-01 07:20:54 +00:00
|
|
|
if (progress_watch.elapsed() >= send_progress_interval_ms * 1000000)
|
|
|
|
{
|
|
|
|
progress_watch.restart();
|
2017-01-30 05:13:58 +00:00
|
|
|
|
2017-04-01 07:20:54 +00:00
|
|
|
/// Send all common headers before our special progress headers.
|
|
|
|
startSendHeaders();
|
2019-04-19 12:14:10 +00:00
|
|
|
writeHeaderProgress();
|
2017-04-01 07:20:54 +00:00
|
|
|
}
|
2017-01-30 05:13:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void WriteBufferFromHTTPServerResponse::finalize()
|
|
|
|
{
|
2017-04-01 07:20:54 +00:00
|
|
|
if (offset())
|
|
|
|
{
|
|
|
|
next();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/// If no remaining data, just send headers.
|
2019-01-02 06:44:36 +00:00
|
|
|
std::lock_guard lock(mutex);
|
2017-04-01 07:20:54 +00:00
|
|
|
startSendHeaders();
|
|
|
|
finishSendHeaders();
|
|
|
|
}
|
2017-01-30 05:13:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
WriteBufferFromHTTPServerResponse::~WriteBufferFromHTTPServerResponse()
|
|
|
|
{
|
2017-04-01 07:20:54 +00:00
|
|
|
try
|
|
|
|
{
|
|
|
|
finalize();
|
|
|
|
}
|
|
|
|
catch (...)
|
|
|
|
{
|
|
|
|
tryLogCurrentException(__PRETTY_FUNCTION__);
|
|
|
|
}
|
2017-01-30 05:13:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|