/src/crow/include/crow/http_connection.h
Line | Count | Source |
1 | | #pragma once |
2 | | |
3 | | #ifdef CROW_USE_BOOST |
4 | | #include <boost/asio.hpp> |
5 | | #else |
6 | | #ifndef ASIO_STANDALONE |
7 | | #define ASIO_STANDALONE |
8 | | #endif |
9 | | #include <asio.hpp> |
10 | | #endif |
11 | | |
12 | | #include <algorithm> |
13 | | #include <atomic> |
14 | | #include <chrono> |
15 | | #include <memory> |
16 | | #include <vector> |
17 | | |
18 | | #include "crow/http_parser_merged.h" |
19 | | #include "crow/common.h" |
20 | | #include "crow/compression.h" |
21 | | #include "crow/http_response.h" |
22 | | #include "crow/logging.h" |
23 | | #include "crow/middleware.h" |
24 | | #include "crow/middleware_context.h" |
25 | | #include "crow/parser.h" |
26 | | #include "crow/settings.h" |
27 | | #include "crow/socket_adaptors.h" |
28 | | #include "crow/task_timer.h" |
29 | | #include "crow/utility.h" |
30 | | |
31 | | namespace crow |
32 | | { |
33 | | #ifdef CROW_USE_BOOST |
34 | | namespace asio = boost::asio; |
35 | | using error_code = boost::system::error_code; |
36 | | #else |
37 | | using error_code = asio::error_code; |
38 | | #endif |
39 | | using tcp = asio::ip::tcp; |
40 | | |
41 | | #ifdef CROW_ENABLE_DEBUG |
42 | | static std::atomic<int> connectionCount; |
43 | | #endif |
44 | | |
45 | | /// An HTTP connection. |
46 | | template<typename Adaptor, typename Handler, typename... Middlewares> |
47 | | class Connection : public std::enable_shared_from_this<Connection<Adaptor, Handler, Middlewares...>> |
48 | | { |
49 | | friend struct crow::response; |
50 | | |
51 | | public: |
52 | | Connection( |
53 | | asio::io_context& io_context, |
54 | | Handler* handler, |
55 | | const std::string& server_name, |
56 | | std::tuple<Middlewares...>* middlewares, |
57 | | std::function<std::string()>& get_cached_date_str_f, |
58 | | detail::task_timer& task_timer, |
59 | | typename Adaptor::context* adaptor_ctx_, |
60 | | std::atomic<unsigned int>& queue_length): |
61 | 0 | adaptor_(io_context, adaptor_ctx_), |
62 | 0 | handler_(handler), |
63 | 0 | parser_(this), |
64 | 0 | req_(parser_.req), |
65 | 0 | server_name_(server_name), |
66 | 0 | middlewares_(middlewares), |
67 | 0 | get_cached_date_str(get_cached_date_str_f), |
68 | 0 | task_timer_(task_timer), |
69 | 0 | res_stream_threshold_(handler->stream_threshold()), |
70 | 0 | queue_length_(queue_length) |
71 | 0 | { |
72 | 0 | queue_length_++; |
73 | | #ifdef CROW_ENABLE_DEBUG |
74 | | connectionCount++; |
75 | | CROW_LOG_DEBUG << "Connection (" << this << ") allocated, total: " << connectionCount; |
76 | | #endif |
77 | 0 | } Unexecuted instantiation: crow::Connection<crow::UnixSocketAdaptor, crow::Crow<>>::Connection(asio::io_context&, crow::Crow<>*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::tuple<>*, std::__1::function<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > ()>&, crow::detail::task_timer&, void*, std::__1::atomic<unsigned int>&) Unexecuted instantiation: crow::Connection<crow::SocketAdaptor, crow::Crow<>>::Connection(asio::io_context&, crow::Crow<>*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::tuple<>*, std::__1::function<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > ()>&, crow::detail::task_timer&, void*, std::__1::atomic<unsigned int>&) |
78 | | |
79 | | ~Connection() |
80 | 0 | { |
81 | 0 | queue_length_--; |
82 | | #ifdef CROW_ENABLE_DEBUG |
83 | | connectionCount--; |
84 | | CROW_LOG_DEBUG << "Connection (" << this << ") freed, total: " << connectionCount; |
85 | | #endif |
86 | 0 | } Unexecuted instantiation: crow::Connection<crow::UnixSocketAdaptor, crow::Crow<>>::~Connection() Unexecuted instantiation: crow::Connection<crow::SocketAdaptor, crow::Crow<>>::~Connection() |
87 | | |
88 | | /// The TCP socket on top of which the connection is established. |
89 | | decltype(std::declval<Adaptor>().raw_socket())& socket() |
90 | 0 | { |
91 | 0 | return adaptor_.raw_socket(); |
92 | 0 | } Unexecuted instantiation: crow::Connection<crow::UnixSocketAdaptor, crow::Crow<>>::socket() Unexecuted instantiation: crow::Connection<crow::SocketAdaptor, crow::Crow<>>::socket() |
93 | | |
94 | | void start() |
95 | 0 | { |
96 | 0 | auto self = this->shared_from_this(); |
97 | 0 | adaptor_.start([self](const error_code& ec) { |
98 | 0 | if (!ec) |
99 | 0 | { |
100 | 0 | self->start_deadline(); |
101 | 0 | self->parser_.clear(); |
102 | |
|
103 | 0 | self->do_read(); |
104 | 0 | } |
105 | 0 | else |
106 | 0 | { |
107 | 0 | CROW_LOG_ERROR << "Could not start adaptor: " << ec.message(); |
108 | 0 | } |
109 | 0 | }); Unexecuted instantiation: crow::Connection<crow::UnixSocketAdaptor, crow::Crow<>>::start()::{lambda(std::__1::error_code const&)#1}::operator()(std::__1::error_code const&) constUnexecuted instantiation: crow::Connection<crow::SocketAdaptor, crow::Crow<>>::start()::{lambda(std::__1::error_code const&)#1}::operator()(std::__1::error_code const&) const |
110 | 0 | } Unexecuted instantiation: crow::Connection<crow::UnixSocketAdaptor, crow::Crow<>>::start() Unexecuted instantiation: crow::Connection<crow::SocketAdaptor, crow::Crow<>>::start() |
111 | | |
112 | | void handle_url() |
113 | 0 | { |
114 | 0 | routing_handle_result_ = handler_->handle_initial(req_, res); |
115 | | // if no route is found for the request method, return the response without parsing or processing anything further. |
116 | 0 | if (!routing_handle_result_->rule_index && !routing_handle_result_->catch_all && (req_.method != HTTPMethod::Options || routing_handle_result_->method == HTTPMethod::InternalMethodCount)) |
117 | 0 | { |
118 | 0 | parser_.done(); |
119 | 0 | need_to_call_after_handlers_ = true; |
120 | 0 | complete_request(); |
121 | 0 | } |
122 | 0 | } Unexecuted instantiation: crow::Connection<crow::UnixSocketAdaptor, crow::Crow<>>::handle_url() Unexecuted instantiation: crow::Connection<crow::SocketAdaptor, crow::Crow<>>::handle_url() |
123 | | |
124 | | void handle_header() |
125 | 0 | { |
126 | | // HTTP 1.1 Expect: 100-continue |
127 | 0 | if (req_.http_ver_major == 1 && req_.http_ver_minor == 1 && get_header_value(req_.headers, "expect") == "100-continue") |
128 | 0 | { |
129 | 0 | continue_requested = true; |
130 | 0 | buffers_.clear(); |
131 | 0 | static const std::string expect_100_continue = "HTTP/1.1 100 Continue\r\n\r\n"; |
132 | 0 | buffers_.emplace_back(expect_100_continue.data(), expect_100_continue.size()); |
133 | 0 | error_code ec = do_write_sync(buffers_); |
134 | 0 | if (ec) |
135 | 0 | { |
136 | 0 | CROW_LOG_ERROR << ec << " buffer write error happened while handling sending continuation buffer header"; |
137 | 0 | } |
138 | 0 | } |
139 | 0 | if (!routing_handle_result_->rule_index && !routing_handle_result_->catch_all && req_.method == HTTPMethod::Options) |
140 | 0 | { |
141 | 0 | parser_.done(); |
142 | 0 | need_to_call_after_handlers_ = true; |
143 | 0 | complete_request(); |
144 | 0 | } |
145 | 0 | } Unexecuted instantiation: crow::Connection<crow::UnixSocketAdaptor, crow::Crow<>>::handle_header() Unexecuted instantiation: crow::Connection<crow::SocketAdaptor, crow::Crow<>>::handle_header() |
146 | | |
147 | | void handle() |
148 | 0 | { |
149 | | // TODO(EDev): cancel_deadline_timer should be looked into, it might be a good idea to add it to handle_url() and then restart the timer once everything passes |
150 | 0 | cancel_deadline_timer(); |
151 | 0 | bool is_invalid_request = false; |
152 | 0 | add_keep_alive_ = false; |
153 | | |
154 | | // Create context |
155 | 0 | ctx_ = detail::context<Middlewares...>(); |
156 | 0 | req_.middleware_context = static_cast<void*>(&ctx_); |
157 | 0 | req_.middleware_container = static_cast<void*>(middlewares_); |
158 | 0 | req_.io_context = &adaptor_.get_io_context(); |
159 | 0 | req_.remote_ip_address = adaptor_.address(); |
160 | 0 | add_keep_alive_ = req_.keep_alive; |
161 | 0 | close_connection_ = req_.close_connection; |
162 | |
|
163 | 0 | if (req_.check_version(1, 1)) // HTTP/1.1 |
164 | 0 | { |
165 | 0 | if (!req_.headers.count("host")) |
166 | 0 | { |
167 | 0 | is_invalid_request = true; |
168 | 0 | res = response(400); |
169 | 0 | } |
170 | 0 | else if (req_.upgrade && req_.method != HTTPMethod::Options) |
171 | 0 | { |
172 | | // h2 or h2c headers |
173 | 0 | if (req_.get_header_value("upgrade").find("h2")==0) |
174 | 0 | { |
175 | | // TODO(ipkn): HTTP/2 |
176 | | // currently, ignore upgrade header |
177 | 0 | } |
178 | 0 | else |
179 | 0 | { |
180 | |
|
181 | 0 | detail::middleware_call_helper<detail::middleware_call_criteria_only_global, |
182 | 0 | 0, decltype(ctx_), decltype(*middlewares_)>({}, *middlewares_, req_, res, ctx_); |
183 | 0 | close_connection_ = true; |
184 | 0 | handler_->handle_upgrade(req_, res, std::move(adaptor_)); |
185 | 0 | return; |
186 | 0 | } |
187 | 0 | } |
188 | 0 | } |
189 | | |
190 | 0 | CROW_LOG_INFO << "Request: " << utility::lexical_cast<std::string>(adaptor_.remote_endpoint()) << " " << this << " HTTP/" << (char)(req_.http_ver_major + '0') << "." << (char)(req_.http_ver_minor + '0') << ' ' << method_name(req_.method) << " " << req_.url; |
191 | | |
192 | |
|
193 | 0 | need_to_call_after_handlers_ = false; |
194 | 0 | if (!is_invalid_request) |
195 | 0 | { |
196 | 0 | res.complete_request_handler_ = nullptr; |
197 | 0 | auto self = this->shared_from_this(); |
198 | 0 | res.is_alive_helper_ = [self]() -> bool { |
199 | 0 | return self->adaptor_.is_open(); |
200 | 0 | }; Unexecuted instantiation: crow::Connection<crow::UnixSocketAdaptor, crow::Crow<>>::handle()::{lambda()#1}::operator()() constUnexecuted instantiation: crow::Connection<crow::SocketAdaptor, crow::Crow<>>::handle()::{lambda()#1}::operator()() const |
201 | |
|
202 | 0 | detail::middleware_call_helper<detail::middleware_call_criteria_only_global, |
203 | 0 | 0, decltype(ctx_), decltype(*middlewares_)>({}, *middlewares_, req_, res, ctx_); |
204 | |
|
205 | 0 | if (!res.completed_) |
206 | 0 | { |
207 | 0 | res.complete_request_handler_ = [self] { |
208 | 0 | self->complete_request(); |
209 | 0 | }; Unexecuted instantiation: crow::Connection<crow::UnixSocketAdaptor, crow::Crow<>>::handle()::{lambda()#2}::operator()() constUnexecuted instantiation: crow::Connection<crow::SocketAdaptor, crow::Crow<>>::handle()::{lambda()#2}::operator()() const |
210 | 0 | need_to_call_after_handlers_ = true; |
211 | 0 | handler_->handle(req_, res, routing_handle_result_); |
212 | 0 | if (add_keep_alive_) |
213 | 0 | res.set_header("connection", "Keep-Alive"); |
214 | 0 | } |
215 | 0 | else |
216 | 0 | { |
217 | 0 | complete_request(); |
218 | 0 | } |
219 | 0 | } |
220 | 0 | else |
221 | 0 | { |
222 | 0 | complete_request(); |
223 | 0 | } |
224 | 0 | } Unexecuted instantiation: crow::Connection<crow::UnixSocketAdaptor, crow::Crow<>>::handle() Unexecuted instantiation: crow::Connection<crow::SocketAdaptor, crow::Crow<>>::handle() |
225 | | |
226 | | /// Call the after handle middleware and send the write the response to the connection. |
227 | | void complete_request() |
228 | 0 | { |
229 | 0 | CROW_LOG_INFO << "Response: " << this << ' ' << req_.raw_url << ' ' << res.code << ' ' << close_connection_; |
230 | 0 | res.is_alive_helper_ = nullptr; |
231 | |
|
232 | 0 | if (need_to_call_after_handlers_) |
233 | 0 | { |
234 | 0 | need_to_call_after_handlers_ = false; |
235 | | |
236 | | // call all after_handler of middlewares |
237 | 0 | detail::after_handlers_call_helper< |
238 | 0 | detail::middleware_call_criteria_only_global, |
239 | 0 | (static_cast<int>(sizeof...(Middlewares)) - 1), |
240 | 0 | decltype(ctx_), |
241 | 0 | decltype(*middlewares_)>({}, *middlewares_, ctx_, req_, res); |
242 | 0 | } |
243 | | #ifdef CROW_ENABLE_COMPRESSION |
244 | | if (!res.body.empty() && handler_->compression_used()) |
245 | | { |
246 | | std::string accept_encoding = req_.get_header_value("Accept-Encoding"); |
247 | | if (!accept_encoding.empty() && res.compressed) |
248 | | { |
249 | | switch (handler_->compression_algorithm()) |
250 | | { |
251 | | case compression::DEFLATE: |
252 | | if (accept_encoding.find("deflate") != std::string::npos) |
253 | | { |
254 | | res.body = compression::compress_string(res.body, compression::algorithm::DEFLATE); |
255 | | res.set_header("Content-Encoding", "deflate"); |
256 | | } |
257 | | break; |
258 | | case compression::GZIP: |
259 | | if (accept_encoding.find("gzip") != std::string::npos) |
260 | | { |
261 | | res.body = compression::compress_string(res.body, compression::algorithm::GZIP); |
262 | | res.set_header("Content-Encoding", "gzip"); |
263 | | } |
264 | | break; |
265 | | default: |
266 | | break; |
267 | | } |
268 | | } |
269 | | } |
270 | | #endif |
271 | |
|
272 | 0 | prepare_buffers(); |
273 | |
|
274 | 0 | if (res.is_static_type()) |
275 | 0 | { |
276 | 0 | do_write_static(); |
277 | 0 | } |
278 | 0 | else |
279 | 0 | { |
280 | 0 | do_write_general(); |
281 | 0 | } |
282 | 0 | } Unexecuted instantiation: crow::Connection<crow::UnixSocketAdaptor, crow::Crow<>>::complete_request() Unexecuted instantiation: crow::Connection<crow::SocketAdaptor, crow::Crow<>>::complete_request() |
283 | | |
284 | | private: |
285 | | void prepare_buffers() |
286 | 0 | { |
287 | 0 | res.complete_request_handler_ = nullptr; |
288 | 0 | res.is_alive_helper_ = nullptr; |
289 | |
|
290 | 0 | if (!adaptor_.is_open()) |
291 | 0 | { |
292 | | //CROW_LOG_DEBUG << this << " delete (socket is closed) " << is_reading << ' ' << is_writing; |
293 | | //delete this; |
294 | 0 | return; |
295 | 0 | } |
296 | 0 | res.write_header_into_buffer(buffers_, content_length_, add_keep_alive_, server_name_); |
297 | 0 | } Unexecuted instantiation: crow::Connection<crow::UnixSocketAdaptor, crow::Crow<>>::prepare_buffers() Unexecuted instantiation: crow::Connection<crow::SocketAdaptor, crow::Crow<>>::prepare_buffers() |
298 | | |
299 | | void do_write_static() |
300 | 0 | { |
301 | 0 | asio::write(adaptor_.socket(), buffers_); |
302 | |
|
303 | 0 | if (res.file_info.statResult == 0) |
304 | 0 | { |
305 | 0 | std::ifstream is(res.file_info.path.c_str(), std::ios::in | std::ios::binary); |
306 | 0 | std::vector<asio::const_buffer> buffers{1}; |
307 | 0 | char buf[16384]; |
308 | 0 | is.read(buf, sizeof(buf)); |
309 | 0 | while (is.gcount() > 0) |
310 | 0 | { |
311 | 0 | buffers[0] = asio::buffer(buf, is.gcount()); |
312 | 0 | error_code ec = do_write_sync(buffers); |
313 | 0 | if (ec) { |
314 | 0 | CROW_LOG_ERROR << ec << " - buffer write error happened while sending content of file " |
315 | 0 | << res.file_info.path << ". Writing stopped premature."; |
316 | 0 | break; |
317 | 0 | } |
318 | 0 | is.read(buf, sizeof(buf)); |
319 | 0 | } |
320 | 0 | } |
321 | 0 | if (close_connection_) |
322 | 0 | { |
323 | 0 | adaptor_.shutdown_readwrite(); |
324 | 0 | adaptor_.close(); |
325 | 0 | CROW_LOG_DEBUG << this << " from write (static)"; |
326 | 0 | } |
327 | |
|
328 | 0 | res.end(); |
329 | 0 | res.clear(); |
330 | 0 | buffers_.clear(); |
331 | 0 | parser_.clear(); |
332 | 0 | } Unexecuted instantiation: crow::Connection<crow::UnixSocketAdaptor, crow::Crow<>>::do_write_static() Unexecuted instantiation: crow::Connection<crow::SocketAdaptor, crow::Crow<>>::do_write_static() |
333 | | |
334 | | void do_write_general() |
335 | 0 | { |
336 | 0 | error_code ec; |
337 | 0 | if (res.body.length() < res_stream_threshold_) |
338 | 0 | { |
339 | 0 | res_body_copy_.swap(res.body); |
340 | 0 | buffers_.emplace_back(res_body_copy_.data(), res_body_copy_.size()); |
341 | |
|
342 | 0 | ec = do_write_sync(buffers_); |
343 | 0 | if (ec) { |
344 | 0 | CROW_LOG_ERROR << ec << " - buffer write error happened while sending response. Writing stopped premature."; |
345 | 0 | } |
346 | 0 | if (need_to_start_read_after_complete_) |
347 | 0 | { |
348 | 0 | need_to_start_read_after_complete_ = false; |
349 | 0 | start_deadline(); |
350 | 0 | do_read(); |
351 | 0 | } |
352 | 0 | } |
353 | 0 | else |
354 | 0 | { |
355 | 0 | asio::write(adaptor_.socket(), buffers_,ec); // Write the response start / headers |
356 | 0 | if (ec) { |
357 | 0 | CROW_LOG_ERROR << ec << "- buffer write error happened while sending response start / headers. Writing stopped premature."; |
358 | 0 | } |
359 | 0 | cancel_deadline_timer(); |
360 | 0 | if (res.body.length() > 0) |
361 | 0 | { |
362 | 0 | std::vector<asio::const_buffer> buffers{1}; |
363 | 0 | const uint8_t* data = reinterpret_cast<const uint8_t*>(res.body.data()); |
364 | 0 | size_t length = res.body.length(); |
365 | 0 | for (size_t transferred = 0; transferred < length;) |
366 | 0 | { |
367 | 0 | size_t to_transfer = CROW_MIN(16384UL, length - transferred); |
368 | 0 | buffers[0] = asio::const_buffer(data + transferred, to_transfer); |
369 | 0 | ec = do_write_sync(buffers); |
370 | 0 | if (ec) { |
371 | 0 | CROW_LOG_ERROR << ec << " - " << transferred << " - buffer write error happened while sending response. Writing stopped premature."; |
372 | 0 | break; |
373 | 0 | } |
374 | 0 | transferred += to_transfer; |
375 | 0 | } |
376 | 0 | } |
377 | 0 | if (close_connection_) |
378 | 0 | { |
379 | 0 | adaptor_.shutdown_readwrite(); |
380 | 0 | adaptor_.close(); |
381 | 0 | CROW_LOG_DEBUG << this << " from write (res_stream)"; |
382 | 0 | } |
383 | |
|
384 | 0 | res.end(); |
385 | 0 | res.clear(); |
386 | 0 | buffers_.clear(); |
387 | 0 | parser_.clear(); |
388 | 0 | } |
389 | 0 | } Unexecuted instantiation: crow::Connection<crow::UnixSocketAdaptor, crow::Crow<>>::do_write_general() Unexecuted instantiation: crow::Connection<crow::SocketAdaptor, crow::Crow<>>::do_write_general() |
390 | | |
391 | | void do_read() |
392 | 0 | { |
393 | 0 | auto self = this->shared_from_this(); |
394 | 0 | adaptor_.socket().async_read_some( |
395 | 0 | asio::buffer(buffer_), |
396 | 0 | [self](const error_code& ec, std::size_t bytes_transferred) { |
397 | 0 | bool error_while_reading = true; |
398 | 0 | if (!ec) |
399 | 0 | { |
400 | 0 | bool ret = self->parser_.feed(self->buffer_.data(), bytes_transferred); |
401 | 0 | if (ret && self->adaptor_.is_open()) |
402 | 0 | { |
403 | 0 | error_while_reading = false; |
404 | 0 | } |
405 | 0 | } |
406 | |
|
407 | 0 | if (error_while_reading) |
408 | 0 | { |
409 | 0 | self->cancel_deadline_timer(); |
410 | 0 | self->parser_.done(); |
411 | 0 | self->adaptor_.shutdown_read(); |
412 | 0 | self->adaptor_.close(); |
413 | 0 | CROW_LOG_DEBUG << self << " from read(1) with description: \"" << http_errno_description(static_cast<http_errno>(self->parser_.http_errno)) << '\"'; |
414 | 0 | } |
415 | 0 | else if (self->close_connection_) |
416 | 0 | { |
417 | 0 | self->cancel_deadline_timer(); |
418 | 0 | self->parser_.done(); |
419 | | // adaptor will close after write |
420 | 0 | } |
421 | 0 | else if (!self->need_to_call_after_handlers_) |
422 | 0 | { |
423 | 0 | self->start_deadline(); |
424 | 0 | self->do_read(); |
425 | 0 | } |
426 | 0 | else |
427 | 0 | { |
428 | | // res will be completed later by user |
429 | 0 | self->need_to_start_read_after_complete_ = true; |
430 | 0 | } |
431 | 0 | }); Unexecuted instantiation: crow::Connection<crow::UnixSocketAdaptor, crow::Crow<>>::do_read()::{lambda(std::__1::error_code const&, unsigned long)#1}::operator()(std::__1::error_code const&, unsigned long) constUnexecuted instantiation: crow::Connection<crow::SocketAdaptor, crow::Crow<>>::do_read()::{lambda(std::__1::error_code const&, unsigned long)#1}::operator()(std::__1::error_code const&, unsigned long) const |
432 | 0 | } Unexecuted instantiation: crow::Connection<crow::UnixSocketAdaptor, crow::Crow<>>::do_read() Unexecuted instantiation: crow::Connection<crow::SocketAdaptor, crow::Crow<>>::do_read() |
433 | | |
434 | | void do_write() |
435 | | { |
436 | | auto self = this->shared_from_this(); |
437 | | asio::async_write( |
438 | | adaptor_.socket(), buffers_, |
439 | | [self](const error_code& ec, std::size_t /*bytes_transferred*/) { |
440 | | self->res.clear(); |
441 | | self->res_body_copy_.clear(); |
442 | | if (!self->continue_requested) |
443 | | { |
444 | | self->parser_.clear(); |
445 | | } |
446 | | else |
447 | | { |
448 | | self->continue_requested = false; |
449 | | } |
450 | | |
451 | | if (!ec) |
452 | | { |
453 | | if (self->close_connection_) |
454 | | { |
455 | | self->adaptor_.shutdown_write(); |
456 | | self->adaptor_.close(); |
457 | | CROW_LOG_DEBUG << self << " from write(1)"; |
458 | | } |
459 | | } |
460 | | else |
461 | | { |
462 | | CROW_LOG_DEBUG << self << " from write(2)"; |
463 | | } |
464 | | }); |
465 | | } |
466 | | |
467 | | inline error_code do_write_sync(std::vector<asio::const_buffer>& buffers) |
468 | 0 | { |
469 | 0 | error_code ec; |
470 | 0 | asio::write(adaptor_.socket(), buffers, ec); |
471 | 0 | if (ec) |
472 | 0 | { |
473 | | // CROW_LOG_ERROR << ec << " - happened while sending buffers"; |
474 | 0 | CROW_LOG_DEBUG << this << " from write (sync)(2)"; |
475 | 0 | } |
476 | |
|
477 | 0 | this->res.clear(); |
478 | 0 | this->res_body_copy_.clear(); |
479 | 0 | if (this->continue_requested) |
480 | 0 | { |
481 | 0 | this->continue_requested = false; |
482 | 0 | } |
483 | 0 | else |
484 | 0 | { |
485 | 0 | this->parser_.clear(); |
486 | 0 | } |
487 | |
|
488 | 0 | return ec; |
489 | 0 | } Unexecuted instantiation: crow::Connection<crow::UnixSocketAdaptor, crow::Crow<>>::do_write_sync(std::__1::vector<asio::const_buffer, std::__1::allocator<asio::const_buffer> >&) Unexecuted instantiation: crow::Connection<crow::SocketAdaptor, crow::Crow<>>::do_write_sync(std::__1::vector<asio::const_buffer, std::__1::allocator<asio::const_buffer> >&) |
490 | | |
491 | | void cancel_deadline_timer() |
492 | 0 | { |
493 | 0 | CROW_LOG_DEBUG << this << " timer cancelled: " << &task_timer_ << ' ' << task_id_; |
494 | 0 | task_timer_.cancel(task_id_); |
495 | 0 | } Unexecuted instantiation: crow::Connection<crow::UnixSocketAdaptor, crow::Crow<>>::cancel_deadline_timer() Unexecuted instantiation: crow::Connection<crow::SocketAdaptor, crow::Crow<>>::cancel_deadline_timer() |
496 | | |
497 | | void start_deadline(/*int timeout = 5*/) |
498 | 0 | { |
499 | 0 | cancel_deadline_timer(); |
500 | |
|
501 | 0 | auto self = this->shared_from_this(); |
502 | 0 | task_id_ = task_timer_.schedule([self] { |
503 | 0 | if (!self->adaptor_.is_open()) |
504 | 0 | { |
505 | 0 | return; |
506 | 0 | } |
507 | 0 | self->adaptor_.shutdown_readwrite(); |
508 | 0 | self->adaptor_.close(); |
509 | 0 | }); Unexecuted instantiation: crow::Connection<crow::UnixSocketAdaptor, crow::Crow<>>::start_deadline()::{lambda()#1}::operator()() constUnexecuted instantiation: crow::Connection<crow::SocketAdaptor, crow::Crow<>>::start_deadline()::{lambda()#1}::operator()() const |
510 | 0 | CROW_LOG_DEBUG << this << " timer added: " << &task_timer_ << ' ' << task_id_; |
511 | 0 | } Unexecuted instantiation: crow::Connection<crow::UnixSocketAdaptor, crow::Crow<>>::start_deadline() Unexecuted instantiation: crow::Connection<crow::SocketAdaptor, crow::Crow<>>::start_deadline() |
512 | | |
513 | | private: |
514 | | Adaptor adaptor_; |
515 | | Handler* handler_; |
516 | | |
517 | | std::array<char, 4096> buffer_; |
518 | | |
519 | | HTTPParser<Connection> parser_; |
520 | | std::unique_ptr<routing_handle_result> routing_handle_result_; |
521 | | request& req_; |
522 | | response res; |
523 | | |
524 | | bool close_connection_ = false; |
525 | | |
526 | | const std::string& server_name_; |
527 | | std::vector<asio::const_buffer> buffers_; |
528 | | |
529 | | std::string content_length_; |
530 | | std::string date_str_; |
531 | | std::string res_body_copy_; |
532 | | |
533 | | detail::task_timer::identifier_type task_id_{}; |
534 | | |
535 | | bool continue_requested{}; |
536 | | bool need_to_call_after_handlers_{}; |
537 | | bool need_to_start_read_after_complete_{}; |
538 | | bool add_keep_alive_{}; |
539 | | |
540 | | std::tuple<Middlewares...>* middlewares_; |
541 | | detail::context<Middlewares...> ctx_; |
542 | | |
543 | | std::function<std::string()>& get_cached_date_str; |
544 | | detail::task_timer& task_timer_; |
545 | | |
546 | | size_t res_stream_threshold_; |
547 | | |
548 | | std::atomic<unsigned int>& queue_length_; |
549 | | }; |
550 | | |
551 | | } // namespace crow |