diff --git a/internal/reader/sanitizer/sanitizer.go b/internal/reader/sanitizer/sanitizer.go
index 28b9d94b..fab21fa9 100644
--- a/internal/reader/sanitizer/sanitizer.go
+++ b/internal/reader/sanitizer/sanitizer.go
@@ -46,7 +46,7 @@ var (
"h6": {"id"},
"hr": {},
"iframe": {"width", "height", "frameborder", "src", "allowfullscreen"},
- "img": {"alt", "title", "src", "srcset", "sizes", "width", "height"},
+ "img": {"alt", "title", "src", "srcset", "sizes", "width", "height", "fetchpriority", "decoding"},
"ins": {},
"kbd": {},
"li": {"id"},
@@ -234,6 +234,18 @@ func sanitizeAttributes(baseURL, tagName string, attributes []html.Attribute, sa
continue
}
+ if tagName == "img" && attribute.Key == "fetchpriority" {
+ if !isValidFetchPriorityValue(value) {
+ continue
+ }
+ }
+
+ if tagName == "img" && attribute.Key == "decoding" {
+ if !isValidDecodingValue(value) {
+ continue
+ }
+ }
+
if (tagName == "img" || tagName == "source") && attribute.Key == "srcset" {
value = sanitizeSrcsetAttr(baseURL, value)
}
@@ -540,3 +552,13 @@ func getIntegerAttributeValue(name string, attributes []html.Attribute) int {
}
return 0
}
+
+func isValidFetchPriorityValue(value string) bool {
+ allowedValues := []string{"high", "low", "auto"}
+ return slices.Contains(allowedValues, value)
+}
+
+func isValidDecodingValue(value string) bool {
+ allowedValues := []string{"sync", "async", "auto"}
+ return slices.Contains(allowedValues, value)
+}
diff --git a/internal/reader/sanitizer/sanitizer_test.go b/internal/reader/sanitizer/sanitizer_test.go
index 2e4d6424..afe2e928 100644
--- a/internal/reader/sanitizer/sanitizer_test.go
+++ b/internal/reader/sanitizer/sanitizer_test.go
@@ -139,6 +139,100 @@ func TestImgWithSrcsetAndNoSrcAttribute(t *testing.T) {
}
}
+func TestImgWithFetchPriorityAttribute(t *testing.T) {
+ cases := []struct {
+ input string
+ expected string
+ }{
+ {
+ ``,
+ `
`,
+ },
+ {
+ `
`,
+ `
`,
+ },
+ {
+ `
`,
+ `
`,
+ },
+ }
+
+ for _, tc := range cases {
+ output := SanitizeHTMLWithDefaultOptions("http://example.org/", tc.input)
+ if output != tc.expected {
+ t.Errorf(`Wrong output for input %q: expected %q, got %q`, tc.input, tc.expected, output)
+ }
+ }
+}
+
+func TestImgWithInvalidFetchPriorityAttribute(t *testing.T) {
+ input := `
`
+ expected := `
`
+ output := SanitizeHTMLWithDefaultOptions("http://example.org/", input)
+
+ if output != expected {
+ t.Errorf(`Wrong output: expected %q, got %q`, expected, output)
+ }
+}
+
+func TestNonImgWithFetchPriorityAttribute(t *testing.T) {
+ input := `
Text
` + expected := `Text
` + output := SanitizeHTMLWithDefaultOptions("http://example.org/", input) + + if output != expected { + t.Errorf(`Wrong output: expected %q, got %q`, expected, output) + } +} + +func TestImgWithDecodingAttribute(t *testing.T) { + cases := []struct { + input string + expected string + }{ + { + `Text
` + expected := `Text
` + output := SanitizeHTMLWithDefaultOptions("http://example.org/", input) + + if output != expected { + t.Errorf(`Wrong output: expected %q, got %q`, expected, output) + } +} + func TestSourceWithSrcsetAndMedia(t *testing.T) { input := `