Split apart repository reference into domain and path
Allows having other parsers which are capable of unambiguously keeping domain and path separated in a Reference type. Signed-off-by: Derek McGowan <derek@mcgstyle.net> (github: dmcgowan)master
							parent
							
								
									76f514b618
								
							
						
					
					
						commit
						9a43b8f696
					
				|  | @ -4,11 +4,11 @@ | |||
| // Grammar
 | ||||
| //
 | ||||
| // 	reference                       := name [ ":" tag ] [ "@" digest ]
 | ||||
| //	name                            := [hostname '/'] component ['/' component]*
 | ||||
| //	hostname                        := hostcomponent ['.' hostcomponent]* [':' port-number]
 | ||||
| //	hostcomponent                   := /([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9])/
 | ||||
| //	name                            := [domain '/'] path-component ['/' path-component]*
 | ||||
| //	domain                          := domain-component ['.' domain-component]* [':' port-number]
 | ||||
| //	domain-component                := /([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9])/
 | ||||
| //	port-number                     := /[0-9]+/
 | ||||
| //	component                       := alpha-numeric [separator alpha-numeric]*
 | ||||
| //	path-component                  := alpha-numeric [separator alpha-numeric]*
 | ||||
| // 	alpha-numeric                   := /[a-z0-9]+/
 | ||||
| //	separator                       := /[_.]|__|[-]*/
 | ||||
| //
 | ||||
|  | @ -126,23 +126,56 @@ type Digested interface { | |||
| } | ||||
| 
 | ||||
| // Canonical reference is an object with a fully unique
 | ||||
| // name including a name with hostname and digest
 | ||||
| // name including a name with domain and digest
 | ||||
| type Canonical interface { | ||||
| 	Named | ||||
| 	Digest() digest.Digest | ||||
| } | ||||
| 
 | ||||
| // NamedRepository is a reference to a repository with a name.
 | ||||
| // A NamedRepository has both domain and path components.
 | ||||
| type NamedRepository interface { | ||||
| 	Named | ||||
| 	Domain() string | ||||
| 	Path() string | ||||
| } | ||||
| 
 | ||||
| // Domain returns the domain part of the Named reference
 | ||||
| func Domain(named Named) string { | ||||
| 	if r, ok := named.(NamedRepository); ok { | ||||
| 		return r.Domain() | ||||
| 	} | ||||
| 	domain, _ := splitDomain(named.Name()) | ||||
| 	return domain | ||||
| } | ||||
| 
 | ||||
| // Path returns the name without the domain part of the Named reference
 | ||||
| func Path(named Named) (name string) { | ||||
| 	if r, ok := named.(NamedRepository); ok { | ||||
| 		return r.Path() | ||||
| 	} | ||||
| 	_, path := splitDomain(named.Name()) | ||||
| 	return path | ||||
| } | ||||
| 
 | ||||
| func splitDomain(name string) (string, string) { | ||||
| 	match := anchoredNameRegexp.FindStringSubmatch(name) | ||||
| 	if len(match) != 3 { | ||||
| 		return "", name | ||||
| 	} | ||||
| 	return match[1], match[2] | ||||
| } | ||||
| 
 | ||||
| // SplitHostname splits a named reference into a
 | ||||
| // hostname and name string. If no valid hostname is
 | ||||
| // found, the hostname is empty and the full value
 | ||||
| // is returned as name
 | ||||
| // DEPRECATED: Use Domain or Path
 | ||||
| func SplitHostname(named Named) (string, string) { | ||||
| 	name := named.Name() | ||||
| 	match := anchoredNameRegexp.FindStringSubmatch(name) | ||||
| 	if len(match) != 3 { | ||||
| 		return "", name | ||||
| 	if r, ok := named.(NamedRepository); ok { | ||||
| 		return r.Domain(), r.Path() | ||||
| 	} | ||||
| 	return match[1], match[2] | ||||
| 	return splitDomain(named.Name()) | ||||
| } | ||||
| 
 | ||||
| // Parse parses s and returns a syntactically valid Reference.
 | ||||
|  | @ -164,9 +197,20 @@ func Parse(s string) (Reference, error) { | |||
| 		return nil, ErrNameTooLong | ||||
| 	} | ||||
| 
 | ||||
| 	var repo repository | ||||
| 
 | ||||
| 	nameMatch := anchoredNameRegexp.FindStringSubmatch(matches[1]) | ||||
| 	if nameMatch != nil && len(nameMatch) == 3 { | ||||
| 		repo.domain = nameMatch[1] | ||||
| 		repo.path = nameMatch[2] | ||||
| 	} else { | ||||
| 		repo.domain = "" | ||||
| 		repo.path = matches[1] | ||||
| 	} | ||||
| 
 | ||||
| 	ref := reference{ | ||||
| 		name: matches[1], | ||||
| 		tag:  matches[2], | ||||
| 		repository: repo, | ||||
| 		tag:        matches[2], | ||||
| 	} | ||||
| 	if matches[3] != "" { | ||||
| 		var err error | ||||
|  | @ -207,10 +251,15 @@ func WithName(name string) (Named, error) { | |||
| 	if len(name) > NameTotalLengthMax { | ||||
| 		return nil, ErrNameTooLong | ||||
| 	} | ||||
| 	if !anchoredNameRegexp.MatchString(name) { | ||||
| 
 | ||||
| 	match := anchoredNameRegexp.FindStringSubmatch(name) | ||||
| 	if match == nil || len(match) != 3 { | ||||
| 		return nil, ErrReferenceInvalidFormat | ||||
| 	} | ||||
| 	return repository(name), nil | ||||
| 	return repository{ | ||||
| 		domain: match[1], | ||||
| 		path:   match[2], | ||||
| 	}, nil | ||||
| } | ||||
| 
 | ||||
| // WithTag combines the name from "name" and the tag from "tag" to form a
 | ||||
|  | @ -219,16 +268,23 @@ func WithTag(name Named, tag string) (NamedTagged, error) { | |||
| 	if !anchoredTagRegexp.MatchString(tag) { | ||||
| 		return nil, ErrTagInvalidFormat | ||||
| 	} | ||||
| 	var repo repository | ||||
| 	if r, ok := name.(NamedRepository); ok { | ||||
| 		repo.domain = r.Domain() | ||||
| 		repo.path = r.Path() | ||||
| 	} else { | ||||
| 		repo.path = name.Name() | ||||
| 	} | ||||
| 	if canonical, ok := name.(Canonical); ok { | ||||
| 		return reference{ | ||||
| 			name:   name.Name(), | ||||
| 			repository: repo, | ||||
| 			tag:    tag, | ||||
| 			digest: canonical.Digest(), | ||||
| 		}, nil | ||||
| 	} | ||||
| 	return taggedReference{ | ||||
| 		name: name.Name(), | ||||
| 		tag:  tag, | ||||
| 		repository: repo, | ||||
| 		tag:        tag, | ||||
| 	}, nil | ||||
| } | ||||
| 
 | ||||
|  | @ -238,16 +294,23 @@ func WithDigest(name Named, digest digest.Digest) (Canonical, error) { | |||
| 	if !anchoredDigestRegexp.MatchString(digest.String()) { | ||||
| 		return nil, ErrDigestInvalidFormat | ||||
| 	} | ||||
| 	var repo repository | ||||
| 	if r, ok := name.(NamedRepository); ok { | ||||
| 		repo.domain = r.Domain() | ||||
| 		repo.path = r.Path() | ||||
| 	} else { | ||||
| 		repo.path = name.Name() | ||||
| 	} | ||||
| 	if tagged, ok := name.(Tagged); ok { | ||||
| 		return reference{ | ||||
| 			name:   name.Name(), | ||||
| 			repository: repo, | ||||
| 			tag:    tagged.Tag(), | ||||
| 			digest: digest, | ||||
| 		}, nil | ||||
| 	} | ||||
| 	return canonicalReference{ | ||||
| 		name:   name.Name(), | ||||
| 		digest: digest, | ||||
| 		repository: repo, | ||||
| 		digest:     digest, | ||||
| 	}, nil | ||||
| } | ||||
| 
 | ||||
|  | @ -267,7 +330,7 @@ func TrimNamed(ref Named) Named { | |||
| } | ||||
| 
 | ||||
| func getBestReferenceType(ref reference) Reference { | ||||
| 	if ref.name == "" { | ||||
| 	if ref.repository.path == "" { | ||||
| 		// Allow digest only references
 | ||||
| 		if ref.digest != "" { | ||||
| 			return digestReference(ref.digest) | ||||
|  | @ -277,16 +340,16 @@ func getBestReferenceType(ref reference) Reference { | |||
| 	if ref.tag == "" { | ||||
| 		if ref.digest != "" { | ||||
| 			return canonicalReference{ | ||||
| 				name:   ref.name, | ||||
| 				digest: ref.digest, | ||||
| 				repository: ref.repository, | ||||
| 				digest:     ref.digest, | ||||
| 			} | ||||
| 		} | ||||
| 		return repository(ref.name) | ||||
| 		return ref.repository | ||||
| 	} | ||||
| 	if ref.digest == "" { | ||||
| 		return taggedReference{ | ||||
| 			name: ref.name, | ||||
| 			tag:  ref.tag, | ||||
| 			repository: ref.repository, | ||||
| 			tag:        ref.tag, | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
|  | @ -294,17 +357,13 @@ func getBestReferenceType(ref reference) Reference { | |||
| } | ||||
| 
 | ||||
| type reference struct { | ||||
| 	name   string | ||||
| 	repository | ||||
| 	tag    string | ||||
| 	digest digest.Digest | ||||
| } | ||||
| 
 | ||||
| func (r reference) String() string { | ||||
| 	return r.name + ":" + r.tag + "@" + r.digest.String() | ||||
| } | ||||
| 
 | ||||
| func (r reference) Name() string { | ||||
| 	return r.name | ||||
| 	return r.Name() + ":" + r.tag + "@" + r.digest.String() | ||||
| } | ||||
| 
 | ||||
| func (r reference) Tag() string { | ||||
|  | @ -315,14 +374,28 @@ func (r reference) Digest() digest.Digest { | |||
| 	return r.digest | ||||
| } | ||||
| 
 | ||||
| type repository string | ||||
| type repository struct { | ||||
| 	domain string | ||||
| 	path   string | ||||
| } | ||||
| 
 | ||||
| func (r repository) String() string { | ||||
| 	return string(r) | ||||
| 	return r.Name() | ||||
| } | ||||
| 
 | ||||
| func (r repository) Name() string { | ||||
| 	return string(r) | ||||
| 	if r.domain == "" { | ||||
| 		return r.path | ||||
| 	} | ||||
| 	return r.domain + "/" + r.path | ||||
| } | ||||
| 
 | ||||
| func (r repository) Domain() string { | ||||
| 	return r.domain | ||||
| } | ||||
| 
 | ||||
| func (r repository) Path() string { | ||||
| 	return r.path | ||||
| } | ||||
| 
 | ||||
| type digestReference digest.Digest | ||||
|  | @ -336,16 +409,12 @@ func (d digestReference) Digest() digest.Digest { | |||
| } | ||||
| 
 | ||||
| type taggedReference struct { | ||||
| 	name string | ||||
| 	tag  string | ||||
| 	repository | ||||
| 	tag string | ||||
| } | ||||
| 
 | ||||
| func (t taggedReference) String() string { | ||||
| 	return t.name + ":" + t.tag | ||||
| } | ||||
| 
 | ||||
| func (t taggedReference) Name() string { | ||||
| 	return t.name | ||||
| 	return t.Name() + ":" + t.tag | ||||
| } | ||||
| 
 | ||||
| func (t taggedReference) Tag() string { | ||||
|  | @ -353,16 +422,12 @@ func (t taggedReference) Tag() string { | |||
| } | ||||
| 
 | ||||
| type canonicalReference struct { | ||||
| 	name   string | ||||
| 	repository | ||||
| 	digest digest.Digest | ||||
| } | ||||
| 
 | ||||
| func (c canonicalReference) String() string { | ||||
| 	return c.name + "@" + c.digest.String() | ||||
| } | ||||
| 
 | ||||
| func (c canonicalReference) Name() string { | ||||
| 	return c.name | ||||
| 	return c.Name() + "@" + c.digest.String() | ||||
| } | ||||
| 
 | ||||
| func (c canonicalReference) Digest() digest.Digest { | ||||
|  |  | |||
|  | @ -21,8 +21,8 @@ func TestReferenceParse(t *testing.T) { | |||
| 		err error | ||||
| 		// repository is the string representation for the reference
 | ||||
| 		repository string | ||||
| 		// hostname is the hostname expected in the reference
 | ||||
| 		hostname string | ||||
| 		// domain is the domain expected in the reference
 | ||||
| 		domain string | ||||
| 		// tag is the tag for the reference
 | ||||
| 		tag string | ||||
| 		// digest is the digest for the reference (enforces digest reference)
 | ||||
|  | @ -44,37 +44,37 @@ func TestReferenceParse(t *testing.T) { | |||
| 		}, | ||||
| 		{ | ||||
| 			input:      "test.com/repo:tag", | ||||
| 			hostname:   "test.com", | ||||
| 			domain:     "test.com", | ||||
| 			repository: "test.com/repo", | ||||
| 			tag:        "tag", | ||||
| 		}, | ||||
| 		{ | ||||
| 			input:      "test:5000/repo", | ||||
| 			hostname:   "test:5000", | ||||
| 			domain:     "test:5000", | ||||
| 			repository: "test:5000/repo", | ||||
| 		}, | ||||
| 		{ | ||||
| 			input:      "test:5000/repo:tag", | ||||
| 			hostname:   "test:5000", | ||||
| 			domain:     "test:5000", | ||||
| 			repository: "test:5000/repo", | ||||
| 			tag:        "tag", | ||||
| 		}, | ||||
| 		{ | ||||
| 			input:      "test:5000/repo@sha256:ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", | ||||
| 			hostname:   "test:5000", | ||||
| 			domain:     "test:5000", | ||||
| 			repository: "test:5000/repo", | ||||
| 			digest:     "sha256:ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", | ||||
| 		}, | ||||
| 		{ | ||||
| 			input:      "test:5000/repo:tag@sha256:ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", | ||||
| 			hostname:   "test:5000", | ||||
| 			domain:     "test:5000", | ||||
| 			repository: "test:5000/repo", | ||||
| 			tag:        "tag", | ||||
| 			digest:     "sha256:ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", | ||||
| 		}, | ||||
| 		{ | ||||
| 			input:      "test:5000/repo", | ||||
| 			hostname:   "test:5000", | ||||
| 			domain:     "test:5000", | ||||
| 			repository: "test:5000/repo", | ||||
| 		}, | ||||
| 		{ | ||||
|  | @ -122,7 +122,7 @@ func TestReferenceParse(t *testing.T) { | |||
| 		}, | ||||
| 		{ | ||||
| 			input:      strings.Repeat("a/", 127) + "a:tag-puts-this-over-max", | ||||
| 			hostname:   "a", | ||||
| 			domain:     "a", | ||||
| 			repository: strings.Repeat("a/", 127) + "a", | ||||
| 			tag:        "tag-puts-this-over-max", | ||||
| 		}, | ||||
|  | @ -132,30 +132,30 @@ func TestReferenceParse(t *testing.T) { | |||
| 		}, | ||||
| 		{ | ||||
| 			input:      "sub-dom1.foo.com/bar/baz/quux", | ||||
| 			hostname:   "sub-dom1.foo.com", | ||||
| 			domain:     "sub-dom1.foo.com", | ||||
| 			repository: "sub-dom1.foo.com/bar/baz/quux", | ||||
| 		}, | ||||
| 		{ | ||||
| 			input:      "sub-dom1.foo.com/bar/baz/quux:some-long-tag", | ||||
| 			hostname:   "sub-dom1.foo.com", | ||||
| 			domain:     "sub-dom1.foo.com", | ||||
| 			repository: "sub-dom1.foo.com/bar/baz/quux", | ||||
| 			tag:        "some-long-tag", | ||||
| 		}, | ||||
| 		{ | ||||
| 			input:      "b.gcr.io/test.example.com/my-app:test.example.com", | ||||
| 			hostname:   "b.gcr.io", | ||||
| 			domain:     "b.gcr.io", | ||||
| 			repository: "b.gcr.io/test.example.com/my-app", | ||||
| 			tag:        "test.example.com", | ||||
| 		}, | ||||
| 		{ | ||||
| 			input:      "xn--n3h.com/myimage:xn--n3h.com", // ☃.com in punycode
 | ||||
| 			hostname:   "xn--n3h.com", | ||||
| 			domain:     "xn--n3h.com", | ||||
| 			repository: "xn--n3h.com/myimage", | ||||
| 			tag:        "xn--n3h.com", | ||||
| 		}, | ||||
| 		{ | ||||
| 			input:      "xn--7o8h.com/myimage:xn--7o8h.com@sha512:ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", // 🐳.com in punycode
 | ||||
| 			hostname:   "xn--7o8h.com", | ||||
| 			domain:     "xn--7o8h.com", | ||||
| 			repository: "xn--7o8h.com/myimage", | ||||
| 			tag:        "xn--7o8h.com", | ||||
| 			digest:     "sha512:ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", | ||||
|  | @ -167,7 +167,7 @@ func TestReferenceParse(t *testing.T) { | |||
| 		}, | ||||
| 		{ | ||||
| 			input:      "foo/foo_bar.com:8080", | ||||
| 			hostname:   "foo", | ||||
| 			domain:     "foo", | ||||
| 			repository: "foo/foo_bar.com", | ||||
| 			tag:        "8080", | ||||
| 		}, | ||||
|  | @ -198,11 +198,11 @@ func TestReferenceParse(t *testing.T) { | |||
| 			if named.Name() != testcase.repository { | ||||
| 				failf("unexpected repository: got %q, expected %q", named.Name(), testcase.repository) | ||||
| 			} | ||||
| 			hostname, _ := SplitHostname(named) | ||||
| 			if hostname != testcase.hostname { | ||||
| 				failf("unexpected hostname: got %q, expected %q", hostname, testcase.hostname) | ||||
| 			domain, _ := SplitHostname(named) | ||||
| 			if domain != testcase.domain { | ||||
| 				failf("unexpected domain: got %q, expected %q", domain, testcase.domain) | ||||
| 			} | ||||
| 		} else if testcase.repository != "" || testcase.hostname != "" { | ||||
| 		} else if testcase.repository != "" || testcase.domain != "" { | ||||
| 			failf("expected named type, got %T", repo) | ||||
| 		} | ||||
| 
 | ||||
|  | @ -282,39 +282,39 @@ func TestWithNameFailure(t *testing.T) { | |||
| 
 | ||||
| func TestSplitHostname(t *testing.T) { | ||||
| 	testcases := []struct { | ||||
| 		input    string | ||||
| 		hostname string | ||||
| 		name     string | ||||
| 		input  string | ||||
| 		domain string | ||||
| 		name   string | ||||
| 	}{ | ||||
| 		{ | ||||
| 			input:    "test.com/foo", | ||||
| 			hostname: "test.com", | ||||
| 			name:     "foo", | ||||
| 			input:  "test.com/foo", | ||||
| 			domain: "test.com", | ||||
| 			name:   "foo", | ||||
| 		}, | ||||
| 		{ | ||||
| 			input:    "test_com/foo", | ||||
| 			hostname: "", | ||||
| 			name:     "test_com/foo", | ||||
| 			input:  "test_com/foo", | ||||
| 			domain: "", | ||||
| 			name:   "test_com/foo", | ||||
| 		}, | ||||
| 		{ | ||||
| 			input:    "test:8080/foo", | ||||
| 			hostname: "test:8080", | ||||
| 			name:     "foo", | ||||
| 			input:  "test:8080/foo", | ||||
| 			domain: "test:8080", | ||||
| 			name:   "foo", | ||||
| 		}, | ||||
| 		{ | ||||
| 			input:    "test.com:8080/foo", | ||||
| 			hostname: "test.com:8080", | ||||
| 			name:     "foo", | ||||
| 			input:  "test.com:8080/foo", | ||||
| 			domain: "test.com:8080", | ||||
| 			name:   "foo", | ||||
| 		}, | ||||
| 		{ | ||||
| 			input:    "test-com:8080/foo", | ||||
| 			hostname: "test-com:8080", | ||||
| 			name:     "foo", | ||||
| 			input:  "test-com:8080/foo", | ||||
| 			domain: "test-com:8080", | ||||
| 			name:   "foo", | ||||
| 		}, | ||||
| 		{ | ||||
| 			input:    "xn--n3h.com:18080/foo", | ||||
| 			hostname: "xn--n3h.com:18080", | ||||
| 			name:     "foo", | ||||
| 			input:  "xn--n3h.com:18080/foo", | ||||
| 			domain: "xn--n3h.com:18080", | ||||
| 			name:   "foo", | ||||
| 		}, | ||||
| 	} | ||||
| 	for _, testcase := range testcases { | ||||
|  | @ -327,9 +327,9 @@ func TestSplitHostname(t *testing.T) { | |||
| 		if err != nil { | ||||
| 			failf("error parsing name: %s", err) | ||||
| 		} | ||||
| 		hostname, name := SplitHostname(named) | ||||
| 		if hostname != testcase.hostname { | ||||
| 			failf("unexpected hostname: got %q, expected %q", hostname, testcase.hostname) | ||||
| 		domain, name := SplitHostname(named) | ||||
| 		if domain != testcase.domain { | ||||
| 			failf("unexpected domain: got %q, expected %q", domain, testcase.domain) | ||||
| 		} | ||||
| 		if name != testcase.name { | ||||
| 			failf("unexpected name: got %q, expected %q", name, testcase.name) | ||||
|  |  | |||
|  | @ -19,18 +19,18 @@ var ( | |||
| 		alphaNumericRegexp, | ||||
| 		optional(repeated(separatorRegexp, alphaNumericRegexp))) | ||||
| 
 | ||||
| 	// hostnameComponentRegexp restricts the registry hostname component of a
 | ||||
| 	// repository name to start with a component as defined by hostnameRegexp
 | ||||
| 	// domainComponentRegexp restricts the registry domain component of a
 | ||||
| 	// repository name to start with a component as defined by domainRegexp
 | ||||
| 	// and followed by an optional port.
 | ||||
| 	hostnameComponentRegexp = match(`(?:[a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9])`) | ||||
| 	domainComponentRegexp = match(`(?:[a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9])`) | ||||
| 
 | ||||
| 	// hostnameRegexp defines the structure of potential hostname components
 | ||||
| 	// domainRegexp defines the structure of potential domain components
 | ||||
| 	// that may be part of image names. This is purposely a subset of what is
 | ||||
| 	// allowed by DNS to ensure backwards compatibility with Docker image
 | ||||
| 	// names.
 | ||||
| 	hostnameRegexp = expression( | ||||
| 		hostnameComponentRegexp, | ||||
| 		optional(repeated(literal(`.`), hostnameComponentRegexp)), | ||||
| 	domainRegexp = expression( | ||||
| 		domainComponentRegexp, | ||||
| 		optional(repeated(literal(`.`), domainComponentRegexp)), | ||||
| 		optional(literal(`:`), match(`[0-9]+`))) | ||||
| 
 | ||||
| 	// TagRegexp matches valid tag names. From docker/docker:graph/tags.go.
 | ||||
|  | @ -48,17 +48,17 @@ var ( | |||
| 	anchoredDigestRegexp = anchored(DigestRegexp) | ||||
| 
 | ||||
| 	// NameRegexp is the format for the name component of references. The
 | ||||
| 	// regexp has capturing groups for the hostname and name part omitting
 | ||||
| 	// regexp has capturing groups for the domain and name part omitting
 | ||||
| 	// the separating forward slash from either.
 | ||||
| 	NameRegexp = expression( | ||||
| 		optional(hostnameRegexp, literal(`/`)), | ||||
| 		optional(domainRegexp, literal(`/`)), | ||||
| 		nameComponentRegexp, | ||||
| 		optional(repeated(literal(`/`), nameComponentRegexp))) | ||||
| 
 | ||||
| 	// anchoredNameRegexp is used to parse a name value, capturing the
 | ||||
| 	// hostname and trailing components.
 | ||||
| 	// domain and trailing components.
 | ||||
| 	anchoredNameRegexp = anchored( | ||||
| 		optional(capture(hostnameRegexp), literal(`/`)), | ||||
| 		optional(capture(domainRegexp), literal(`/`)), | ||||
| 		capture(nameComponentRegexp, | ||||
| 			optional(repeated(literal(`/`), nameComponentRegexp)))) | ||||
| 
 | ||||
|  |  | |||
|  | @ -33,7 +33,7 @@ func checkRegexp(t *testing.T, r *regexp.Regexp, m regexpMatch) { | |||
| 	} | ||||
| } | ||||
| 
 | ||||
| func TestHostRegexp(t *testing.T) { | ||||
| func TestDomainRegexp(t *testing.T) { | ||||
| 	hostcases := []regexpMatch{ | ||||
| 		{ | ||||
| 			input: "test.com", | ||||
|  | @ -116,7 +116,7 @@ func TestHostRegexp(t *testing.T) { | |||
| 			match: true, | ||||
| 		}, | ||||
| 	} | ||||
| 	r := regexp.MustCompile(`^` + hostnameRegexp.String() + `$`) | ||||
| 	r := regexp.MustCompile(`^` + domainRegexp.String() + `$`) | ||||
| 	for i := range hostcases { | ||||
| 		checkRegexp(t, r, hostcases[i]) | ||||
| 	} | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue