Repository: thundernest/k-9
Issue: Relative link and `<base>` tag

### Checklist

- [X] I have used the search function to see if someone else has already submitted the same bug report.
- [X] I will describe the problem with as much detail as possible.

### App version

6.502

### Where did you get the app from?

None

### Android version

doesn't matter

### Device model

_No response_

### Steps to reproduce

1. Open a message containing a `<base>` element and a relative link
2. Tap the link

```email
MIME-Version: 1.0
From: "cketti" <cketti@k9mail.example>
Date: Tue, 17 Jan 2023 16:00:00 +0100
Message-ID: <inbox-2@k9mail.example>
Subject: Relative link
To: User <user@k9mail.example>
Content-Type: text/html; charset=UTF-8

<html>
  <head>
    <base href="https://k9mail.app/">
  </head>
  <body>
    <a href="/2022/06/13/K-9-Mail-and-Thunderbird">Link</a>
  </body>
</html>
```

### Expected behavior

K-9 Mail resolves the relative URL using the base URL and hands the proper URL to an external app for viewing.

### Actual behavior

The URL can't be resolved and the URI `about:blank#blocked` is used when launching an external app.

Long-pressing the link also doesn't work.

### Logs

_No response_

Changed files:
app/html-cleaner/src/test/java/app/k9mail/html/cleaner/HtmlSanitizerTest.kt, app/html-cleaner/src/main/java/app/k9mail/html/cleaner/HeadCleaner.kt

diff --git a/app/html-cleaner/src/main/java/app/k9mail/html/cleaner/HeadCleaner.kt b/app/html-cleaner/src/main/java/app/k9mail/html/cleaner/HeadCleaner.kt
index d9ac70f81..148529142 100644
--- a/app/html-cleaner/src/main/java/app/k9mail/html/cleaner/HeadCleaner.kt
+++ b/app/html-cleaner/src/main/java/app/k9mail/html/cleaner/HeadCleaner.kt
@@ -9,7 +9,7 @@ import org.jsoup.parser.Tag
 import org.jsoup.select.NodeTraversor
 import org.jsoup.select.NodeVisitor
 
-private val ALLOWED_TAGS = listOf("style", "meta")
+private val ALLOWED_TAGS = listOf("style", "meta", "base")
 
 internal class HeadCleaner {
     fun clean(dirtyDocument: Document, cleanedDocument: Document) {
diff --git a/app/html-cleaner/src/test/java/app/k9mail/html/cleaner/HtmlSanitizerTest.kt b/app/html-cleaner/src/test/java/app/k9mail/html/cleaner/HtmlSanitizerTest.kt
index d60ae8b38..902500006 100644
--- a/app/html-cleaner/src/test/java/app/k9mail/html/cleaner/HtmlSanitizerTest.kt
+++ b/app/html-cleaner/src/test/java/app/k9mail/html/cleaner/HtmlSanitizerTest.kt
@@ -465,6 +465,25 @@ class HtmlSanitizerTest {
         assertTagsNotStripped("var")
     }
 
+    @Test
+    fun `should keep 'base' element`() {
+        val html =
+            """
+            <html>
+              <head>
+                <base href="https://domain.example/">
+              </head>
+              <body>
+                <a href="relative">Link</a>
+              </body>
+            </html>
+            """.compactHtml()
+
+        val result = htmlSanitizer.sanitize(html)
+
+        assertThat(result.toCompactString()).isEqualTo(html)
+    }
+
     private fun assertTagsNotStripped(element: String) {
         val html = """<$element>some text</$element>"""
 
@@ -491,4 +510,6 @@ class HtmlSanitizerTest {
     }
 
     private fun String.trimLineBreaks() = replace("\\n", "")
+
+    private fun String.compactHtml() = lines().joinToString(separator = "") { it.trim() }
 }