From b08b62e7946b71a18409ca801effacea168cca12 Mon Sep 17 00:00:00 2001 From: Jason Streifling Date: Tue, 15 Oct 2024 19:32:14 +0200 Subject: [PATCH] Add check for summary element of entry --- content.go | 4 +++- entry.go | 29 +++++++++++++++++++++++++++-- inlineOtherContent.go | 6 +++++- inlineTextContent.go | 6 +++++- inlineXHTMLContent.go | 6 +++++- outOfLineContent.go | 6 +++++- 6 files changed, 50 insertions(+), 7 deletions(-) diff --git a/content.go b/content.go index 5f95d6f..8e07372 100644 --- a/content.go +++ b/content.go @@ -1,6 +1,8 @@ package atomfeed type Content interface { + isContent() bool + hasSRC() bool + getType() string Check() error - IsContent() bool } diff --git a/entry.go b/entry.go index 0589295..458fcf4 100644 --- a/entry.go +++ b/entry.go @@ -4,6 +4,8 @@ import ( "encoding/xml" "errors" "fmt" + "mime" + "strings" ) // It is advisable that each atom:entry element contain a non-empty atom:title @@ -14,7 +16,7 @@ type Entry struct { *CommonAttributes Authors []*Person `xml:"author,omitempty"` Categories []*Category `xml:"category,omitempty"` - Content *Content `xml:"content,omitempty"` + Content Content `xml:"content,omitempty"` Contributors []*Person `xml:"contributors,omitempty"` ID *ID `xml:"id"` Links []*Link `xml:"link,omitempty"` @@ -57,6 +59,10 @@ func alternateRelExists(l []*Link) bool { return false } +func isXMLMediaType(mediaType string) bool { + return strings.HasSuffix(mediaType, "/xml") || strings.HasSuffix(mediaType, "+xml") +} + func (e *Entry) AddExtension(name string, value any) { e.Extensions = append(e.Extensions, &ExtensionElement{XMLName: xml.Name{Local: name}, Value: value}) } @@ -81,7 +87,7 @@ func (e *Entry) Check() error { } if e.Content != nil { - if err := (*e.Content).Check(); err != nil { + if err := e.Content.Check(); err != nil { return fmt.Errorf("content element of entry %v: %v", e.ID.URI, err) } } else { @@ -130,6 +136,25 @@ func (e *Entry) Check() error { if err := e.Summary.Check(); err != nil { return fmt.Errorf("summary element of entry %v: %v", e.ID.URI, err) } + } else { + // atom:entry elements MUST contain an atom:summary element in either + // of the following cases: + // the atom:entry contains an atom:content that has a "src" attribute + // (and is thus empty). + if e.Content.hasSRC() { + return fmt.Errorf("no summary element of entry %v but content of type out of line content", e.ID.URI) + } + // the atom:entry contains content that is encoded in Base64; i.e., the + // "type" attribute of atom:content is a MIME media type [MIMEREG], but + // is not an XML media type [RFC3023], does not begin with "text/", and + // does not end with "/xml" or "+xml". + mediaType, _, err := mime.ParseMediaType(e.Content.getType()) + if err != nil { + return fmt.Errorf("type attribute of content element of entry %v: %v", e.ID.URI, err) + } + if !isXMLMediaType(mediaType) && !strings.HasPrefix(mediaType, "text/") { + return fmt.Errorf("no summary element of entry %v but media type not xml", e.ID.URI) + } } if e.Title == nil { diff --git a/inlineOtherContent.go b/inlineOtherContent.go index a2b0973..dec8bd2 100644 --- a/inlineOtherContent.go +++ b/inlineOtherContent.go @@ -6,6 +6,10 @@ type InlineOtherContent struct { AnyElement []*any `xml:"anyelement,omitempty"` } -func (i *InlineOtherContent) IsContent() bool { return true } +func (i *InlineOtherContent) isContent() bool { return true } + +func (i *InlineOtherContent) hasSRC() bool { return false } + +func (i *InlineOtherContent) getType() string { return string(i.Type) } func (i *InlineOtherContent) Check() error { return nil } diff --git a/inlineTextContent.go b/inlineTextContent.go index 7a3fbfb..be94161 100644 --- a/inlineTextContent.go +++ b/inlineTextContent.go @@ -8,7 +8,11 @@ type InlineTextContent struct { Texts []string `xml:"texts,omitempty"` } -func (i *InlineTextContent) IsContent() bool { return true } +func (i *InlineTextContent) isContent() bool { return true } + +func (i *InlineTextContent) hasSRC() bool { return false } + +func (i *InlineTextContent) getType() string { return i.Type } func (i *InlineTextContent) Check() error { if i.Type != "" && i.Type != "text" && i.Type != "html" { diff --git a/inlineXHTMLContent.go b/inlineXHTMLContent.go index da33782..0d0b33e 100644 --- a/inlineXHTMLContent.go +++ b/inlineXHTMLContent.go @@ -8,7 +8,11 @@ type InlineXHTMLContent struct { XHTMLDiv string `xml:"xhtmldiv"` } -func (i *InlineXHTMLContent) IsContent() bool { return true } +func (i *InlineXHTMLContent) isContent() bool { return true } + +func (i *InlineXHTMLContent) hasSRC() bool { return false } + +func (i *InlineXHTMLContent) getType() string { return i.Type } func (i *InlineXHTMLContent) Check() error { if i.Type != "xhtml" { diff --git a/outOfLineContent.go b/outOfLineContent.go index 72fd200..e3805e9 100644 --- a/outOfLineContent.go +++ b/outOfLineContent.go @@ -8,7 +8,11 @@ type OutOfLineContent struct { SRC URI `xml:"src,attr"` } -func (o *OutOfLineContent) IsContent() bool { return true } +func (o *OutOfLineContent) isContent() bool { return true } + +func (o *OutOfLineContent) hasSRC() bool { return true } + +func (o *OutOfLineContent) getType() string { return string(o.Type) } func (o *OutOfLineContent) Check() error { if o.SRC == "" {