4
4
#include < optional>
5
5
#include < string>
6
6
#include < string_view>
7
+ #include < vector>
7
8
8
9
// TODO: remove these once the warnings are fixed
9
10
#pragma clang diagnostic push
15
16
#include " host_call.h"
16
17
#include " js/Conversions.h"
17
18
18
- bool isDash (char character) { return character == 45 ; }
19
- bool isDot (char character) { return character == 46 ; }
20
-
21
- bool isNotAlphaNumericOrDash (char character) {
22
- return !std::isalnum (character) && !isDash (character);
23
- }
24
-
25
- bool isNotAlphaNumericDotOrDash (char character) {
26
- return !std::isalnum (character) && !isDash (character) && !isDot (character);
19
+ std::vector<std::string_view> split (std::string_view string, char delimiter) {
20
+ auto start = 0 ;
21
+ auto end = string.find (delimiter, start);
22
+ std::vector<std::string_view> result;
23
+ while (end != std::string::npos) {
24
+ result.push_back (string.substr (start, end - start));
25
+ start = end + 1 ;
26
+ end = string.find (delimiter, start);
27
+ }
28
+ result.push_back (string.substr (start));
29
+ return result;
27
30
}
28
31
32
+ // A "host" is a "hostname" and an optional "port" in the format hostname:port
33
+ // A "hostname" is between 1 and 255 octets -- https://www.rfc-editor.org/rfc/rfc1123#page-13
34
+ // A "hostname" must start with a letter or digit -- https://www.rfc-editor.org/rfc/rfc1123#page-13
35
+ // A "hostname" is made up of "labels" delimited by a dot `.`
36
+ // A "label" is between 1 and 63 octets
29
37
bool isValidHost (std::string_view host) {
30
- // ValidHostRegex =
31
- // "^(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\-]*[A-Za-z0-9])(:[0-9]+)$";
38
+ if (host.length () < 1 ) {
39
+ return false ;
40
+ }
32
41
auto firstCharacter = host.front ();
33
42
// check first character is in the regex [a-zA-Z0-9]
34
43
if (!std::isalnum (firstCharacter)) {
@@ -38,37 +47,42 @@ bool isValidHost(std::string_view host) {
38
47
int pos = host.find_first_of (' :' );
39
48
std::string_view hostname = host.substr (0 , pos);
40
49
50
+ // hostnames can not be longer than 253 characters
51
+ // This is because a hostname is represented as a series of labels, and is terminated by a label of length zero.
52
+ // A label consists of a length octet followed by that number of octets representing the name itself.
53
+ // https://www.rfc-editor.org/rfc/rfc1035#section-3.3
54
+ // https://www.rfc-editor.org/rfc/rfc2181#section-11
55
+ if (hostname.length () > 253 ) {
56
+ return false ;
57
+ }
58
+
41
59
auto lastCharacter = hostname.back ();
42
60
// check last character is in the regex [a-zA-Z0-9]
43
61
if (!std::isalnum (lastCharacter)) {
44
62
return false ;
45
63
}
46
64
47
- // find the position of the last .
48
- auto lastDot = hostname.rfind (' .' );
49
- if (lastDot == std::string::npos) {
50
- return true ;
51
- }
65
+ auto labels = split (hostname, ' .' );
52
66
53
- // check the character before the last . is in the regex [a-zA-Z0-9]
54
- if (!std::isalnum (hostname.at (lastDot - 1 ))) {
55
- return false ;
56
- }
57
- // check all other characters before the last . are in the regex [a-zA-Z0-9\-.]
58
- auto last = std::next (hostname.begin (), lastDot);
59
- auto it = std::find_if (std::next (hostname.begin ()), last, isNotAlphaNumericDotOrDash);
67
+ for (auto label:labels) {
68
+ // Each label in a hostname can not be longer than 63 characters
69
+ // https://www.rfc-editor.org/rfc/rfc2181#section-11
70
+ if (label.length () > 63 ) {
71
+ return false ;
72
+ }
60
73
61
- if (it != last) {
62
- return false ;
63
- }
64
- // check all characters after the last . (but not the last character) are in the regex
65
- // [a-zA-Z0-9\-]
66
- last = std::prev (hostname.end ());
67
- it = std::find_if (std::next (hostname.begin (), lastDot + 1 ), last, isNotAlphaNumericOrDash);
68
- if (it != last) {
69
- return false ;
74
+ // Each label can only contain the characters in the regex [a-zA-Z0-9\-]
75
+ auto it = std::find_if_not (label.begin (), label.end (), [&](auto character) {
76
+ return std::isalnum (character) || character == ' -' ;
77
+ });
78
+ if (it != label.end ()) {
79
+
80
+ return false ;
81
+ }
70
82
}
83
+
71
84
// if there is a port - confirm it is all digits and is between 0 and 65536
85
+ // https://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.xhtml
72
86
if (pos != std::string::npos) {
73
87
std::string_view port = host.substr (pos + 1 );
74
88
if (!std::all_of (port.begin (), port.end (), ::isdigit)) {
0 commit comments