Repository: miniflux/v2 (Go)

Issue:
Api convert sometimes characters into html Entities
I have problem with miniflux, when I use it with newsboat. Some greater and less than sign are converted into html entities, and newsboat have problem with parsing url in such case.

I'm not sure if it is miniflux or newsboat error, but when using python client I still get html entries instead of greater/less sign

https://www.angrymetalguy.com/feed/
Problematic part of parsed feed
```
<p><iframe class="aligncenter" style="border: 0; width: 500px; height: 120px;" src="https://bandcamp.com/EmbeddedPlayer/album=657880708/size=large/bgcol=ffffff/linkcol=0687f5/tracklist=false/artwork=small/transparent=true/" seamless=""><span data-mce-type="bookmark" style="display: inline-block; width: 0px; overflow: hidden; line-height: 0;" class="mce_SELRES_start">﻿</span><a href="https://keysoforthanc.bandcamp.com/album/of-the-lineage-of-kings">Of the Lineage of Kings by Keys of Orthanc</a></iframe></p>
```

Api return:
```
<p><iframe src="https://bandcamp.com/EmbeddedPlayer/album=657880708/size=large/bgcol=ffffff/linkcol=0687f5/tracklist=false/artwork=small/transparent=true/" sandbox="allow-scripts allow-same-origin allow-popups" loading="lazy">&lt;span data-mce-type=&#34;bookmark&#34; style=&#34;display: inline-block; width: 0px; overflow: hidden; line-height: 0;&#34; class=&#34;mce_SELRES_start&#34;&gt;\ufeff&lt;/span&gt;&lt;a href=&#34;https://keysoforthanc.bandcamp.com/album/of-the-lineage-of-kings&#34;&gt;Of the Lineage of Kings by Keys of Orthanc&lt;/a&gt;</iframe></p>
```


Discussion:
The feed is correct, but Miniflux behaves badly: https://validator.w3.org/feed/check.cgi?url=https%3A%2F%2Fwww.angrymetalguy.com%2Ffeed%2F

See #999, 291bf96
You are referring to the content inside an iframe element `<iframe>html here</iframe>`. An iframe element is not supposed to have inner child elements.

Citing the HTML 5 standard:

> An iframe element never has fallback content, as it will always create a nested browsing context, regardless of whether the specified initial contents are successfully used.

https://www.w3.org/TR/2010/WD-html5-20101019/the-iframe-element.html#the-iframe-element

Miniflux sanitize HTML elements. The issue is not related to the API or the links mentioned in the comment above. Actually, Miniflux should remove iframe inner contents.

The relevant part of the code is there: https://github.com/miniflux/v2/blob/master/reader/sanitizer/sanitizer.go#L49

In a web browser, the article is correctly rendered:

![image](https://user-images.githubusercontent.com/323546/107860291-6b52c880-6df3-11eb-8be9-23126a1160bf.png)

Ok, so this is proper way… and no issue

So I will probably use replace rule to get only url, and forget player, which I don't use…
```
replace("<\/?iframe(.*?)>"|" ")
```




Patch:
diff --git a/reader/sanitizer/sanitizer.go b/reader/sanitizer/sanitizer.go
index 2da7b48386f..3abafc87612 100644
--- a/reader/sanitizer/sanitizer.go
+++ b/reader/sanitizer/sanitizer.go
@@ -24,11 +24,12 @@ var (
 
 // Sanitize returns safe HTML.
 func Sanitize(baseURL, input string) string {
-	tokenizer := html.NewTokenizer(bytes.NewBufferString(input))
 	var buffer bytes.Buffer
 	var tagStack []string
+	var parentTag string
 	blacklistedTagDepth := 0
 
+	tokenizer := html.NewTokenizer(bytes.NewBufferString(input))
 	for {
 		if tokenizer.Next() == html.ErrorToken {
 			err := tokenizer.Err()
@@ -46,9 +47,16 @@ func Sanitize(baseURL, input string) string {
 				continue
 			}
 
+			// An iframe element never has fallback content.
+			// See https://www.w3.org/TR/2010/WD-html5-20101019/the-iframe-element.html#the-iframe-element
+			if parentTag == "iframe" {
+				continue
+			}
+
 			buffer.WriteString(html.EscapeString(token.Data))
 		case html.StartTagToken:
 			tagName := token.DataAtom.String()
+			parentTag = tagName
 
 			if !isPixelTracker(tagName, token.Attr) && isValidTag(tagName) {
 				attrNames, htmlAttributes := sanitizeAttributes(baseURL, tagName, token.Attr)


Test patch:
diff --git a/reader/sanitizer/sanitizer_test.go b/reader/sanitizer/sanitizer_test.go
index 9bf4528eebc..72729b37986 100644
--- a/reader/sanitizer/sanitizer_test.go
+++ b/reader/sanitizer/sanitizer_test.go
@@ -173,6 +173,16 @@ func TestInvalidIFrame(t *testing.T) {
 	}
 }
 
+func TestIFrameWithChildElements(t *testing.T) {
+	input := `<iframe src="https://www.youtube.com/"><p>test</p></iframe>`
+	expected := `<iframe src="https://www.youtube.com/" sandbox="allow-scripts allow-same-origin allow-popups" loading="lazy"></iframe>`
+	output := Sanitize("http://example.com/", input)
+
+	if expected != output {
+		t.Errorf(`Wrong output: "%s" != "%s"`, expected, output)
+	}
+}
+
 func TestInvalidURLScheme(t *testing.T) {
 	input := `<p>This link is <a src="file:///etc/passwd">not valid</a></p>`
 	expected := `<p>This link is not valid</p>`