diff --git a/internal/reader/atom/atom_10_test.go b/internal/reader/atom/atom_10_test.go
index be6e9148..7b69f29d 100644
--- a/internal/reader/atom/atom_10_test.go
+++ b/internal/reader/atom/atom_10_test.go
@@ -217,12 +217,31 @@ func TestParseFeedURL(t *testing.T) {
}
}
-func TestParseFeedWithRelativeURL(t *testing.T) {
+func TestParseFeedWithRelativeFeedURL(t *testing.T) {
+ data := `
+
+ Example Feed
+
+
+ 2003-12-13T18:30:02Z
+ `
+
+ feed, err := Parse("https://example.org/", bytes.NewReader([]byte(data)), "10")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if feed.FeedURL != "https://example.org/feed" {
+ t.Errorf("Incorrect feed URL, got: %s", feed.FeedURL)
+ }
+}
+
+func TestParseFeedWithRelativeSiteURL(t *testing.T) {
data := `
Example Feed
-
+
Test
@@ -241,15 +260,47 @@ func TestParseFeedWithRelativeURL(t *testing.T) {
}
if feed.FeedURL != "https://example.org/blog/atom.xml" {
- t.Errorf("Incorrect feed URL, got: %s", feed.FeedURL)
+ t.Errorf("Incorrect feed URL, got: %q", feed.FeedURL)
}
if feed.SiteURL != "https://example.org/blog" {
- t.Errorf("Incorrect site URL, got: %s", feed.SiteURL)
+ t.Errorf("Incorrect site URL, got: %q", feed.SiteURL)
}
if feed.Entries[0].URL != "https://example.org/blog/article.html" {
- t.Errorf("Incorrect entry URL, got: %s", feed.Entries[0].URL)
+ t.Errorf("Incorrect entry URL, got: %q", feed.Entries[0].URL)
+ }
+}
+
+func TestParseFeedSiteURLWithTrailingSpace(t *testing.T) {
+ data := `
+
+
+ `
+
+ feed, err := Parse("https://example.org/", bytes.NewReader([]byte(data)), "10")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if feed.SiteURL != "http://example.org" {
+ t.Errorf("Incorrect site URL, got: %q", feed.SiteURL)
+ }
+}
+
+func TestParseFeedWithFeedURLWithTrailingSpace(t *testing.T) {
+ data := `
+
+
+ `
+
+ feed, err := Parse("https://example.org/", bytes.NewReader([]byte(data)), "10")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if feed.FeedURL != "https://example.org/blog/atom.xml" {
+ t.Errorf("Incorrect site URL, got: %q", feed.FeedURL)
}
}
diff --git a/internal/reader/json/adapter.go b/internal/reader/json/adapter.go
index e944f75a..cf54100f 100644
--- a/internal/reader/json/adapter.go
+++ b/internal/reader/json/adapter.go
@@ -24,15 +24,15 @@ func NewJSONAdapter(jsonFeed *JSONFeed) *JSONAdapter {
return &JSONAdapter{jsonFeed}
}
-func (j *JSONAdapter) BuildFeed(feedURL string) *model.Feed {
+func (j *JSONAdapter) BuildFeed(baseURL string) *model.Feed {
feed := &model.Feed{
Title: strings.TrimSpace(j.jsonFeed.Title),
- FeedURL: j.jsonFeed.FeedURL,
- SiteURL: j.jsonFeed.HomePageURL,
+ FeedURL: strings.TrimSpace(j.jsonFeed.FeedURL),
+ SiteURL: strings.TrimSpace(j.jsonFeed.HomePageURL),
}
if feed.FeedURL == "" {
- feed.FeedURL = feedURL
+ feed.FeedURL = strings.TrimSpace(baseURL)
}
// Fallback to the feed URL if the site URL is empty.
@@ -40,11 +40,11 @@ func (j *JSONAdapter) BuildFeed(feedURL string) *model.Feed {
feed.SiteURL = feed.FeedURL
}
- if feedURL, err := urllib.AbsoluteURL(feedURL, j.jsonFeed.FeedURL); err == nil {
+ if feedURL, err := urllib.AbsoluteURL(baseURL, feed.FeedURL); err == nil {
feed.FeedURL = feedURL
}
- if siteURL, err := urllib.AbsoluteURL(feedURL, j.jsonFeed.HomePageURL); err == nil {
+ if siteURL, err := urllib.AbsoluteURL(baseURL, feed.SiteURL); err == nil {
feed.SiteURL = siteURL
}
diff --git a/internal/reader/json/parser_test.go b/internal/reader/json/parser_test.go
index 8e4102e0..0bbd39ec 100644
--- a/internal/reader/json/parser_test.go
+++ b/internal/reader/json/parser_test.go
@@ -177,6 +177,82 @@ func TestParsePodcast(t *testing.T) {
}
}
+func TestParseFeedWithFeedURLWithTrailingSpace(t *testing.T) {
+ data := `{
+ "version": "https://jsonfeed.org/version/1",
+ "title": "My Example Feed",
+ "home_page_url": "https://example.org/",
+ "feed_url": "https://example.org/feed.json ",
+ "items": []
+ }`
+
+ feed, err := Parse("https://example.org/feed.json", bytes.NewBufferString(data))
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if feed.FeedURL != "https://example.org/feed.json" {
+ t.Errorf("Incorrect feed URL, got: %s", feed.FeedURL)
+ }
+}
+
+func TestParseFeedWithRelativeFeedURL(t *testing.T) {
+ data := `{
+ "version": "https://jsonfeed.org/version/1",
+ "title": "My Example Feed",
+ "home_page_url": "https://example.org/",
+ "feed_url": "/feed.json",
+ "items": []
+ }`
+
+ feed, err := Parse("https://example.org/feed.json", bytes.NewBufferString(data))
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if feed.FeedURL != "https://example.org/feed.json" {
+ t.Errorf("Incorrect feed URL, got: %s", feed.FeedURL)
+ }
+}
+
+func TestParseFeedSiteURLWithTrailingSpace(t *testing.T) {
+ data := `{
+ "version": "https://jsonfeed.org/version/1",
+ "title": "My Example Feed",
+ "home_page_url": "https://example.org/ ",
+ "feed_url": "https://example.org/feed.json",
+ "items": []
+ }`
+
+ feed, err := Parse("https://example.org/feed.json", bytes.NewBufferString(data))
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if feed.SiteURL != "https://example.org/" {
+ t.Errorf("Incorrect site URL, got: %s", feed.SiteURL)
+ }
+}
+
+func TestParseFeedWithRelativeSiteURL(t *testing.T) {
+ data := `{
+ "version": "https://jsonfeed.org/version/1",
+ "title": "My Example Feed",
+ "home_page_url": "/home ",
+ "feed_url": "https://example.org/feed.json",
+ "items": []
+ }`
+
+ feed, err := Parse("https://example.org/feed.json", bytes.NewBufferString(data))
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if feed.SiteURL != "https://example.org/home" {
+ t.Errorf("Incorrect site URL, got: %s", feed.SiteURL)
+ }
+}
+
func TestParseFeedWithoutTitle(t *testing.T) {
data := `{
"version": "https://jsonfeed.org/version/1",
diff --git a/internal/reader/rdf/adapter.go b/internal/reader/rdf/adapter.go
index bc8c76ed..f90ebaca 100644
--- a/internal/reader/rdf/adapter.go
+++ b/internal/reader/rdf/adapter.go
@@ -24,18 +24,18 @@ func NewRDFAdapter(rdf *RDF) *RDFAdapter {
return &RDFAdapter{rdf}
}
-func (r *RDFAdapter) BuildFeed(feedURL string) *model.Feed {
+func (r *RDFAdapter) BuildFeed(baseURL string) *model.Feed {
feed := &model.Feed{
Title: stripTags(r.rdf.Channel.Title),
- FeedURL: feedURL,
- SiteURL: r.rdf.Channel.Link,
+ FeedURL: strings.TrimSpace(baseURL),
+ SiteURL: strings.TrimSpace(r.rdf.Channel.Link),
}
if feed.Title == "" {
- feed.Title = feedURL
+ feed.Title = baseURL
}
- if siteURL, err := urllib.AbsoluteURL(feedURL, r.rdf.Channel.Link); err == nil {
+ if siteURL, err := urllib.AbsoluteURL(feed.FeedURL, feed.SiteURL); err == nil {
feed.SiteURL = siteURL
}
diff --git a/internal/reader/rdf/parser_test.go b/internal/reader/rdf/parser_test.go
index 5009a412..021772b4 100644
--- a/internal/reader/rdf/parser_test.go
+++ b/internal/reader/rdf/parser_test.go
@@ -289,7 +289,37 @@ func TestParseRDFFeedWithRelativeLink(t *testing.T) {
xmlns="http://purl.org/rss/1.0/">
Example Feed
- /test/index.html
+ /test/index.html
+
+ -
+ Example
+ http://example.org/item
+ Test
+
+ `
+
+ feed, err := Parse("http://example.org/feed", bytes.NewReader([]byte(data)))
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if feed.SiteURL != "http://example.org/test/index.html" {
+ t.Errorf(`Incorrect SiteURL, got: %q`, feed.SiteURL)
+ }
+
+ if feed.FeedURL != "http://example.org/feed" {
+ t.Errorf(`Incorrect FeedURL, got: %q`, feed.FeedURL)
+ }
+}
+
+func TestParseRDFFeedSiteURLWithTrailingSpace(t *testing.T) {
+ data := `
+
+
+ Example Feed
+ http://example.org/test/index.html
-
Example
diff --git a/internal/reader/rss/adapter.go b/internal/reader/rss/adapter.go
index 531cc53f..48def825 100644
--- a/internal/reader/rss/adapter.go
+++ b/internal/reader/rss/adapter.go
@@ -26,14 +26,15 @@ func NewRSSAdapter(rss *RSS) *RSSAdapter {
return &RSSAdapter{rss}
}
-func (r *RSSAdapter) BuildFeed(feedURL string) *model.Feed {
+func (r *RSSAdapter) BuildFeed(baseURL string) *model.Feed {
feed := &model.Feed{
Title: html.UnescapeString(strings.TrimSpace(r.rss.Channel.Title)),
- FeedURL: feedURL,
- SiteURL: r.rss.Channel.Link,
+ FeedURL: strings.TrimSpace(baseURL),
+ SiteURL: strings.TrimSpace(r.rss.Channel.Link),
}
- if siteURL, err := urllib.AbsoluteURL(feedURL, r.rss.Channel.Link); err == nil {
+ // Ensure the Site URL is absolute.
+ if siteURL, err := urllib.AbsoluteURL(baseURL, feed.SiteURL); err == nil {
feed.SiteURL = siteURL
}
@@ -41,7 +42,7 @@ func (r *RSSAdapter) BuildFeed(feedURL string) *model.Feed {
for _, atomLink := range r.rss.Channel.AtomLinks.Links {
atomLinkHref := strings.TrimSpace(atomLink.Href)
if atomLinkHref != "" && atomLink.Rel == "self" {
- if absoluteFeedURL, err := urllib.AbsoluteURL(feedURL, atomLinkHref); err == nil {
+ if absoluteFeedURL, err := urllib.AbsoluteURL(feed.FeedURL, atomLinkHref); err == nil {
feed.FeedURL = absoluteFeedURL
break
}
diff --git a/internal/reader/rss/parser_test.go b/internal/reader/rss/parser_test.go
index d9dacac6..e3f8450f 100644
--- a/internal/reader/rss/parser_test.go
+++ b/internal/reader/rss/parser_test.go
@@ -109,6 +109,100 @@ func TestParseRss2Sample(t *testing.T) {
}
}
+func TestParseFeedWithFeedURLWithTrailingSpace(t *testing.T) {
+ data := `
+
+
+ Example
+ https://example.org/
+
+
-
+ Test
+ https://example.org/item
+
+
+ `
+
+ feed, err := Parse("https://example.org/ ", bytes.NewReader([]byte(data)))
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if feed.FeedURL != "https://example.org/rss" {
+ t.Errorf("Incorrect feed URL, got: %s", feed.FeedURL)
+ }
+}
+
+func TestParseFeedWithRelativeFeedURL(t *testing.T) {
+ data := `
+
+
+ Example
+ https://example.org/
+
+ -
+ Test
+ https://example.org/item
+
+
+ `
+
+ feed, err := Parse("https://example.org/", bytes.NewReader([]byte(data)))
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if feed.FeedURL != "https://example.org/rss" {
+ t.Errorf("Incorrect feed URL, got: %s", feed.FeedURL)
+ }
+}
+
+func TestParseFeedSiteURLWithTrailingSpace(t *testing.T) {
+ data := `
+
+
+ Example
+ https://example.org/
+ -
+ Test
+ https://example.org/item
+
+
+ `
+
+ feed, err := Parse("https://example.org/", bytes.NewReader([]byte(data)))
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if feed.SiteURL != "https://example.org/" {
+ t.Errorf("Incorrect site URL, got: %s", feed.SiteURL)
+ }
+}
+
+func TestParseFeedWithRelativeSiteURL(t *testing.T) {
+ data := `
+
+
+ Example
+ /example
+ -
+ Test
+ https://example.org/item
+
+
+ `
+
+ feed, err := Parse("https://example.org/", bytes.NewReader([]byte(data)))
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if feed.SiteURL != "https://example.org/example" {
+ t.Errorf("Incorrect site URL, got: %s", feed.SiteURL)
+ }
+}
+
func TestParseFeedWithoutTitle(t *testing.T) {
data := `