MySQL 26.7.0
Source Code Documentation
connection.h
Go to the documentation of this file.
1/*
2 Copyright (c) 2021, 2026, Oracle and/or its affiliates.
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License, version 2.0,
6 as published by the Free Software Foundation.
7
8 This program is designed to work with certain software (including
9 but not limited to OpenSSL) that is licensed under separate terms,
10 as designated in a particular file or component or in included license
11 documentation. The authors of MySQL hereby grant you an additional
12 permission to link the program and your derivative works with the
13 separately licensed software that they have either included with
14 the program or referenced in the documentation.
15
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
20
21 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software
23 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
24*/
25
26#ifndef ROUTER_SRC_HTTP_INCLUDE_HTTP_BASE_CONNECTION_H_
27#define ROUTER_SRC_HTTP_INCLUDE_HTTP_BASE_CONNECTION_H_
28
29#include <algorithm>
30#include <atomic>
31#include <bitset>
32#include <list>
33#include <map>
34#include <optional>
35#include <sstream>
36#include <string>
37#include <string_view>
38#include <utility>
39#include <vector>
40
41#include "cno/core.h"
44#include "http/base/details/owned_buffer.h"
45#include "http/base/http_time.h"
46#include "http/base/method.h"
51#include "http/cno/error_code.h"
52#include "http/cno/string.h"
53
57
58namespace http {
59namespace base {
60
61namespace impl {
62
63inline void set_socket_parent(net::ip::tcp::socket *, const char *) {
64 // Do nothing, net::ip::tcp::socket, is missing the custom
65 // `set_parent` method.
66}
67
70 return s;
71}
72
73template <typename T>
75 return get_socket(&s->lower_layer());
76}
77
78template <typename T>
79auto *get_socket1(T *s) {
80 return &s->lower_layer();
81}
82
83template <typename T>
85 return get_socket(&s->lower_layer());
86}
87
88template <typename T>
89void set_socket_parent(T *s, const char *parent) {
90 s->set_parent(parent);
91
93}
94
95} // namespace impl
96
97enum Pending {
101 k_pending_writing = 1 << 3
103
104template <typename IOLayer>
106 public:
113 using IO = IOLayer;
114
115 public:
116 Connection(IOLayer s, base::method::Bitset *allowed_method,
117 ConnectionStatusCallbacks *connection_handler,
118 CNO_CONNECTION_KIND kind, CNO_HTTP_VERSION version)
119 : socket_(std::move(s)),
120 allowed_method_(allowed_method),
121 connection_handler_{connection_handler} {
122 std::stringstream ss;
123 ss << "HTTP-" << this;
124
125 socket_.set_option(net::ip::tcp::no_delay{true});
126 impl::set_socket_parent(&socket_, ss.str().c_str());
127 cno_init(&cno_, kind);
128 cno_.disallow_h2_prior_knowledge = 1;
129 cno::callback_init(&cno_, this);
130 output_buffers_.emplace_back(4096);
131 cno_begin(&cno_, version);
132 }
133
134 ~Connection() override {
135 cno_fini(&cno_);
136 socket_.close();
137 }
138
139 public: // ConnectionInterface implementation
140 void shutdown(bool) override {
142 }
143
144 bool send(const uint32_t *stream_id_ptr, const int status_code,
145 const std::string &method, const std::string &path,
146 const Headers &headers, const IOBuffer &data) override {
147 cno_message_t message;
148 std::vector<cno_header_t> cno_header(headers.size(), cno_header_t());
149 std::vector<std::string> http2_headers_names;
150 const bool only_header = 0 == data.length();
151
152 if (CNO_HTTP2 == cno_.mode) {
153 http2_headers_names.reserve(headers.size());
154 }
155
156 auto output = cno_header.data();
157
158 for (const auto &entry : headers) {
159 if (CNO_HTTP2 == cno_.mode) {
160 auto &header_name = http2_headers_names.emplace_back(
162 output->name.size = header_name.length();
163 output->name.data = header_name.c_str();
164 } else {
165 output->name.size = entry.first.length();
166 output->name.data = entry.first.c_str();
167 }
168
169 output->value.size = entry.second.length();
170 output->value.data = entry.second.c_str();
171 ++output;
172 }
173
174 message.code = status_code;
175 message.headers = cno_header.data();
176 message.headers_len = cno_header.size();
177 message.path.data = path.c_str();
178 message.path.size = path.length();
179 message.method.data = method.c_str();
180 message.method.size = method.length();
181
182 uint32_t stream_id =
183 stream_id_ptr ? *stream_id_ptr : cno_next_stream(&cno_);
184 if (CNO_OK != cno_write_head(&cno_, stream_id, &message, only_header)) {
185 return false;
186 }
187
188 if (!only_header) {
189 return CNO_OK == cno_write_data(&cno_, stream_id, data.get().c_str(),
190 data.length(), true);
191 }
192
193 return true;
194 }
195
196 std::string get_peer_address() const override {
197 auto *s = impl::get_socket(&socket_);
198 if (auto e = s->remote_endpoint()) {
199 return e->address().to_string();
200 }
201
202 return {};
203 }
204
205 uint16_t get_peer_port() const override {
206 auto *s = impl::get_socket(&socket_);
207 if (auto e = s->remote_endpoint()) {
208 return e->port();
209 }
210
211 return 0;
212 }
213
214 IOLayer &get_socket() { return socket_; }
215
216 void start() override { do_net_recv(); }
217
218 protected:
219 void do_net_send() {
221 [this](std::error_code error, auto size) {
222 switch (on_net_send(error, size)) {
223 case k_pending_none:
224 break;
225
227 break;
228
230 do_net_send();
231 break;
232
236 break;
237 }
238 });
239 }
240
241 void do_net_recv() {
242 reading_pending_ = true;
243 socket_.async_receive(
244 input_mutable_buffer_, [this](std::error_code error, auto size) {
245 switch (on_net_receive(error, size)) {
247 do_net_recv();
248 break;
249
251 case k_pending_none:
252 reading_pending_ = false;
253 break;
254
256 reading_pending_ = false;
259 break;
260 }
261 });
262 }
263
264 Pending on_net_receive(const std::error_code &ec,
265 std::size_t bytes_transferred) {
266 if (!running_) {
268 }
269
270 if (ec) {
273 }
274
275 const int result = cno_consume(
276 &cno_, reinterpret_cast<char *>(input_buffer_), bytes_transferred);
277
278 if (result < 0) {
279 const cno_error_t *cno_ec = cno_error();
280 if (!cno_.client) {
281 if (const auto reason =
284 *reason);
287 }
288 }
289
290 auto ec = make_error_code(cno_ec);
293 }
294
295 if (!keep_alive_) {
297 }
298
299 if (!running_) {
301 }
302
303 if (suspend_) return k_pending_none;
304
305 return k_pending_reading;
306 }
307
308 Pending on_net_send(const std::error_code &ec, size_t size) {
309 bool has_more = true;
310 bool should_close = false;
311 {
312 std::unique_lock<std::mutex> lock(output_buffer_mutex_);
313
314 if (!ec) {
315 while (size) {
316 auto &page = output_buffers_.front();
317 auto size_on_page = std::min(page.size(), size);
318 page += size_on_page;
319 size -= size_on_page;
320
321 if (page.empty()) {
322 if (1 == output_buffers_.size()) {
323 page.reset();
324 } else {
325 output_buffers_.pop_front();
326 }
327 }
328 }
329 }
330
331 if (0 == output_buffers_.front().size()) {
332 has_more = false;
333 output_pending_ = false;
334
335 if (!running_) {
336 should_close = true;
337 }
338 }
339 }
340
341 if (ec) {
342 stop_running();
343 output_pending_ = false;
344
347 }
348 if (has_more) return k_pending_writing;
349
351
352 if (should_close) {
354 }
355 if (suspend_) return k_pending_none;
356
357 return k_pending_reading;
358 }
359
360 void resume() { suspend_ = false; }
361 void suspend() { suspend_ = true; }
362
363 /**
364 * Mark the connection that it should stop running
365 *
366 * @returns information if the object may be delete
367 * @retval 'false' Connection object can be removed immediately
368 * @retval 'true' Connection object must wait until IO is finished.
369 */
371 std::unique_lock<std::mutex> lock(output_buffer_mutex_);
372 running_ = false;
373
374 return output_pending_;
375 }
376
377 protected:
378 virtual void on_output_buffer_empty() {}
379
380 static std::optional<std::string_view>
382 if (ec->code != CNO_ERRNO_PROTOCOL) return std::nullopt;
383
384 using namespace std::literals;
385 switch (ec->detail) {
386 case CNO_ERROR_DETAIL_INVALID_CONTENT_LENGTH:
387 case CNO_ERROR_DETAIL_MULTIPLE_CONTENT_LENGTHS:
388 return "invalid Content-Length"sv;
389 default:
390 return std::nullopt;
391 }
392 }
393
395 Headers headers;
396 static const IOBuffer k_empty;
397 headers.add("Connection", "close");
398 headers.add("Content-Length", "0");
399
400 auto stream_id = cno_.last_stream[CNO_REMOTE];
402 send(&stream_id, status_code::BadRequest,
404 keep_alive_ = false;
405 }
406
407 void prepare_h1_error_response_stream(uint32_t stream_id) {
408 if (cno_.client || cno_.mode == CNO_HTTP2) return;
409
410 // cno_when_h1_head() normally enables server writes before on_message_head.
411 // Protocol errors during header parsing happen earlier, so mirror that step
412 // before sending the error response through cno_write_head().
413 if (cno_.last_stream[CNO_LOCAL] == 0) {
414 cno_.last_stream[CNO_LOCAL] = stream_id;
415 }
416 }
417
418 protected: // CnoInterface implementation
419 int on_cno_writev(const cno_buffer_t *buffer, size_t count) override {
420 bool was_first = false;
421 {
422 std::unique_lock<std::mutex> lock(output_buffer_mutex_);
424
425 bool expected = false;
426 if (impl::get_socket(&socket_)->is_open())
427 was_first = output_pending_.compare_exchange_weak(expected, true);
428 auto source_it = buffers.begin();
429
430 while (source_it != buffers.end()) {
431 // The constructor fills the output buffer with single page
432 // and all algorithms that clear not used pages, leave at
433 // last one page.
434 // thus we do not need to check if there are no pages.
435 auto &obuffer = output_buffers_.back();
436
437 if (0 == source_it->size()) {
438 ++source_it;
439 continue;
440 }
441
442 if (0 == obuffer.space_left()) {
443 output_buffers_.emplace_back(4096);
444 continue;
445 }
446
447 (*source_it) += obuffer.write(
448 static_cast<const uint8_t *>(source_it->data()), source_it->size());
449 }
450 }
451
452 if (was_first) {
453 do_net_send();
454 }
455
456 return 0;
457 }
458
459 int on_cno_message_tail([[maybe_unused]] const uint32_t session_id,
460 [[maybe_unused]] const cno_tail_t *tail) override {
461 // processed_request_ = true;
462 return 0;
463 }
464
465 int on_cno_stream_start([[maybe_unused]] const uint32_t id) override {
466 return 0;
467 }
468
469 int on_cno_close() override {
470 keep_alive_ = false;
471 return 0;
472 }
473
474 protected:
475 bool keep_alive_{true};
476 IOLayer socket_;
478 cno_connection_t cno_;
479
480 uint8_t input_buffer_[512];
482
484 std::list<owned_buffer> output_buffers_;
485
486 std::atomic<bool> output_pending_{false};
487 std::atomic<bool> reading_pending_{false};
488 std::atomic<bool> running_{true};
489 std::atomic<bool> suspend_{false};
490
492};
493
494} // namespace base
495} // namespace http
496
497#endif // ROUTER_SRC_HTTP_INCLUDE_HTTP_BASE_CONNECTION_H_
Definition: connection_interface.h:41
Definition: connection_status_callbacks.h:36
virtual void log_invalid_request_body_headers_rejection(std::string_view)
Definition: connection_status_callbacks.h:43
virtual void on_connection_io_error(Connection *connection, const std::error_code &ec)=0
virtual void on_connection_close(Connection *connection)=0
Definition: connection.h:105
int on_cno_close() override
Definition: connection.h:469
void shutdown(bool) override
Definition: connection.h:140
void start() override
Definition: connection.h:216
int on_cno_message_tail(const uint32_t session_id, const cno_tail_t *tail) override
Definition: connection.h:459
bool stop_running()
Mark the connection that it should stop running.
Definition: connection.h:370
base::method::Bitset Methods
Definition: connection.h:109
virtual void on_output_buffer_empty()
Definition: connection.h:378
std::atomic< bool > suspend_
Definition: connection.h:489
void prepare_h1_error_response_stream(uint32_t stream_id)
Definition: connection.h:407
Pending on_net_send(const std::error_code &ec, size_t size)
Definition: connection.h:308
Methods * allowed_method_
Definition: connection.h:477
ConnectionStatusCallbacks * connection_handler_
Definition: connection.h:491
int on_cno_writev(const cno_buffer_t *buffer, size_t count) override
Definition: connection.h:419
void send_bad_request_and_close()
Definition: connection.h:394
std::string get_peer_address() const override
Definition: connection.h:196
void do_net_recv()
Definition: connection.h:241
uint16_t get_peer_port() const override
Definition: connection.h:205
bool send(const uint32_t *stream_id_ptr, const int status_code, const std::string &method, const std::string &path, const Headers &headers, const IOBuffer &data) override
Definition: connection.h:144
IOLayer IO
Definition: connection.h:113
http::base::details::ref_buffers< std::list< owned_buffer > > ref_buffers
Definition: connection.h:112
void suspend()
Definition: connection.h:361
cno_connection_t cno_
Definition: connection.h:478
std::atomic< bool > reading_pending_
Definition: connection.h:487
bool keep_alive_
Definition: connection.h:475
std::list< owned_buffer > output_buffers_
Definition: connection.h:484
Pending on_net_receive(const std::error_code &ec, std::size_t bytes_transferred)
Definition: connection.h:264
void resume()
Definition: connection.h:360
std::atomic< bool > output_pending_
Definition: connection.h:486
uint8_t input_buffer_[512]
Definition: connection.h:480
static std::optional< std::string_view > invalid_request_body_headers_rejection_reason(const cno_error_t *ec)
Definition: connection.h:381
IOLayer & get_socket()
Definition: connection.h:214
std::mutex output_buffer_mutex_
Definition: connection.h:483
IOLayer socket_
Definition: connection.h:476
int on_cno_stream_start(const uint32_t id) override
Definition: connection.h:465
std::atomic< bool > running_
Definition: connection.h:488
~Connection() override
Definition: connection.h:134
net::mutable_buffer input_mutable_buffer_
Definition: connection.h:481
void do_net_send()
Definition: connection.h:219
Connection(IOLayer s, base::method::Bitset *allowed_method, ConnectionStatusCallbacks *connection_handler, CNO_CONNECTION_KIND kind, CNO_HTTP_VERSION version)
Definition: connection.h:116
headers of a HTTP response/request.
Definition: headers.h:43
virtual uint32_t size() const
Definition: headers.cc:84
virtual void add(const std::string_view &key, std::string &&value)
Definition: headers.cc:47
Definition: io_buffer.h:41
virtual const std::string & get() const
Definition: io_buffer.h:82
virtual size_t length() const
Definition: io_buffer.h:52
Definition: owned_buffer.h:83
Definition: owned_buffer.h:68
Definition: buffer_sequence.h:53
Definition: cno_interface.h:36
Definition: socket.h:1090
Definition: buffer.h:113
static constexpr shutdown_type shutdown_send
Definition: socket.h:185
int page
Definition: ctype-mb.cc:1226
#define T
Definition: jit_executor_value.cc:373
static int count
Definition: myisam_ftdump.cc:45
void error(const char *format,...)
static char * path
Definition: mysqldump.cc:151
void set_socket_parent(net::ip::tcp::socket *, const char *)
Definition: connection.h:63
auto * get_socket1(T *s)
Definition: connection.h:79
net::ip::tcp::socket * get_socket(net::ip::tcp::socket *s)
Definition: connection.h:68
std::bitset< Pos::_LAST+1 > Bitset
Definition: method.h:57
constexpr key_type BadRequest
Definition: status_code.h:64
HTTP_COMMON_EXPORT name_type to_string(key_type key)
Definition: status_code.cc:33
Pending
Definition: connection.h:97
@ k_pending_none
Definition: connection.h:98
@ k_pending_reading
Definition: connection.h:100
@ k_pending_closing
Definition: connection.h:99
@ k_pending_writing
Definition: connection.h:101
Request::Headers Headers
Definition: request.cc:34
HTTP_COMMON_EXPORT void callback_init(cno_connection_t *cno, CnoInterface *)
Definition: callback_init.cc:90
Definition: connection.h:58
Definition: http_server_component.cc:36
const mysqlrouter::sqlstring k_empty
Definition: query_entries_content_file.cc:34
HARNESS_EXPORT std::string make_lower(std::string s)
lower-case a string.
Definition: string_utils.cc:99
std::error_code make_error_code(DynamicLoaderErrc ec)
make error_code from a DynamicLoaderErrc.
Definition: dynamic_loader.cc:97
size_t size(const char *const c)
Definition: base64.h:46
mutable_buffer buffer(void *p, size_t n) noexcept
Definition: buffer.h:418
Define std::hash<Gtid>.
Definition: gtid.h:355
static std::mutex lock
Definition: net_ns.cc:56
required uint64 version
Definition: replication_group_member_actions.proto:41
Definition: completion_hash.h:35
Definition: result.h:30