Security update for Core, with self-updated composer
[yaffs-website] / web / core / modules / aggregator / src / Plugin / aggregator / fetcher / DefaultFetcher.php
1 <?php
2
3 namespace Drupal\aggregator\Plugin\aggregator\fetcher;
4
5 use Drupal\aggregator\Plugin\FetcherInterface;
6 use Drupal\aggregator\FeedInterface;
7 use Drupal\Component\Datetime\DateTimePlus;
8 use Drupal\Core\Http\ClientFactory;
9 use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
10 use GuzzleHttp\Exception\RequestException;
11 use GuzzleHttp\Psr7\Request;
12 use Psr\Http\Message\RequestInterface;
13 use Psr\Http\Message\ResponseInterface;
14 use Psr\Http\Message\UriInterface;
15 use Psr\Log\LoggerInterface;
16 use Symfony\Component\DependencyInjection\ContainerInterface;
17
18 /**
19  * Defines a default fetcher implementation.
20  *
21  * Uses the http_client service to download the feed.
22  *
23  * @AggregatorFetcher(
24  *   id = "aggregator",
25  *   title = @Translation("Default fetcher"),
26  *   description = @Translation("Downloads data from a URL using Drupal's HTTP request handler.")
27  * )
28  */
29 class DefaultFetcher implements FetcherInterface, ContainerFactoryPluginInterface {
30
31   /**
32    * The HTTP client to fetch the feed data with.
33    *
34    * @var \Drupal\Core\Http\ClientFactory
35    */
36   protected $httpClientFactory;
37
38   /**
39    * A logger instance.
40    *
41    * @var \Psr\Log\LoggerInterface
42    */
43   protected $logger;
44
45   /**
46    * Constructs a DefaultFetcher object.
47    *
48    * @param \Drupal\Core\Http\ClientFactory $http_client_factory
49    *   A Guzzle client object.
50    * @param \Psr\Log\LoggerInterface $logger
51    *   A logger instance.
52    */
53   public function __construct(ClientFactory $http_client_factory, LoggerInterface $logger) {
54     $this->httpClientFactory = $http_client_factory;
55     $this->logger = $logger;
56   }
57
58   /**
59    * {@inheritdoc}
60    */
61   public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
62     return new static(
63       $container->get('http_client_factory'),
64       $container->get('logger.factory')->get('aggregator')
65     );
66   }
67
68   /**
69    * {@inheritdoc}
70    */
71   public function fetch(FeedInterface $feed) {
72     $request = new Request('GET', $feed->getUrl());
73     $feed->source_string = FALSE;
74
75     // Generate conditional GET headers.
76     if ($feed->getEtag()) {
77       $request = $request->withAddedHeader('If-None-Match', $feed->getEtag());
78     }
79     if ($feed->getLastModified()) {
80       $request = $request->withAddedHeader('If-Modified-Since', gmdate(DateTimePlus::RFC7231, $feed->getLastModified()));
81     }
82
83     try {
84
85       /** @var \Psr\Http\Message\UriInterface $actual_uri */
86       $actual_uri = NULL;
87       $response = $this->httpClientFactory->fromOptions([
88         'allow_redirects' => [
89           'on_redirect' => function (RequestInterface $request, ResponseInterface $response, UriInterface $uri) use (&$actual_uri) {
90             $actual_uri = (string) $uri;
91           }
92         ],
93       ])->send($request);
94
95       // In case of a 304 Not Modified, there is no new content, so return
96       // FALSE.
97       if ($response->getStatusCode() == 304) {
98         return FALSE;
99       }
100
101       $feed->source_string = (string) $response->getBody();
102       if ($response->hasHeader('ETag')) {
103         $feed->setEtag($response->getHeaderLine('ETag'));
104       }
105       if ($response->hasHeader('Last-Modified')) {
106         $feed->setLastModified(strtotime($response->getHeaderLine('Last-Modified')));
107       }
108       $feed->http_headers = $response->getHeaders();
109
110       // Update the feed URL in case of a 301 redirect.
111       if ($actual_uri && $actual_uri !== $feed->getUrl()) {
112         $feed->setUrl($actual_uri);
113       }
114       return TRUE;
115     }
116     catch (RequestException $e) {
117       $this->logger->warning('The feed from %site seems to be broken because of error "%error".', ['%site' => $feed->label(), '%error' => $e->getMessage()]);
118       drupal_set_message(t('The feed from %site seems to be broken because of error "%error".', ['%site' => $feed->label(), '%error' => $e->getMessage()]), 'warning');
119       return FALSE;
120     }
121   }
122
123 }