Support subscriptions to redirect URLs
authorChristian Weiske <cweiske@cweiske.de>
Sat, 7 Mar 2020 21:26:59 +0000 (22:26 +0100)
committerChristian Weiske <cweiske@cweiske.de>
Sat, 7 Mar 2020 21:26:59 +0000 (22:26 +0100)
Resolves: https://github.com/cweiske/phinde/issues/37

src/phinde/HubUrlExtractor.php
tests/HubUrlExtractorTest.php

index 4f1baa388726019baffdaab58e8ec529d9a084a2..da29650cf0b4363927f48778a5ca372db2754d1d 100644 (file)
@@ -19,7 +19,8 @@ class HubUrlExtractor
      * Get the hub and self/canonical URL of a given topic URL.
      * Uses link headers and parses HTML link rels.
      *
      * Get the hub and self/canonical URL of a given topic URL.
      * Uses link headers and parses HTML link rels.
      *
-     * @param string $url Topic URL
+     * @param string $url       Topic URL
+     * @param int    $redirects Number of redirects that were followed
      *
      * @return array Array of URLs with keys: hub, self.
      *               - "self" value is the URL
      *
      * @return array Array of URLs with keys: hub, self.
      *               - "self" value is the URL
@@ -27,12 +28,13 @@ class HubUrlExtractor
      *               Keys may be there but most not if the URL
      *               does not advertise them.
      */
      *               Keys may be there but most not if the URL
      *               does not advertise them.
      */
-    public function getUrls($url)
+    public function getUrls($url, $redirects = 0)
     {
         //at first, try a HEAD request that does not transfer so much data
         $req = $this->getRequest();
         $req->setUrl($url);
         $req->setMethod(\HTTP_Request2::METHOD_HEAD);
     {
         //at first, try a HEAD request that does not transfer so much data
         $req = $this->getRequest();
         $req->setUrl($url);
         $req->setMethod(\HTTP_Request2::METHOD_HEAD);
+        $req->setConfig('follow_redirects', false);
         $res = $req->send();
 
         if (intval($res->getStatus() / 100) >= 4
         $res = $req->send();
 
         if (intval($res->getStatus() / 100) >= 4
@@ -49,6 +51,15 @@ class HubUrlExtractor
             return $this->absolutifyUrls($urls, $base);
         }
 
             return $this->absolutifyUrls($urls, $base);
         }
 
+        if ($res->isRedirect()) {
+            //we tried header links and that failed, now follow the redirect
+            if ($redirects > 5) {
+                return [];
+            }
+            $redirectUrl = (string) $base->resolve($res->getHeader('location'));
+            return $this->getUrls($redirectUrl, $redirects + 1);
+        }
+
         list($type) = explode(';', $res->getHeader('Content-type'));
         if ($type != 'text/html' && $type != 'text/xml'
             && $type != 'application/xhtml+xml'
         list($type) = explode(';', $res->getHeader('Content-type'));
         if ($type != 'text/html' && $type != 'text/xml'
             && $type != 'application/xhtml+xml'
index 2018467c09c33628b676be47810bb7e6ce996bf6..a4d4651e6ae4b3437673fb441d746fcce86d7e55 100644 (file)
@@ -344,5 +344,82 @@ HTM,
         }
         return $response;
     }
         }
         return $response;
     }
+
+    /**
+     * It is possible to subscribe to URLs that redirect if
+     * they have a hub and self links in the HTTP headers.
+     * If they don't, we need to follow the redirect.
+     */
+    public function testGetUrlsHEADLinksForRedirect()
+    {
+        $mock = new HTTP_Request2_Adapter_Mock();
+        $this->addResponse(
+            $mock,
+            "HTTP/1.0 307 Temporary Redirect\r\n"
+            . "Content-type: text/html\r\n"
+            . "Location: http://example.org/redir-target\r\n"
+            . "Link: <https://hub.example.com/>; rel=\"hub\"\r\n"
+            . "Link: <http://example.com/feed>; rel=\"self\"\r\n"
+            . "\r\n",
+            'http://example.org/'
+        );
+        $this->addResponse(
+            $mock,
+            "HTTP/1.0 200 OK\r\n"
+            . "Content-type: text/html\r\n"
+            . "Link: <https://redir-hub.example.com/>; rel=\"hub\"\r\n"
+            . "Link: <http://example.com/redir-feed>; rel=\"self\"\r\n"
+            . "\r\n",
+            'http://example.org/redir-target'
+        );
+
+        $extractor = new phinde\HubUrlExtractor();
+        $extractor->setRequestTemplate(
+            new HTTP_Request2(null, null, ['adapter' => $mock])
+        );
+
+        $this->assertEquals(
+            [
+                'hub'  => ['https://hub.example.com/'],
+                'self' => 'http://example.com/feed',
+            ],
+            $extractor->getUrls('http://example.org/')
+        );
+    }
+
+    public function testGetUrlsHEADLinksForRedirectNone()
+    {
+        $mock = new HTTP_Request2_Adapter_Mock();
+        $this->addResponse(
+            $mock,
+            "HTTP/1.0 307 Temporary Redirect\r\n"
+            . "Content-type: text/html\r\n"
+            . "Location: http://example.org/redir-target\r\n"
+            . "\r\n",
+            'http://example.org/'
+        );
+        $this->addResponse(
+            $mock,
+            "HTTP/1.0 200 OK\r\n"
+            . "Content-type: text/html\r\n"
+            . "Link: <https://redir-hub.example.com/>; rel=\"hub\"\r\n"
+            . "Link: <http://example.com/redir-feed>; rel=\"self\"\r\n"
+            . "\r\n",
+            'http://example.org/redir-target'
+        );
+
+        $extractor = new phinde\HubUrlExtractor();
+        $extractor->setRequestTemplate(
+            new HTTP_Request2(null, null, ['adapter' => $mock])
+        );
+
+        $this->assertEquals(
+            [
+                'hub'  => ['https://redir-hub.example.com/'],
+                'self' => 'http://example.com/redir-feed',
+            ],
+            $extractor->getUrls('http://example.org/')
+        );
+    }
 }
 ?>
 }
 ?>