// Copyright 2016 Glyn Matthews. // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #include "uri_parse_authority.hpp" #include #include #include #include "grammar.hpp" namespace network { namespace detail { namespace { enum class authority_state { user_info, host, host_ipv6, port }; } // namespace bool parse_authority(string_view::const_iterator &it, string_view::const_iterator last, optional &user_info, optional &host, optional &port) { auto first = it; auto state = authority_state::user_info; while (it != last) { if (state == authority_state::user_info) { if (is_in(first, last, "@:")) { return false; } if (*it == '@') { user_info = uri_part(first, it); state = authority_state::host; ++it; first = it; continue; } else if (*it == '[') { // this is an IPv6 address state = authority_state::host_ipv6; first = it; continue; } else if (*it == ':') { // this is actually the host, and the next part is expected to be the // port host = uri_part(first, it); state = authority_state::port; ++it; first = it; continue; } } else if (state == authority_state::host) { if (*first == ':') { return false; } if (*it == ':') { host = uri_part(first, it); state = authority_state::port; ++it; first = it; continue; } } else if (state == authority_state::host_ipv6) { if (*first != '[') { return false; } if (*it == ']') { host = uri_part(first, it); ++it; // Then test if the next part is a host, part, or the end of the file if (it == last) { break; } else if (*it == ':') { host = uri_part(first, it); state = authority_state::port; ++it; first = it; } } } else if (state == authority_state::port) { if (*first == '/') { // the port is empty, but valid port = uri_part(first, it); if (!is_valid_port(std::begin(*port))) { return false; } continue; } if (!isdigit(it, last)) { return false; } } ++it; } if (state == authority_state::user_info) { host = uri_part(first, last); } else if (state == authority_state::host) { host = uri_part(first, last); } else if (state == authority_state::host_ipv6) { host = uri_part(first, last); } else if (state == authority_state::port) { port = uri_part(first, last); if (!is_valid_port(std::begin(*port))) { return false; } } return true; } } // namespace detail } // namespace network