diff --git a/atom.go b/atom.go index e9af0ac..24c163a 100644 --- a/atom.go +++ b/atom.go @@ -3,6 +3,7 @@ package atomfeed import ( "mime" "net/url" + "regexp" "strings" ) @@ -13,11 +14,20 @@ type ( URI string ) -func isValidURL(testURL URI) bool { - _, err := url.ParseRequestURI(string(testURL)) +func isValidURL(uri URI) bool { + _, err := url.ParseRequestURI(string(uri)) return err == nil } +func isValidURN(uri URI) bool { + pattern := `\A(?i:urn:(?!urn:)(?[a-z0-9][a-z0-9-]{1,31}):(?(?:[-a-z0-9()+,.:=@;$_!*'&~\/]|%[0-9a-f]{2})+)(?:\?\+(?.*?))?(?:\?=(?.*?))?(?:#(?.*?))?)\z` + return regexp.MustCompile(pattern).MatchString(string(uri)) +} + +func isValidURI(uri URI) bool { + return isValidURL(uri) || isValidURN(uri) +} + func isCompositeMediaType(mediaType string) bool { mediaType, _, err := mime.ParseMediaType(mediaType) if err != nil { diff --git a/category.go b/category.go index acbc854..aa9f547 100644 --- a/category.go +++ b/category.go @@ -27,6 +27,12 @@ func (c *Category) Check() error { return errors.New("term attribute of category empty") } + if c.Scheme != "" { + if !isValidURI(c.Scheme) { + return fmt.Errorf("scheme attribute of category %v not correctly formatted", c.Scheme) + } + } + if c.Content == nil { return errors.New("no content element of category") } else { diff --git a/outOfLineContent.go b/outOfLineContent.go index 1a87068..b8ab7d7 100644 --- a/outOfLineContent.go +++ b/outOfLineContent.go @@ -22,7 +22,7 @@ func newOutOfLineContent(mediaType string, content any) (*OutOfLineContent, erro return nil, fmt.Errorf("content type %T incompatible with out of line content", content) } - if !isValidURL(content.(URI)) { + if !isValidURI(content.(URI)) { return nil, errors.New("content not a valid uri") } diff --git a/person.go b/person.go index 7314a7e..27818d9 100644 --- a/person.go +++ b/person.go @@ -29,7 +29,7 @@ func (p *Person) Check() error { } if p.URI != "" { - if !isValidURL(p.URI) { + if !isValidURI(p.URI) { return fmt.Errorf("uri element of person %v not correctly formatted", p.Name) } }