aboutsummaryrefslogtreecommitdiffhomepage
path: root/vendor/github.com/hashicorp/terraform/registry/regsrc/friendly_host.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/hashicorp/terraform/registry/regsrc/friendly_host.go')
-rw-r--r--vendor/github.com/hashicorp/terraform/registry/regsrc/friendly_host.go140
1 files changed, 140 insertions, 0 deletions
diff --git a/vendor/github.com/hashicorp/terraform/registry/regsrc/friendly_host.go b/vendor/github.com/hashicorp/terraform/registry/regsrc/friendly_host.go
new file mode 100644
index 0000000..14b4dce
--- /dev/null
+++ b/vendor/github.com/hashicorp/terraform/registry/regsrc/friendly_host.go
@@ -0,0 +1,140 @@
1package regsrc
2
3import (
4 "regexp"
5 "strings"
6
7 "github.com/hashicorp/terraform/svchost"
8)
9
10var (
11 // InvalidHostString is a placeholder returned when a raw host can't be
12 // converted by IDNA spec. It will never be returned for any host for which
13 // Valid() is true.
14 InvalidHostString = "<invalid host>"
15
16 // urlLabelEndSubRe is a sub-expression that matches any character that's
17 // allowed at the start or end of a URL label according to RFC1123.
18 urlLabelEndSubRe = "[0-9A-Za-z]"
19
20 // urlLabelEndSubRe is a sub-expression that matches any character that's
21 // allowed at in a non-start or end of a URL label according to RFC1123.
22 urlLabelMidSubRe = "[0-9A-Za-z-]"
23
24 // urlLabelUnicodeSubRe is a sub-expression that matches any non-ascii char
25 // in an IDN (Unicode) display URL. It's not strict - there are only ~15k
26 // valid Unicode points in IDN RFC (some with conditions). We are just going
27 // with being liberal with matching and then erroring if we fail to convert
28 // to punycode later (which validates chars fully). This at least ensures
29 // ascii chars dissalowed by the RC1123 parts above don't become legal
30 // again.
31 urlLabelUnicodeSubRe = "[^[:ascii:]]"
32
33 // hostLabelSubRe is the sub-expression that matches a valid hostname label.
34 // It does not anchor the start or end so it can be composed into more
35 // complex RegExps below. Note that for sanity we don't handle disallowing
36 // raw punycode in this regexp (esp. since re2 doesn't support negative
37 // lookbehind, but we can capture it's presence here to check later).
38 hostLabelSubRe = "" +
39 // Match valid initial char, or unicode char
40 "(?:" + urlLabelEndSubRe + "|" + urlLabelUnicodeSubRe + ")" +
41 // Optionally, match 0 to 61 valid URL or Unicode chars,
42 // followed by one valid end char or unicode char
43 "(?:" +
44 "(?:" + urlLabelMidSubRe + "|" + urlLabelUnicodeSubRe + "){0,61}" +
45 "(?:" + urlLabelEndSubRe + "|" + urlLabelUnicodeSubRe + ")" +
46 ")?"
47
48 // hostSubRe is the sub-expression that matches a valid host prefix.
49 // Allows custom port.
50 hostSubRe = hostLabelSubRe + "(?:\\." + hostLabelSubRe + ")+(?::\\d+)?"
51
52 // hostRe is a regexp that matches a valid host prefix. Additional
53 // validation of unicode strings is needed for matches.
54 hostRe = regexp.MustCompile("^" + hostSubRe + "$")
55)
56
57// FriendlyHost describes a registry instance identified in source strings by a
58// simple bare hostname like registry.terraform.io.
59type FriendlyHost struct {
60 Raw string
61}
62
63func NewFriendlyHost(host string) *FriendlyHost {
64 return &FriendlyHost{Raw: host}
65}
66
67// ParseFriendlyHost attempts to parse a valid "friendly host" prefix from the
68// given string. If no valid prefix is found, host will be nil and rest will
69// contain the full source string. The host prefix must terminate at the end of
70// the input or at the first / character. If one or more characters exist after
71// the first /, they will be returned as rest (without the / delimiter).
72// Hostnames containing punycode WILL be parsed successfully since they may have
73// come from an internal normalized source string, however should be considered
74// invalid if the string came from a user directly. This must be checked
75// explicitly for user-input strings by calling Valid() on the
76// returned host.
77func ParseFriendlyHost(source string) (host *FriendlyHost, rest string) {
78 parts := strings.SplitN(source, "/", 2)
79
80 if hostRe.MatchString(parts[0]) {
81 host = &FriendlyHost{Raw: parts[0]}
82 if len(parts) == 2 {
83 rest = parts[1]
84 }
85 return
86 }
87
88 // No match, return whole string as rest along with nil host
89 rest = source
90 return
91}
92
93// Valid returns whether the host prefix is considered valid in any case.
94// Example of invalid prefixes might include ones that don't conform to the host
95// name specifications. Not that IDN prefixes containing punycode are not valid
96// input which we expect to always be in user-input or normalised display form.
97func (h *FriendlyHost) Valid() bool {
98 return svchost.IsValid(h.Raw)
99}
100
101// Display returns the host formatted for display to the user in CLI or web
102// output.
103func (h *FriendlyHost) Display() string {
104 return svchost.ForDisplay(h.Raw)
105}
106
107// Normalized returns the host formatted for internal reference or comparison.
108func (h *FriendlyHost) Normalized() string {
109 host, err := svchost.ForComparison(h.Raw)
110 if err != nil {
111 return InvalidHostString
112 }
113 return string(host)
114}
115
116// String returns the host formatted as the user originally typed it assuming it
117// was parsed from user input.
118func (h *FriendlyHost) String() string {
119 return h.Raw
120}
121
122// Equal compares the FriendlyHost against another instance taking normalization
123// into account. Invalid hosts cannot be compared and will always return false.
124func (h *FriendlyHost) Equal(other *FriendlyHost) bool {
125 if other == nil {
126 return false
127 }
128
129 otherHost, err := svchost.ForComparison(other.Raw)
130 if err != nil {
131 return false
132 }
133
134 host, err := svchost.ForComparison(h.Raw)
135 if err != nil {
136 return false
137 }
138
139 return otherHost == host
140}