| 100 | { |
| 101 | |
| 102 | bool tryParseConnectionString( |
| 103 | std::string_view connection_string, |
| 104 | std::vector<std::string> & common_arguments, |
| 105 | std::vector<std::vector<std::string>> & hosts_and_ports_arguments) |
| 106 | { |
| 107 | if (connection_string == CONNECTION_URI_SCHEME) |
| 108 | return true; |
| 109 | |
| 110 | if (!connection_string.starts_with(CONNECTION_URI_SCHEME)) |
| 111 | return false; |
| 112 | |
| 113 | size_t offset = CONNECTION_URI_SCHEME.size(); |
| 114 | if ((connection_string.substr(offset).starts_with("//"))) |
| 115 | offset += 2; |
| 116 | |
| 117 | auto hosts_end_pos = std::string_view::npos; |
| 118 | auto hosts_or_user_info_end_pos = connection_string.find_first_of("?/@", offset); |
| 119 | |
| 120 | auto has_user_info = hosts_or_user_info_end_pos != std::string_view::npos && connection_string[hosts_or_user_info_end_pos] == '@'; |
| 121 | if (has_user_info) |
| 122 | { |
| 123 | // Move offset right after user info |
| 124 | offset = hosts_or_user_info_end_pos + 1; |
| 125 | hosts_end_pos = connection_string.find_first_of("?/@", offset); |
| 126 | // Several '@' symbols in connection string is prohibited. |
| 127 | // If user name contains '@' then it should be percent-encoded. |
| 128 | // several users: 'usr1@host1,@usr2@host2' is invalid. |
| 129 | if (hosts_end_pos != std::string_view::npos && connection_string[hosts_end_pos] == '@') |
| 130 | { |
| 131 | throw Exception(ErrorCodes::BAD_ARGUMENTS, |
| 132 | "Symbols '@' in URI in password or user name should be percent-encoded. Individual user names for different hosts also prohibited. {}", |
| 133 | connection_string); |
| 134 | } |
| 135 | } |
| 136 | else |
| 137 | hosts_end_pos = hosts_or_user_info_end_pos; |
| 138 | |
| 139 | const auto hosts_end = hosts_end_pos != std::string_view::npos ? connection_string.begin() + hosts_end_pos |
| 140 | : connection_string.end(); |
| 141 | |
| 142 | try |
| 143 | { |
| 144 | /** Poco::URI doesn't support several hosts in URI. |
| 145 | * Split string clickhouse:[user[:password]@]host1:port1, ... , hostN:portN[database]?[query_parameters] |
| 146 | * into multiple string for each host: |
| 147 | * clickhouse:[user[:password]@]host1:port1[database]?[query_parameters] |
| 148 | * ... |
| 149 | * clickhouse:[user[:password]@]hostN:portN[database]?[query_parameters] |
| 150 | */ |
| 151 | Poco::URI uri; |
| 152 | auto last_host_begin = connection_string.begin() + offset; |
| 153 | for (auto it = last_host_begin; it != hosts_end; ++it) |
| 154 | { |
| 155 | if (*it == ',') |
| 156 | { |
| 157 | buildConnectionString({last_host_begin, it}, {hosts_end, connection_string.end()}, uri, hosts_and_ports_arguments); |
| 158 | last_host_begin = it + 1; |
| 159 | } |
no test coverage detected