Skip to content

Commit 5b53df1

Browse files
authored
Merge pull request #871 from jpurnell/fix/rss-xml-escaping
Fix XML escaping in RSS feed generator
2 parents 01a96b2 + 0317f30 commit 5b53df1

2 files changed

Lines changed: 25 additions & 1 deletion

File tree

Sources/Ignite/Publishing/FeedGenerator.swift

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,15 @@ struct FeedGenerator {
1717
self.content = content
1818
}
1919

20+
private func xmlEscape(_ string: String) -> String {
21+
string
22+
.replacingOccurrences(of: "&", with: "&")
23+
.replacingOccurrences(of: "<", with: "&lt;")
24+
.replacingOccurrences(of: ">", with: "&gt;")
25+
.replacingOccurrences(of: "\"", with: "&quot;")
26+
.replacingOccurrences(of: "'", with: "&apos;")
27+
}
28+
2029
func generateFeed() -> String {
2130
let contentXML = generateContentXML()
2231
var result = generateRSSHeader()
@@ -25,7 +34,7 @@ struct FeedGenerator {
2534
result += """
2635
<image>\
2736
<url>\(image.url)</url>\
28-
<title>\(site.name)</title>\
37+
<title>\(xmlEscape(site.name))</title>\
2938
<link>\(site.url.absoluteString)</link>\
3039
<width>\(image.width)</width>\
3140
<height>\(image.height)</height>\

Tests/IgniteTesting/Publishing/FeedGenerator.swift

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,21 @@ struct FeedGeneratorTests {
2020
TestSite(timeZone: .init(abbreviation: "EST")!)
2121
]
2222

23+
@Test("XML-escapes special characters in titles")
24+
func xmlEscapesSpecialCharacters() async throws {
25+
let site = TestSite()
26+
let config = site.feedConfiguration!
27+
var article = Article()
28+
article.title = "Donations & Sponsorships"
29+
article.description = "Example Description"
30+
31+
let generator = FeedGenerator(config: config, site: site, content: [article])
32+
let feed = generator.generateFeed()
33+
34+
#expect(feed.contains("<title>Donations &amp; Sponsorships</title>"))
35+
#expect(!feed.contains("<title>Donations & Sponsorships</title>"))
36+
}
37+
2338
@Test("generateFeed()", arguments: await sites)
2439
func generateFeed(for site: any Site) async throws {
2540
let config = site.feedConfiguration!

0 commit comments

Comments
 (0)