nandi/gleanpublic Fork 0
e82f9b0
Commits
Clone
git clone https://git.rickub.com/nandi/glean.git
git clone ssh://git@rickub.com/nandi/glean.git

Host key fingerprint (ed25519): SHA256:iycHnxEyq0Q7uyVpB7JlznP0G7JrTPXLYRcAU5CSLhc — verify it before your first connect.

Improve XML parsingUnverified

Julien Robert committed 2026-04-23T22:33:49+02:00 Browse files
e82f9b0 parent: ff5d998
modified internal/feed/parser.go +35 -16
@@ -1,6 +1,7 @@
11 package feed
22
33 import (
4+ "bytes"
45 "encoding/json"
56 "encoding/xml"
67 "fmt"
@@ -182,8 +183,8 @@ func parseJSONFeed(data []byte, feedURL string) (*ParseResult, error) {
182183 return result, nil
183184 }
184185
185-func makeXMLDecoder(data []byte) *xml.Decoder {
186- decoder := xml.NewDecoder(strings.NewReader(string(data)))
186+func makeXMLDecoder(r io.Reader) *xml.Decoder {
187+ decoder := xml.NewDecoder(r)
187188 decoder.Strict = false
188189 decoder.CharsetReader = func(charset string, input io.Reader) (io.Reader, error) {
189190 return htmlcharset.NewReader(input, "text/xml; charset="+charset)
@@ -191,26 +192,44 @@ func makeXMLDecoder(data []byte) *xml.Decoder {
191192 return decoder
192193 }
193194
194-func parseXMLFeed(data []byte, feedURL string) (*ParseResult, error) {
195- var rss rssFeed
196- if err := makeXMLDecoder(data).Decode(&rss); err == nil {
197- if rss.XMLName.Local == "rss" {
198- return convertRSS(&rss, feedURL), nil
195+func detectXMLRoot(data []byte) string {
196+ decoder := makeXMLDecoder(bytes.NewReader(data))
197+ for {
198+ tok, err := decoder.Token()
199+ if err != nil {
200+ return ""
201+ }
202+ if se, ok := tok.(xml.StartElement); ok {
203+ return se.Name.Local
199204 }
200205 }
206+}
201207
202- var atom atomFeed
203- if err := makeXMLDecoder(data).Decode(&atom); err == nil {
204- if atom.XMLName.Local == "feed" {
205- return convertAtom(&atom, feedURL), nil
206- }
208+func parseXMLFeed(data []byte, feedURL string) (*ParseResult, error) {
209+ root := detectXMLRoot(data)
210+ if root == "" {
211+ return nil, fmt.Errorf("unable to detect feed format")
207212 }
208213
209- var rdf rdfFeed
210- if err := makeXMLDecoder(data).Decode(&rdf); err == nil {
211- if rdf.XMLName.Local == "RDF" {
212- return convertRDF(&rdf, feedURL), nil
214+ switch root {
215+ case "rss":
216+ var rss rssFeed
217+ if err := makeXMLDecoder(bytes.NewReader(data)).Decode(&rss); err != nil {
218+ return nil, fmt.Errorf("parsing RSS feed: %w", err)
219+ }
220+ return convertRSS(&rss, feedURL), nil
221+ case "feed":
222+ var atom atomFeed
223+ if err := makeXMLDecoder(bytes.NewReader(data)).Decode(&atom); err != nil {
224+ return nil, fmt.Errorf("parsing Atom feed: %w", err)
225+ }
226+ return convertAtom(&atom, feedURL), nil
227+ case "RDF":
228+ var rdf rdfFeed
229+ if err := makeXMLDecoder(bytes.NewReader(data)).Decode(&rdf); err != nil {
230+ return nil, fmt.Errorf("parsing RDF feed: %w", err)
213231 }
232+ return convertRDF(&rdf, feedURL), nil
214233 }
215234
216235 return nil, fmt.Errorf("unable to detect feed format")
@@ -1,6 +1,7 @@
1 package feed1 package feed
2 2
3 import (3 import (
4+ "bytes"
4 "encoding/json"5 "encoding/json"
5 "encoding/xml"6 "encoding/xml"
6 "fmt"7 "fmt"
@@ -182,8 +183,8 @@ func parseJSONFeed(data []byte, feedURL string) (*ParseResult, error) {
182 return result, nil183 return result, nil
183 }184 }
184 185
185-func makeXMLDecoder(data []byte) *xml.Decoder {186+func makeXMLDecoder(r io.Reader) *xml.Decoder {
186- decoder := xml.NewDecoder(strings.NewReader(string(data)))187+ decoder := xml.NewDecoder(r)
187 decoder.Strict = false188 decoder.Strict = false
188 decoder.CharsetReader = func(charset string, input io.Reader) (io.Reader, error) {189 decoder.CharsetReader = func(charset string, input io.Reader) (io.Reader, error) {
189 return htmlcharset.NewReader(input, "text/xml; charset="+charset)190 return htmlcharset.NewReader(input, "text/xml; charset="+charset)
@@ -191,26 +192,44 @@ func makeXMLDecoder(data []byte) *xml.Decoder {
191 return decoder192 return decoder
192 }193 }
193 194
194-func parseXMLFeed(data []byte, feedURL string) (*ParseResult, error) {195+func detectXMLRoot(data []byte) string {
195- var rss rssFeed196+ decoder := makeXMLDecoder(bytes.NewReader(data))
196- if err := makeXMLDecoder(data).Decode(&rss); err == nil {197+ for {
197- if rss.XMLName.Local == "rss" {198+ tok, err := decoder.Token()
198- return convertRSS(&rss, feedURL), nil199+ if err != nil {
200+ return ""
201+ }
202+ if se, ok := tok.(xml.StartElement); ok {
203+ return se.Name.Local
199 }204 }
200 }205 }
206+}
201 207
202- var atom atomFeed208+func parseXMLFeed(data []byte, feedURL string) (*ParseResult, error) {
203- if err := makeXMLDecoder(data).Decode(&atom); err == nil {209+ root := detectXMLRoot(data)
204- if atom.XMLName.Local == "feed" {210+ if root == "" {
205- return convertAtom(&atom, feedURL), nil211+ return nil, fmt.Errorf("unable to detect feed format")
206- }
207 }212 }
208 213
209- var rdf rdfFeed214+ switch root {
210- if err := makeXMLDecoder(data).Decode(&rdf); err == nil {215+ case "rss":
211- if rdf.XMLName.Local == "RDF" {216+ var rss rssFeed
212- return convertRDF(&rdf, feedURL), nil217+ if err := makeXMLDecoder(bytes.NewReader(data)).Decode(&rss); err != nil {
218+ return nil, fmt.Errorf("parsing RSS feed: %w", err)
219+ }
220+ return convertRSS(&rss, feedURL), nil
221+ case "feed":
222+ var atom atomFeed
223+ if err := makeXMLDecoder(bytes.NewReader(data)).Decode(&atom); err != nil {
224+ return nil, fmt.Errorf("parsing Atom feed: %w", err)
225+ }
226+ return convertAtom(&atom, feedURL), nil
227+ case "RDF":
228+ var rdf rdfFeed
229+ if err := makeXMLDecoder(bytes.NewReader(data)).Decode(&rdf); err != nil {
230+ return nil, fmt.Errorf("parsing RDF feed: %w", err)
213 }231 }
232+ return convertRDF(&rdf, feedURL), nil
214 }233 }
215 234
216 return nil, fmt.Errorf("unable to detect feed format")235 return nil, fmt.Errorf("unable to detect feed format")