1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
|
// 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 <cstdlib>
#include <iterator>
#include <limits>
#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<uri_part> &user_info, optional<uri_part> &host,
optional<uri_part> &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
|