2012-10-29 07:19:47 +00:00
|
|
|
#pragma once
|
|
|
|
|
2017-11-20 04:15:43 +00:00
|
|
|
#include <optional>
|
2017-01-22 15:03:55 +00:00
|
|
|
#include <mutex>
|
2017-09-01 21:46:12 +00:00
|
|
|
#include <Poco/Net/HTTPServerRequest.h>
|
|
|
|
#include <Poco/Net/HTTPServerResponse.h>
|
2017-02-07 19:45:55 +00:00
|
|
|
#include <Poco/Version.h>
|
2020-01-09 14:07:49 +00:00
|
|
|
#include <IO/CompressionMethod.h>
|
2017-04-01 09:19:00 +00:00
|
|
|
#include <IO/WriteBuffer.h>
|
2020-01-04 22:59:08 +00:00
|
|
|
#include <IO/BufferWithOwnMemory.h>
|
2017-04-01 09:19:00 +00:00
|
|
|
#include <IO/WriteBufferFromOStream.h>
|
|
|
|
#include <IO/HTTPCommon.h>
|
2019-02-10 17:40:52 +00:00
|
|
|
#include <IO/Progress.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>
|
2012-10-29 07:19:47 +00:00
|
|
|
|
|
|
|
|
2017-01-30 05:13:58 +00:00
|
|
|
namespace Poco
|
2016-01-11 21:46:36 +00:00
|
|
|
{
|
2017-04-01 07:20:54 +00:00
|
|
|
namespace Net
|
|
|
|
{
|
|
|
|
class HTTPServerResponse;
|
|
|
|
}
|
2016-01-11 21:46:36 +00:00
|
|
|
}
|
|
|
|
|
2012-10-29 07:19:47 +00:00
|
|
|
|
2017-01-30 05:13:58 +00:00
|
|
|
namespace DB
|
|
|
|
{
|
|
|
|
|
2017-01-07 16:11:30 +00:00
|
|
|
/// The difference from WriteBufferFromOStream is that this buffer gets the underlying std::ostream
|
|
|
|
/// (using response.send()) only after data is flushed for the first time. This is needed in HTTP
|
|
|
|
/// servers to change some HTTP headers (e.g. response code) before any data is sent to the client
|
|
|
|
/// (headers can't be changed after response.send() is called).
|
|
|
|
///
|
|
|
|
/// In short, it allows delaying the call to response.send().
|
|
|
|
///
|
|
|
|
/// Additionally, supports HTTP response compression (in this case corresponding Content-Encoding
|
|
|
|
/// header will be set).
|
2017-01-29 22:53:29 +00:00
|
|
|
///
|
|
|
|
/// Also this class write and flush special X-ClickHouse-Progress HTTP headers
|
|
|
|
/// if no data was sent at the time of progress notification.
|
|
|
|
/// This allows to implement progress bar in HTTP clients.
|
2020-03-18 18:26:40 +00:00
|
|
|
class WriteBufferFromHTTPServerResponse final : public BufferWithOwnMemory<WriteBuffer>
|
2012-10-29 07:19:47 +00:00
|
|
|
{
|
|
|
|
private:
|
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-01-07 16:11:30 +00:00
|
|
|
|
2017-04-01 07:20:54 +00:00
|
|
|
bool add_cors_header = false;
|
2017-09-08 16:41:35 +00:00
|
|
|
unsigned keep_alive_timeout = 0;
|
2017-04-01 07:20:54 +00:00
|
|
|
bool compress = false;
|
2019-02-13 20:54:12 +00:00
|
|
|
CompressionMethod compression_method;
|
2020-01-04 07:31:00 +00:00
|
|
|
int compression_level = 1;
|
2012-10-29 07:19:47 +00:00
|
|
|
|
2017-04-01 07:20:54 +00:00
|
|
|
std::ostream * response_body_ostr = nullptr;
|
2017-02-07 19:45:55 +00:00
|
|
|
|
2019-02-15 11:46:07 +00:00
|
|
|
#if defined(POCO_CLICKHOUSE_PATCH)
|
2017-04-01 07:20:54 +00:00
|
|
|
std::ostream * response_header_ostr = nullptr;
|
2017-02-07 19:45:55 +00:00
|
|
|
#endif
|
2017-01-22 15:42:42 +00:00
|
|
|
|
2020-01-04 07:31:00 +00:00
|
|
|
std::unique_ptr<WriteBuffer> out;
|
2016-02-11 21:40:51 +00:00
|
|
|
|
2017-04-01 07:20:54 +00:00
|
|
|
bool headers_started_sending = false;
|
|
|
|
bool headers_finished_sending = false; /// If true, you could not add any headers.
|
2017-01-22 15:03:55 +00:00
|
|
|
|
2017-04-01 07:20:54 +00:00
|
|
|
Progress accumulated_progress;
|
|
|
|
size_t send_progress_interval_ms = 100;
|
|
|
|
Stopwatch progress_watch;
|
2017-01-22 16:19:24 +00:00
|
|
|
|
2017-04-01 07:20:54 +00:00
|
|
|
std::mutex mutex; /// progress callback could be called from different threads.
|
2017-01-22 15:03:55 +00:00
|
|
|
|
|
|
|
|
2017-04-01 07:20:54 +00:00
|
|
|
/// Must be called under locked mutex.
|
|
|
|
/// This method send headers, if this was not done already,
|
|
|
|
/// but not finish them with \r\n, allowing to send more headers subsequently.
|
|
|
|
void startSendHeaders();
|
2016-02-11 21:40:51 +00:00
|
|
|
|
2019-05-10 06:50:48 +00:00
|
|
|
// Used for write the header X-ClickHouse-Progress
|
2019-04-19 12:14:10 +00:00
|
|
|
void writeHeaderProgress();
|
2019-05-10 06:50:48 +00:00
|
|
|
// Used for write the header X-ClickHouse-Summary
|
2019-04-26 03:38:39 +00:00
|
|
|
void writeHeaderSummary();
|
2019-04-19 12:14:10 +00:00
|
|
|
|
2017-04-01 07:20:54 +00:00
|
|
|
/// This method finish headers with \r\n, allowing to start to send body.
|
|
|
|
void finishSendHeaders();
|
2017-01-22 17:09:00 +00:00
|
|
|
|
2017-04-01 07:20:54 +00:00
|
|
|
void nextImpl() override;
|
2012-10-29 07:19:47 +00:00
|
|
|
|
2017-01-22 15:13:50 +00:00
|
|
|
public:
|
2017-04-01 07:20:54 +00:00
|
|
|
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_ = false, /// If true - set Content-Encoding header and compress the result.
|
2020-01-04 22:59:08 +00:00
|
|
|
CompressionMethod compression_method_ = CompressionMethod::None);
|
2017-04-01 07:20:54 +00:00
|
|
|
|
|
|
|
/// Writes progess in repeating HTTP headers.
|
|
|
|
void onProgress(const Progress & progress);
|
|
|
|
|
|
|
|
/// Send at least HTTP headers if no data has been sent yet.
|
|
|
|
/// Use after the data has possibly been sent and no error happened (and thus you do not plan
|
|
|
|
/// to change response HTTP code.
|
|
|
|
/// This method is idempotent.
|
2019-11-19 17:11:13 +00:00
|
|
|
void finalize() override;
|
2017-04-01 07:20:54 +00:00
|
|
|
|
|
|
|
/// Turn compression on or off.
|
|
|
|
/// The setting has any effect only if HTTP headers haven't been sent yet.
|
|
|
|
void setCompression(bool enable_compression)
|
|
|
|
{
|
|
|
|
compress = enable_compression;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Set compression level if the compression is turned on.
|
|
|
|
/// The setting has any effect only if HTTP headers haven't been sent yet.
|
|
|
|
void setCompressionLevel(int level)
|
|
|
|
{
|
|
|
|
compression_level = level;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Turn CORS on or off.
|
|
|
|
/// The setting has any effect only if HTTP headers haven't been sent yet.
|
|
|
|
void addHeaderCORS(bool enable_cors)
|
|
|
|
{
|
|
|
|
add_cors_header = enable_cors;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Don't send HTTP headers with progress more frequently.
|
|
|
|
void setSendProgressInterval(size_t send_progress_interval_ms_)
|
|
|
|
{
|
|
|
|
send_progress_interval_ms = send_progress_interval_ms_;
|
|
|
|
}
|
|
|
|
|
2018-08-10 04:02:56 +00:00
|
|
|
~WriteBufferFromHTTPServerResponse() override;
|
2012-10-29 07:19:47 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
}
|