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