diff --git a/reader/atom/atom_03.go b/reader/atom/atom_03.go
index 7a86204b..36fbb12c 100644
--- a/reader/atom/atom_03.go
+++ b/reader/atom/atom_03.go
@@ -27,12 +27,24 @@ type atom03Feed struct {
Entries []atom03Entry `xml:"entry"`
}
-func (a *atom03Feed) Transform() *model.Feed {
- feed := new(model.Feed)
- feed.FeedURL = a.Links.firstLinkWithRelation("self")
- feed.SiteURL = a.Links.originalLink()
- feed.Title = a.Title.String()
+func (a *atom03Feed) Transform(baseURL string) *model.Feed {
+ var err error
+ feed := new(model.Feed)
+
+ feedURL := a.Links.firstLinkWithRelation("self")
+ feed.FeedURL, err = url.AbsoluteURL(baseURL, feedURL)
+ if err != nil {
+ feed.FeedURL = feedURL
+ }
+
+ siteURL := a.Links.originalLink()
+ feed.SiteURL, err = url.AbsoluteURL(baseURL, siteURL)
+ if err != nil {
+ feed.SiteURL = siteURL
+ }
+
+ feed.Title = a.Title.String()
if feed.Title == "" {
feed.Title = feed.SiteURL
}
diff --git a/reader/atom/atom_03_test.go b/reader/atom/atom_03_test.go
index 063b02c4..75083d93 100644
--- a/reader/atom/atom_03_test.go
+++ b/reader/atom/atom_03_test.go
@@ -28,7 +28,7 @@ func TestParseAtom03(t *testing.T) {
`
- feed, err := Parse(bytes.NewBufferString(data))
+ feed, err := Parse("http://diveintomark.org/", bytes.NewBufferString(data))
if err != nil {
t.Fatal(err)
}
@@ -37,7 +37,7 @@ func TestParseAtom03(t *testing.T) {
t.Errorf("Incorrect title, got: %s", feed.Title)
}
- if feed.FeedURL != "" {
+ if feed.FeedURL != "http://diveintomark.org/" {
t.Errorf("Incorrect feed URL, got: %s", feed.FeedURL)
}
@@ -88,7 +88,7 @@ func TestParseAtom03WithoutFeedTitle(t *testing.T) {
`
- feed, err := Parse(bytes.NewBufferString(data))
+ feed, err := Parse("http://diveintomark.org/", bytes.NewBufferString(data))
if err != nil {
t.Fatal(err)
}
@@ -111,7 +111,7 @@ func TestParseAtom03WithoutEntryTitle(t *testing.T) {
`
- feed, err := Parse(bytes.NewBufferString(data))
+ feed, err := Parse("http://diveintomark.org/", bytes.NewBufferString(data))
if err != nil {
t.Fatal(err)
}
@@ -142,7 +142,7 @@ func TestParseAtom03WithSummaryOnly(t *testing.T) {
`
- feed, err := Parse(bytes.NewBufferString(data))
+ feed, err := Parse("http://diveintomark.org/", bytes.NewBufferString(data))
if err != nil {
t.Fatal(err)
}
@@ -173,7 +173,7 @@ func TestParseAtom03WithXMLContent(t *testing.T) {
`
- feed, err := Parse(bytes.NewBufferString(data))
+ feed, err := Parse("http://diveintomark.org/", bytes.NewBufferString(data))
if err != nil {
t.Fatal(err)
}
@@ -204,7 +204,7 @@ func TestParseAtom03WithBase64Content(t *testing.T) {
`
- feed, err := Parse(bytes.NewBufferString(data))
+ feed, err := Parse("http://diveintomark.org/", bytes.NewBufferString(data))
if err != nil {
t.Fatal(err)
}
diff --git a/reader/atom/atom_10.go b/reader/atom/atom_10.go
index e7797d2e..d60c3ce4 100644
--- a/reader/atom/atom_10.go
+++ b/reader/atom/atom_10.go
@@ -31,12 +31,24 @@ type atom10Feed struct {
Entries []atom10Entry `xml:"entry"`
}
-func (a *atom10Feed) Transform() *model.Feed {
- feed := new(model.Feed)
- feed.FeedURL = a.Links.firstLinkWithRelation("self")
- feed.SiteURL = a.Links.originalLink()
- feed.Title = a.Title.String()
+func (a *atom10Feed) Transform(baseURL string) *model.Feed {
+ var err error
+ feed := new(model.Feed)
+
+ feedURL := a.Links.firstLinkWithRelation("self")
+ feed.FeedURL, err = url.AbsoluteURL(baseURL, feedURL)
+ if err != nil {
+ feed.FeedURL = feedURL
+ }
+
+ siteURL := a.Links.originalLink()
+ feed.SiteURL, err = url.AbsoluteURL(baseURL, siteURL)
+ if err != nil {
+ feed.SiteURL = siteURL
+ }
+
+ feed.Title = a.Title.String()
if feed.Title == "" {
feed.Title = feed.SiteURL
}
diff --git a/reader/atom/atom_10_test.go b/reader/atom/atom_10_test.go
index ad897440..4999aca2 100644
--- a/reader/atom/atom_10_test.go
+++ b/reader/atom/atom_10_test.go
@@ -32,7 +32,7 @@ func TestParseAtomSample(t *testing.T) {
`
- feed, err := Parse(bytes.NewBufferString(data))
+ feed, err := Parse("http://example.org/feed.xml", bytes.NewBufferString(data))
if err != nil {
t.Fatal(err)
}
@@ -41,7 +41,7 @@ func TestParseAtomSample(t *testing.T) {
t.Errorf("Incorrect title, got: %s", feed.Title)
}
- if feed.FeedURL != "" {
+ if feed.FeedURL != "http://example.org/feed.xml" {
t.Errorf("Incorrect feed URL, got: %s", feed.FeedURL)
}
@@ -90,7 +90,7 @@ func TestParseFeedWithoutTitle(t *testing.T) {
2003-12-13T18:30:02Z
`
- feed, err := Parse(bytes.NewBufferString(data))
+ feed, err := Parse("https://example.org/", bytes.NewBufferString(data))
if err != nil {
t.Fatal(err)
}
@@ -121,7 +121,7 @@ func TestParseEntryWithoutTitle(t *testing.T) {
`
- feed, err := Parse(bytes.NewBufferString(data))
+ feed, err := Parse("https://example.org/", bytes.NewBufferString(data))
if err != nil {
t.Fatal(err)
}
@@ -140,7 +140,7 @@ func TestParseFeedURL(t *testing.T) {
2003-12-13T18:30:02Z
`
- feed, err := Parse(bytes.NewBufferString(data))
+ feed, err := Parse("https://example.org/", bytes.NewBufferString(data))
if err != nil {
t.Fatal(err)
}
@@ -154,6 +154,42 @@ func TestParseFeedURL(t *testing.T) {
}
}
+func TestParseFeedWithRelativeURL(t *testing.T) {
+ data := `
+
+ Example Feed
+
+
+
+
+ Test
+
+
+ /blog/article.html
+ 2003-12-13T18:30:02Z
+ Some text.
+
+
+ `
+
+ feed, err := Parse("https://example.org/", bytes.NewBufferString(data))
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if feed.FeedURL != "https://example.org/blog/atom.xml" {
+ t.Errorf("Incorrect feed URL, got: %s", feed.FeedURL)
+ }
+
+ if feed.SiteURL != "https://example.org/blog" {
+ t.Errorf("Incorrect site URL, got: %s", feed.SiteURL)
+ }
+
+ if feed.Entries[0].URL != "https://example.org/blog/article.html" {
+ t.Errorf("Incorrect entry URL, got: %s", feed.Entries[0].URL)
+ }
+}
+
func TestParseEntryWithRelativeURL(t *testing.T) {
data := `
@@ -170,7 +206,7 @@ func TestParseEntryWithRelativeURL(t *testing.T) {
`
- feed, err := Parse(bytes.NewBufferString(data))
+ feed, err := Parse("https://example.net/", bytes.NewBufferString(data))
if err != nil {
t.Fatal(err)
}
@@ -198,7 +234,7 @@ func TestParseEntryTitleWithWhitespaces(t *testing.T) {
`
- feed, err := Parse(bytes.NewBufferString(data))
+ feed, err := Parse("https://example.org/", bytes.NewBufferString(data))
if err != nil {
t.Fatal(err)
}
@@ -224,7 +260,7 @@ func TestParseEntryTitleWithHTMLAndCDATA(t *testing.T) {
`
- feed, err := Parse(bytes.NewBufferString(data))
+ feed, err := Parse("https://example.org/", bytes.NewBufferString(data))
if err != nil {
t.Fatal(err)
}
@@ -250,7 +286,7 @@ func TestParseEntryTitleWithHTML(t *testing.T) {
`
- feed, err := Parse(bytes.NewBufferString(data))
+ feed, err := Parse("https://example.org/", bytes.NewBufferString(data))
if err != nil {
t.Fatal(err)
}
@@ -276,7 +312,7 @@ func TestParseEntryTitleWithXHTML(t *testing.T) {
`
- feed, err := Parse(bytes.NewBufferString(data))
+ feed, err := Parse("https://example.org/", bytes.NewBufferString(data))
if err != nil {
t.Fatal(err)
}
@@ -302,7 +338,7 @@ func TestParseEntrySummaryWithXHTML(t *testing.T) {
`
- feed, err := Parse(bytes.NewBufferString(data))
+ feed, err := Parse("https://example.org/", bytes.NewBufferString(data))
if err != nil {
t.Fatal(err)
}
@@ -328,7 +364,7 @@ func TestParseEntrySummaryWithHTML(t *testing.T) {
`
- feed, err := Parse(bytes.NewBufferString(data))
+ feed, err := Parse("https://example.org/", bytes.NewBufferString(data))
if err != nil {
t.Fatal(err)
}
@@ -354,7 +390,7 @@ func TestParseEntrySummaryWithPlainText(t *testing.T) {
`
- feed, err := Parse(bytes.NewBufferString(data))
+ feed, err := Parse("https://example.org/", bytes.NewBufferString(data))
if err != nil {
t.Fatal(err)
}
@@ -383,7 +419,7 @@ func TestParseEntryWithAuthorName(t *testing.T) {
`
- feed, err := Parse(bytes.NewBufferString(data))
+ feed, err := Parse("https://example.org/", bytes.NewBufferString(data))
if err != nil {
t.Fatal(err)
}
@@ -412,7 +448,7 @@ func TestParseEntryWithoutAuthorName(t *testing.T) {
`
- feed, err := Parse(bytes.NewBufferString(data))
+ feed, err := Parse("https://example.org/", bytes.NewBufferString(data))
if err != nil {
t.Fatal(err)
}
@@ -462,7 +498,7 @@ func TestParseEntryWithEnclosures(t *testing.T) {
`
- feed, err := Parse(bytes.NewBufferString(data))
+ feed, err := Parse("https://example.org/", bytes.NewBufferString(data))
if err != nil {
t.Fatal(err)
}
@@ -522,7 +558,7 @@ func TestParseEntryWithoutEnclosureURL(t *testing.T) {
`
- feed, err := Parse(bytes.NewBufferString(data))
+ feed, err := Parse("https://example.org/", bytes.NewBufferString(data))
if err != nil {
t.Fatal(err)
}
@@ -555,7 +591,7 @@ func TestParseEntryWithPublished(t *testing.T) {
`
- feed, err := Parse(bytes.NewBufferString(data))
+ feed, err := Parse("https://example.org/", bytes.NewBufferString(data))
if err != nil {
t.Fatal(err)
}
@@ -581,7 +617,7 @@ func TestParseEntryWithPublishedAndUpdated(t *testing.T) {
`
- feed, err := Parse(bytes.NewBufferString(data))
+ feed, err := Parse("https://example.org/", bytes.NewBufferString(data))
if err != nil {
t.Fatal(err)
}
@@ -593,7 +629,7 @@ func TestParseEntryWithPublishedAndUpdated(t *testing.T) {
func TestParseInvalidXml(t *testing.T) {
data := `garbage`
- _, err := Parse(bytes.NewBufferString(data))
+ _, err := Parse("https://example.org/", bytes.NewBufferString(data))
if err == nil {
t.Error("Parse should returns an error")
}
@@ -608,7 +644,7 @@ func TestParseTitleWithSingleQuote(t *testing.T) {
`
- feed, err := Parse(bytes.NewBufferString(data))
+ feed, err := Parse("https://example.org/", bytes.NewBufferString(data))
if err != nil {
t.Fatal(err)
}
@@ -627,7 +663,7 @@ func TestParseTitleWithEncodedSingleQuote(t *testing.T) {
`
- feed, err := Parse(bytes.NewBufferString(data))
+ feed, err := Parse("https://example.org/", bytes.NewBufferString(data))
if err != nil {
t.Fatal(err)
}
@@ -646,7 +682,7 @@ func TestParseTitleWithSingleQuoteAndHTMLType(t *testing.T) {
`
- feed, err := Parse(bytes.NewBufferString(data))
+ feed, err := Parse("https://example.org/", bytes.NewBufferString(data))
if err != nil {
t.Fatal(err)
}
@@ -665,7 +701,7 @@ func TestParseWithHTMLEntity(t *testing.T) {
`
- feed, err := Parse(bytes.NewBufferString(data))
+ feed, err := Parse("https://example.org/", bytes.NewBufferString(data))
if err != nil {
t.Fatal(err)
}
@@ -684,7 +720,7 @@ func TestParseWithInvalidCharacterEntity(t *testing.T) {
`
- feed, err := Parse(bytes.NewBufferString(data))
+ feed, err := Parse("https://example.org/", bytes.NewBufferString(data))
if err != nil {
t.Fatal(err)
}
@@ -717,7 +753,7 @@ A website: http://example.org/
`
- feed, err := Parse(bytes.NewBufferString(data))
+ feed, err := Parse("https://example.org/", bytes.NewBufferString(data))
if err != nil {
t.Fatal(err)
}
@@ -783,7 +819,7 @@ A website: http://example.org/
`
- feed, err := Parse(bytes.NewBufferString(data))
+ feed, err := Parse("https://example.org/", bytes.NewBufferString(data))
if err != nil {
t.Fatal(err)
}
@@ -854,7 +890,7 @@ func TestParseRepliesLinkRelationWithHTMLType(t *testing.T) {
`
- feed, err := Parse(bytes.NewBufferString(data))
+ feed, err := Parse("https://example.org/", bytes.NewBufferString(data))
if err != nil {
t.Fatal(err)
}
@@ -898,7 +934,7 @@ func TestParseRepliesLinkRelationWithXHTMLType(t *testing.T) {
`
- feed, err := Parse(bytes.NewBufferString(data))
+ feed, err := Parse("https://example.org/", bytes.NewBufferString(data))
if err != nil {
t.Fatal(err)
}
@@ -937,7 +973,7 @@ func TestParseRepliesLinkRelationWithNoType(t *testing.T) {
`
- feed, err := Parse(bytes.NewBufferString(data))
+ feed, err := Parse("https://example.org/", bytes.NewBufferString(data))
if err != nil {
t.Fatal(err)
}
@@ -977,7 +1013,7 @@ func TestAbsoluteCommentsURL(t *testing.T) {
`
- feed, err := Parse(bytes.NewBufferString(data))
+ feed, err := Parse("https://example.org/", bytes.NewBufferString(data))
if err != nil {
t.Fatal(err)
}
diff --git a/reader/atom/parser.go b/reader/atom/parser.go
index 9a9cb578..e4e66819 100644
--- a/reader/atom/parser.go
+++ b/reader/atom/parser.go
@@ -15,11 +15,11 @@ import (
)
type atomFeed interface {
- Transform() *model.Feed
+ Transform(baseURL string) *model.Feed
}
// Parse returns a normalized feed struct from a Atom feed.
-func Parse(r io.Reader) (*model.Feed, *errors.LocalizedError) {
+func Parse(baseURL string, r io.Reader) (*model.Feed, *errors.LocalizedError) {
var buf bytes.Buffer
tee := io.TeeReader(r, &buf)
@@ -36,7 +36,7 @@ func Parse(r io.Reader) (*model.Feed, *errors.LocalizedError) {
return nil, errors.NewLocalizedError("Unable to parse Atom feed: %q", err)
}
- return rawFeed.Transform(), nil
+ return rawFeed.Transform(baseURL), nil
}
func getAtomFeedVersion(data io.Reader) string {
diff --git a/reader/feed/handler.go b/reader/feed/handler.go
index 96609544..1fe5a0d5 100644
--- a/reader/feed/handler.go
+++ b/reader/feed/handler.go
@@ -58,7 +58,7 @@ func (h *Handler) CreateFeed(userID, categoryID int64, url string, crawler bool,
return nil, errors.NewLocalizedError(errDuplicate, response.EffectiveURL)
}
- subscription, parseErr := parser.ParseFeed(response.BodyAsString())
+ subscription, parseErr := parser.ParseFeed(response.EffectiveURL, response.BodyAsString())
if parseErr != nil {
return nil, parseErr
}
@@ -137,7 +137,7 @@ func (h *Handler) RefreshFeed(userID, feedID int64) error {
if originalFeed.IgnoreHTTPCache || response.IsModified(originalFeed.EtagHeader, originalFeed.LastModifiedHeader) {
logger.Debug("[Handler:RefreshFeed] Feed #%d has been modified", feedID)
- updatedFeed, parseErr := parser.ParseFeed(response.BodyAsString())
+ updatedFeed, parseErr := parser.ParseFeed(response.EffectiveURL, response.BodyAsString())
if parseErr != nil {
originalFeed.WithError(parseErr.Localize(printer))
h.store.UpdateFeedError(originalFeed)
diff --git a/reader/json/json.go b/reader/json/json.go
index 5eca5e34..45e28888 100644
--- a/reader/json/json.go
+++ b/reader/json/json.go
@@ -55,12 +55,22 @@ func (j *jsonFeed) GetAuthor() string {
return getAuthor(j.Author)
}
-func (j *jsonFeed) Transform() *model.Feed {
- feed := new(model.Feed)
- feed.FeedURL = j.FeedURL
- feed.SiteURL = j.SiteURL
- feed.Title = strings.TrimSpace(j.Title)
+func (j *jsonFeed) Transform(baseURL string) *model.Feed {
+ var err error
+ feed := new(model.Feed)
+
+ feed.FeedURL, err = url.AbsoluteURL(baseURL, j.FeedURL)
+ if err != nil {
+ feed.FeedURL = j.FeedURL
+ }
+
+ feed.SiteURL, err = url.AbsoluteURL(baseURL, j.SiteURL)
+ if err != nil {
+ feed.SiteURL = j.SiteURL
+ }
+
+ feed.Title = strings.TrimSpace(j.Title)
if feed.Title == "" {
feed.Title = feed.SiteURL
}
diff --git a/reader/json/parser.go b/reader/json/parser.go
index babbde15..cb8638bf 100644
--- a/reader/json/parser.go
+++ b/reader/json/parser.go
@@ -13,12 +13,12 @@ import (
)
// Parse returns a normalized feed struct from a JON feed.
-func Parse(data io.Reader) (*model.Feed, *errors.LocalizedError) {
+func Parse(baseURL string, data io.Reader) (*model.Feed, *errors.LocalizedError) {
feed := new(jsonFeed)
decoder := json.NewDecoder(data)
if err := decoder.Decode(&feed); err != nil {
return nil, errors.NewLocalizedError("Unable to parse JSON Feed: %q", err)
}
- return feed.Transform(), nil
+ return feed.Transform(baseURL), nil
}
diff --git a/reader/json/parser_test.go b/reader/json/parser_test.go
index 191423a0..93d8189a 100644
--- a/reader/json/parser_test.go
+++ b/reader/json/parser_test.go
@@ -31,7 +31,7 @@ func TestParseJsonFeed(t *testing.T) {
]
}`
- feed, err := Parse(bytes.NewBufferString(data))
+ feed, err := Parse("https://example.org/feed.json", bytes.NewBufferString(data))
if err != nil {
t.Fatal(err)
}
@@ -113,7 +113,7 @@ func TestParsePodcast(t *testing.T) {
]
}`
- feed, err := Parse(bytes.NewBufferString(data))
+ feed, err := Parse("http://therecord.co/feed.json", bytes.NewBufferString(data))
if err != nil {
t.Fatal(err)
}
@@ -197,7 +197,7 @@ func TestParseEntryWithoutAttachmentURL(t *testing.T) {
]
}`
- feed, err := Parse(bytes.NewBufferString(data))
+ feed, err := Parse("http://therecord.co/feed.json", bytes.NewBufferString(data))
if err != nil {
t.Fatal(err)
}
@@ -226,7 +226,7 @@ func TestParseFeedWithRelativeURL(t *testing.T) {
]
}`
- feed, err := Parse(bytes.NewBufferString(data))
+ feed, err := Parse("https://example.org/feed.json", bytes.NewBufferString(data))
if err != nil {
t.Fatal(err)
}
@@ -258,7 +258,7 @@ func TestParseAuthor(t *testing.T) {
]
}`
- feed, err := Parse(bytes.NewBufferString(data))
+ feed, err := Parse("https://example.org/feed.json", bytes.NewBufferString(data))
if err != nil {
t.Fatal(err)
}
@@ -287,7 +287,7 @@ func TestParseFeedWithoutTitle(t *testing.T) {
]
}`
- feed, err := Parse(bytes.NewBufferString(data))
+ feed, err := Parse("https://example.org/feed.json", bytes.NewBufferString(data))
if err != nil {
t.Fatal(err)
}
@@ -313,7 +313,7 @@ func TestParseFeedItemWithInvalidDate(t *testing.T) {
]
}`
- feed, err := Parse(bytes.NewBufferString(data))
+ feed, err := Parse("https://example.org/feed.json", bytes.NewBufferString(data))
if err != nil {
t.Fatal(err)
}
@@ -341,7 +341,7 @@ func TestParseFeedItemWithoutID(t *testing.T) {
]
}`
- feed, err := Parse(bytes.NewBufferString(data))
+ feed, err := Parse("https://example.org/feed.json", bytes.NewBufferString(data))
if err != nil {
t.Fatal(err)
}
@@ -368,7 +368,7 @@ func TestParseFeedItemWithoutTitle(t *testing.T) {
]
}`
- feed, err := Parse(bytes.NewBufferString(data))
+ feed, err := Parse("https://example.org/feed.json", bytes.NewBufferString(data))
if err != nil {
t.Fatal(err)
}
@@ -395,7 +395,7 @@ func TestParseTruncateItemTitle(t *testing.T) {
]
}`
- feed, err := Parse(bytes.NewBufferString(data))
+ feed, err := Parse("https://example.org/feed.json", bytes.NewBufferString(data))
if err != nil {
t.Fatal(err)
}
@@ -411,7 +411,7 @@ func TestParseTruncateItemTitle(t *testing.T) {
func TestParseInvalidJSON(t *testing.T) {
data := `garbage`
- _, err := Parse(bytes.NewBufferString(data))
+ _, err := Parse("https://example.org/feed.json", bytes.NewBufferString(data))
if err == nil {
t.Error("Parse should returns an error")
}
diff --git a/reader/parser/parser.go b/reader/parser/parser.go
index 726f3552..6214fdb8 100644
--- a/reader/parser/parser.go
+++ b/reader/parser/parser.go
@@ -16,16 +16,16 @@ import (
)
// ParseFeed analyzes the input data and returns a normalized feed object.
-func ParseFeed(data string) (*model.Feed, *errors.LocalizedError) {
+func ParseFeed(baseURL, data string) (*model.Feed, *errors.LocalizedError) {
switch DetectFeedFormat(data) {
case FormatAtom:
- return atom.Parse(strings.NewReader(data))
+ return atom.Parse(baseURL, strings.NewReader(data))
case FormatRSS:
- return rss.Parse(strings.NewReader(data))
+ return rss.Parse(baseURL, strings.NewReader(data))
case FormatJSON:
- return json.Parse(strings.NewReader(data))
+ return json.Parse(baseURL, strings.NewReader(data))
case FormatRDF:
- return rdf.Parse(strings.NewReader(data))
+ return rdf.Parse(baseURL, strings.NewReader(data))
default:
return nil, errors.NewLocalizedError("Unsupported feed format")
}
diff --git a/reader/parser/parser_test.go b/reader/parser/parser_test.go
index ddbaceca..c9a4c019 100644
--- a/reader/parser/parser_test.go
+++ b/reader/parser/parser_test.go
@@ -34,7 +34,7 @@ func TestParseAtom(t *testing.T) {
`
- feed, err := ParseFeed(data)
+ feed, err := ParseFeed("https://example.org/", data)
if err != nil {
t.Error(err)
}
@@ -44,6 +44,42 @@ func TestParseAtom(t *testing.T) {
}
}
+func TestParseAtomFeedWithRelativeURL(t *testing.T) {
+ data := `
+
+ Example Feed
+
+
+
+
+ Test
+
+
+ /blog/article.html
+ 2003-12-13T18:30:02Z
+ Some text.
+
+
+ `
+
+ feed, err := ParseFeed("https://example.org/blog/atom.xml", data)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if feed.FeedURL != "https://example.org/blog/atom.xml" {
+ t.Errorf("Incorrect feed URL, got: %s", feed.FeedURL)
+ }
+
+ if feed.SiteURL != "https://example.org/blog" {
+ t.Errorf("Incorrect site URL, got: %s", feed.SiteURL)
+ }
+
+ if feed.Entries[0].URL != "https://example.org/blog/article.html" {
+ t.Errorf("Incorrect entry URL, got: %s", feed.Entries[0].URL)
+ }
+}
+
func TestParseRSS(t *testing.T) {
data := `
@@ -60,7 +96,7 @@ func TestParseRSS(t *testing.T) {
`
- feed, err := ParseFeed(data)
+ feed, err := ParseFeed("http://liftoff.msfc.nasa.gov/", data)
if err != nil {
t.Error(err)
}
@@ -70,6 +106,44 @@ func TestParseRSS(t *testing.T) {
}
}
+func TestParseRSSFeedWithRelativeURL(t *testing.T) {
+ data := `
+
+
+ Example Feed
+ /blog
+ -
+ Example Entry
+ /blog/article.html
+ Something
+ Tue, 03 Jun 2003 09:39:21 GMT
+ 1234
+
+
+ `
+
+ feed, err := ParseFeed("http://example.org/rss.xml", data)
+ if err != nil {
+ t.Error(err)
+ }
+
+ if feed.Title != "Example Feed" {
+ t.Errorf("Incorrect title, got: %s", feed.Title)
+ }
+
+ if feed.FeedURL != "http://example.org/rss.xml" {
+ t.Errorf("Incorrect feed URL, got: %s", feed.FeedURL)
+ }
+
+ if feed.SiteURL != "http://example.org/blog" {
+ t.Errorf("Incorrect site URL, got: %s", feed.SiteURL)
+ }
+
+ if feed.Entries[0].URL != "http://example.org/blog/article.html" {
+ t.Errorf("Incorrect entry URL, got: %s", feed.Entries[0].URL)
+ }
+}
+
func TestParseRDF(t *testing.T) {
data := `
`
- feed, err := ParseFeed(data)
+ feed, err := ParseFeed("http://example.org/", data)
if err != nil {
t.Error(err)
}
@@ -99,6 +173,43 @@ func TestParseRDF(t *testing.T) {
}
}
+func TestParseRDFWithRelativeURL(t *testing.T) {
+ data := `
+
+
+
+ RDF Example
+ /blog
+
+
+ -
+ Title
+ /blog/article.html
+ Test
+
+ `
+
+ feed, err := ParseFeed("http://example.org/rdf.xml", data)
+ if err != nil {
+ t.Error(err)
+ }
+
+ if feed.FeedURL != "http://example.org/rdf.xml" {
+ t.Errorf("Incorrect feed URL, got: %s", feed.FeedURL)
+ }
+
+ if feed.SiteURL != "http://example.org/blog" {
+ t.Errorf("Incorrect site URL, got: %s", feed.SiteURL)
+ }
+
+ if feed.Entries[0].URL != "http://example.org/blog/article.html" {
+ t.Errorf("Incorrect entry URL, got: %s", feed.Entries[0].URL)
+ }
+}
+
func TestParseJson(t *testing.T) {
data := `{
"version": "https://jsonfeed.org/version/1",
@@ -119,7 +230,7 @@ func TestParseJson(t *testing.T) {
]
}`
- feed, err := ParseFeed(data)
+ feed, err := ParseFeed("https://example.org/feed.json", data)
if err != nil {
t.Error(err)
}
@@ -129,6 +240,43 @@ func TestParseJson(t *testing.T) {
}
}
+func TestParseJsonFeedWithRelativeURL(t *testing.T) {
+ data := `{
+ "version": "https://jsonfeed.org/version/1",
+ "title": "My Example Feed",
+ "home_page_url": "/blog",
+ "feed_url": "/blog/feed.json",
+ "items": [
+ {
+ "id": "2",
+ "content_text": "This is a second item.",
+ "url": "/blog/article.html"
+ }
+ ]
+ }`
+
+ feed, err := ParseFeed("https://example.org/blog/feed.json", data)
+ if err != nil {
+ t.Error(err)
+ }
+
+ if feed.Title != "My Example Feed" {
+ t.Errorf("Incorrect title, got: %s", feed.Title)
+ }
+
+ if feed.FeedURL != "https://example.org/blog/feed.json" {
+ t.Errorf("Incorrect feed URL, got: %s", feed.FeedURL)
+ }
+
+ if feed.SiteURL != "https://example.org/blog" {
+ t.Errorf("Incorrect site URL, got: %s", feed.SiteURL)
+ }
+
+ if feed.Entries[0].URL != "https://example.org/blog/article.html" {
+ t.Errorf("Incorrect entry URL, got: %s", feed.Entries[0].URL)
+ }
+}
+
func TestParseUnknownFeed(t *testing.T) {
data := `
@@ -142,14 +290,14 @@ func TestParseUnknownFeed(t *testing.T) {