summaryrefslogtreecommitdiff
path: root/app/src/main/java/org/terst/feedreader/ui/AddFeedScreen.kt
diff options
context:
space:
mode:
authorPeter Stone <thepeterstone@gmail.com>2026-07-25 01:30:21 +0000
committerPeter Stone <thepeterstone@gmail.com>2026-07-25 01:30:21 +0000
commit72214b9d3617a66a70727819dbf7fe59ea037264 (patch)
tree4ca4f266dfac10de3dbcd1b8068c1a26cac4f926 /app/src/main/java/org/terst/feedreader/ui/AddFeedScreen.kt
parentf202c603259c40c4d21a4385c9f69a3efca87acc (diff)
Migrate http:// feeds to https:// where it actually works; add feeds as https-only going forward
Android blocks cleartext by default (targetSdk 28+), so every http:// feed was failing every single fetch ("CLEARTEXT communication ... not permitted"). Checked each of this user's 9 http feeds live via curl: - 6 work fine over https (5 are a plain scheme swap; divingforpearlsblog.com's own https endpoint redirects through an insecure feedburner hop, so that one points straight at feedburner's https endpoint instead) -- migrated via a new Room migration (v6->v7), rewriting both the feed row and its articles' feedId so read history isn't orphaned. Confirmed live: all 6 now fetch clean with no lastError. - 3 have no usable https at all (bit-player.org: connection refused, no TLS listener; blog.securitymouse.com: broken TLS handshake; webpolicy.org: a certificate that doesn't match the hostname) and are deliberately left alone. Going forward, adding a feed (manually or via OPML import) upgrades a given http:// URL to https:// before using it -- most sites serve identical content either way, and a site with no real https support just fails its very next fetch attempt the normal way instead of silently subscribing to a feed that can never actually update. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EZ7ikw2ukGJFTHE3bJS7zL
Diffstat (limited to 'app/src/main/java/org/terst/feedreader/ui/AddFeedScreen.kt')
-rw-r--r--app/src/main/java/org/terst/feedreader/ui/AddFeedScreen.kt20
1 files changed, 15 insertions, 5 deletions
diff --git a/app/src/main/java/org/terst/feedreader/ui/AddFeedScreen.kt b/app/src/main/java/org/terst/feedreader/ui/AddFeedScreen.kt
index e531fb7..38b0f32 100644
--- a/app/src/main/java/org/terst/feedreader/ui/AddFeedScreen.kt
+++ b/app/src/main/java/org/terst/feedreader/ui/AddFeedScreen.kt
@@ -61,7 +61,7 @@ fun AddFeedScreen(onDone: () -> Unit) {
// exported from a reader with folders/labels) appears once per folder here --
// dedupe by feed URL before reporting a count, or "108 feeds" would be reported
// as some larger number even though upsert already collapses them to one row each.
- val uniqueFeeds = imported.distinctBy { it.xmlUrl }
+ val uniqueFeeds = imported.map { it.copy(xmlUrl = preferHttps(it.xmlUrl)) }.distinctBy { it.xmlUrl }
for (feed in uniqueFeeds) {
// upsert() REPLACEs the whole row -- for a feed that's already subscribed,
// building a bare FeedEntity here would silently wipe readerModeDisabled
@@ -147,20 +147,30 @@ fun AddFeedScreen(onDone: () -> Unit) {
}
}
+// Feeds get added as https:// even if the user (or an OPML export) gave an http:// URL --
+// Android blocks cleartext by default (targetSdk 28+), so an http feed would just fail every
+// fetch forever. Most sites serve identical content either way; this is a plain scheme swap.
+// If a site genuinely doesn't support https, the very next fetch attempt fails immediately and
+// shows up the normal way (the feed list's "Last fetch failed" section) rather than silently
+// adding a feed that looks fine until you notice it never updates.
+private fun preferHttps(url: String): String =
+ if (url.startsWith("http://", ignoreCase = true)) "https://" + url.removePrefix("http://") else url
+
private suspend fun addFeedByUrl(context: android.content.Context, db: AppDatabase, feedUrl: String): String =
withContext(Dispatchers.IO) {
+ val url = preferHttps(feedUrl)
try {
- val response = Net.client.newCall(Request.Builder().url(feedUrl).build()).execute()
+ val response = Net.client.newCall(Request.Builder().url(url).build()).execute()
response.use {
if (!it.isSuccessful) return@withContext "Couldn't fetch feed: HTTP ${it.code}"
val body = it.body ?: return@withContext "Empty response"
val parsed = FeedParser.parse(body.byteStream())
// Same REPLACE-wipes-other-fields concern as the OPML import path.
- val existing = db.feedDao().getById(feedUrl)
+ val existing = db.feedDao().getById(url)
val entity = existing?.copy(
- title = parsed.title.ifBlank { feedUrl },
+ title = parsed.title.ifBlank { url },
siteUrl = parsed.siteUrl ?: existing.siteUrl
- ) ?: FeedEntity(id = feedUrl, title = parsed.title.ifBlank { feedUrl }, siteUrl = parsed.siteUrl)
+ ) ?: FeedEntity(id = url, title = parsed.title.ifBlank { url }, siteUrl = parsed.siteUrl)
db.feedDao().upsert(entity)
}
FeedFetchWorker.fetchNow(context)