1010#include < Poco/Net/HTTPHeaderStream.h>
1111#include < Poco/Net/HTTPStream.h>
1212#include < IO/NullWriteBuffer.h>
13+ #include < sstream>
1314
1415
1516namespace 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