Skip to content

Commit d68039d

Browse files
Merge pull request ClickHouse#84193 from ClickHouse/revert-81595-partial
Revert 81595 partial
2 parents eff6616 + 3668037 commit d68039d

File tree

7 files changed

+97
-153
lines changed

7 files changed

+97
-153
lines changed

src/Common/ProfileEvents.cpp

Lines changed: 11 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -977,24 +977,17 @@ The server successfully detected this situation and will download merged part fr
977977
M(DiskConnectionsErrors, "Number of cases when creation of a connection for disk is failed", ValueType::Number) \
978978
M(DiskConnectionsElapsedMicroseconds, "Total time spend on creating connections for disk", ValueType::Microseconds) \
979979
\
980-
M(HTTPConnectionsCreated, "Number of created client HTTP connections", ValueType::Number) \
981-
M(HTTPConnectionsReused, "Number of reused client HTTP connections", ValueType::Number) \
982-
M(HTTPConnectionsReset, "Number of reset client HTTP connections", ValueType::Number) \
983-
M(HTTPConnectionsPreserved, "Number of preserved client HTTP connections", ValueType::Number) \
984-
M(HTTPConnectionsExpired, "Number of expired client HTTP connections", ValueType::Number) \
985-
M(HTTPConnectionsErrors, "Number of cases when creation of a client HTTP connection failed", ValueType::Number) \
986-
M(HTTPConnectionsElapsedMicroseconds, "Total time spend on creating client HTTP connections", ValueType::Microseconds) \
987-
\
988-
M(HTTPServerConnectionsCreated, "Number of created server HTTP connections", ValueType::Number) \
989-
M(HTTPServerConnectionsReused, "Number of reused server HTTP connections", ValueType::Number) \
990-
M(HTTPServerConnectionsPreserved, "Number of preserved server HTTP connections. Connection kept alive successfully", ValueType::Number) \
991-
M(HTTPServerConnectionsExpired, "Number of expired server HTTP connections.", ValueType::Number) \
992-
M(HTTPServerConnectionsClosed, "Number of closed server HTTP connections. Keep alive has not been negotiated", ValueType::Number) \
993-
M(HTTPServerConnectionsReset, "Number of reset server HTTP connections. Server closes connection", ValueType::Number) \
994-
\
995-
M(AddressesDiscovered, "Total count of new addresses in DNS resolve results for HTTP connections", ValueType::Number) \
996-
M(AddressesExpired, "Total count of expired addresses which is no longer presented in DNS resolve results for HTTP connections", ValueType::Number) \
997-
M(AddressesMarkedAsFailed, "Total count of addresses which have been marked as faulty due to connection errors for HTTP connections", ValueType::Number) \
980+
M(HTTPConnectionsCreated, "Number of created http connections", ValueType::Number) \
981+
M(HTTPConnectionsReused, "Number of reused http connections", ValueType::Number) \
982+
M(HTTPConnectionsReset, "Number of reset http connections", ValueType::Number) \
983+
M(HTTPConnectionsPreserved, "Number of preserved http connections", ValueType::Number) \
984+
M(HTTPConnectionsExpired, "Number of expired http connections", ValueType::Number) \
985+
M(HTTPConnectionsErrors, "Number of cases when creation of a http connection failed", ValueType::Number) \
986+
M(HTTPConnectionsElapsedMicroseconds, "Total time spend on creating http connections", ValueType::Microseconds) \
987+
\
988+
M(AddressesDiscovered, "Total count of new addresses in dns resolve results for http connections", ValueType::Number) \
989+
M(AddressesExpired, "Total count of expired addresses which is no longer presented in dns resolve results for http connections", ValueType::Number) \
990+
M(AddressesMarkedAsFailed, "Total count of addresses which has been marked as faulty due to connection errors for http connections", ValueType::Number) \
998991
\
999992
M(ReadWriteBufferFromHTTPRequestsSent, "Number of HTTP requests sent by ReadWriteBufferFromHTTP", ValueType::Number) \
1000993
M(ReadWriteBufferFromHTTPBytes, "Total size of payload bytes received and sent by ReadWriteBufferFromHTTP. Doesn't include HTTP headers.", ValueType::Bytes) \

src/IO/HTTPChunkedReadBuffer.cpp

Lines changed: 21 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -56,38 +56,30 @@ bool HTTPChunkedReadBuffer::nextImpl()
5656
if (!in)
5757
return false;
5858

59-
try
59+
/// The footer of previous chunk.
60+
if (count())
61+
readChunkFooter();
62+
63+
size_t chunk_size = readChunkHeader();
64+
if (0 == chunk_size)
65+
{
66+
readChunkFooter();
67+
in.reset(); // prevent double-eof situation.
68+
return false;
69+
}
70+
71+
if (in->available() >= chunk_size)
6072
{
61-
/// The footer of previous chunk.
62-
if (count())
63-
readChunkFooter();
64-
65-
size_t chunk_size = readChunkHeader();
66-
if (0 == chunk_size)
67-
{
68-
readChunkFooter();
69-
in.reset(); // prevent double-eof situation.
70-
return false;
71-
}
72-
73-
if (in->available() >= chunk_size)
74-
{
75-
/// Zero-copy read from input.
76-
working_buffer = Buffer(in->position(), in->position() + chunk_size);
77-
in->position() += chunk_size;
78-
}
79-
else
80-
{
81-
/// Chunk is not completely in buffer, copy it to scratch space.
82-
memory.resize(chunk_size);
83-
in->readStrict(memory.data(), chunk_size);
84-
working_buffer = Buffer(memory.data(), memory.data() + chunk_size);
85-
}
73+
/// Zero-copy read from input.
74+
working_buffer = Buffer(in->position(), in->position() + chunk_size);
75+
in->position() += chunk_size;
8676
}
87-
catch (...)
77+
else
8878
{
89-
in.reset();
90-
throw;
79+
/// Chunk is not completely in buffer, copy it to scratch space.
80+
memory.resize(chunk_size);
81+
in->readStrict(memory.data(), chunk_size);
82+
working_buffer = Buffer(memory.data(), memory.data() + chunk_size);
9183
}
9284

9385
/// NOTE: We postpone reading the footer to the next iteration, because it may not be completely in buffer,

src/Server/HTTP/HTTPServerConnection.cpp

Lines changed: 2 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -2,21 +2,8 @@
22
#include <Server/TCPServer.h>
33

44
#include <Poco/Net/NetException.h>
5-
#include <Common/ProfileEvents.h>
65
#include <Common/logger_useful.h>
76

8-
9-
namespace ProfileEvents
10-
{
11-
extern const Event HTTPServerConnectionsCreated;
12-
extern const Event HTTPServerConnectionsReused;
13-
extern const Event HTTPServerConnectionsPreserved;
14-
extern const Event HTTPServerConnectionsExpired;
15-
extern const Event HTTPServerConnectionsClosed;
16-
extern const Event HTTPServerConnectionsReset;
17-
}
18-
19-
207
namespace DB
218
{
229

@@ -38,28 +25,8 @@ void HTTPServerConnection::run()
3825
std::string server = params->getSoftwareVersion();
3926
Poco::Net::HTTPServerSession session(socket(), params);
4027

41-
ProfileEvents::increment(ProfileEvents::HTTPServerConnectionsCreated);
42-
43-
while (!stopped && tcp_server.isOpen() && session.connected())
28+
while (!stopped && tcp_server.isOpen() && session.hasMoreRequests() && session.connected())
4429
{
45-
const bool is_first_request = params->getMaxKeepAliveRequests() == session.getMaxKeepAliveRequests();
46-
47-
if (!session.hasMoreRequests())
48-
{
49-
if (is_first_request)
50-
// it is strange to have a connection being opened but no request has been sent, account it as an error case
51-
ProfileEvents::increment(ProfileEvents::HTTPServerConnectionsReset);
52-
else
53-
ProfileEvents::increment(ProfileEvents::HTTPServerConnectionsExpired);
54-
55-
return;
56-
}
57-
else
58-
{
59-
if (!is_first_request)
60-
ProfileEvents::increment(ProfileEvents::HTTPServerConnectionsReused);
61-
}
62-
6330
try
6431
{
6532
std::lock_guard lock(mutex);
@@ -102,38 +69,10 @@ void HTTPServerConnection::run()
10269
response.sendContinue();
10370

10471
handler->handleRequest(request, response, write_event);
105-
106-
bool keep_alive = false;
107-
if (!params->getKeepAlive() || !request.canKeepAlive())
108-
{
109-
/// Either server is not configured to keep connections alive or client did not ask it
110-
ProfileEvents::increment(ProfileEvents::HTTPServerConnectionsClosed);
111-
}
112-
else if (session.getMaxKeepAliveRequests() == 0 || !session.canKeepAlive())
113-
{
114-
/// connection is expired by max request count
115-
ProfileEvents::increment(ProfileEvents::HTTPServerConnectionsExpired);
116-
}
117-
else if (!response.getKeepAlive())
118-
{
119-
/// server decided to close connection
120-
/// usually it is related to the cases:
121-
/// - the request or response stream is not bounded or
122-
/// - not all data is read from them
123-
ProfileEvents::increment(ProfileEvents::HTTPServerConnectionsReset);
124-
}
125-
else
126-
{
127-
ProfileEvents::increment(ProfileEvents::HTTPServerConnectionsPreserved);
128-
keep_alive = true;
129-
}
130-
131-
session.setKeepAlive(keep_alive);
72+
session.setKeepAlive(params->getKeepAlive() && response.getKeepAlive() && session.canKeepAlive());
13273
}
13374
else
134-
{
13575
sendErrorResponse(session, Poco::Net::HTTPResponse::HTTP_NOT_IMPLEMENTED);
136-
}
13776
}
13877
catch (Poco::Exception &)
13978
{
@@ -195,7 +134,6 @@ void HTTPServerConnection::sendErrorResponse(Poco::Net::HTTPServerSession & sess
195134
response.setKeepAlive(false);
196135
response.send();
197136
session.setKeepAlive(false);
198-
ProfileEvents::increment(ProfileEvents::HTTPServerConnectionsReset);
199137
}
200138

201139
}

src/Server/HTTP/HTTPServerRequest.cpp

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -56,15 +56,11 @@ HTTPServerRequest::HTTPServerRequest(HTTPContextPtr context, HTTPServerResponse
5656
/// and retry with exactly the same (incomplete) set of rows.
5757
/// That's why we have to check body size if it's provided.
5858
if (getChunkedTransferEncoding())
59-
{
6059
stream = std::make_unique<HTTPChunkedReadBuffer>(std::move(in), HTTP_MAX_CHUNK_SIZE);
61-
stream_is_bounded = true;
62-
}
6360
else if (hasContentLength())
6461
{
6562
size_t content_length = getContentLength();
6663
stream = std::make_unique<LimitReadBuffer>(std::move(in), LimitReadBuffer::Settings{.read_no_less = content_length, .read_no_more = content_length, .expect_eof = true});
67-
stream_is_bounded = true;
6864
}
6965
else if (getMethod() != HTTPRequest::HTTP_GET && getMethod() != HTTPRequest::HTTP_HEAD && getMethod() != HTTPRequest::HTTP_DELETE)
7066
{
@@ -74,11 +70,8 @@ HTTPServerRequest::HTTPServerRequest(HTTPContextPtr context, HTTPServerResponse
7470
"and no chunked/multipart encoding, it may be impossible to distinguish graceful EOF from abnormal connection loss");
7571
}
7672
else
77-
{
7873
/// We have to distinguish empty buffer and nullptr.
7974
stream = std::make_unique<EmptyReadBuffer>();
80-
stream_is_bounded = true;
81-
}
8275
}
8376

8477
bool HTTPServerRequest::checkPeerConnected() const

src/Server/HTTP/HTTPServerRequest.h

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -47,14 +47,6 @@ class HTTPServerRequest : public HTTPRequest
4747
X509Certificate peerCertificate() const;
4848
#endif
4949

50-
bool canKeepAlive() const
51-
{
52-
if (stream && stream_is_bounded)
53-
return stream->eof();
54-
55-
return false;
56-
}
57-
5850
private:
5951
/// Limits for basic sanity checks when reading a header
6052
enum Limits
@@ -73,7 +65,6 @@ class HTTPServerRequest : public HTTPRequest
7365
Poco::Net::SocketAddress client_address;
7466
Poco::Net::SocketAddress server_address;
7567

76-
bool stream_is_bounded = false;
7768
bool secure;
7869

7970
void readRequest(ReadBuffer & in);

src/Server/HTTP/HTTPServerResponse.cpp

Lines changed: 54 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include <Poco/Net/HTTPHeaderStream.h>
1111
#include <Poco/Net/HTTPStream.h>
1212
#include <IO/NullWriteBuffer.h>
13+
#include <sstream>
1314

1415

1516
namespace DB
@@ -39,6 +40,9 @@ std::shared_ptr<WriteBuffer> HTTPServerResponse::send()
3940
// the connection would be poisoned.
4041
// Next request over that connection reads previously unreaded message as a HTTP status line
4142

43+
// Send header
44+
Poco::Net::HTTPHeaderOutputStream hs(session);
45+
write(hs);
4246
// make sure that nothing is sent to the client if it was HTTP_HEAD request
4347
stream = std::make_shared<NullWriteBuffer>(write_event);
4448

@@ -49,36 +53,75 @@ std::shared_ptr<WriteBuffer> HTTPServerResponse::send()
4953
// but if we do, then it is safer to close the connection at the end
5054
setKeepAlive(false);
5155

56+
// Send header
57+
Poco::Net::HTTPHeaderOutputStream hs(session);
58+
write(hs);
5259
stream = std::make_shared<AutoFinalizedWriteBuffer<WriteBufferFromPocoSocket>>(session.socket(), write_event);
5360
}
5461
else if (getChunkedTransferEncoding())
5562
{
63+
// Send header
64+
Poco::Net::HTTPHeaderOutputStream hs(session);
65+
write(hs);
5666
stream = std::make_shared<AutoFinalizedWriteBuffer<HTTPWriteBufferChunked>>(session.socket(), write_event);
5767
}
5868
else if (hasContentLength())
5969
{
70+
// Send header
71+
Poco::Net::HTTPHeaderOutputStream hs(session);
72+
write(hs);
6073
stream = std::make_shared<AutoFinalizedWriteBuffer<HTTPWriteBufferFixedLength>>(session.socket(), getContentLength(), write_event);
6174
}
6275
else
6376
{
6477
setKeepAlive(false);
65-
78+
// Send header
79+
Poco::Net::HTTPHeaderOutputStream hs(session);
80+
write(hs);
6681
stream = std::make_shared<AutoFinalizedWriteBuffer<WriteBufferFromPocoSocket>>(session.socket(), write_event);
6782
}
6883

69-
Poco::Net::HTTPHeaderOutputStream hs(session);
70-
beginWrite(hs);
71-
hs << "\r\n";
72-
hs.flush();
73-
84+
send_started = true;
7485
return stream;
7586
}
7687

77-
/// Only this method is called inside WriteBufferFromHTTPServerResponse
78-
void HTTPServerResponse::beginWrite(std::ostream & ostr)
88+
std::pair<std::shared_ptr<WriteBuffer>, std::shared_ptr<WriteBuffer>> HTTPServerResponse::beginSend()
7989
{
80-
allowKeepAliveIFFRequestIsFullyRead();
90+
poco_assert(!stream);
91+
poco_assert(!header_stream);
92+
93+
/// NOTE: Code is not exception safe.
8194

95+
if ((request && request->getMethod() == HTTPRequest::HTTP_HEAD) || getStatus() < 200 || getStatus() == HTTPResponse::HTTP_NO_CONTENT
96+
|| getStatus() == HTTPResponse::HTTP_NOT_MODIFIED)
97+
{
98+
throw Poco::Exception("HTTPServerResponse::beginSend is invalid for HEAD request");
99+
}
100+
101+
if (hasContentLength())
102+
{
103+
throw Poco::Exception("HTTPServerResponse::beginSend is invalid for response with Content-Length header");
104+
}
105+
106+
// Write header to buffer
107+
std::stringstream header; //STYLE_CHECK_ALLOW_STD_STRING_STREAM
108+
beginWrite(header);
109+
// Send header
110+
auto str = header.str();
111+
header_stream = std::make_shared<AutoFinalizedWriteBuffer<WriteBufferFromPocoSocket>>(session.socket(), write_event, str.size());
112+
header_stream->write(str.data(), str.size());
113+
114+
if (getChunkedTransferEncoding())
115+
stream = std::make_shared<AutoFinalizedWriteBuffer<HTTPWriteBufferChunked>>(session.socket(), write_event);
116+
else
117+
stream = std::make_shared<AutoFinalizedWriteBuffer<WriteBufferFromPocoSocket>>(session.socket(), write_event);
118+
119+
send_started = true;
120+
return std::make_pair(header_stream, stream);
121+
}
122+
123+
void HTTPServerResponse::beginWrite(std::ostream & ostr) const
124+
{
82125
HTTPResponse::beginWrite(ostr);
83126
send_started = true;
84127
}
@@ -87,11 +130,9 @@ void HTTPServerResponse::sendBuffer(const void * buffer, std::size_t length)
87130
{
88131
setContentLength(static_cast<int>(length));
89132
setChunkedTransferEncoding(false);
90-
91133
// Send header
92134
Poco::Net::HTTPHeaderOutputStream hs(session);
93-
beginWrite(hs);
94-
hs << "\r\n";
135+
write(hs);
95136
hs.flush();
96137

97138
if (request && request->getMethod() != HTTPRequest::HTTP_HEAD)
@@ -125,17 +166,8 @@ void HTTPServerResponse::redirect(const std::string & uri, HTTPStatus status)
125166

126167
// Send header
127168
Poco::Net::HTTPHeaderOutputStream hs(session);
128-
beginWrite(hs);
129-
hs << "\r\n";
169+
write(hs);
130170
hs.flush();
131171
}
132172

133-
void HTTPServerResponse::allowKeepAliveIFFRequestIsFullyRead()
134-
{
135-
/// Connection can only be reused if we've fully read the previous request and all its POST data.
136-
/// Otherwise we'd misinterpret the leftover data as part of the next request's header.
137-
/// HTTPServerRequest::canKeepAlive() checks that request stream is bounded and is fully read.
138-
if (!request || !request->canKeepAlive())
139-
setKeepAlive(false);
140-
}
141173
}

0 commit comments

Comments
 (0)