MySQL 8.4.11
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 <cctype>
33#include <list>
34#include <map>
35#include <optional>
36#include <sstream>
37#include <string>
38#include <string_view>
39#include <utility>
40#include <vector>
41
42#include "cno/core.h"
46#include "http/base/http_time.h"
47#include "http/base/method.h"
52#include "http/cno/error_code.h"
53#include "http/cno/string.h"
54
58
59namespace http {
60namespace base {
61
62namespace impl {
63
64inline void set_socket_parent(net::ip::tcp::socket *, const char *) {
65 // Do nothing, net::ip::tcp::socket, is missing the custom
66 // `set_parent` method.
67}
68
71 return s;
72}
73
74template <typename T>
76 return get_socket(&s->lower_layer());
77}
78
79template <typename T>
80auto *get_socket1(T *s) {
81 return &s->lower_layer();
82}
83
84template <typename T>
85const net::ip::tcp::socket *get_socket(const T *s) {
86 return get_socket(&s->lower_layer());
87}
88
89template <typename T>
90void set_socket_parent(T *s, const char *parent) {
91 s->set_parent(parent);
92
94}
95
96} // namespace impl
97
98enum Pending {
102 k_pending_writing = 1 << 3
104
105template <typename IOLayer>
107 public:
114 using IO = IOLayer;
115
116 public:
117 Connection(IOLayer s, base::method::Bitset *allowed_method,
118 ConnectionStatusCallbacks *connection_handler,
119 CNO_CONNECTION_KIND kind, CNO_HTTP_VERSION version)
120 : socket_(std::move(s)),
121 allowed_method_(allowed_method),
122 connection_handler_{connection_handler} {
123 std::stringstream ss;
124 ss << "HTTP-" << this;
125
126 socket_.set_option(net::ip::tcp::no_delay{true});
127 impl::set_socket_parent(&socket_, ss.str().c_str());
128 cno_init(&cno_, kind);
129 cno_.disallow_h2_prior_knowledge = 1;
130 cno::callback_init(&cno_, this);
131 output_buffers_.emplace_back(4096);
132 cno_begin(&cno_, version);
133 }
134
135 ~Connection() override {
136 cno_fini(&cno_);
137 socket_.close();
138 }
139
140 public: // ConnectionInterface implementation
141 void shutdown(bool) override {
143 }
144
145 bool send(const uint32_t *stream_id_ptr, const int status_code,
146 const std::string &method, const std::string &path,
147 const Headers &headers, const IOBuffer &data) override {
148 cno_message_t message;
149 std::vector<cno_header_t> cno_header(headers.size(), cno_header_t());
150 std::vector<std::string> http2_headers_names;
151 const bool only_header = 0 == data.length();
152
153 if (CNO_HTTP2 == cno_.mode) {
154 http2_headers_names.reserve(headers.size());
155 }
156
157 auto output = cno_header.data();
158
159 for (const auto &entry : headers) {
160 if (CNO_HTTP2 == cno_.mode) {
161 auto &header_name =
162 http2_headers_names.emplace_back(make_lower(entry.first));
163 output->name.size = header_name.length();
164 output->name.data = header_name.c_str();
165 } else {
166 output->name.size = entry.first.length();
167 output->name.data = entry.first.c_str();
168 }
169
170 output->value.size = entry.second.length();
171 output->value.data = entry.second.c_str();
172 ++output;
173 }
174
175 message.code = status_code;
176 message.headers = cno_header.data();
177 message.headers_len = cno_header.size();
178 message.path.data = path.c_str();
179 message.path.size = path.length();
180 message.method.data = method.c_str();
181 message.method.size = method.length();
182
183 uint32_t stream_id =
184 stream_id_ptr ? *stream_id_ptr : cno_next_stream(&cno_);
185 if (CNO_OK != cno_write_head(&cno_, stream_id, &message, only_header)) {
186 return false;
187 }
188
189 if (!only_header) {
190 return CNO_OK == cno_write_data(&cno_, stream_id, data.get().c_str(),
191 data.length(), true);
192 }
193
194 return true;
195 }
196
197 std::string get_peer_address() const override {
198 auto *s = impl::get_socket(&socket_);
199 if (auto e = s->remote_endpoint()) {
200 return e->address().to_string();
201 }
202
203 return {};
204 }
205
206 uint16_t get_peer_port() const override {
207 auto *s = impl::get_socket(&socket_);
208 if (auto e = s->remote_endpoint()) {
209 return e->port();
210 }
211
212 return 0;
213 }
214
215 IOLayer &get_socket() { return socket_; }
216
217 void start() override { do_net_recv(); }
218
219 protected:
220 std::string make_lower(std::string s) {
221 std::transform(s.begin(), s.end(), s.begin(), ::tolower);
222 return s;
223 }
224
225 void do_net_send() {
227 [this](std::error_code error, auto size) {
228 switch (on_net_send(error, size)) {
229 case k_pending_none:
230 break;
231
233 break;
234
236 do_net_send();
237 break;
238
242 break;
243 }
244 });
245 }
246
247 void do_net_recv() {
248 reading_pending_ = true;
249 socket_.async_receive(
250 input_mutable_buffer_, [this](std::error_code error, auto size) {
251 switch (on_net_receive(error, size)) {
253 do_net_recv();
254 break;
255
257 case k_pending_none:
258 reading_pending_ = false;
259 break;
260
262 reading_pending_ = false;
265 break;
266 }
267 });
268 }
269
270 Pending on_net_receive(const std::error_code &ec,
271 std::size_t bytes_transferred) {
272 if (!running_) {
274 }
275
276 if (ec) {
279 }
280
281 const int result = cno_consume(
282 &cno_, reinterpret_cast<char *>(input_buffer_), bytes_transferred);
283
284 if (result < 0) {
285 const cno_error_t *cno_ec = cno_error();
286 if (!cno_.client) {
287 if (const auto reason =
290 *reason);
293 }
294 }
295
296 auto ec = make_error_code(cno_ec);
299 }
300
301 if (!keep_alive_) {
303 }
304
305 if (!running_) {
307 }
308
309 if (suspend_) return k_pending_none;
310
311 return k_pending_reading;
312 }
313
314 Pending on_net_send(const std::error_code &ec, size_t size) {
315 bool has_more = true;
316 bool should_close = false;
317 {
318 std::unique_lock<std::mutex> lock(output_buffer_mutex_);
319
320 if (!ec) {
321 while (size) {
322 auto &page = output_buffers_.front();
323 auto size_on_page = std::min(page.size(), size);
324 page += size_on_page;
325 size -= size_on_page;
326
327 if (page.empty()) {
328 if (1 == output_buffers_.size()) {
329 page.reset();
330 } else {
331 output_buffers_.pop_front();
332 }
333 }
334 }
335 }
336
337 if (0 == output_buffers_.front().size()) {
338 has_more = false;
339 output_pending_ = false;
340
341 if (!running_) {
342 should_close = true;
343 }
344 }
345 }
346
347 if (ec) {
348 stop_running();
349 output_pending_ = false;
350
353 }
354 if (has_more) return k_pending_writing;
355
357
358 if (should_close) {
360 }
361 if (suspend_) return k_pending_none;
362
363 return k_pending_reading;
364 }
365
366 void resume() { suspend_ = false; }
367 void suspend() { suspend_ = true; }
368
369 /**
370 * Mark the connection that it should stop running
371 *
372 * @returns information if the object may be delete
373 * @retval 'false' Connection object can be removed immediately
374 * @retval 'true' Connection object must wait until IO is finished.
375 */
377 std::unique_lock<std::mutex> lock(output_buffer_mutex_);
378 running_ = false;
379
380 return output_pending_;
381 }
382
383 protected:
384 virtual void on_output_buffer_empty() {}
385
386 static std::optional<std::string_view>
388 if (ec->code != CNO_ERRNO_PROTOCOL) return std::nullopt;
389
390 using namespace std::literals;
391 switch (ec->detail) {
392 case CNO_ERROR_DETAIL_INVALID_CONTENT_LENGTH:
393 case CNO_ERROR_DETAIL_MULTIPLE_CONTENT_LENGTHS:
394 return "invalid Content-Length"sv;
395 default:
396 return std::nullopt;
397 }
398 }
399
401 Headers headers;
402 static const IOBuffer k_empty;
403 headers.add("Connection", "close");
404 headers.add("Content-Length", "0");
405
406 auto stream_id = cno_.last_stream[CNO_REMOTE];
408 send(&stream_id, status_code::BadRequest,
409 status_code::to_string(status_code::BadRequest), "", headers, k_empty);
410 keep_alive_ = false;
411 }
412
413 void prepare_h1_error_response_stream(uint32_t stream_id) {
414 if (cno_.client || cno_.mode == CNO_HTTP2) return;
415
416 // cno_when_h1_head() normally enables server writes before on_message_head.
417 // Protocol errors during header parsing happen earlier, so mirror that step
418 // before sending the error response through cno_write_head().
419 if (cno_.last_stream[CNO_LOCAL] == 0) {
420 cno_.last_stream[CNO_LOCAL] = stream_id;
421 }
422 }
423
424 protected: // CnoInterface implementation
425 int on_cno_writev(const cno_buffer_t *buffer, size_t count) override {
426 bool was_first = false;
427 {
428 std::unique_lock<std::mutex> lock(output_buffer_mutex_);
430
431 bool expected = false;
432 if (impl::get_socket(&socket_)->is_open())
433 was_first = output_pending_.compare_exchange_weak(expected, true);
434 auto source_it = buffers.begin();
435
436 while (source_it != buffers.end()) {
437 // The constructor fills the output buffer with single page
438 // and all algorithms that clear not used pages, leave at
439 // last one page.
440 // thus we do not need to check if there are no pages.
441 auto &obuffer = output_buffers_.back();
442
443 if (0 == source_it->size()) {
444 ++source_it;
445 continue;
446 }
447
448 if (0 == obuffer.space_left()) {
449 output_buffers_.emplace_back(4096);
450 continue;
451 }
452
453 (*source_it) += obuffer.write(
454 static_cast<const uint8_t *>(source_it->data()), source_it->size());
455 }
456 }
457
458 if (was_first) {
459 do_net_send();
460 }
461
462 return 0;
463 }
464
465 int on_cno_message_tail([[maybe_unused]] const uint32_t session_id,
466 [[maybe_unused]] const cno_tail_t *tail) override {
467 // processed_request_ = true;
468 return 0;
469 }
470
471 int on_cno_stream_start([[maybe_unused]] const uint32_t id) override {
472 return 0;
473 }
474
475 int on_cno_close() override {
476 keep_alive_ = false;
477 return 0;
478 }
479
480 protected:
481 bool keep_alive_{true};
482 IOLayer socket_;
484 cno_connection_t cno_;
485
486 uint8_t input_buffer_[512];
488
490 std::list<owned_buffer> output_buffers_;
491
492 std::atomic<bool> output_pending_{false};
493 std::atomic<bool> reading_pending_{false};
494 std::atomic<bool> running_{true};
495 std::atomic<bool> suspend_{false};
496
498};
499
500} // namespace base
501} // namespace http
502
503#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:106
int on_cno_close() override
Definition: connection.h:475
void shutdown(bool) override
Definition: connection.h:141
void start() override
Definition: connection.h:217
int on_cno_message_tail(const uint32_t session_id, const cno_tail_t *tail) override
Definition: connection.h:465
std::string make_lower(std::string s)
Definition: connection.h:220
bool stop_running()
Mark the connection that it should stop running.
Definition: connection.h:376
base::method::Bitset Methods
Definition: connection.h:110
virtual void on_output_buffer_empty()
Definition: connection.h:384
std::atomic< bool > suspend_
Definition: connection.h:495
void prepare_h1_error_response_stream(uint32_t stream_id)
Definition: connection.h:413
Pending on_net_send(const std::error_code &ec, size_t size)
Definition: connection.h:314
Methods * allowed_method_
Definition: connection.h:483
ConnectionStatusCallbacks * connection_handler_
Definition: connection.h:497
int on_cno_writev(const cno_buffer_t *buffer, size_t count) override
Definition: connection.h:425
void send_bad_request_and_close()
Definition: connection.h:400
std::string get_peer_address() const override
Definition: connection.h:197
void do_net_recv()
Definition: connection.h:247
uint16_t get_peer_port() const override
Definition: connection.h:206
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:145
IOLayer IO
Definition: connection.h:114
http::base::details::ref_buffers< std::list< owned_buffer > > ref_buffers
Definition: connection.h:113
void suspend()
Definition: connection.h:367
cno_connection_t cno_
Definition: connection.h:484
std::atomic< bool > reading_pending_
Definition: connection.h:493
bool keep_alive_
Definition: connection.h:481
std::list< owned_buffer > output_buffers_
Definition: connection.h:490
Pending on_net_receive(const std::error_code &ec, std::size_t bytes_transferred)
Definition: connection.h:270
void resume()
Definition: connection.h:366
std::atomic< bool > output_pending_
Definition: connection.h:492
uint8_t input_buffer_[512]
Definition: connection.h:486
static std::optional< std::string_view > invalid_request_body_headers_rejection_reason(const cno_error_t *ec)
Definition: connection.h:387
IOLayer & get_socket()
Definition: connection.h:215
std::mutex output_buffer_mutex_
Definition: connection.h:489
IOLayer socket_
Definition: connection.h:482
int on_cno_stream_start(const uint32_t id) override
Definition: connection.h:471
std::atomic< bool > running_
Definition: connection.h:494
~Connection() override
Definition: connection.h:135
net::mutable_buffer input_mutable_buffer_
Definition: connection.h:487
void do_net_send()
Definition: connection.h:225
Connection(IOLayer s, base::method::Bitset *allowed_method, ConnectionStatusCallbacks *connection_handler, CNO_CONNECTION_KIND kind, CNO_HTTP_VERSION version)
Definition: connection.h:117
headers of a HTTP response/request.
Definition: headers.h:43
virtual uint32_t size() const
Definition: headers.cc:85
virtual void add(const std::string_view &key, std::string &&value)
Definition: headers.cc:48
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:1234
static int count
Definition: myisam_ftdump.cc:45
void error(const char *format,...)
static char * path
Definition: mysqldump.cc:149
bool transform(const dd::Spatial_reference_system *source_srs, const Geometry &in, const dd::Spatial_reference_system *target_srs, const char *func_name, std::unique_ptr< Geometry > *out) noexcept
Transforms a geometry from one SRS to another.
Definition: transform.cc:216
void set_socket_parent(net::ip::tcp::socket *, const char *)
Definition: connection.h:64
auto * get_socket1(T *s)
Definition: connection.h:80
net::ip::tcp::socket * get_socket(net::ip::tcp::socket *s)
Definition: connection.h:69
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:35
Pending
Definition: connection.h:98
@ k_pending_none
Definition: connection.h:99
@ k_pending_reading
Definition: connection.h:101
@ k_pending_closing
Definition: connection.h:100
@ k_pending_writing
Definition: connection.h:102
Request::Headers Headers
Definition: request.cc:35
HTTP_COMMON_EXPORT void callback_init(cno_connection_t *cno, CnoInterface *)
Definition: callback_init.cc:91
Definition: connection.h:59
Definition: http_server_component.cc:36
char tolower(const char &ch)
Definition: parsing_helpers.h:41
std::error_code make_error_code(DynamicLoaderErrc ec)
make error_code from a DynamicLoaderErrc.
Definition: dynamic_loader.cc:79
size_t size(const char *const c)
Definition: base64.h:46
mutable_buffer buffer(void *p, size_t n) noexcept
Definition: buffer.h:418
Definition: gcs_xcom_synode.h:64
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