From 7822231e3652a7b665f96fad3a6fc3be8d6022e4 Mon Sep 17 00:00:00 2001 From: Meir Blumenfeld <33358938+meblum@users.noreply.github.com> Date: Thu, 21 Sep 2023 20:59:23 -0400 Subject: [PATCH] fix: check for nil link to avoid runtime panic #95 (#103) ## What type of PR is this? (check all applicable) - [x] Bug Fix ## Description Check for nil link in feed to avoid runtime panic ## Related Issue - Closes #95 ## Added/updated tests? - [x] Yes --- atom.go | 23 +++++++++++++++-------- feed_test.go | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++++ rss.go | 6 +++++- 3 files changed, 72 insertions(+), 9 deletions(-) diff --git a/atom.go b/atom.go index 93cf15f..73de995 100644 --- a/atom.go +++ b/atom.go @@ -89,13 +89,16 @@ type Atom struct { func newAtomEntry(i *Item) *AtomEntry { id := i.Id - + link := i.Link + if link == nil { + link = &Link{} + } if len(id) == 0 { // if there's no id set, try to create one, either from data or just a uuid - if len(i.Link.Href) > 0 && (!i.Created.IsZero() || !i.Updated.IsZero()) { + if len(link.Href) > 0 && (!i.Created.IsZero() || !i.Updated.IsZero()) { dateStr := anyTimeFormat("2006-01-02", i.Updated, i.Created) - host, path := i.Link.Href, "/invalid.html" - if url, err := url.Parse(i.Link.Href); err == nil { + host, path := link.Href, "/invalid.html" + if url, err := url.Parse(link.Href); err == nil { host, path = url.Host, url.Path } id = fmt.Sprintf("tag:%s,%s:%s", host, dateStr, path) @@ -108,13 +111,13 @@ func newAtomEntry(i *Item) *AtomEntry { name, email = i.Author.Name, i.Author.Email } - link_rel := i.Link.Rel + link_rel := link.Rel if link_rel == "" { link_rel = "alternate" } x := &AtomEntry{ Title: i.Title, - Links: []AtomLink{{Href: i.Link.Href, Rel: link_rel, Type: i.Link.Type}}, + Links: []AtomLink{{Href: link.Href, Rel: link_rel, Type: link.Type}}, Id: id, Updated: anyTimeFormat(time.RFC3339, i.Updated, i.Created), } @@ -142,12 +145,16 @@ func newAtomEntry(i *Item) *AtomEntry { // create a new AtomFeed with a generic Feed struct's data func (a *Atom) AtomFeed() *AtomFeed { updated := anyTimeFormat(time.RFC3339, a.Updated, a.Created) + link := a.Link + if link == nil { + link = &Link{} + } feed := &AtomFeed{ Xmlns: ns, Title: a.Title, - Link: &AtomLink{Href: a.Link.Href, Rel: a.Link.Rel}, + Link: &AtomLink{Href: link.Href, Rel: link.Rel}, Subtitle: a.Description, - Id: a.Link.Href, + Id: link.Href, Updated: updated, Rights: a.Copyright, } diff --git a/feed_test.go b/feed_test.go index 1c178d8..2a37f2a 100644 --- a/feed_test.go +++ b/feed_test.go @@ -504,6 +504,58 @@ func TestFeedSorted(t *testing.T) { } } +func TestFeedNil(t *testing.T) { + now, err := time.Parse(time.RFC3339, "2013-01-16T21:52:35-05:00") + if err != nil { + t.Error(err) + } + tz := time.FixedZone("EST", -5*60*60) + now = now.In(tz) + + feed := &Feed{ + Title: "jmoiron.net blog", + Link: nil, + Description: "discussion about tech, footie, photos", + Author: nil, + Created: now, + Copyright: "This work is copyright © Benjamin Button", + } + + feed.Items = []*Item{ + { + Title: "Limiting Concurrency in Go", + Link: nil, + Description: "A discussion on controlled parallelism in golang", + Author: nil, + Created: now, + Content: `

Go's goroutines make it easy to make embarrassingly parallel programs, but in many "real world" cases resources can be limited and attempting to do everything at once can exhaust your access to them.

`, + }} + + if _, err := feed.ToAtom(); err != nil { + t.Errorf("unexpected error encoding Atom: %v", err) + } + var buf bytes.Buffer + if err := feed.WriteAtom(&buf); err != nil { + t.Errorf("unexpected error writing Atom: %v", err) + } + + if _, err := feed.ToRss(); err != nil { + t.Errorf("unexpected error encoding RSS: %v", err) + } + buf.Reset() + if err := feed.WriteRss(&buf); err != nil { + t.Errorf("unexpected error writing RSS: %v", err) + } + + if _, err := feed.ToJSON(); err != nil { + t.Errorf("unexpected error encoding JSON: %v", err) + } + buf.Reset() + if err := feed.WriteJSON(&buf); err != nil { + t.Errorf("unexpected error writing JSON: %v", err) + } +} + var jsonOutputHub = `{ "version": "https://jsonfeed.org/version/1", "title": "feed title", diff --git a/rss.go b/rss.go index 81a026b..bc615cd 100644 --- a/rss.go +++ b/rss.go @@ -145,9 +145,13 @@ func (r *Rss) RssFeed() *RssFeed { image = &RssImage{Url: r.Image.Url, Title: r.Image.Title, Link: r.Image.Link, Width: r.Image.Width, Height: r.Image.Height} } + var href string + if r.Link != nil { + href = r.Link.Href + } channel := &RssFeed{ Title: r.Title, - Link: r.Link.Href, + Link: href, Description: r.Description, ManagingEditor: author, PubDate: pub,