fix feed parser links to always be list
[websub-hub] / src / link-helper.js
index 1f3cd0992810f482717f0448781968afb0298723..5c6b83939f579b18491fc935c87fddd65a93131b 100644 (file)
@@ -41,40 +41,46 @@ class LinkHelper {
     // Add Link headers first, as they take priority over link elements in body.
     const linkHeader = getHeader(headers, Enum.Header.Link);
     const links = [];
-    try {
-      links.push(...parseLinkHeader(linkHeader));
-    } catch (e) {
-      if (e instanceof ParseSyntaxError) {
-        this.logger.debug(_scope, 'failed to parse link header, bad syntax', { error: e, linkHeader });
-      } else {
-        this.logger.error(_scope, 'failed to parse link header', { error: e, linkHeader });
+    if (linkHeader) {
+      try {
+        links.push(...parseLinkHeader(linkHeader));
+      } catch (e) {
+        if (e instanceof ParseSyntaxError) {
+          this.logger.debug(_scope, 'failed to parse link header, bad syntax', { error: e, linkHeader });
+        } else {
+          this.logger.error(_scope, 'failed to parse link header', { error: e, linkHeader });
+        }
       }
     }
-
     const contentType = getHeader(headers, Enum.Header.ContentType);
-    let bodyLinks = [];
-    switch (contentType) {
-      case Enum.ContentType.ApplicationAtom:
-      case Enum.ContentType.ApplicationRDF:
-      case Enum.ContentType.ApplicationRSS:
-      case Enum.ContentType.ApplicationXML:
-      case Enum.ContentType.TextXML: {
-        bodyLinks = await this.linksFromFeedBody(url, body);
-        break;
-      }
+    if (contentType) {
+      const [contentTypeBase, _contentTypeEncoding] = contentType.split(/; +/);
+      let bodyLinks = [];
+      switch (contentTypeBase) {
+        case Enum.ContentType.ApplicationAtom:
+        case Enum.ContentType.ApplicationRDF:
+        case Enum.ContentType.ApplicationRSS:
+        case Enum.ContentType.ApplicationXML:
+        case Enum.ContentType.TextXML: {
+          bodyLinks = await this.linksFromFeedBody(url, body);
+          break;
+        }
 
-      case Enum.ContentType.TextHTML:
-        bodyLinks = this.linksFromHTMLBody(body);
-        break;
+        case Enum.ContentType.TextHTML:
+          bodyLinks = this.linksFromHTMLBody(body);
+          break;
 
-      default:
-        this.logger.debug(_scope, 'no parser for content type', { contentType });
+        default:
+          this.logger.debug(_scope, 'no parser for content type', { contentType });
+      }
+      links.push(...bodyLinks);
     }
-    links.push(...bodyLinks);
 
     // Fetch all hub relation targets from headers, resolving relative URIs.
     const hubs = LinkHelper.locateHubTargets(links).map((link) => this.absoluteURI(link, url));
 
+    this.logger.debug(_scope, 'valid hubs for url', { url, hubs });
+
     return hubs.includes(this.selfUrl);
   }
 
@@ -106,7 +112,11 @@ class LinkHelper {
       });
       feedParser.on('meta', (meta) => {
         this.logger.debug(_scope, 'FeedParser meta', { meta });
-        const feedLinks = meta['atom:link'] || [];
+        let feedLinks = meta['atom:link'] || [];
+        if (!Array.isArray(feedLinks)) {
+          // Parsing RSS seems to return a single entry for this rather than a list.
+          feedLinks = [feedLinks];
+        }
         feedLinks
           .map((l) => l['@'])
           .forEach((l) => {