From 3bdeb10cc292888c1cdca985f221b4bd7a01267c 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 d05da19..8c227a8 100644 --- a/rss.go +++ b/rss.go @@ -137,9 +137,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,