Browse Source

Handle more encoding conversion edge cases

Frédéric Guillot 11 months ago
parent
commit
ae1dc1a91e

+ 27 - 14
http/client/response.go

@@ -5,15 +5,18 @@
 package client // import "miniflux.app/http/client"
 
 import (
+	"bytes"
 	"io"
 	"io/ioutil"
 	"mime"
+	"regexp"
 	"strings"
 
 	"golang.org/x/net/html/charset"
-	"miniflux.app/logger"
 )
 
+var xmlEncodingRegex = regexp.MustCompile(`<\?xml(.*)encoding="(.+)"(.*)\?>`)
+
 // Response wraps a server response.
 type Response struct {
 	Body          io.Reader
@@ -63,22 +66,32 @@ func (r *Response) IsModified(etag, lastModified string) bool {
 // This is used by the scraper and feed readers.
 //
 // Do not forget edge cases:
-// - Some non-utf8 feeds specify encoding only in Content-Type, not in XML document.
-func (r *Response) EnsureUnicodeBody() error {
-	_, params, err := mime.ParseMediaType(r.ContentType)
-	if err == nil {
-		if enc, found := params["charset"]; found {
-			enc = strings.ToLower(enc)
-			if enc != "utf-8" && enc != "utf8" && enc != "" {
-				logger.Debug("[EnsureUnicodeBody] Convert body to utf-8 from %s", enc)
-				r.Body, err = charset.NewReader(r.Body, r.ContentType)
-				if err != nil {
-					return err
-				}
+//
+// - Feeds with encoding specified only in Content-Type header and not in XML document
+// - Feeds with encoding specified in both places
+// - Feeds with encoding specified only in XML document and not in HTTP header
+// - Feeds with wrong encoding defined and already in UTF-8
+func (r *Response) EnsureUnicodeBody() (err error) {
+	if r.ContentType != "" {
+		mediaType, _, mediaErr := mime.ParseMediaType(r.ContentType)
+		if mediaErr != nil {
+			return mediaErr
+		}
+
+		if strings.Contains(mediaType, "xml") {
+			buffer, _ := ioutil.ReadAll(r.Body)
+			r.Body = bytes.NewReader(buffer)
+
+			// We ignore documents with encoding specified in XML prolog.
+			// This is going to be handled by the XML parser.
+			if xmlEncodingRegex.Match(buffer[0:1024]) {
+				return
 			}
 		}
 	}
-	return nil
+
+	r.Body, err = charset.NewReader(r.Body, r.ContentType)
+	return err
 }
 
 // String returns the response body as string.

+ 103 - 13
http/client/response_test.go

@@ -4,26 +4,62 @@
 
 package client // import "miniflux.app/http/client"
 
-import "testing"
+import (
+	"bytes"
+	"io/ioutil"
+	"strings"
+	"testing"
+	"unicode/utf8"
+)
 
-func TestHasServerFailureWith200Status(t *testing.T) {
-	r := &Response{StatusCode: 200}
-	if r.HasServerFailure() {
-		t.Error("200 is not a failure")
+func TestIsNotFound(t *testing.T) {
+	scenarios := map[int]bool{
+		200: false,
+		404: true,
+		410: true,
+	}
+
+	for input, expected := range scenarios {
+		r := &Response{StatusCode: input}
+		actual := r.IsNotFound()
+
+		if actual != expected {
+			t.Errorf(`Unexpected result, got %v instead of %v for status code %d`, actual, expected, input)
+		}
 	}
 }
 
-func TestHasServerFailureWith404Status(t *testing.T) {
-	r := &Response{StatusCode: 404}
-	if !r.HasServerFailure() {
-		t.Error("404 is a failure")
+func TestIsNotAuthorized(t *testing.T) {
+	scenarios := map[int]bool{
+		200: false,
+		401: true,
+		403: false,
+	}
+
+	for input, expected := range scenarios {
+		r := &Response{StatusCode: input}
+		actual := r.IsNotAuthorized()
+
+		if actual != expected {
+			t.Errorf(`Unexpected result, got %v instead of %v for status code %d`, actual, expected, input)
+		}
 	}
 }
 
-func TestHasServerFailureWith500Status(t *testing.T) {
-	r := &Response{StatusCode: 500}
-	if !r.HasServerFailure() {
-		t.Error("500 is a failure")
+func TestHasServerFailure(t *testing.T) {
+	scenarios := map[int]bool{
+		200: false,
+		404: true,
+		500: true,
+	}
+
+	for input, expected := range scenarios {
+		r := &Response{StatusCode: input}
+		actual := r.HasServerFailure()
+
+		if actual != expected {
+			t.Errorf(`Unexpected result, got %v instead of %v for status code %d`, actual, expected, input)
+		}
 	}
 }
 
@@ -54,3 +90,57 @@ func TestIsModifiedWithDifferentHeaders(t *testing.T) {
 		t.Error("The resource should be considered modified")
 	}
 }
+
+func TestToString(t *testing.T) {
+	input := `test`
+	r := &Response{Body: strings.NewReader(input)}
+
+	if r.String() != input {
+		t.Error(`Unexpected ouput`)
+	}
+}
+
+func TestEnsureUnicodeWithHTMLDocuments(t *testing.T) {
+	var unicodeTestCases = []struct {
+		filename, contentType string
+		convertedToUnicode    bool
+	}{
+		{"HTTP-charset.html", "text/html; charset=iso-8859-15", true},
+		{"UTF-16LE-BOM.html", "", true},
+		{"UTF-16BE-BOM.html", "", true},
+		{"meta-content-attribute.html", "text/html", true},
+		{"meta-charset-attribute.html", "text/html", true},
+		{"No-encoding-declaration.html", "text/html", true},
+		{"HTTP-vs-UTF-8-BOM.html", "text/html; charset=iso-8859-15", true},
+		{"HTTP-vs-meta-content.html", "text/html; charset=iso-8859-15", true},
+		{"HTTP-vs-meta-charset.html", "text/html; charset=iso-8859-15", true},
+		{"UTF-8-BOM-vs-meta-content.html", "text/html", true},
+		{"UTF-8-BOM-vs-meta-charset.html", "text/html", true},
+		{"windows_1251.html", "text/html; charset=windows-1251", true},
+		{"gb2312.html", "text/html", true},
+		{"urdu.xml", "text/xml; charset=utf-8", true},
+		{"content-type-only-win-8859-1.xml", "application/xml; charset=ISO-8859-1", true},
+		{"rdf_utf8.xml", "application/rss+xml; charset=utf-8", true},
+		{"charset-content-type-xml-iso88591.xml", "application/rss+xml; charset=ISO-8859-1", false},
+		{"windows_1251.xml", "text/xml", false},
+	}
+
+	for _, tc := range unicodeTestCases {
+		content, err := ioutil.ReadFile("testdata/" + tc.filename)
+		if err != nil {
+			t.Fatalf(`Unable to read file %q: %v`, tc.filename, err)
+		}
+
+		r := &Response{Body: bytes.NewReader(content), ContentType: tc.contentType}
+		parseErr := r.EnsureUnicodeBody()
+		if parseErr != nil {
+			t.Fatalf(`Unicode conversion error for %q - %q: %v`, tc.filename, tc.contentType, err)
+		}
+
+		isUnicode := utf8.ValidString(r.String())
+		if isUnicode != tc.convertedToUnicode {
+			t.Errorf(`Unicode conversion %q - %q, got: %v, expected: %v`,
+				tc.filename, tc.contentType, isUnicode, tc.convertedToUnicode)
+		}
+	}
+}

File diff suppressed because it is too large
+ 48 - 0
http/client/testdata/HTTP-charset.html


File diff suppressed because it is too large
+ 48 - 0
http/client/testdata/HTTP-vs-UTF-8-BOM.html


File diff suppressed because it is too large
+ 49 - 0
http/client/testdata/HTTP-vs-meta-charset.html


File diff suppressed because it is too large
+ 49 - 0
http/client/testdata/HTTP-vs-meta-content.html


File diff suppressed because it is too large
+ 47 - 0
http/client/testdata/No-encoding-declaration.html


+ 9 - 0
http/client/testdata/README

@@ -0,0 +1,9 @@
+These test cases come from
+http://www.w3.org/International/tests/repository/html5/the-input-byte-stream/results-basics
+
+Distributed under both the W3C Test Suite License
+(http://www.w3.org/Consortium/Legal/2008/04-testsuite-license)
+and the W3C 3-clause BSD License
+(http://www.w3.org/Consortium/Legal/2008/03-bsd-license).
+To contribute to a W3C Test Suite, see the policies and contribution
+forms (http://www.w3.org/2004/10/27-testcases).

BIN
http/client/testdata/UTF-16BE-BOM.html


BIN
http/client/testdata/UTF-16LE-BOM.html


File diff suppressed because it is too large
+ 49 - 0
http/client/testdata/UTF-8-BOM-vs-meta-charset.html


File diff suppressed because it is too large
+ 48 - 0
http/client/testdata/UTF-8-BOM-vs-meta-content.html


File diff suppressed because it is too large
+ 422 - 0
http/client/testdata/charset-content-type-xml-iso88591.xml


+ 79 - 0
http/client/testdata/content-type-only-win-8859-1.xml

@@ -0,0 +1,79 @@
+<rss version="2.0" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
+<channel>
+	<title>Flux RSS du magazine de psychologie Le Cercle Psy</title>
+	<link>https://le-cercle-psy.scienceshumaines.com/rss</link>
+	<description>Flux RSS du magazine de psychologie Le Cercle Psy, le magazine de toutes les psychologies.</description>
+	<copyright>Le Cercle Psy</copyright>
+	
+			<item>
+				<title>Perturbateurs endocriniens : quels effets sur le cerveau ?</title>
+				<link>https://le-cercle-psy.scienceshumaines.com/perturbateurs-endocriniens-quels-effets-sur-le-cerveau_sh_39995</link>
+				<pubDate>Wed, 17 Oct 2018 10:30:00 GMT</pubDate>
+				<description>Si leur impact semble discret au premier abord, nombre d'études montrent que les perturbateurs endocriniens pourraient être à l'origine de troubles neuro-développementaux chez l'enfant.</description>
+			</item>
+						
+			<item>
+				<title>Masters en Psycho : une simplificationet#8230; très complexe </title>
+				<link>https://le-cercle-psy.scienceshumaines.com/masters-en-psycho-une-simplification-tres-complexe_sh_40065</link>
+				<pubDate>Wed, 17 Oct 2018 10:30:00 GMT</pubDate>
+				<description>Une nouvelle nomenclature adoptée en 2014 a voulu simplifier les options proposées aux étudiants en Master de Psychologie. Mais on en revient à des choix aussi illisibles qu'auparavant !</description>
+			</item>
+				
+			<item>
+				<title>La criminalité liée surtout à... l'ennui ?</title>
+				<link>https://le-cercle-psy.scienceshumaines.com/la-criminalite-liee-surtout-a-l-ennui_sh_39986</link>
+				<pubDate>Wed, 17 Oct 2018 10:30:00 GMT</pubDate>
+				<description>« L'oisiveté est mère de tous les vices », dit le proverbe... Certains chercheurs américains paraissent proches de cette position !</description>
+			</item>
+				
+			<item>
+				<title></title>
+				<link></link>
+				<pubDate>Wed, 17 Oct 2018 10:30:00 GMT</pubDate>
+				<description></description>
+			</item>
+						
+			<item>
+				<title>Caroline Eliacheff : « Dolto reste authentiquement subversive »</title>
+				<link>https://le-cercle-psy.scienceshumaines.com/caroline-eliacheff-dolto-reste-authentiquement-subversive_sh_39992</link>
+				<pubDate>Wed, 17 Oct 2018 10:30:00 GMT</pubDate>
+				<description>Françoise Dolto est morte il y a trente ans. D'abord adulée par des générations de parents et de collègues, on lui a ensuite reproché d'avoir favorisé l'émergence d'enfants-rois tyranniques. Et s'il existait une autre voie ?</description>
+			</item>
+						
+			<item>
+				<title>L'enfant doué : quand trop comprendre... empêche parfois de comprendre</title>
+				<link>https://le-cercle-psy.scienceshumaines.com/l-enfant-doue-quand-trop-comprendre-empeche-parfois-de-comprendre_sh_40004</link>
+				<pubDate>Wed, 17 Oct 2018 10:30:00 GMT</pubDate>
+				<description>On ne le répètera jamais assez : réaliser le portrait-robot d'un enfant « doué », « surdoué », « à haut potentiel », peu importe la qualification choisie, est vain. Cet ouvrage nous rappelle que chaque facilité, talent, compétence ou même don, peut s'accompagner d'un versant potentiellement plus problématique. Mais insistons : potentiellement.</description>
+			</item>
+								
+			<item>
+				<title>Travail, organisations, emploi : les modèles européens</title>
+				<link>https://le-cercle-psy.scienceshumaines.com/travail-organisations-emploi-les-modeles-europeens_sh_33090</link>
+				<pubDate>Wed, 17 Oct 2018 10:30:00 GMT</pubDate>
+				<description>Les pays européens diffèrent en matière de performance, de niveau de chômage et de qualité de vie au travail. Certains pays réussissent mieux que d'autres et sont pris comme «modèles». Comment font-ils?</description>
+			</item>
+						
+			<item>
+				<title>Migrants : l'urgence thérapeutique</title>
+				<link>https://le-cercle-psy.scienceshumaines.com/migrants-l-urgence-therapeutique_sh_39180</link>
+				<pubDate>Wed, 17 Oct 2018 10:30:00 GMT</pubDate>
+				<description>Poussés à l'exil par les conflits, la pauvreté et l'espoir d'une vie meilleure, les migrants arrivent après un long parcours. Beaucoup sont blessés, brisés, désespérés parfois. Quelle réponse pour les aider ?</description>
+			</item>
+				
+			<item>
+				<title>Psy en prison, une mission impossible ?</title>
+				<link>https://le-cercle-psy.scienceshumaines.com/psy-en-prison-une-mission-impossible_sh_38718</link>
+				<pubDate>Wed, 17 Oct 2018 10:30:00 GMT</pubDate>
+				<description>Détenus proches de la psychose, manque cruel de moyens, hiérarchie intrusive... Les praticiens intervenant en prison n'ont pas un quotidien facile. Retour sur un sacerdoce des temps modernes.</description>
+			</item>
+				
+			<item>
+				<title>Psychologue à domicile : de la clinique à l'état brut</title>
+				<link>https://le-cercle-psy.scienceshumaines.com/psychologue-a-domicile-de-la-clinique-a-l-etat-brut_sh_35540</link>
+				<pubDate>Wed, 17 Oct 2018 10:30:00 GMT</pubDate>
+				<description>Si tu ne peux pas venir au psychologue, le psychologue viendra à toi ! L'intervention à domicile demeure une pratique encore peu répandue chez les psys. En quoi diffère-t-elle d'une consultation ordinaire ?</description>
+			</item>
+					</channel>
+</rss>
+

File diff suppressed because it is too large
+ 862 - 0
http/client/testdata/gb2312.html


File diff suppressed because it is too large
+ 48 - 0
http/client/testdata/meta-charset-attribute.html


File diff suppressed because it is too large
+ 48 - 0
http/client/testdata/meta-content-attribute.html


+ 374 - 0
http/client/testdata/rdf_utf8.xml

@@ -0,0 +1,374 @@
+<?xml version="1.0" encoding="utf-8"?>
+<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://my.netscape.com/rdf/simple/0.9/">
+	<channel>
+ 	 <title>heise online News</title>
+ 	 <link>https://www.heise.de/newsticker/</link>
+ 	 <description>Nachrichten nicht nur aus der Welt der Computer</description>
+	</channel>
+
+
+	<item>
+		<title>OLED-TVs: Vorsichtsmaßnahmen gegen Einbrennen</title>
+		<link>https://www.heise.de/newsticker/meldung/OLED-TVs-Vorsichtsmassnahmen-gegen-Einbrennen-4205274.html?wt_mc=rss.ho.beitrag.rdf</link>
+			<description>Wer gerade einen neuen OLED-Fernseher gekauft hat oder sich zu Weihnachten einen zuzulegen möchte, sollte unbedingt ein paar Hinweise beachten.</description>
+	</item>
+
+	<item>
+		<title>Mega-Deal: IBM übernimmt Red Hat</title>
+		<link>https://www.heise.de/newsticker/meldung/Mega-Deal-IBM-uebernimmt-Red-Hat-4205582.html?wt_mc=rss.ho.beitrag.rdf</link>
+			<description>Giganten-Hochzeit in den USA: Der Computerkonzern IBM übernimmt den Open-Source-Anbieter Red Hat für umgerechnet 30 Milliarden Euro.</description>
+	</item>
+
+	<item>
+		<title>Fortnite-Macher: Epic Games soll 15 Milliarden Dollar wert sein</title>
+		<link>https://www.heise.de/newsticker/meldung/Fortnite-Macher-Epic-Games-soll-15-Milliarden-Dollar-wert-sein-4205522.html?wt_mc=rss.ho.beitrag.rdf</link>
+			<description>Epic Games konnte bei einer Investionsrunde einige neue Geldgeber von sich überzeugen. Insgesamt flossen 1,25 Milliarden US-Dollar.</description>
+	</item>
+
+	<item>
+		<title>Erster nichtstaatlicher Raketenstart in China fehlgeschlagen</title>
+		<link>https://www.heise.de/newsticker/meldung/Erster-nichtstaatlicher-Rekatenstart-in-China-fehlgeschlagen-4205524.html?wt_mc=rss.ho.beitrag.rdf</link>
+			<description>Die Trägerrakete ZQ-1 hat es wegen unbekannter technischer Probleme nach dem Start nicht in die Erdumlaufbahn geschafft.</description>
+	</item>
+
+	<item>
+		<title>eARC: Immer mehr Hersteller schalten HDMI-Audio-Rückkanal frei</title>
+		<link>https://www.heise.de/newsticker/meldung/eARC-Hersteller-schalten-HDMI-Audio-Rueckkanal-frei-4205518.html?wt_mc=rss.ho.beitrag.rdf</link>
+			<description>Während andere HDMI-2.1-Funktionen auf sich warten lassen, ist der &quot;enhanced Audio Return Channel&quot; nach einem Firmware-Update schon bei AV-Receivern nutzbar.</description>
+	</item>
+
+	<item>
+		<title>Vorschau: Neue PC-Spiele im November 2018</title>
+		<link>https://www.heise.de/newsticker/meldung/Vorschau-Neue-PC-Spiele-im-November-2018-4202098.html?wt_mc=rss.ho.beitrag.rdf</link>
+			<description>Jeden Monat schicken Spiele-Hersteller zahlreiche neue Titel ins Rennen. Wir haben die wichtigsten Spiele-Neuerscheinungen im November herausgesucht.</description>
+	</item>
+
+	<item>
+		<title>Israelisches Start-up baut faltbares Elektroauto</title>
+		<link>https://www.heise.de/newsticker/meldung/Israelisches-Start-up-baut-faltbares-Elektroauto-4205501.html?wt_mc=rss.ho.beitrag.rdf</link>
+			<description>Das zweisitzige Auto kann sein Fahrgestell zum Parken einklappen und passt dann auf einen Motorradparkplatz.</description>
+	</item>
+
+	<item>
+		<title>Flash-Speicher: WD will Produktion einschränken</title>
+		<link>https://www.heise.de/newsticker/meldung/Flash-Speicher-WD-will-Produktion-einschraenken-4205498.html?wt_mc=rss.ho.beitrag.rdf</link>
+			<description>Die Preise für NAND-Flash-Speicher kennen derzeit nur eine Richtung: abwärts. WD will dem mit Produktionseinschränkungen begegnen.</description>
+	</item>
+
+	<item>
+		<title>LED-Tastatur Aukey KM-G6 im Test: mechanisch, günstig und laut</title>
+		<link>https://www.techstage.de/news/Mechanische-Tastatur-Aukey-KM-G6-im-Test-guenstig-und-laut-4205068.html?wt_mc=rss.ho.beitrag.rdf</link>
+			<description>Die Aukey KM-G6 kostet weniger als 50 Euro und zeigt, dass mechanische Tastaturen nicht teuer sein müssen. Wir testen das Keyboard.</description>
+	</item>
+
+	<item>
+		<title>Einhörner zum Leben erwecken - Kultur-Hackathon in Mainz gestartet</title>
+		<link>https://www.heise.de/newsticker/meldung/Einhoerner-zum-Leben-erwecken-Kultur-Hackathon-in-Mainz-gestartet-4205490.html?wt_mc=rss.ho.beitrag.rdf</link>
+			<description>In Museen, Bibliotheken und Archive stecken viele Daten, die sich kreativ nutzen lassen. Programmierer, Designer und Historiker haben sich das vorgenommen.</description>
+	</item>
+
+	<item>
+		<title>Impressionen von der SPIEL 2018: Gesellschaftsspiele für Nerds und Geeks</title>
+		<link>https://www.heise.de/newsticker/meldung/Impressionen-von-der-SPIEL-2018-Gesellschaftsspiele-fuer-Nerds-und-Geeks-4205405.html?wt_mc=rss.ho.beitrag.rdf</link>
+			<description>Weg von Bildschirm und Controller, hin zu Würfeln und Karten. Die SPIEL-Messe zeigt Neuheiten bei IT-affinen Brett-, Karten- und Tabletop-Spielen.</description>
+	</item>
+
+	<item>
+		<title>Missing Link: Vor 100 Jahren begann die deutsche Revolution</title>
+		<link>https://www.heise.de/newsticker/meldung/Missing-Link-Vor-100-Jahren-begann-die-deutsche-Revolution-4205422.html?wt_mc=rss.ho.beitrag.rdf</link>
+			<description>Von den Sturmvögeln zu den Stiefkindern der Revolution: Mit dem Matrosenaufstand startete Deutschland in die erste Republik.</description>
+	</item>
+
+	<item>
+		<title>4W: Was war. Was wird. Wettrüsten oder Waffelessen, das ist die Frage.</title>
+		<link>https://www.heise.de/newsticker/meldung/Was-war-Wettruesten-oder-Waffelessen-das-ist-die-Frage-4205432.html?wt_mc=rss.ho.beitrag.rdf</link>
+			<description>Zeit! Irgendwann gab es sie gar nicht, heute wird sie uns geschenkt. Ja, auch Hal Faber weiß, dass das Quatsch ist. Wie so vieles andere.</description>
+	</item>
+
+	<item>
+		<title>Kommentar: Vom DNS, aktuellen Hypes, Überwachung und Zensur</title>
+		<link>https://www.heise.de/newsticker/meldung/Kommentar-Vom-DNS-aktuellen-Hypes-Ueberwachung-und-Zensur-4205380.html?wt_mc=rss.ho.beitrag.rdf</link>
+			<description>Das DNS ist gereift, es kann mit den Bedrohungen der Überwachung und Zensur umgehen. Eine Antwort von Lutz Donnerhacke auf &quot;Die Gruft DNS gehört ausgelüftet&quot;.</description>
+	</item>
+
+	<item>
+		<title>Microsoft will Militär und Geheimdienste beliefern</title>
+		<link>https://www.heise.de/newsticker/meldung/Microsoft-will-Militaer-und-Geheimdienste-beliefern-4205383.html?wt_mc=rss.ho.beitrag.rdf</link>
+			<description>Microsoft ist trotz Protesten von Mitarbeitern bereit, dem Militär und den Geheimdiensten des Landes KI-Systeme und sonstige Technologien zu verkaufen.</description>
+	</item>
+
+	<item>
+		<title>Zurück zur &quot;Normalzeit&quot;: Uhren werden (möglichweise zum letzten Mal) um eine Stunde zurückgestellt</title>
+		<link>https://www.heise.de/newsticker/meldung/Zurueck-zur-Normalzeit-Uhren-werden-moeglichweise-zum-letzten-Mal-um-eine-Stunde-zurueckgestellt-4205376.html?wt_mc=rss.ho.beitrag.rdf</link>
+			<description>Die Zeitumstellung könnte bald Geschichte sein. Es gibt aber Bereiche, in denen eine Umstellung sehr aufwendig werden könnte.</description>
+	</item>
+
+	<item>
+		<title>5G: Seehofer fordert Änderung der Vergaberegeln</title>
+		<link>https://www.heise.de/newsticker/meldung/5G-Seehofer-fordert-Aenderung-der-Vergaberegeln-4205373.html?wt_mc=rss.ho.beitrag.rdf</link>
+			<description>Der Bundesinnenminister sieht Bewohner ländlicher Gebiete durch die Ausschreibungsregeln für das 5G-Netz benachteiligt und verlangt Nachbesserungen.</description>
+	</item>
+
+	<item>
+		<title>Ausstellung erinnert an das Lebenswerk von Konrad Zuse</title>
+		<link>https://www.heise.de/newsticker/meldung/Ausstellung-erinnert-an-das-Lebenswerk-von-Konrad-Zuse-4205359.html?wt_mc=rss.ho.beitrag.rdf</link>
+			<description>In Hopferau im Ostallgäu stellte Konrad Zuse seine Rechenmaschine Z4 fertig. Jetzt erinnert eine Ausstellung im Schloss Hopferau an den Computerpionier.</description>
+	</item>
+
+	<item>
+		<title>Test TrackerID LTS-450: GPS-Flaschenhalter am Fahrrad</title>
+		<link>https://www.techstage.de/news/Test-TrackerID-LTS-450-GPS-Flaschenhalter-am-Fahrrad-4205272.html?wt_mc=rss.ho.beitrag.rdf</link>
+			<description>Fahrraddiebe sind blöd, aber nicht dumm: Sehen sie einen GPS-Tracker, entfernen sie ihn. Deswegen tarnt sich der TrackerID LTS-450 in einem Flaschenhalter.</description>
+	</item>
+
+	<item>
+		<title>Fünf mobile Beamer im Vergleichstest</title>
+		<link>https://www.techstage.de/news/Fuenf-mobile-Beamer-im-Vergleichstest-4204823.html?wt_mc=rss.ho.beitrag.rdf</link>
+			<description>In den vergangenen Wochen haben wir uns fünf kompakte Beamer mit integriertem Akku angeschaut. Im Vergleichstest zeigen wir Vor- und Nachteile.</description>
+	</item>
+
+	<item>
+		<title>In Japan geht ein weiterer Atomreaktor wieder ans Netz</title>
+		<link>https://www.heise.de/newsticker/meldung/In-Japan-geht-ein-weiterer-Atomreaktor-wieder-ans-Netz-4205351.html?wt_mc=rss.ho.beitrag.rdf</link>
+			<description>Das Atomkraftwerk Ikata in Japan hat einen Reaktor wieder hochgefahren, gegen dessen Betrieb eine Bürgergruppe geklagt hatte.</description>
+	</item>
+
+	<item>
+		<title>FlyCroTug: Kleine Drohne mit großer Zugkraft</title>
+		<link>https://www.heise.de/newsticker/meldung/FlyCroTug-Kleine-Drohne-mit-grosser-Zugkraft-4205335.html?wt_mc=rss.ho.beitrag.rdf</link>
+			<description>Forscher haben 100 Gramm leichte Minidrohnen entwickelt, die von einem festen Haltepunkt aus das 40-fache ihres Gewichts bewegen können.
+ </description>
+	</item>
+
+	<item>
+		<title>Google Office-Programme: Neue Dokumente in Browserzeile anlegen</title>
+		<link>https://www.heise.de/newsticker/meldung/Google-Docs-Neue-Dokumente-in-Browserzeile-anlegen-4205346.html?wt_mc=rss.ho.beitrag.rdf</link>
+			<description>Für seine webbasierten Office-Programme hat Google eine praktische Abkürzung direkt in die Anwendungen Docs, Sheets, Slides und Forms veröffentlicht.</description>
+	</item>
+
+	<item>
+		<title>Wo Hobby-Astronomen den Profis voraus sind</title>
+		<link>https://www.heise.de/newsticker/meldung/Wo-Hobby-Astronomen-den-Profis-voraus-sind-4205332.html?wt_mc=rss.ho.beitrag.rdf</link>
+			<description>Hobby-Astronomen leisten einen wertvollen Beitrag zur Wissenschaft, etwa durch das Beobachten veränderlicher Sterne oder die Suche nach Meteoriten.</description>
+	</item>
+
+	<item>
+		<title>Zahlen geschönt? FBI-Untersuchung gegen Tesla</title>
+		<link>https://www.heise.de/newsticker/meldung/Zahlen-geschoent-FBI-Untersuchung-gegen-Tesla-4205285.html?wt_mc=rss.ho.beitrag.rdf</link>
+			<description>Es besteht der Verdacht, dass Tesla Produktionszahlen wissentlich überoptimistisch vorhergesagt hat. Das FBI ermittelt strafrechtlich.</description>
+	</item>
+
+	<item>
+		<title>c't uplink 24.6: Linux mit UEFI / OLED-Defekte / Dropbox-Alternativen</title>
+		<link>https://www.heise.de/ct/artikel/c-t-uplink-24-6-Linux-mit-UEFI-OLED-Defekte-Dropbox-Alternativen-4205070.html?wt_mc=rss.ho.beitrag.rdf</link>
+			<description>Die c't-uplink Show: Dieses Mal mit eingebrannten Logos bei OLED-TVs, Alternativen zu Dropbox und wie man Linux am besten mit UEFI verheiratet.</description>
+	</item>
+
+	<item>
+		<title>Die Bilder der Woche (KW 43): Von Porträt bis Landschaft</title>
+		<link>https://www.heise.de/foto/meldung/Die-Bilder-der-Woche-KW-43-Von-Portraet-bis-Landschaft-4204550.html?wt_mc=rss.ho.beitrag.rdf</link>
+			<description>Blickfang: Unsere Bilder des Tages haben in dieser Woche keine Scheu vor direktem Augenkontakt und Spiegelbildern.</description>
+	</item>
+
+	<item>
+		<title>BIOS-Option macht ThinkPads zu Briefbeschwerern</title>
+		<link>https://www.heise.de/newsticker/meldung/BIOS-Option-macht-ThinkPads-zu-Briefbeschwerern-4205185.html?wt_mc=rss.ho.beitrag.rdf</link>
+			<description>Ein einziger Klick im BIOS-Setup - und einige aktuelle Lenovo-Notebooks starten nicht mehr; eine Lösung des Problems fehlt noch.</description>
+	</item>
+
+	<item>
+		<title>Markenstreit um “Dash”: Bragi beantragt einstweilige Verfügung gegen Oneplus</title>
+		<link>https://www.heise.de/newsticker/meldung/Markenstreit-um-Dash-Bragi-beantragt-einstweilige-Verfuegung-gegen-Oneplus-4205223.html?wt_mc=rss.ho.beitrag.rdf</link>
+			<description>Der Hersteller der smarten Kopfhörer “The Dash” sieht seine Markenrechte durch die Schnelladegeräte der chinesischen Smartphones verletzt.</description>
+	</item>
+
+	<item>
+		<title>Übernahme von GitHub durch Microsoft abgeschlossen</title>
+		<link>https://www.heise.de/newsticker/meldung/Uebernahme-von-GitHub-durch-Microsoft-abgeschlossen-4205119.html?wt_mc=rss.ho.beitrag.rdf</link>
+			<description>Microsofts Übernahme von GitHub ist abgeschlossen. Ab Montag beginnt die Arbeit des neuen CEO Nat Friedman. Er will GitHub für die Entwickler besser machen.</description>
+	</item>
+
+	<item>
+		<title>Webhosting und Cloud Computing: Aus 1&amp;1 und ProfitBricks wird 1&amp;1 Ionos</title>
+		<link>https://www.heise.de/newsticker/meldung/Webhosting-und-Cloud-Computing-Aus-1-1-und-ProfitBricks-wird-1-1-Ionos-4205066.html?wt_mc=rss.ho.beitrag.rdf</link>
+			<description>1&amp;1 bietet seine Webhosting- und Cloud-Produkte künftig unter dem Namen 1&amp;1 Ionos an. Besserer Service soll Unternehmen den Cloud-Start schmackhaft machen.</description>
+	</item>
+
+	<item>
+		<title>iPhone XR: Die 10 wichtigsten Testergebnisse</title>
+		<link>https://www.heise.de/mac-and-i/meldung/iPhone-XR-Die-10-wichtigsten-Testergebnisse-4204845.html?wt_mc=rss.ho.beitrag.rdf</link>
+			<description>Seit heute ist das dritte und günstigste von Apples neuen Smartphones im Handel. Mac &amp; i konnte es bereits testen.</description>
+	</item>
+
+	<item>
+		<title>Motorola One: Android-One-Smartphone für 299 Euro im Test</title>
+		<link>https://www.techstage.de/news/Motorola-One-im-Test-Android-One-Smartphone-mit-Notch-4203618.html?wt_mc=rss.ho.beitrag.rdf</link>
+			<description>Das Motorola One ist ein Smartphone mit schickem Design und Android One als Betriebssystem. Ob und für wen sich der Kauf lohnt, hat TechStage getestet.</description>
+	</item>
+
+	<item>
+		<title>US Copyright Office: DRM darf für Reparaturen umgangen werden</title>
+		<link>https://www.heise.de/newsticker/meldung/US-Copyright-Office-DRM-darf-fuer-Reparaturen-umgangen-werden-4205173.html?wt_mc=rss.ho.beitrag.rdf</link>
+			<description>In den USA ist es künftig legal, den Kopierschutz elektronischer Geräte zu knacken, um etwa sein Smartphone, Auto oder den vernetzten Kühlschrank zu reparieren.</description>
+	</item>
+
+	<item>
+		<title>Ausprobiert: Haptik-Datenhandschuhe von Senseglove</title>
+		<link>https://www.heise.de/newsticker/meldung/Ausprobiert-Haptik-Datenhandschuhe-von-Senseglove-4205142.html?wt_mc=rss.ho.beitrag.rdf</link>
+			<description>Der Senseglove-Datenhandschuh trackt nicht nur jeden Finger, sondern simuliert auch Widerstand und Haptik. Wir haben ihn ausprobiert.</description>
+	</item>
+
+	<item>
+		<title>Apple News soll &quot;Netflix für Nachrichten&quot; werden</title>
+		<link>https://www.heise.de/mac-and-i/meldung/Apple-News-soll-Netflix-fuer-Nachrichten-werden-4204886.html?wt_mc=rss.ho.beitrag.rdf</link>
+			<description>Apple betreibt für seinen hauseigenen Infodienst eine eigene Redaktion – und setzt kaum auf Algorithmen. Im Abo könnten bald diverse Magazine hinzukommen.</description>
+	</item>
+
+	<item>
+		<title>Xbox One X im 4K-Test: Spaßzentrale für UHD-TVs</title>
+		<link>https://www.techstage.de/news/Xbox-One-X-im-4K-Test-Spasszentrale-fuer-UHD-TVs-4204803.html?wt_mc=rss.ho.beitrag.rdf</link>
+			<description>Die aktuelle Xbox One X bewirbt Microsoft als idealen Zuspieler für UHD-Fernseher. Wir haben ihre 4K-Fähigkeiten bei Filmen und Spielen getestet. </description>
+	</item>
+
+	<item>
+		<title>Red Dead Redemption 2: Die Entschleunigung des Action-Adventures</title>
+		<link>https://www.heise.de/newsticker/meldung/Red-Dead-Redemption-2-Die-Entschleunigung-des-Action-Adventures-4205034.html?wt_mc=rss.ho.beitrag.rdf</link>
+			<description>Nach dem Live-Stream: Unsere Eindrücke aus den ersten Stunden des Gaming-Blockbusters Red Dead Redemption 2.</description>
+	</item>
+
+	<item>
+		<title>Grüne: Netzbetreiber sollen Breitband-Universaldienst finanzieren</title>
+		<link>https://www.heise.de/newsticker/meldung/Gruene-Netzbetreiber-sollen-Breitband-Universaldienst-finanzieren-4205022.html?wt_mc=rss.ho.beitrag.rdf</link>
+			<description>Schwarz-Rot will bis spätestens 2025 einen Anspruch auf Breitband für alle gesetzlich verankern. Die Grünen sehen dagegen sofortigen Handlungsbedarf.</description>
+	</item>
+
+	<item>
+		<title>Programmiersprache: Rust 1.30 will mehr Klarheit schaffen</title>
+		<link>https://www.heise.de/developer/meldung/Programmiersprache-Rust-1-30-will-mehr-Klarheit-schaffen-4204893.html?wt_mc=rss.ho.beitrag.rdf</link>
+			<description>Der Umgang mit absoluten Pfaden und neue prozedurale Makros sind die Highlights der aktuellen Rust-Version.</description>
+	</item>
+
+	<item>
+		<title>Apples Oktober-Event: iPad Pro 2018 und neue Macs vor der Tür</title>
+		<link>https://www.heise.de/mac-and-i/meldung/Apples-Oktober-Event-iPad-Pro-2018-und-neue-Macs-vor-der-Tuer-4204922.html?wt_mc=rss.ho.beitrag.rdf</link>
+			<description>Nach der Einführung der iPhones wird sich Apple der Zukunft seiner Computer zuwenden: Wichtige Neuerungen stehen an. </description>
+	</item>
+
+	<item>
+		<title>Magento-Shops: Verwundbare Add-ons als Schlupfloch für Kreditkarten-Skimmer</title>
+		<link>https://www.heise.de/security/meldung/Magento-Shops-Verwundbare-Add-ons-als-Schlupfloch-fuer-Kreditkarten-Skimmer-4204828.html?wt_mc=rss.ho.beitrag.rdf</link>
+			<description>Ein Sicherheitsforscher warnt vor knapp über 20 Add-ons, die Onlineshops basierend auf der Magento-Software angreifbar machen. </description>
+	</item>
+
+	<item>
+		<title>Atomkraft: Gericht kippt Schließungs-Dekret für Fessenheim</title>
+		<link>https://www.heise.de/newsticker/meldung/Atomkraft-Gericht-kippt-Schliessungs-Dekret-fuer-Fessenheim-4204853.html?wt_mc=rss.ho.beitrag.rdf</link>
+			<description>Der Conseil d'État hat zu Gunsten der Gemeinde Fessenheim und der Gewerkschaften entschieden.</description>
+	</item>
+
+	<item>
+		<title>Qt Design Studio erreicht Version 1.0</title>
+		<link>https://www.heise.de/developer/meldung/Qt-Design-Studio-erreicht-Version-1-0-4204902.html?wt_mc=rss.ho.beitrag.rdf</link>
+			<description>Neue Funktionen wie die Qt Photoshop Bridge und zeitachsenbasierte Animationen sollen die Zusammenarbeit von Entwicklern und Designern vereinfachen.</description>
+	</item>
+
+	<item>
+		<title>Vodafone bringt Mini-Handy von Palm nach Deutschland</title>
+		<link>https://www.heise.de/newsticker/meldung/Vodafone-bringt-Mini-Handy-von-Palm-nach-Deutschland-4204878.html?wt_mc=rss.ho.beitrag.rdf</link>
+			<description>Das neue Palm kommt auch in Deutschland auf den Markt: Vodafone bringt das kuriose Mini-Handy exklusiv in den Handel. </description>
+	</item>
+
+	<item>
+		<title>Xeons und Modems bescheren Intel Rekordquartal</title>
+		<link>https://www.heise.de/newsticker/meldung/Xeons-und-Modems-bescheren-Intel-Rekordquartal-4204869.html?wt_mc=rss.ho.beitrag.rdf</link>
+			<description>Starke Nachfrage nach Prozessoren für Cloud-Rechenzentren sowie LTE-Modems lassen bei Intel die Gewinne sprudeln und bescheren gute Aussichten.</description>
+	</item>
+
+	<item>
+		<title>KI druckt Kunst: Auktionshaus Christie's versteigert KI-Gemälde für 380.000 Euro</title>
+		<link>https://www.heise.de/newsticker/meldung/KI-druckt-Kunst-Auktionshaus-Christie-s-versteigert-KI-Gemaelde-fuer-380-000-Euro-4204793.html?wt_mc=rss.ho.beitrag.rdf</link>
+			<description>Das renommierte Auktionshaus Christie's hat erstmals ein von einer KI erschaffenes Bild versteigert. Der Preis war wesentlich höher als erwartet.</description>
+	</item>
+
+	<item>
+		<title>EU-Parlament verabschiedet Resolution zur Datenschutzuntersuchung bei Facebook </title>
+		<link>https://www.heise.de/newsticker/meldung/EU-Parlament-verabschiedet-Resolution-zur-Datenschutzuntersuchung-bei-Facebook-4204766.html?wt_mc=rss.ho.beitrag.rdf</link>
+			<description>Facebook soll mehr Aufklärung über seine Datenschutzpraxis leisten. Das EU-Parlament hat deshalb eine Untersuchung durch EU-Institutionen verabschiedet.</description>
+	</item>
+
+	<item>
+		<title>IBM setzt auf 277.000 Apple-Geräte</title>
+		<link>https://www.heise.de/mac-and-i/meldung/IBM-setzt-auf-277-000-Apple-Geraete-4204728.html?wt_mc=rss.ho.beitrag.rdf</link>
+			<description>Bei IBM stellen Macs inzwischen ein Viertel aller Laptops. Das Open-Source-Tool Mac@IBM soll auch Admins anderer Firmen die Einrichtung erleichtern.</description>
+	</item>
+
+	<item>
+		<title>heise-Angebot: #TGIQF - das c't-Retroquiz: 8 Bit &amp; mehr</title>
+		<link>https://www.heise.de/newsticker/meldung/TGIQF-das-c-t-Retroquiz-8-Bit-mehr-4202717.html?wt_mc=rss.ho.beitrag.rdf</link>
+			<description>C64, ZX Spectrum, Apple II ... die Heimcomputer lösten eine IT-Revolution in den Kinderzimmern aus. Wie viel ist aus der Zeit bei Ihnen hängen geblieben?</description>
+	</item>
+
+	<item>
+		<title>heise-Angebot: c't Fotografie: Spiegeloses Vollformat im Test</title>
+		<link>https://www.heise.de/foto/meldung/c-t-Fotografie-Spiegeloses-Vollformat-im-Test-4201826.html?wt_mc=rss.ho.beitrag.rdf</link>
+			<description>Lange war Sony der einzige Anbieter für spiegellose Vollformatkameras. Mit der Canon EOS R und der Nikon Z-Serie werden die Karten neu gemischt.</description>
+	</item>
+
+	<item>
+		<title>British-Airways-Hack: 185.000 weitere Kunden betroffen</title>
+		<link>https://www.heise.de/newsticker/meldung/British-Airways-Hack-185-000-weitere-Kunden-betroffen-4204675.html?wt_mc=rss.ho.beitrag.rdf</link>
+			<description>Die Fluggesellschaft hat nun bekanntgegeben, dass bis dato Unbekannte Kreditkartendaten von noch mehr Kunden als bislang bekannt kopiert haben.</description>
+	</item>
+
+	<item>
+		<title>Google: 48 Mitarbeiter wegen sexueller Belästigung gefeuert</title>
+		<link>https://www.heise.de/newsticker/meldung/Google-48-Mitarbeiter-wegen-sexueller-Belaestigung-gefeuert-4204687.html?wt_mc=rss.ho.beitrag.rdf</link>
+			<description>Der Weggang von Android-Schöpfer Andy Rubin von Google war wohl nicht freiwillig – ihm wurde sexuelle Nötigung vorgeworfen. Und er war nicht der einzige.</description>
+	</item>
+
+	<item>
+		<title>Fujitsu schließt Werk in Augsburg</title>
+		<link>https://www.heise.de/newsticker/meldung/Fujitsu-schliesst-Werk-in-Augsburg-4204722.html?wt_mc=rss.ho.beitrag.rdf</link>
+			<description>Fujitsu plant einen Konzernumbau. In Augsburg sind davon 1500 Beschäftigte betroffen.</description>
+	</item>
+
+	<item>
+		<title>Ego-Shooter Metro 2033 bei Steam kostenlos</title>
+		<link>https://www.heise.de/newsticker/meldung/Metro-2033-ist-bei-Steam-heute-kostenlos-4204706.html?wt_mc=rss.ho.beitrag.rdf</link>
+			<description>Metro 2033 wird am heutigen Freitag auf Steam kostenlos angeboten. Der Ego-Shooter basiert auf dem gleichnamigen Roman von Dmitri Gluchowski.</description>
+	</item>
+
+	<item>
+		<title>Lightroom-Alternative: DxO bringt PhotoLab 2 </title>
+		<link>https://www.heise.de/foto/meldung/Lightroom-Alternative-DxO-bringt-PhotoLab-2-4204614.html?wt_mc=rss.ho.beitrag.rdf</link>
+			<description>PhotoLab gibt es nun in Version 2: Verbessert wurde unter anderem die Bildverwaltung, zudem integriert DxO die von den Nik-Filtern bekannte U-Point-Technologie.</description>
+	</item>
+
+	<item>
+		<title>Google schaltet Nearby Notifcations in Android ab</title>
+		<link>https://www.heise.de/developer/meldung/Google-schaltet-Nearby-Notifcations-in-Android-ab-4204667.html?wt_mc=rss.ho.beitrag.rdf</link>
+			<description>Die Funktion für standortbasierte Benachrichtigungen lieferte wohl mehr Spam als nützliche Inhalte.</description>
+	</item>
+
+	<item>
+		<title>iPhone XR: Verkaufsstart ohne Ansturm</title>
+		<link>https://www.heise.de/mac-and-i/meldung/iPhone-XR-Verkaufsstart-ohne-Ansturm-4204679.html?wt_mc=rss.ho.beitrag.rdf</link>
+			<description>Apple bringt die billigeren und bunten iPhone-Modellreihe in den Handel. Groß anstehen mussten Kunden dafür nicht.
+</description>
+	</item>
+
+	<item>
+		<title>Snapchat: Aktienabsturz durch Nutzerschwund</title>
+		<link>https://www.heise.de/newsticker/meldung/Snapchat-Aktienabsturz-durch-Nutzerschwund-4204631.html?wt_mc=rss.ho.beitrag.rdf</link>
+			<description>Snapchat laufen weiterhin die Nutzer weg – und das wird sich vorerst nicht ändern, sagt Snap. Die Aktie stürzte trotz geringerer Verluste um zehn Prozent ab.</description>
+	</item>
+
+	<item>
+		<title>Mi Mix 3: Xiaomi-Flaggschiff mit Kamera-Slider und 10 GByte RAM</title>
+		<link>https://www.heise.de/newsticker/meldung/Mi-Mix-3-Xiaomi-Flaggschiff-mit-Kamera-Slider-und-10-GByte-RAM-4204655.html?wt_mc=rss.ho.beitrag.rdf</link>
+			<description>Xiaomis nächstes Flaggschiff bietet eine fast randlose Display-Front. Die Selfie-Kamera ist in einem magnetischen Slider-Mechanismus untergebracht.</description>
+	</item>
+
+
+
+</rdf:RDF>

File diff suppressed because it is too large
+ 226 - 0
http/client/testdata/urdu.xml


File diff suppressed because it is too large
+ 242 - 0
http/client/testdata/windows_1251.html


File diff suppressed because it is too large
+ 359 - 0
http/client/testdata/windows_1251.xml


+ 13 - 12
reader/encoding/encoding.go

@@ -7,6 +7,7 @@ package encoding // import "miniflux.app/reader/encoding"
 import (
 	"bytes"
 	"io"
+	"io/ioutil"
 	"unicode/utf8"
 
 	"golang.org/x/net/html/charset"
@@ -19,20 +20,20 @@ import (
 //
 // Several edge cases could exists:
 //
-// - Feeds with charset specified only in Content-Type header and not in XML document
-// - Feeds with charset specified in both places
-// - Feeds with charset specified only in XML document and not in HTTP header
+// - Feeds with encoding specified only in Content-Type header and not in XML document
+// - Feeds with encoding specified in both places
+// - Feeds with encoding specified only in XML document and not in HTTP header
+// - Feeds with wrong encoding defined and already in UTF-8
 func CharsetReader(label string, input io.Reader) (io.Reader, error) {
-	var buf1, buf2 bytes.Buffer
-	w := io.MultiWriter(&buf1, &buf2)
-	io.Copy(w, input)
-	r := bytes.NewReader(buf2.Bytes())
+	buffer, _ := ioutil.ReadAll(input)
+	r := bytes.NewReader(buffer)
 
-	if !utf8.Valid(buf1.Bytes()) {
-		// Transform document to UTF-8 from the specified XML encoding.
-		return charset.NewReaderLabel(label, r)
+	// The document is already UTF-8, do not do anything (avoid double-encoding).
+	// That means the specified encoding in XML prolog is wrong.
+	if utf8.Valid(buffer) {
+		return r, nil
 	}
 
-	// The document is already UTF-8, do not do anything (avoid double-encoding)
-	return r, nil
+	// Transform document to UTF-8 from the specified encoding in XML prolog.
+	return charset.NewReaderLabel(label, r)
 }

BIN
reader/parser/debug.test


+ 1 - 1
reader/parser/parser_test.go

@@ -190,7 +190,7 @@ func TestDifferentEncodingWithResponse(t *testing.T) {
 		r.EnsureUnicodeBody()
 		feed, parseErr := ParseFeed(r.String())
 		if parseErr != nil {
-			t.Errorf(`Parsing error for %q - %q: %v`, tc.filename, tc.contentType, parseErr)
+			t.Fatalf(`Parsing error for %q - %q: %v`, tc.filename, tc.contentType, parseErr)
 		}
 
 		if feed.Entries[tc.index].Title != tc.title {