File indexing completed on 2025-04-19 08:33:51
0001
0002
0003
0004
0005
0006
0007
0008 #ifndef BOOST_MYSQL_IMPL_INTERNAL_PROTOCOL_DESERIALIZATION_HPP
0009 #define BOOST_MYSQL_IMPL_INTERNAL_PROTOCOL_DESERIALIZATION_HPP
0010
0011 #include <boost/mysql/client_errc.hpp>
0012 #include <boost/mysql/column_type.hpp>
0013 #include <boost/mysql/common_server_errc.hpp>
0014 #include <boost/mysql/diagnostics.hpp>
0015 #include <boost/mysql/error_categories.hpp>
0016 #include <boost/mysql/error_code.hpp>
0017 #include <boost/mysql/field_kind.hpp>
0018 #include <boost/mysql/field_view.hpp>
0019 #include <boost/mysql/metadata_collection_view.hpp>
0020 #include <boost/mysql/string_view.hpp>
0021
0022 #include <boost/mysql/detail/coldef_view.hpp>
0023 #include <boost/mysql/detail/config.hpp>
0024 #include <boost/mysql/detail/make_string_view.hpp>
0025 #include <boost/mysql/detail/ok_view.hpp>
0026 #include <boost/mysql/detail/resultset_encoding.hpp>
0027
0028 #include <boost/mysql/impl/internal/error/server_error_to_string.hpp>
0029 #include <boost/mysql/impl/internal/protocol/capabilities.hpp>
0030 #include <boost/mysql/impl/internal/protocol/db_flavor.hpp>
0031 #include <boost/mysql/impl/internal/protocol/impl/binary_protocol.hpp>
0032 #include <boost/mysql/impl/internal/protocol/impl/deserialization_context.hpp>
0033 #include <boost/mysql/impl/internal/protocol/impl/null_bitmap.hpp>
0034 #include <boost/mysql/impl/internal/protocol/impl/protocol_field_type.hpp>
0035 #include <boost/mysql/impl/internal/protocol/impl/text_protocol.hpp>
0036 #include <boost/mysql/impl/internal/protocol/static_buffer.hpp>
0037
0038 #include <boost/config.hpp>
0039 #include <boost/core/ignore_unused.hpp>
0040 #include <boost/core/span.hpp>
0041
0042 #include <cstddef>
0043 #include <cstdint>
0044
0045 namespace boost {
0046 namespace mysql {
0047 namespace detail {
0048
0049
0050 inline error_code deserialize_ok_packet(span<const std::uint8_t> msg, ok_view& output);
0051
0052
0053 struct err_view
0054 {
0055 std::uint16_t error_code;
0056 string_view error_message;
0057 };
0058 BOOST_ATTRIBUTE_NODISCARD inline error_code deserialize_error_packet(
0059 span<const std::uint8_t> message,
0060 err_view& pack,
0061 bool has_sql_state = true
0062 );
0063 BOOST_ATTRIBUTE_NODISCARD inline error_code process_error_packet(
0064 span<const std::uint8_t> message,
0065 db_flavor flavor,
0066 diagnostics& diag,
0067 bool has_sql_state = true
0068 );
0069
0070
0071
0072
0073
0074 BOOST_ATTRIBUTE_NODISCARD inline error_code deserialize_ok_response(
0075 span<const std::uint8_t> message,
0076 db_flavor flavor,
0077 diagnostics& diag,
0078 bool& backslash_escapes
0079 );
0080
0081
0082 BOOST_ATTRIBUTE_NODISCARD inline error_code deserialize_column_definition(
0083 span<const std::uint8_t> input,
0084 coldef_view& output
0085 );
0086
0087
0088 struct prepare_stmt_response
0089 {
0090 std::uint32_t id;
0091 std::uint16_t num_columns;
0092 std::uint16_t num_params;
0093 };
0094 BOOST_ATTRIBUTE_NODISCARD inline error_code deserialize_prepare_stmt_response_impl(
0095 span<const std::uint8_t> message,
0096 prepare_stmt_response& output
0097 );
0098 BOOST_ATTRIBUTE_NODISCARD inline error_code deserialize_prepare_stmt_response(
0099 span<const std::uint8_t> message,
0100 db_flavor flavor,
0101 prepare_stmt_response& output,
0102 diagnostics& diag
0103 );
0104
0105
0106 struct execute_response
0107 {
0108 enum class type_t
0109 {
0110 num_fields,
0111 ok_packet,
0112 error
0113 } type;
0114 union data_t
0115 {
0116 std::size_t num_fields;
0117 ok_view ok_pack;
0118 error_code err;
0119
0120 data_t(size_t v) noexcept : num_fields(v) {}
0121 data_t(const ok_view& v) noexcept : ok_pack(v) {}
0122 data_t(error_code v) noexcept : err(v) {}
0123 } data;
0124
0125 execute_response(std::size_t v) noexcept : type(type_t::num_fields), data(v) {}
0126 execute_response(const ok_view& v) noexcept : type(type_t::ok_packet), data(v) {}
0127 execute_response(error_code v) noexcept : type(type_t::error), data(v) {}
0128 };
0129 inline execute_response deserialize_execute_response(
0130 span<const std::uint8_t> msg,
0131 db_flavor flavor,
0132 diagnostics& diag
0133 );
0134
0135 struct row_message
0136 {
0137 enum class type_t
0138 {
0139 row,
0140 ok_packet,
0141 error
0142 } type;
0143 union data_t
0144 {
0145 span<const std::uint8_t> row;
0146 ok_view ok_pack;
0147 error_code err;
0148
0149 data_t(span<const std::uint8_t> row) noexcept : row(row) {}
0150 data_t(const ok_view& ok_pack) noexcept : ok_pack(ok_pack) {}
0151 data_t(error_code err) noexcept : err(err) {}
0152 } data;
0153
0154 row_message(span<const std::uint8_t> row) noexcept : type(type_t::row), data(row) {}
0155 row_message(const ok_view& ok_pack) noexcept : type(type_t::ok_packet), data(ok_pack) {}
0156 row_message(error_code v) noexcept : type(type_t::error), data(v) {}
0157 };
0158 inline row_message deserialize_row_message(span<const std::uint8_t> msg, db_flavor flavor, diagnostics& diag);
0159
0160 inline error_code deserialize_row(
0161 resultset_encoding encoding,
0162 span<const std::uint8_t> message,
0163 metadata_collection_view meta,
0164 span<field_view> output
0165 );
0166
0167
0168 struct server_hello
0169 {
0170 using auth_buffer_type = static_buffer<8 + 0xff>;
0171 db_flavor server;
0172 auth_buffer_type auth_plugin_data;
0173 capabilities server_capabilities{};
0174 string_view auth_plugin_name;
0175 };
0176 BOOST_ATTRIBUTE_NODISCARD inline error_code deserialize_server_hello_impl(
0177 span<const std::uint8_t> msg,
0178 server_hello& output
0179 );
0180 BOOST_ATTRIBUTE_NODISCARD inline error_code deserialize_server_hello(
0181 span<const std::uint8_t> msg,
0182 server_hello& output,
0183 diagnostics& diag
0184 );
0185
0186
0187 struct auth_switch
0188 {
0189 string_view plugin_name;
0190 span<const std::uint8_t> auth_data;
0191 };
0192 BOOST_ATTRIBUTE_NODISCARD inline error_code deserialize_auth_switch(
0193 span<const std::uint8_t> msg,
0194 auth_switch& output
0195 );
0196
0197
0198 struct handhake_server_response
0199 {
0200 struct ok_follows_t
0201 {
0202 };
0203
0204 enum class type_t
0205 {
0206 ok,
0207 error,
0208 ok_follows,
0209 auth_switch,
0210 auth_more_data
0211 } type;
0212
0213 union data_t
0214 {
0215 ok_view ok;
0216 error_code err;
0217 ok_follows_t ok_follows;
0218 auth_switch auth_sw;
0219 span<const std::uint8_t> more_data;
0220
0221 data_t(const ok_view& ok) noexcept : ok(ok) {}
0222 data_t(error_code err) noexcept : err(err) {}
0223 data_t(ok_follows_t) noexcept : ok_follows({}) {}
0224 data_t(auth_switch msg) noexcept : auth_sw(msg) {}
0225 data_t(span<const std::uint8_t> more_data) noexcept : more_data(more_data) {}
0226 } data;
0227
0228 handhake_server_response(const ok_view& ok) noexcept : type(type_t::ok), data(ok) {}
0229 handhake_server_response(error_code err) noexcept : type(type_t::error), data(err) {}
0230 handhake_server_response(ok_follows_t) noexcept : type(type_t::ok_follows), data(ok_follows_t{}) {}
0231 handhake_server_response(auth_switch auth_switch) noexcept : type(type_t::auth_switch), data(auth_switch)
0232 {
0233 }
0234 handhake_server_response(span<const std::uint8_t> more_data) noexcept
0235 : type(type_t::auth_more_data), data(more_data)
0236 {
0237 }
0238 };
0239 inline handhake_server_response deserialize_handshake_server_response(
0240 span<const std::uint8_t> buff,
0241 db_flavor flavor,
0242 diagnostics& diag
0243 );
0244
0245 }
0246 }
0247 }
0248
0249
0250
0251
0252
0253 namespace boost {
0254 namespace mysql {
0255 namespace detail {
0256
0257
0258 BOOST_INLINE_CONSTEXPR std::uint8_t error_packet_header = 0xff;
0259 BOOST_INLINE_CONSTEXPR std::uint8_t ok_packet_header = 0x00;
0260
0261 }
0262 }
0263 }
0264
0265
0266
0267
0268
0269
0270 boost::mysql::error_code boost::mysql::detail::deserialize_ok_packet(
0271 span<const std::uint8_t> msg,
0272 ok_view& output
0273 )
0274 {
0275 struct ok_packet
0276 {
0277
0278 int_lenenc affected_rows;
0279 int_lenenc last_insert_id;
0280 int2 status_flags;
0281 int2 warnings;
0282
0283 string_lenenc info;
0284 } pack{};
0285
0286 deserialization_context ctx(msg);
0287 auto err = ctx.deserialize(pack.affected_rows, pack.last_insert_id, pack.status_flags, pack.warnings);
0288 if (err != deserialize_errc::ok)
0289 return to_error_code(err);
0290
0291 if (ctx.enough_size(1))
0292 {
0293 err = pack.info.deserialize(ctx);
0294 if (err != deserialize_errc::ok)
0295 return to_error_code(err);
0296 }
0297
0298 output = {
0299 pack.affected_rows.value,
0300 pack.last_insert_id.value,
0301 pack.status_flags.value,
0302 pack.warnings.value,
0303 pack.info.value,
0304 };
0305
0306 return ctx.check_extra_bytes();
0307 }
0308
0309
0310 boost::mysql::error_code boost::mysql::detail::deserialize_error_packet(
0311 span<const std::uint8_t> msg,
0312 err_view& output,
0313 bool has_sql_state
0314 )
0315 {
0316 struct err_packet
0317 {
0318
0319 int2 error_code;
0320
0321 string_fixed<1> sql_state_marker;
0322 string_fixed<5> sql_state;
0323
0324 string_eof error_message;
0325 } pack{};
0326
0327 deserialization_context ctx(msg);
0328 auto err = has_sql_state ? ctx.deserialize(
0329 pack.error_code,
0330 pack.sql_state_marker,
0331 pack.sql_state,
0332 pack.error_message
0333 )
0334 : ctx.deserialize(pack.error_code, pack.error_message);
0335 if (err != deserialize_errc::ok)
0336 return to_error_code(err);
0337
0338 output = err_view{
0339 pack.error_code.value,
0340 pack.error_message.value,
0341 };
0342
0343 return ctx.check_extra_bytes();
0344 }
0345
0346 boost::mysql::error_code boost::mysql::detail::process_error_packet(
0347 span<const std::uint8_t> msg,
0348 db_flavor flavor,
0349 diagnostics& diag,
0350 bool has_sql_state
0351 )
0352 {
0353 err_view error_packet{};
0354 auto err = deserialize_error_packet(msg, error_packet, has_sql_state);
0355 if (err)
0356 return err;
0357
0358
0359 access::get_impl(diag).assign_server(error_packet.error_message);
0360
0361
0362 if (common_error_to_string(error_packet.error_code))
0363 {
0364
0365
0366
0367 return static_cast<common_server_errc>(error_packet.error_code);
0368 }
0369 else
0370 {
0371
0372
0373 const auto& cat = flavor == db_flavor::mysql ? get_mysql_server_category()
0374 : get_mariadb_server_category();
0375 return error_code(error_packet.error_code, cat);
0376 }
0377 }
0378
0379
0380 boost::mysql::error_code boost::mysql::detail::deserialize_column_definition(
0381 span<const std::uint8_t> input,
0382 coldef_view& output
0383 )
0384 {
0385 deserialization_context ctx(input);
0386
0387 struct column_definition_packet
0388 {
0389 string_lenenc catalog;
0390 string_lenenc schema;
0391 string_lenenc table;
0392 string_lenenc org_table;
0393 string_lenenc name;
0394 string_lenenc org_name;
0395 string_lenenc fixed_fields;
0396 } pack{};
0397
0398
0399
0400 struct fixed_fields_pack
0401 {
0402 int2 character_set;
0403 int4 column_length;
0404 int1 type;
0405 int2 flags;
0406 int1 decimals;
0407
0408 } fixed_fields{};
0409
0410
0411 auto err = ctx.deserialize(
0412 pack.catalog,
0413 pack.schema,
0414 pack.table,
0415 pack.org_table,
0416 pack.name,
0417 pack.org_name,
0418 pack.fixed_fields
0419 );
0420 if (err != deserialize_errc::ok)
0421 return to_error_code(err);
0422
0423
0424
0425
0426 deserialization_context subctx(to_span(pack.fixed_fields.value));
0427 err = subctx.deserialize(
0428 fixed_fields.character_set,
0429 fixed_fields.column_length,
0430 fixed_fields.type,
0431 fixed_fields.flags,
0432 fixed_fields.decimals
0433 );
0434 if (err != deserialize_errc::ok)
0435 return to_error_code(err);
0436
0437
0438 output = coldef_view{
0439 pack.schema.value,
0440 pack.table.value,
0441 pack.org_table.value,
0442 pack.name.value,
0443 pack.org_name.value,
0444 fixed_fields.character_set.value,
0445 fixed_fields.column_length.value,
0446 compute_column_type(
0447 static_cast<protocol_field_type>(fixed_fields.type.value),
0448 fixed_fields.flags.value,
0449 fixed_fields.character_set.value
0450 ),
0451 fixed_fields.flags.value,
0452 fixed_fields.decimals.value,
0453 };
0454
0455 return ctx.check_extra_bytes();
0456 }
0457
0458 boost::mysql::error_code boost::mysql::detail::deserialize_ok_response(
0459 span<const std::uint8_t> message,
0460 db_flavor flavor,
0461 diagnostics& diag,
0462 bool& backslash_escapes
0463 )
0464 {
0465
0466 int1 header{};
0467 deserialization_context ctx(message);
0468 auto err = to_error_code(header.deserialize(ctx));
0469 if (err)
0470 return err;
0471
0472 if (header.value == ok_packet_header)
0473 {
0474
0475 ok_view ok{};
0476 err = deserialize_ok_packet(ctx.to_span(), ok);
0477 if (err)
0478 return err;
0479 backslash_escapes = ok.backslash_escapes();
0480 return error_code();
0481 }
0482 else if (header.value == error_packet_header)
0483 {
0484
0485 return process_error_packet(ctx.to_span(), flavor, diag);
0486 }
0487 else
0488 {
0489
0490 return client_errc::protocol_value_error;
0491 }
0492 }
0493
0494 boost::mysql::error_code boost::mysql::detail::deserialize_prepare_stmt_response_impl(
0495 span<const std::uint8_t> message,
0496 prepare_stmt_response& output
0497 )
0498 {
0499 struct com_stmt_prepare_ok_packet
0500 {
0501
0502 int4 statement_id;
0503 int2 num_columns;
0504 int2 num_params;
0505 int1 reserved_1;
0506 int2 warning_count;
0507
0508 } pack{};
0509
0510 deserialization_context ctx(message);
0511
0512 auto err = ctx.deserialize(
0513 pack.statement_id,
0514 pack.num_columns,
0515 pack.num_params,
0516 pack.reserved_1,
0517 pack.warning_count
0518 );
0519 if (err != deserialize_errc::ok)
0520 return to_error_code(err);
0521
0522 output = prepare_stmt_response{
0523 pack.statement_id.value,
0524 pack.num_columns.value,
0525 pack.num_params.value,
0526 };
0527
0528 return ctx.check_extra_bytes();
0529 }
0530
0531 boost::mysql::error_code boost::mysql::detail::deserialize_prepare_stmt_response(
0532 span<const std::uint8_t> message,
0533 db_flavor flavor,
0534 prepare_stmt_response& output,
0535 diagnostics& diag
0536 )
0537 {
0538 deserialization_context ctx(message);
0539 int1 msg_type{};
0540 auto err = to_error_code(msg_type.deserialize(ctx));
0541 if (err)
0542 return err;
0543
0544 if (msg_type.value == error_packet_header)
0545 {
0546 return process_error_packet(ctx.to_span(), flavor, diag);
0547 }
0548 else if (msg_type.value != 0)
0549 {
0550 return client_errc::protocol_value_error;
0551 }
0552 else
0553 {
0554 return deserialize_prepare_stmt_response_impl(ctx.to_span(), output);
0555 }
0556 }
0557
0558
0559 boost::mysql::detail::execute_response boost::mysql::detail::deserialize_execute_response(
0560 span<const std::uint8_t> msg,
0561 db_flavor flavor,
0562 diagnostics& diag
0563 )
0564 {
0565
0566
0567
0568 deserialization_context ctx(msg);
0569 int1 msg_type{};
0570 auto err = to_error_code(msg_type.deserialize(ctx));
0571 if (err)
0572 return err;
0573
0574 if (msg_type.value == ok_packet_header)
0575 {
0576 ok_view ok{};
0577 err = deserialize_ok_packet(ctx.to_span(), ok);
0578 if (err)
0579 return err;
0580 return ok;
0581 }
0582 else if (msg_type.value == error_packet_header)
0583 {
0584 return process_error_packet(ctx.to_span(), flavor, diag);
0585 }
0586 else
0587 {
0588
0589
0590
0591 ctx.rewind(1);
0592 int_lenenc num_fields{};
0593 err = to_error_code(num_fields.deserialize(ctx));
0594 if (err)
0595 return err;
0596 err = ctx.check_extra_bytes();
0597 if (err)
0598 return err;
0599
0600
0601
0602
0603 if (num_fields.value == 0 || num_fields.value > 0xffffu)
0604 {
0605 return make_error_code(client_errc::protocol_value_error);
0606 }
0607
0608 return static_cast<std::size_t>(num_fields.value);
0609 }
0610 }
0611
0612 boost::mysql::detail::row_message boost::mysql::detail::deserialize_row_message(
0613 span<const std::uint8_t> msg,
0614 db_flavor flavor,
0615 diagnostics& diag
0616 )
0617 {
0618 constexpr std::uint8_t eof_packet_header = 0xfe;
0619
0620
0621 int1 msg_type{};
0622 deserialization_context ctx(msg);
0623 auto deser_errc = msg_type.deserialize(ctx);
0624 if (deser_errc != deserialize_errc::ok)
0625 {
0626 return to_error_code(deser_errc);
0627 }
0628
0629 if (msg_type.value == eof_packet_header)
0630 {
0631
0632 ok_view ok{};
0633 auto err = deserialize_ok_packet(ctx.to_span(), ok);
0634 if (err)
0635 return err;
0636 return ok;
0637 }
0638 else if (msg_type.value == error_packet_header)
0639 {
0640
0641 return process_error_packet(ctx.to_span(), flavor, diag);
0642 }
0643 else
0644 {
0645
0646 ctx.rewind(1);
0647 return span<const std::uint8_t>(ctx.first(), ctx.size());
0648 }
0649 }
0650
0651
0652 namespace boost {
0653 namespace mysql {
0654 namespace detail {
0655
0656 inline bool is_next_field_null(const deserialization_context& ctx)
0657 {
0658 if (!ctx.enough_size(1))
0659 return false;
0660 return *ctx.first() == 0xfb;
0661 }
0662
0663 inline error_code deserialize_text_row(
0664 deserialization_context& ctx,
0665 metadata_collection_view meta,
0666 field_view* output
0667 )
0668 {
0669 for (std::vector<field_view>::size_type i = 0; i < meta.size(); ++i)
0670 {
0671 if (is_next_field_null(ctx))
0672 {
0673 ctx.advance(1);
0674 output[i] = field_view(nullptr);
0675 }
0676 else
0677 {
0678 string_lenenc value_str;
0679 auto err = value_str.deserialize(ctx);
0680 if (err != deserialize_errc::ok)
0681 return to_error_code(err);
0682 err = deserialize_text_field(value_str.value, meta[i], output[i]);
0683 if (err != deserialize_errc::ok)
0684 return to_error_code(err);
0685 }
0686 }
0687 return ctx.check_extra_bytes();
0688 }
0689
0690 inline error_code deserialize_binary_row(
0691 deserialization_context& ctx,
0692 metadata_collection_view meta,
0693 field_view* output
0694 )
0695 {
0696
0697
0698 if (!ctx.enough_size(1))
0699 return client_errc::incomplete_message;
0700 ctx.advance(1);
0701
0702
0703 std::size_t num_fields = meta.size();
0704
0705
0706 null_bitmap_parser null_bitmap(num_fields);
0707 const std::uint8_t* null_bitmap_first = ctx.first();
0708 std::size_t null_bitmap_size = null_bitmap.byte_count();
0709 if (!ctx.enough_size(null_bitmap_size))
0710 return client_errc::incomplete_message;
0711 ctx.advance(null_bitmap_size);
0712
0713
0714 for (std::vector<field_view>::size_type i = 0; i < num_fields; ++i)
0715 {
0716 if (null_bitmap.is_null(null_bitmap_first, i))
0717 {
0718 output[i] = field_view(nullptr);
0719 }
0720 else
0721 {
0722 auto err = deserialize_binary_field(ctx, meta[i], output[i]);
0723 if (err != deserialize_errc::ok)
0724 return to_error_code(err);
0725 }
0726 }
0727
0728
0729 return ctx.check_extra_bytes();
0730 }
0731
0732 }
0733 }
0734 }
0735
0736 boost::mysql::error_code boost::mysql::detail::deserialize_row(
0737 resultset_encoding encoding,
0738 span<const std::uint8_t> buff,
0739 metadata_collection_view meta,
0740 span<field_view> output
0741 )
0742 {
0743 BOOST_ASSERT(meta.size() == output.size());
0744 deserialization_context ctx(buff);
0745 return encoding == detail::resultset_encoding::text ? deserialize_text_row(ctx, meta, output.data())
0746 : deserialize_binary_row(ctx, meta, output.data());
0747 }
0748
0749
0750 namespace boost {
0751 namespace mysql {
0752 namespace detail {
0753
0754 inline capabilities compose_capabilities(string_fixed<2> low, string_fixed<2> high)
0755 {
0756 std::uint32_t res = 0;
0757 auto capabilities_begin = reinterpret_cast<std::uint8_t*>(&res);
0758 memcpy(capabilities_begin, low.value.data(), 2);
0759 memcpy(capabilities_begin + 2, high.value.data(), 2);
0760 return capabilities(boost::endian::little_to_native(res));
0761 }
0762
0763 inline db_flavor parse_db_version(string_view version_string)
0764 {
0765 return version_string.find("MariaDB") != string_view::npos ? db_flavor::mariadb : db_flavor::mysql;
0766 }
0767
0768 }
0769 }
0770 }
0771
0772 boost::mysql::error_code boost::mysql::detail::deserialize_server_hello_impl(
0773 span<const std::uint8_t> msg,
0774 server_hello& output
0775 )
0776 {
0777 struct server_hello_packet
0778 {
0779
0780 string_null server_version;
0781 int4 connection_id;
0782 string_fixed<8> auth_plugin_data_part_1;
0783 int1 filler;
0784 string_fixed<2> capability_flags_low;
0785 int1 character_set;
0786 int2 status_flags;
0787 string_fixed<2> capability_flags_high;
0788 int1 auth_plugin_data_len;
0789 string_fixed<10> reserved;
0790
0791 string_null auth_plugin_name;
0792 } pack{};
0793
0794 deserialization_context ctx(msg);
0795
0796 auto err = ctx.deserialize(
0797 pack.server_version,
0798 pack.connection_id,
0799 pack.auth_plugin_data_part_1,
0800 pack.filler,
0801 pack.capability_flags_low,
0802 pack.character_set,
0803 pack.status_flags,
0804 pack.capability_flags_high
0805 );
0806 if (err != deserialize_errc::ok)
0807 return to_error_code(err);
0808
0809
0810 auto cap = compose_capabilities(pack.capability_flags_low, pack.capability_flags_high);
0811
0812
0813 if (!cap.has(CLIENT_PLUGIN_AUTH))
0814 return client_errc::server_unsupported;
0815
0816
0817 err = ctx.deserialize(pack.auth_plugin_data_len, pack.reserved);
0818 if (err != deserialize_errc::ok)
0819 return to_error_code(err);
0820
0821
0822 auto auth2_length = static_cast<std::uint8_t>((std::max)(
0823 static_cast<std::size_t>(13u),
0824 static_cast<std::size_t>(pack.auth_plugin_data_len.value - pack.auth_plugin_data_part_1.value.size())
0825 ));
0826 const void* auth2_data = ctx.first();
0827 if (!ctx.enough_size(auth2_length))
0828 return client_errc::incomplete_message;
0829 ctx.advance(auth2_length);
0830
0831
0832 err = pack.auth_plugin_name.deserialize(ctx);
0833 if (err != deserialize_errc::ok)
0834 return to_error_code(err);
0835
0836
0837 output.server = parse_db_version(pack.server_version.value);
0838 output.server_capabilities = cap;
0839 output.auth_plugin_name = pack.auth_plugin_name.value;
0840
0841
0842 output.auth_plugin_data.clear();
0843 output.auth_plugin_data.append(
0844 pack.auth_plugin_data_part_1.value.data(),
0845 pack.auth_plugin_data_part_1.value.size()
0846 );
0847 output.auth_plugin_data.append(auth2_data,
0848 auth2_length - 1);
0849
0850 return ctx.check_extra_bytes();
0851 }
0852
0853 boost::mysql::error_code boost::mysql::detail::deserialize_server_hello(
0854 span<const std::uint8_t> msg,
0855 server_hello& output,
0856 diagnostics& diag
0857 )
0858 {
0859 constexpr std::uint8_t handshake_protocol_version_9 = 9;
0860 constexpr std::uint8_t handshake_protocol_version_10 = 10;
0861
0862 deserialization_context ctx(msg);
0863
0864
0865 int1 msg_type{};
0866 auto err = to_error_code(msg_type.deserialize(ctx));
0867 if (err)
0868 return err;
0869 if (msg_type.value == handshake_protocol_version_9)
0870 {
0871 return make_error_code(client_errc::server_unsupported);
0872 }
0873 else if (msg_type.value == error_packet_header)
0874 {
0875
0876
0877
0878 return process_error_packet(ctx.to_span(), db_flavor::mysql, diag, false);
0879 }
0880 else if (msg_type.value != handshake_protocol_version_10)
0881 {
0882 return make_error_code(client_errc::protocol_value_error);
0883 }
0884 else
0885 {
0886 return deserialize_server_hello_impl(ctx.to_span(), output);
0887 }
0888 }
0889
0890
0891 BOOST_ATTRIBUTE_NODISCARD
0892 boost::mysql::error_code boost::mysql::detail::deserialize_auth_switch(
0893 span<const std::uint8_t> msg,
0894 auth_switch& output
0895 )
0896 {
0897 struct auth_switch_request_packet
0898 {
0899 string_null plugin_name;
0900 string_eof auth_plugin_data;
0901 } pack{};
0902
0903 deserialization_context ctx(msg);
0904
0905 auto err = ctx.deserialize(pack.plugin_name, pack.auth_plugin_data);
0906 if (err != deserialize_errc::ok)
0907 return to_error_code(err);
0908
0909
0910 string_view auth_data = pack.auth_plugin_data.value;
0911 if (!auth_data.empty() && auth_data.back() == 0)
0912 {
0913 auth_data = auth_data.substr(0, auth_data.size() - 1);
0914 }
0915
0916 output = {
0917 pack.plugin_name.value,
0918 to_span(auth_data),
0919 };
0920
0921 return ctx.check_extra_bytes();
0922 }
0923
0924 boost::mysql::detail::handhake_server_response boost::mysql::detail::deserialize_handshake_server_response(
0925 span<const std::uint8_t> buff,
0926 db_flavor flavor,
0927 diagnostics& diag
0928 )
0929 {
0930 constexpr std::uint8_t auth_switch_request_header = 0xfe;
0931 constexpr std::uint8_t auth_more_data_header = 0x01;
0932 constexpr string_view fast_auth_complete_challenge = make_string_view("\3");
0933
0934 deserialization_context ctx(buff);
0935 int1 msg_type{};
0936 auto err = to_error_code(msg_type.deserialize(ctx));
0937 if (err)
0938 return err;
0939
0940 if (msg_type.value == ok_packet_header)
0941 {
0942 ok_view ok{};
0943 err = deserialize_ok_packet(ctx.to_span(), ok);
0944 if (err)
0945 return err;
0946 return ok;
0947 }
0948 else if (msg_type.value == error_packet_header)
0949 {
0950 return process_error_packet(ctx.to_span(), flavor, diag);
0951 }
0952 else if (msg_type.value == auth_switch_request_header)
0953 {
0954
0955 auth_switch auth_sw{};
0956 err = deserialize_auth_switch(ctx.to_span(), auth_sw);
0957 if (err)
0958 return err;
0959 return auth_sw;
0960 }
0961 else if (msg_type.value == auth_more_data_header)
0962 {
0963
0964
0965 string_eof auth_more_data;
0966 auto ec = auth_more_data.deserialize(ctx);
0967 BOOST_ASSERT(ec == deserialize_errc::ok);
0968 boost::ignore_unused(ec);
0969
0970
0971
0972
0973
0974 string_view challenge = auth_more_data.value;
0975 if (challenge == fast_auth_complete_challenge)
0976 {
0977 return handhake_server_response::ok_follows_t();
0978 }
0979
0980
0981 return handhake_server_response(to_span(challenge));
0982 }
0983 else
0984 {
0985
0986 return make_error_code(client_errc::protocol_value_error);
0987 }
0988 }
0989
0990 #endif