Line data Source code
1 : #include "server_connection.hpp"
2 : #include "server_base.hpp"
3 : #include "request.hpp"
4 : #include "response_observer.hpp"
5 : #include "../../asio/sockets/tcp_socket.hpp"
6 : #include "../../asio/sockets/unix_socket.hpp"
7 : #include "../../util/logger.hpp"
8 : #include <boost/asio/bind_cancellation_slot.hpp>
9 : #include <boost/asio/defer.hpp>
10 : #include <boost/asio/post.hpp>
11 :
12 : namespace thinger::http {
13 :
14 : namespace {
15 :
16 : // The Connection header of a response head, written as the head is serialized: whatever
17 : // decided the connection closes after the response, the head says so. A protocol switch
18 : // keeps the Connection header set for it (Upgrade)
19 23259 : void announce_disposition(const http_stream& stream, http_response& head) {
20 23259 : if (head.get_status() == http_response::status::switching_protocols) return;
21 19589 : head.set_keep_alive(!stream.reason());
22 : }
23 :
24 : // Lingering close once the server shuts down: brief, not to hold it
25 : constexpr std::chrono::milliseconds shutdown_linger_timeout{500};
26 :
27 : // Stop sending on the connection, reading on: TCP (TLS included) and Unix sockets
28 902 : bool shutdown_send(asio::socket& socket) {
29 902 : if (auto* tcp = dynamic_cast<asio::tcp_socket*>(&socket)) return tcp->shutdown_send();
30 246 : if (auto* local = dynamic_cast<asio::unix_socket*>(&socket)) return local->shutdown_send();
31 3 : return false;
32 : }
33 :
34 : // Read what arrives to drop it: from the TCP stream itself under TLS, whose records are
35 : // not decrypted (nor read by the TLS stream, whose reads were cancelled)
36 684536 : awaitable<io_result> read_to_drop(asio::socket& socket, uint8_t* buffer, size_t size) {
37 : if (auto* tcp = dynamic_cast<asio::tcp_socket*>(&socket)) {
38 : co_return co_await tcp->get_socket().async_read_some(boost::asio::buffer(buffer, size),
39 : use_nothrow_awaitable);
40 : }
41 : co_return co_await socket.read_some(buffer, size);
42 1369072 : }
43 :
44 : }
45 :
46 23792 : server_connection::server_connection(std::shared_ptr<asio::socket> socket,
47 23792 : std::shared_ptr<const connection_options> options)
48 23792 : : socket_(std::move(socket))
49 : // A member, called only while this lives. It does not keep the connection alive: once
50 : // neither the read loop nor a write holds it (e.g. the read loop stopped with a response
51 : // left unfinished), it is released and the socket closed
52 23792 : , timeout_timer_(socket_->get_io_context().get_executor(), [this] {
53 242 : if (auto self = weak_from_this().lock()) self->deadline_expired();
54 242 : })
55 47584 : , options_(options ? std::move(options) : std::make_shared<const connection_options>()) {
56 23792 : timeout_ = options_->idle_timeout;
57 23792 : LOG_DEBUG("created http server connection");
58 23792 : }
59 :
60 23792 : server_connection::~server_connection() {
61 23792 : LOG_DEBUG("releasing http server connection");
62 : // The requests may outlive the connection, with their streams
63 34420 : for (; !request_queue_.empty(); request_queue_.pop_front()) request_queue_.front()->detach();
64 23792 : }
65 :
66 23786 : void server_connection::track(const std::shared_ptr<connection_tracker>& tracker) {
67 23786 : tracked_connection::track(tracker, weak_from_this(), socket_->get_io_context(), connection_type::http);
68 23786 : }
69 :
70 23792 : void server_connection::start() {
71 23792 : if (running_) return;
72 : // Accepted while the server shuts down (e.g. it was in a TLS handshake): nothing is
73 : // waiting for it yet
74 23792 : if (auto tracker = this->tracker(); tracker && tracker->current_phase() != connection_tracker::phase::serving) {
75 2 : untrack();
76 2 : socket_->close();
77 2 : return;
78 23792 : }
79 23790 : running_ = true;
80 :
81 : // Its first request starts now: a client that sends nothing is bounded by its header deadline
82 23790 : last_activity_ = request_start_ = clock::now();
83 23790 : reading_head_ = true;
84 23790 : arm_deadline();
85 :
86 : // The read loop runs the handlers of the requests: bound to the signal their scopes emit
87 : // (see start_request())
88 23790 : co_spawn(socket_->get_io_context(),
89 71370 : [self = shared_from_this()]() -> awaitable<void> {
90 : co_await self->read_loop();
91 47580 : },
92 47580 : boost::asio::bind_cancellation_slot(handler_signal_.slot(), detached));
93 : // The peer watcher starts once a handler yields first (see wake_watcher())
94 : }
95 :
96 6140 : void server_connection::close() {
97 6140 : running_ = false;
98 6140 : timeout_timer_.cancel();
99 6140 : if (reader_wake_) reader_wake_->set();
100 6140 : stop_watcher();
101 6140 : socket_->close();
102 : // Nothing left to drain, even if the connection is still referenced
103 6140 : untrack();
104 6140 : }
105 :
106 5102 : void server_connection::close_after(const http_stream& stream) {
107 5102 : if (stream.input_pending()) {
108 897 : linger();
109 : } else {
110 4205 : close();
111 : }
112 5102 : }
113 :
114 929 : void server_connection::linger() {
115 1005 : if (lingering_) return;
116 929 : size_t max_bytes = options_->linger_max_bytes;
117 929 : std::chrono::milliseconds timeout = options_->linger_timeout;
118 : // The server shuts down: briefly, so it does not hold the shutdown
119 929 : if (frame_watch_ & watch_draining) timeout = std::min(timeout, shutdown_linger_timeout);
120 929 : if (max_bytes == 0 || timeout.count() <= 0 || !socket_->is_open() || !shutdown_send(*socket_)) {
121 76 : close();
122 76 : return;
123 : }
124 : // The connection stops serving: no more requests, nor its timeout. Whatever reads it ends
125 : // now (the read loop, or a handler still reading the body, which reads nothing more), so
126 : // only the graceful close reads it from now on
127 853 : lingering_ = true;
128 853 : running_ = false;
129 853 : timeout_timer_.cancel();
130 853 : if (reader_wake_) reader_wake_->set();
131 853 : stop_watcher();
132 853 : socket_->cancel();
133 853 : co_spawn(socket_->get_io_context(),
134 2559 : [self = shared_from_this(), max_bytes, timeout]() -> awaitable<void> {
135 : co_await self->drop_input(max_bytes, timeout);
136 1706 : },
137 : detached);
138 : }
139 :
140 853 : awaitable<void> server_connection::drop_input(size_t max_bytes, std::chrono::milliseconds timeout) {
141 : // Into the connection buffer, which the read loop no longer uses: the memory of a
142 : // connection does not grow while it drops input
143 : size_t dropped = 0;
144 853 : auto drop = [&]() -> awaitable<void> {
145 : while (dropped < max_bytes) {
146 : auto [ec, bytes] = co_await read_to_drop(*socket_, buffer_, std::min(MAX_BUFFER_SIZE, max_bytes - dropped));
147 : if (ec) co_return; // the client closed (or reset) the connection
148 : dropped += bytes;
149 : }
150 1706 : };
151 : boost::asio::steady_timer timer(socket_->get_io_context(), timeout);
152 : auto result = co_await (timer.async_wait(use_nothrow_awaitable) || drop());
153 : LOG_DEBUG("http server connection closed gracefully: {} bytes dropped{}", dropped,
154 : result.index() == 0 ? ", until the timeout" : dropped >= max_bytes ? ", up to the limit" : "");
155 : close();
156 1706 : }
157 :
158 23790 : awaitable<void> server_connection::read_loop() {
159 : auto self = shared_from_this();
160 :
161 : // Headers only: the handler layer reads the body
162 : request_parser_.set_headers_only(true);
163 :
164 : size_t buffered = 0; // bytes of valid data in buffer_
165 :
166 : while (running_ && socket_->is_open()) {
167 : // A pipelined request, already read with the one before it. The request before it ended
168 : // (its stream may be gone): none is in progress until this one starts
169 : bool pipelined = buffered > 0;
170 : in_progress_ = nullptr;
171 : // Not while the responses back up (the client does not read them): they would pile up.
172 : // Then from the top: the loop ends if the connection stopped meanwhile
173 : if (reading_paused()) [[unlikely]] {
174 : co_await wait_output();
175 : continue;
176 : }
177 : if (buffered == 0) {
178 : auto [ec, bytes] = co_await socket_->read_some(buffer_, MAX_BUFFER_SIZE);
179 : // (or stopped meanwhile: its head was answered at its deadline)
180 : if (ec || !running_) break;
181 : extend_timeout();
182 : buffered = bytes;
183 : }
184 : head_started(pipelined);
185 :
186 : uint8_t* begin = buffer_;
187 : uint8_t* end = buffer_ + buffered;
188 : boost::tribool result = request_parser_.parse(begin, end);
189 : if (boost::indeterminate(result)) {
190 : // Every byte went to the parser: more are needed, within the header deadline
191 : buffered = 0;
192 : head_incomplete();
193 : continue;
194 : }
195 : reading_head_ = false;
196 : if (!result) {
197 : reject_request();
198 : break;
199 : }
200 :
201 : auto [stream, req] = start_request(self, begin, static_cast<size_t>(end - begin));
202 :
203 : // The client is watched while the request is handled, and until its response starts
204 : watch(stream);
205 :
206 : // The handler decides how to read the body
207 : if (handler_) {
208 : co_await handler_(req);
209 : // Not once the response closed the connection (or it was taken over): the
210 : // timer would be armed just to be cancelled
211 : extend_timeout();
212 : }
213 :
214 : // A response sent later, from a copy of the response, may still take over the
215 : // connection: wait for it to start before reading what follows this request
216 : if (!stream->responded()) co_await wait_response(*stream);
217 :
218 : // The read loop reads the socket again, alone: a read of the watcher in progress
219 : // (over TLS) ends first
220 : unwatch();
221 : while (watch_reading_) {
222 : watch_idle_->reset();
223 : co_await watch_idle_->wait();
224 : }
225 :
226 : // Read-ahead bytes the request did not consume belong to whatever follows it (they
227 : // may come from later socket reads, e.g. after a chunked body)
228 : if (stream->takes_over()) {
229 : hand_over_reader(*stream, *req);
230 : co_return;
231 : }
232 :
233 : // Without keep-alive, reading stops after this request. The leftover stays with the
234 : // request: its handler may still be reading the body (e.g. the request was answered
235 : // by its timeout)
236 : if (stream->disposition() == detail::after_response::close || !keep_pipelined(*req, buffered)) {
237 : // The response ended before the connection was to close (e.g. a body left unread
238 : // turned out too large to drop): close it now, gracefully if the body still comes.
239 : // A response not ended yet closes it once it ends
240 : linger_unread(*stream);
241 : break;
242 : }
243 : }
244 :
245 : stop_reading();
246 47580 : }
247 :
248 5196 : void server_connection::linger_unread(const http_stream& stream) {
249 5196 : if (request_queue_.empty() && stream.input_pending()) linger();
250 5196 : }
251 :
252 18032 : void server_connection::stop_reading() {
253 18032 : running_ = false;
254 18032 : reader_stopped_ = true;
255 18032 : in_progress_ = nullptr;
256 18032 : reading_head_ = false;
257 : // A response still waiting for the socket stays bounded by its write deadline: the client
258 : // may never read it (see frame_written() for those written afterwards)
259 18032 : if (write_waits_ && !lingering_ && socket_->is_open()) {
260 787 : arm_deadline();
261 : } else {
262 17245 : timeout_timer_.cancel();
263 : }
264 18032 : stop_watcher();
265 :
266 : // Draining, with every response written: done now, even if something still holds the
267 : // connection (e.g. a copy of the request). Unless it closes gracefully already
268 18032 : if ((frame_watch_ & watch_draining) && request_queue_.empty() && !lingering_) close();
269 18032 : }
270 :
271 23512 : std::pair<std::shared_ptr<http_stream>, std::shared_ptr<request>> server_connection::start_request(
272 : const std::shared_ptr<server_connection>& self, const uint8_t* read_ahead, size_t read_ahead_size) {
273 23512 : auto http_req = request_parser_.consume_request();
274 23512 : http_req->set_ssl(socket_->is_secure());
275 :
276 23512 : auto stream = std::make_shared<http_stream>(++request_id_, *http_req, socket_->get_io_context().get_executor());
277 : // Its handler runs on the read loop (which awaits handler_), one request at a time: its
278 : // scope interrupts it through the signal of the read loop
279 23512 : stream->bind_handler(&handler_signal_);
280 23512 : in_progress_ = stream.get();
281 : // Its body is on the connection until read to its end (where it ends may be unknown),
282 : // unless it arrived whole with the head, maybe with what follows it
283 46461 : bool input_pending = !http_req->has_valid_framing() || http_req->is_chunked_transfer() ||
284 22949 : read_ahead_size < http_req->pending_body_size();
285 23512 : stream->set_input_pending(input_pending, !input_pending && read_ahead_size > http_req->pending_body_size());
286 : // Read within the request deadline, which its route may change (see request_timed_out()); none
287 : // for a request received with its head
288 23512 : request_deadline_ = input_pending ? options_->request_timeout : std::chrono::milliseconds{0};
289 23512 : read_bounded_ = false;
290 23512 : if (input_pending) arm_deadline();
291 :
292 : // The client may wait for 100 Continue before sending the body: sent once the body is
293 : // read, unless the client already started sending it
294 23512 : if (http_req->get_expectation() == http_request::expectation::continue_100 &&
295 23512 : http_req->has_pending_body() && read_ahead_size == 0) [[unlikely]] {
296 234 : stream->set_continue(http_stream::continue_state::pending);
297 234 : frame_watch_ |= watch_continue;
298 : }
299 :
300 : // Queued in order, for pipelining
301 23512 : request_queue_.push_back(stream);
302 :
303 23512 : http_req->log("SERVER REQUEST", options_->logging);
304 :
305 23512 : auto req = std::make_shared<request>(make_source(*stream), stream, std::move(http_req));
306 23512 : if (read_ahead_size > 0) {
307 4478 : req->set_read_ahead(read_ahead, read_ahead_size);
308 : }
309 47024 : return {std::move(stream), std::move(req)};
310 23512 : }
311 :
312 372 : void server_connection::reject_request() {
313 : // Bad request, or a header section over the limits
314 372 : auto status = http_response::status::bad_request;
315 372 : if (request_parser_.header_section_too_large()) {
316 54 : LOG_DEBUG("http request header section too large");
317 54 : status = http_response::status::request_header_fields_too_large;
318 : } else {
319 318 : LOG_DEBUG("invalid http request");
320 : }
321 : // The rest of a header section too large may still be arriving (big cookies, say), and its
322 : // client is worth an answer; not that of a request that is not HTTP, as Go does
323 372 : answer_and_close(status, detail::close_reason::body_error,
324 : status == http_response::status::request_header_fields_too_large);
325 372 : }
326 :
327 4315 : void server_connection::hand_over_reader(http_stream& stream, request& req) {
328 4315 : auto leftover = req.take_read_ahead();
329 4315 : stream.takeover_reader_stopped(std::string(leftover.begin(), leftover.end()));
330 4315 : in_progress_ = nullptr;
331 4315 : complete_takeover(stream);
332 4315 : }
333 :
334 13339 : bool server_connection::keep_pipelined(request& req, size_t& buffered) {
335 : // The leftover is at most what was read at once: the connection buffer, or the body
336 : // reader framing reads
337 13339 : auto leftover = req.take_read_ahead();
338 : static_assert(body_reader::framing_read_size <= MAX_BUFFER_SIZE,
339 : "body framing reads must fit in the connection buffer, or the leftover is dropped");
340 13339 : if (leftover.size() > MAX_BUFFER_SIZE) {
341 0 : LOG_ERROR("pipelined data exceeds the connection buffer");
342 0 : return false;
343 : }
344 13339 : if (!leftover.empty()) {
345 3192 : std::memcpy(buffer_, leftover.data(), leftover.size());
346 : }
347 13339 : buffered = leftover.size();
348 13339 : return true;
349 13339 : }
350 :
351 51 : awaitable<void> server_connection::wait_response(const http_stream& stream) {
352 : // The watcher still watches the client meanwhile (see watch_peer()): a client resetting
353 : // the connection before a late response closes it now, not at the connection timeout
354 : frame_watch_ |= watch_response_start;
355 : if (!reader_wake_) reader_wake_.emplace(socket_->get_io_context().get_executor());
356 : while (!stream.responded() && running_ && socket_->is_open()) {
357 : reader_wake_->reset(); // woken by the next frame, not by one before
358 : co_await reader_wake_->wait();
359 : }
360 : frame_watch_ &= ~watch_response_start;
361 102 : }
362 :
363 2197 : awaitable<void> server_connection::wait_output() {
364 : // Within the deadlines of the connection: the write deadline while the front response waits
365 : // for the socket, the idle one otherwise. Its close (or a stop) wakes it
366 : output_waited_ = true;
367 : if (!reader_wake_) reader_wake_.emplace(socket_->get_io_context().get_executor());
368 : while (output_backed_up() && running_ && socket_->is_open()) {
369 : reader_wake_->reset();
370 : co_await reader_wake_->wait();
371 : }
372 : output_waited_ = false;
373 4394 : }
374 :
375 23512 : void server_connection::watch(const std::shared_ptr<http_stream>& stream) {
376 23512 : watched_ = stream;
377 : // The watcher wakes once the handler yields, unless the response ended meanwhile: a
378 : // handler answering at once costs a deferred call (on this thread, no lock), not a round
379 : // of the watcher
380 23512 : boost::asio::defer(socket_->get_io_context(), [self = shared_from_this(), watched = stream.get()] {
381 23105 : if (self->watched_.get() == watched && !watched->response_ended()) self->wake_watcher();
382 23105 : });
383 23512 : }
384 :
385 2886 : void server_connection::wake_watcher() {
386 2886 : if (watch_wake_) {
387 127 : watch_wake_->set();
388 127 : return;
389 : }
390 : // Its first need: a connection whose handlers all answer at once never starts it. It runs
391 : // while the read loop runs (stopped through its slot, see unwatch())
392 2759 : auto executor = socket_->get_io_context().get_executor();
393 2759 : watch_wake_.emplace(executor);
394 2759 : watch_idle_.emplace(executor);
395 2759 : co_spawn(socket_->get_io_context(),
396 8277 : [self = shared_from_this()]() -> awaitable<void> {
397 : co_await self->watch_loop();
398 5518 : },
399 5518 : boost::asio::bind_cancellation_slot(watch_stop_.slot(), detached));
400 2759 : }
401 :
402 52187 : void server_connection::unwatch() {
403 52187 : watched_ = nullptr;
404 52187 : if (watch_waiting_) watch_stop_.emit(boost::asio::cancellation_type::terminal);
405 52187 : }
406 :
407 29337 : void server_connection::stop_watcher() {
408 29337 : unwatch();
409 29337 : if (watch_wake_) watch_wake_->set();
410 29337 : }
411 :
412 3654 : bool server_connection::watching(const http_stream& stream) const {
413 : // Not a stream taking over the connection: its socket goes to a new owner
414 3654 : return watched_.get() == &stream && running_ && !lingering_ && socket_->is_open() && !stream.takes_over();
415 : }
416 :
417 2759 : awaitable<void> server_connection::watch_loop() {
418 : // Stopped through its slot (see unwatch()), which ends the wait in progress, and nothing else
419 : co_await boost::asio::this_coro::throw_if_cancelled(false);
420 : while (running_) {
421 : co_await boost::asio::this_coro::reset_cancellation_state();
422 : if (auto stream = watched_) {
423 : co_await watch_peer(*stream);
424 : if (watched_ == stream) watched_ = nullptr;
425 : continue;
426 : }
427 : watch_wake_->reset();
428 : co_await watch_wake_->wait();
429 : }
430 5518 : }
431 :
432 2884 : awaitable<void> server_connection::watch_peer(http_stream& stream) {
433 : // (woken after the handler yields, see watch())
434 : if (!watching(stream) || stream.response_ended()) co_return;
435 :
436 : // The body is read by the request: the socket is read here only once it was read to its
437 : // end (or dropped), never meanwhile
438 : if (stream.input_pending()) {
439 : watch_waiting_ = true;
440 : bool read = co_await stream.wait_input_read();
441 : watch_waiting_ = false;
442 : if (!read || !watching(stream)) co_return;
443 : }
444 : // What follows the request was read along with it (a pipelined request): it stays for
445 : // the next request
446 : if (stream.input_follows()) co_return;
447 :
448 : watch_waiting_ = true;
449 : auto ec = co_await socket_->wait(boost::asio::socket_base::wait_read);
450 : watch_waiting_ = false;
451 : // Stopped, or a socket that cannot wait (e.g. one defined by an application)
452 : if (ec || !watching(stream)) co_return;
453 :
454 : watch_reading_ = true;
455 : ec = co_await socket_->peer_closed();
456 : watch_reading_ = false;
457 : watch_idle_->set();
458 :
459 : // Data (the next request, or data for a takeover) stays readable from the socket. A
460 : // half-close after the request is no leaving (RFC 9112 section 9.6): its response is
461 : // written, and the connection closed after it. Anything else is the client gone (a
462 : // reset): unless the connection closed meanwhile
463 : if (!ec || ec == boost::asio::error::operation_not_supported || ec == boost::asio::error::operation_aborted) {
464 : co_return;
465 : }
466 : if (ec == boost::asio::error::eof) {
467 : stream.must_close(detail::close_reason::client_asked);
468 : co_return;
469 : }
470 : LOG_DEBUG("http client left while its request was handled: {}", ec.message());
471 : stream.cancel(cancel_reason::client_gone);
472 : if (!lingering_) close();
473 5768 : }
474 :
475 564 : void server_connection::observe_frame(http_stream& stream, http_frame& frame) {
476 : // The head of the response (an interim response is not one): on the server, a response
477 564 : if (frame.kind() == frame_kind::head) {
478 408 : auto& head = static_cast<http_response&>(frame);
479 408 : stream.observer()->head(head.get_status(), !frame.end_stream() && !stream.takes_over());
480 : }
481 564 : }
482 :
483 38973 : void server_connection::frame_written(http_stream& stream, const std::shared_ptr<http_frame>& frame,
484 : const boost::system::error_code& ec) {
485 38973 : bool written = !ec;
486 : // A write the client reset (or whose connection broke) tells that the client is gone
487 38973 : if (ec && (ec == boost::asio::error::connection_reset || ec == boost::asio::error::broken_pipe)) [[unlikely]] {
488 121 : stream.cancel(cancel_reason::client_gone);
489 : }
490 :
491 : // Whoever waits for the frame (a streamed response) may write the next one
492 38973 : frame->notify_written(written);
493 :
494 : // The response ended (or cannot be written anymore), for the response hook
495 38973 : if (auto* observer = stream.observer(); observer && (frame->end_stream() || !written)) [[unlikely]] {
496 813 : observer->ended(!written ? response_outcome::aborted
497 405 : : stream.takes_over() ? response_outcome::taken_over : response_outcome::completed);
498 : }
499 :
500 : // Reset timeout on activity. The timer holds a weak reference: once the read loop stopped
501 : // (the connection closes after this response), only a pending write keeps the connection,
502 : // so a response still unfinished when its queued frames are written (e.g. chunks written
503 : // from detached code after the handler returned) loses the connection then
504 38973 : last_activity_ = clock::now();
505 38973 : arm_deadline();
506 :
507 38973 : if (frame->end_stream()) {
508 23111 : stream.set_response_ended();
509 : // Response of a request taking over the connection: the socket may now belong to
510 : // someone else, never close it from here
511 23111 : if (stream.takes_over()) {
512 4312 : stream.takeover_response_written();
513 4312 : complete_takeover(stream);
514 4312 : return;
515 : }
516 :
517 18799 : if (stream.disposition() == detail::after_response::close) {
518 5438 : if (written) {
519 5102 : close_after(stream);
520 : } else {
521 336 : close();
522 : }
523 13361 : } else if (!written) [[unlikely]] {
524 : // The connection broke (the client reset it, say): closed, so the requests it read
525 : // ahead (pipelined) are not handled for a client gone, as Go and Node do
526 96 : close();
527 : } else {
528 13265 : if (!request_queue_.empty()) {
529 13265 : stream.detach();
530 13265 : request_queue_.pop_front();
531 13265 : output_progressed();
532 : }
533 : }
534 : }
535 : }
536 :
537 46150 : void server_connection::process_output_queue() {
538 85267 : while (!writing_) {
539 103189 : if (request_queue_.empty()) return;
540 64594 : auto stream = request_queue_.front();
541 64594 : if (stream->empty_queue()) return;
542 :
543 39117 : auto frame = stream->current_frame();
544 39117 : stream->pop_frame();
545 :
546 : // The only writer of the Connection header of a response (see announce_disposition())
547 39117 : if (frame->kind() == frame_kind::head) announce_disposition(*stream, static_cast<http_response&>(*frame));
548 :
549 39117 : frame->log("SERVER RESPONSE", options_->logging);
550 39117 : auto* observer = stream->observer();
551 39117 : if (observer) [[unlikely]] observe_frame(*stream, *frame);
552 :
553 39117 : auto& buffers = write_buffers_;
554 39117 : buffers.clear();
555 39117 : frame->fill_buffer(buffers);
556 :
557 : // Most frames fit in the socket send buffer: write them right away, without waiting.
558 : // A write error is left to the read loop, as for a write that waited
559 39117 : boost::system::error_code ec;
560 39117 : size_t written = socket_->write_now(buffers, ec);
561 39117 : if (observer) [[unlikely]] observer->add_bytes(written);
562 39117 : if (written == boost::asio::buffer_size(buffers)) {
563 31450 : frame_written(*stream, frame, {});
564 31450 : continue;
565 : }
566 7667 : if (ec && ec != boost::asio::error::would_block && ec != boost::asio::error::operation_not_supported) {
567 328 : frame_written(*stream, frame, ec);
568 328 : continue;
569 : }
570 :
571 : // Write the rest once the socket accepts it, within the write deadline
572 7339 : asio::socket::consume(buffers, written);
573 7339 : write_started();
574 7339 : co_spawn(socket_->get_io_context(),
575 29356 : [this, self = shared_from_this(), stream = std::move(stream), frame = std::move(frame),
576 7339 : buffers = std::move(buffers)]() mutable -> awaitable<void> {
577 : auto [ec, bytes] = write_in_slices(buffers)
578 13890 : ? co_await socket_->write_slices(buffers, [this]{ write_progress_ = clock::now(); })
579 : : co_await socket_->write(buffers);
580 : write_waits_ = false;
581 : if (auto* observer = stream->observer()) [[unlikely]] observer->add_bytes(bytes);
582 : frame_written(*stream, frame, ec);
583 : writing_ = false;
584 :
585 : process_output_queue();
586 : output_progressed();
587 14678 : },
588 : detached);
589 96372 : }
590 : }
591 :
592 39102 : void server_connection::queue_frame(const std::shared_ptr<http_stream>& stream, std::shared_ptr<http_frame> frame) {
593 39102 : if (frame_watch_) [[unlikely]] watch_frame(*stream);
594 39102 : stream->add_frame(std::move(frame));
595 :
596 39102 : if (request_queue_.empty()) {
597 0 : LOG_ERROR("trying to send response without a pending request!");
598 0 : return;
599 : }
600 :
601 : // Only the front stream writes: responses go in the order of their requests
602 39102 : if (request_queue_.front()->id() == stream->id()) {
603 38805 : process_output_queue();
604 : }
605 : }
606 :
607 558 : void server_connection::watch_frame(http_stream& stream) {
608 : // The waiter wakes up once this call returns, with the frame queued
609 558 : if (frame_watch_ & watch_response_start) reader_wake_->set();
610 :
611 : // A response starting while the connection drains is the last one: its head tells the client
612 558 : if ((frame_watch_ & watch_draining) && !stream.responded() && !stream.takes_over()) {
613 417 : stream.must_close(detail::close_reason::draining);
614 : }
615 :
616 : // A response starting before the 100 Continue its client waits for: the client may send
617 : // the body or not, so where the next request starts is unknown. Not sent anymore, and the
618 : // connection is closed after the response, which tells the client (as Go and Node do)
619 558 : if ((frame_watch_ & watch_continue) && stream.get_continue() == http_stream::continue_state::pending) {
620 84 : frame_watch_ &= ~watch_continue;
621 84 : stream.set_continue(http_stream::continue_state::skipped);
622 84 : if (!stream.takes_over()) stream.must_close(detail::close_reason::continue_skipped);
623 : }
624 558 : }
625 :
626 150 : void server_connection::send_continue(http_stream& stream) {
627 150 : if (stream.get_continue() != http_stream::continue_state::pending || !running_) return;
628 150 : stream.set_continue(http_stream::continue_state::sent);
629 150 : frame_watch_ &= ~watch_continue;
630 : // Queued as the first frame of the stream, before its response: written once the
631 : // responses of the previous requests are
632 150 : stream.add_interim_frame(std::make_shared<detail::continue_frame>());
633 150 : if (!request_queue_.empty() && request_queue_.front().get() == &stream) {
634 150 : process_output_queue();
635 : }
636 : }
637 :
638 681 : void server_connection::shutdown_drain() {
639 681 : if (!tracked() || (frame_watch_ & watch_draining)) return;
640 681 : frame_watch_ |= watch_draining;
641 : // Closing gracefully: its response was written whole, so it does not hold the shutdown
642 681 : if (lingering_) {
643 9 : close();
644 9 : return;
645 : }
646 672 : if (!running_) return;
647 :
648 : // Handling a request: the connection is closed after its response (whose head tells the
649 : // client unless it already started), and the read loop stops after it
650 672 : if (in_progress_) {
651 417 : in_progress_->must_close(detail::close_reason::draining);
652 417 : return;
653 : }
654 :
655 : // Waiting for a request with nothing to write: idle
656 255 : if (request_queue_.empty() && request_parser_.idle()) {
657 207 : LOG_DEBUG("closing an idle http server connection: the server shuts down");
658 207 : close();
659 207 : return;
660 : }
661 :
662 : // A response still being written (the read loop went on to the next request): the
663 : // connection is closed after it. Or part of a request arrived: its response closes it
664 48 : if (!request_queue_.empty()) request_queue_.back()->must_close(detail::close_reason::draining);
665 : }
666 :
667 493 : void server_connection::shutdown_cancel() {
668 : // The handlers still running: that of the request being read, and those of the requests
669 : // waiting for their responses (interrupted once, see http_stream::cancel())
670 493 : if (in_progress_ && in_progress_->handler_running()) in_progress_->cancel(cancel_reason::shutdown);
671 872 : for (const auto& stream : request_queue_) {
672 379 : if (stream->handler_running()) stream->cancel(cancel_reason::shutdown);
673 : }
674 493 : }
675 :
676 493 : void server_connection::shutdown_close() {
677 493 : if (tracked()) close();
678 493 : }
679 :
680 34787 : void server_connection::handle_stream(std::shared_ptr<http_stream> stream,
681 : std::shared_ptr<http_frame> frame) {
682 : // Frames are queued in the order of the calls, from whatever threads they come (e.g.
683 : // chunks written from the IO thread after headers sent from another one): inline only
684 : // on the connection thread and with no frame of the stream still posted
685 34787 : auto& io_context = socket_->get_io_context();
686 34787 : if (io_context.get_executor().running_in_this_thread() && !stream->has_posted_frames()) {
687 34740 : queue_frame(stream, std::move(frame));
688 34740 : return;
689 : }
690 47 : stream->frame_posted();
691 47 : boost::asio::post(io_context,
692 47 : [this, self = shared_from_this(), stream = std::move(stream), frame = std::move(frame)]() mutable {
693 47 : stream->posted_frame_queued();
694 47 : queue_frame(stream, std::move(frame));
695 47 : });
696 : }
697 :
698 4315 : void server_connection::take_over(std::shared_ptr<http_stream> stream, std::shared_ptr<http_frame> response,
699 : takeover_handler handler) {
700 4315 : boost::asio::dispatch(socket_->get_io_context(),
701 12945 : [this, self = shared_from_this(), stream = std::move(stream), response = std::move(response),
702 4315 : handler = std::move(handler)]() mutable {
703 : // The read loop already stopped (the client left, the connection timed out...):
704 : // the connection is gone and cannot be handed over
705 4315 : if (reader_stopped_) {
706 0 : LOG_WARNING("connection closed before it could be taken over: the takeover handler is not called");
707 0 : return;
708 : }
709 4315 : stream->set_takeover(std::move(handler));
710 4315 : queue_frame(stream, std::move(response));
711 : });
712 4315 : }
713 :
714 411 : void server_connection::handle_stock_error(std::shared_ptr<http_stream> stream,
715 : http_response::status status) {
716 : // Its head tells what happens to the connection, as any other (see process_output_queue())
717 411 : handle_stream(stream, http_response::stock_http_reply(status));
718 411 : }
719 :
720 4312 : std::shared_ptr<asio::socket> server_connection::release_socket() {
721 : // The socket belongs to someone else from now on: the server neither drains nor closes it
722 4312 : untrack();
723 4312 : running_ = false;
724 4312 : stop_watcher();
725 4312 : socket_->cancel();
726 4306 : timeout_timer_.cancel();
727 4306 : return socket_;
728 : }
729 :
730 8627 : void server_connection::complete_takeover(http_stream& stream) {
731 : // Both the response must be written and the read loop stopped, in either order
732 8627 : auto [handler, buffered] = stream.release_takeover();
733 8627 : if (!handler) return;
734 :
735 : // From now on the connection counts as taken over, while the socket handed out lives.
736 : // Tracked before this one leaves, so a shutdown never sees the server without connections
737 : // meanwhile
738 4312 : std::shared_ptr<detail::taken_over_tracking> taken_over;
739 4312 : if (auto tracker = this->tracker()) {
740 4306 : if (tracker->current_phase() == connection_tracker::phase::closing) {
741 0 : LOG_WARNING("connection closed before it could be taken over: the server shuts down");
742 0 : close();
743 0 : return;
744 : }
745 4306 : taken_over = detail::taken_over_tracking::track(std::move(tracker), socket_);
746 4312 : }
747 4312 : auto socket = release_socket();
748 : // The handler gets the socket owning the tracking, and its scope (none if not tracked)
749 4306 : handler(taken_over ? taken_over->hand_out(std::move(buffered))
750 0 : : upgraded_connection{std::move(socket), std::move(buffered), {}});
751 : // Told now if the server started shutting down meanwhile (the handler may have set what
752 : // to do then)
753 4306 : if (taken_over) taken_over->handed_over();
754 8633 : }
755 :
756 3 : void server_connection::release() {
757 3 : boost::asio::dispatch(socket_->get_io_context(),
758 6 : [this, self = shared_from_this()] {
759 3 : close();
760 3 : });
761 3 : }
762 :
763 89621 : void server_connection::extend_timeout() {
764 89621 : if (!running_) return;
765 85228 : last_activity_ = clock::now();
766 85228 : arm_deadline();
767 : }
768 :
769 225 : void server_connection::hold_until(std::chrono::steady_clock::time_point time) {
770 : // Of the idle deadline only (see next_deadline()): not of those of the request
771 225 : hold_ = std::max(hold_, time);
772 225 : }
773 :
774 798 : std::shared_ptr<asio::socket> server_connection::get_socket() {
775 798 : return socket_;
776 : }
777 :
778 0 : void server_connection::update_connection_timeout(std::chrono::seconds timeout) {
779 0 : boost::asio::dispatch(socket_->get_io_context(),
780 0 : [this, self = shared_from_this(), timeout] {
781 0 : timeout_ = timeout;
782 0 : last_activity_ = clock::now();
783 0 : arm_deadline();
784 0 : });
785 0 : }
786 :
787 : }
|