diff --git a/core/modules/aggregator/lib/Drupal/aggregator/ItemsImporter.php b/core/modules/aggregator/lib/Drupal/aggregator/ItemsImporter.php
index 6bc4dec..b7477b6 100644
--- a/core/modules/aggregator/lib/Drupal/aggregator/ItemsImporter.php
+++ b/core/modules/aggregator/lib/Drupal/aggregator/ItemsImporter.php
@@ -78,13 +78,13 @@ public function delete(FeedInterface $feed) {
   public function refresh(FeedInterface $feed) {
     // Store feed URL to track changes.
     $feed_url = $feed->getUrl();
+    $fetched_data =  NULL;
 
     // Fetch the feed.
     try {
-      $success = $this->fetcherManager->createInstance($this->config->get('fetcher'))->fetch($feed);
+      $fetched_data = $this->fetcherManager->createInstance($this->config->get('fetcher'))->fetch($feed);
     }
     catch (PluginException $e) {
-      $success = FALSE;
       watchdog_exception('aggregator', $e);
     }
 
@@ -102,14 +102,16 @@ public function refresh(FeedInterface $feed) {
     // We store the hash of feed data in the database. When refreshing a
     // feed we compare stored hash and new hash calculated from downloaded
     // data. If both are equal we say that feed is not updated.
-    $hash = hash('sha256', $feed->source_string);
-    $has_new_content = $success && ($feed->getHash() != $hash);
+    $hash = hash('sha256', $fetched_data);
+    $has_new_content = $fetched_data && ($feed->getHash() != $hash);
 
     if ($has_new_content) {
       // Parse the feed.
       try {
-        if ($this->parserManager->createInstance($this->config->get('parser'))->parse($feed)) {
-          if ($feed->getWebsiteUrl()) {
+        $parser = $this->parserManager->createInstance($this->config->get('parser'));
+        if ($parser) {
+          $items = $parser->parse($feed, $fetched_data);
+          if (!$feed->getWebsiteUrl()) {
             $feed->setWebsiteUrl($feed->getUrl());
           }
           $feed->setHash($hash);
@@ -124,9 +126,9 @@ public function refresh(FeedInterface $feed) {
           watchdog('aggregator', 'There is new syndicated content from %site.', array('%site' => $feed->label()));
 
           // If there are items on the feed, let enabled processors process them.
-          if (!empty($feed->items)) {
+          if (!empty($items)) {
             foreach ($processor_instances as $instance) {
-              $instance->process($feed);
+              $instance->process($feed, $items);
             }
           }
         }
diff --git a/core/modules/aggregator/lib/Drupal/aggregator/Plugin/FetcherInterface.php b/core/modules/aggregator/lib/Drupal/aggregator/Plugin/FetcherInterface.php
index 65567fa..8982828 100644
--- a/core/modules/aggregator/lib/Drupal/aggregator/Plugin/FetcherInterface.php
+++ b/core/modules/aggregator/lib/Drupal/aggregator/Plugin/FetcherInterface.php
@@ -26,11 +26,9 @@
    * @param \Drupal\aggregator\FeedInterface $feed
    *   A feed object representing the resource to be downloaded.
    *   $feed->getUrl() contains the link to the feed.
-   *   Download the data at the URL and expose it
-   *   to other modules by attaching it to $feed->source_string.
    *
-   * @return
-   *   TRUE if fetching was successful, FALSE otherwise.
+   * @return string|null
+   *   The feed data if fetching was successful, NULL otherwise.
    */
   public function fetch(FeedInterface $feed);
 
diff --git a/core/modules/aggregator/lib/Drupal/aggregator/Plugin/ParserInterface.php b/core/modules/aggregator/lib/Drupal/aggregator/Plugin/ParserInterface.php
index 8a4db68..450c0d4 100644
--- a/core/modules/aggregator/lib/Drupal/aggregator/Plugin/ParserInterface.php
+++ b/core/modules/aggregator/lib/Drupal/aggregator/Plugin/ParserInterface.php
@@ -25,29 +25,29 @@
    * Parses feed data.
    *
    * @param \Drupal\aggregator\FeedInterface $feed
-   *   An object describing the resource to be parsed.
-   *   $feed->source_string->value contains the raw feed data. Parse the data
-   *   and add the following properties to the $feed object:
+   *   The feed that is being processed. Parse the fetched data and update the
+   *   following properties to the $feed object:
    *   - description: The human-readable description of the feed.
    *   - link: A full URL that directly relates to the feed.
    *   - image: An image URL used to display an image of the feed.
    *   - etag: An entity tag from the HTTP header used for cache validation to
    *     determine if the content has been changed.
    *   - modified: The UNIX timestamp when the feed was last modified.
-   *   - items: An array of feed items. The common format for a single feed item
-   *     is an associative array containing:
-   *     - title: The human-readable title of the feed item.
-   *     - description: The full body text of the item or a summary.
-   *     - timestamp: The UNIX timestamp when the feed item was last published.
-   *     - author: The author of the feed item.
-   *     - guid: The global unique identifier (GUID) string that uniquely
-   *       identifies the item. If not available, the link is used to identify
-   *       the item.
-   *     - link: A full URL to the individual feed item.
+   * @param string $fetched_data
+   *   The raw feed data as returned by the active fetcher.
    *
-   * @return bool
-   *   TRUE if parsing was successful, FALSE otherwise.
+   * @return array
+   *   An array of feed items. The common format for a single feed item
+   *   is an associative array containing:
+   *    - title: The human-readable title of the feed item.
+   *    - description: The full body text of the item or a summary.
+   *    - timestamp: The UNIX timestamp when the feed item was last published.
+   *    - author: The author of the feed item.
+   *    - guid: The global unique identifier (GUID) string that uniquely
+   *      identifies the item. If not available, the link is used to identify
+   *      the item.
+   *    - link: A full URL to the individual feed item.
    */
-  public function parse(FeedInterface $feed);
+  public function parse(FeedInterface $feed, $fetched_data);
 
 }
diff --git a/core/modules/aggregator/lib/Drupal/aggregator/Plugin/ProcessorInterface.php b/core/modules/aggregator/lib/Drupal/aggregator/Plugin/ProcessorInterface.php
index 1b51e24..63cd734 100644
--- a/core/modules/aggregator/lib/Drupal/aggregator/Plugin/ProcessorInterface.php
+++ b/core/modules/aggregator/lib/Drupal/aggregator/Plugin/ProcessorInterface.php
@@ -25,12 +25,13 @@
    *
    * @param \Drupal\aggregator\FeedInterface $feed
    *   A feed object representing the resource to be processed.
-   *   $feed->items contains an array of feed items downloaded and parsed at the
-   *   parsing stage. See \Drupal\aggregator\Plugin\FetcherInterface::parse()
-   *   for the basic format of a single item in the $feed->items array.
+   * @param array $items
+   *   An array of feed items downloaded and parsed at the parsing stage.
+   *   See \Drupal\aggregator\Plugin\ParserInterface::parse() for the basic
+   *   format of a single item in the $feed->items array.
    *   For the exact format refer to the particular parser in use.
    */
-  public function process(FeedInterface $feed);
+  public function process(FeedInterface $feed, array &$items);
 
   /**
    * Refreshes feed information.
diff --git a/core/modules/aggregator/lib/Drupal/aggregator/Plugin/aggregator/fetcher/DefaultFetcher.php b/core/modules/aggregator/lib/Drupal/aggregator/Plugin/aggregator/fetcher/DefaultFetcher.php
index 1ebd7bc..a20542b 100644
--- a/core/modules/aggregator/lib/Drupal/aggregator/Plugin/aggregator/fetcher/DefaultFetcher.php
+++ b/core/modules/aggregator/lib/Drupal/aggregator/Plugin/aggregator/fetcher/DefaultFetcher.php
@@ -59,7 +59,6 @@ public static function create(ContainerInterface $container, array $configuratio
    */
   public function fetch(FeedInterface $feed) {
     $request = $this->httpClient->get($feed->getUrl());
-    $feed->source_string = FALSE;
 
     // Generate conditional GET headers.
     if ($feed->getEtag()) {
@@ -78,28 +77,24 @@ public function fetch(FeedInterface $feed) {
         return FALSE;
       }
 
-      $feed->source_string = $response->getBody(TRUE);
       $feed->setEtag($response->getEtag());
       $feed->setLastModified(strtotime($response->getLastModified()));
-      $feed->http_headers = $response->getHeaders();
 
       // Update the feed URL in case of a 301 redirect.
 
       if ($response->getEffectiveUrl() != $feed->getUrl()) {
         $feed->setUrl($response->getEffectiveUrl());
       }
-      return TRUE;
+      return $response->getBody(TRUE);
     }
     catch (BadResponseException $e) {
       $response = $e->getResponse();
       watchdog('aggregator', 'The feed from %site seems to be broken because of error "%error".', array('%site' => $feed->label(), '%error' => $response->getStatusCode() . ' ' . $response->getReasonPhrase()), WATCHDOG_WARNING);
       drupal_set_message(t('The feed from %site seems to be broken because of error "%error".', array('%site' => $feed->label(), '%error' => $response->getStatusCode() . ' ' . $response->getReasonPhrase())));
-      return FALSE;
     }
     catch (RequestException $e) {
       watchdog('aggregator', 'The feed from %site seems to be broken because of error "%error".', array('%site' => $feed->label(), '%error' => $e->getMessage()), WATCHDOG_WARNING);
       drupal_set_message(t('The feed from %site seems to be broken because of error "%error".', array('%site' => $feed->label(), '%error' => $e->getMessage())));
-      return FALSE;
     }
   }
 }
diff --git a/core/modules/aggregator/lib/Drupal/aggregator/Plugin/aggregator/parser/DefaultParser.php b/core/modules/aggregator/lib/Drupal/aggregator/Plugin/aggregator/parser/DefaultParser.php
index 4b91c6e..235457e 100644
--- a/core/modules/aggregator/lib/Drupal/aggregator/Plugin/aggregator/parser/DefaultParser.php
+++ b/core/modules/aggregator/lib/Drupal/aggregator/Plugin/aggregator/parser/DefaultParser.php
@@ -29,17 +29,17 @@ class DefaultParser implements ParserInterface {
   /**
    * {@inheritdoc}
    */
-  public function parse(FeedInterface $feed) {
+  public function parse(FeedInterface $feed, $fetched_data) {
     // Set our bridge extension manager to Zend Feed.
     Reader::setExtensionManager(\Drupal::service('feed.bridge.reader'));
     try {
-      $channel = Reader::importString($feed->source_string);
+      $channel = Reader::importString($fetched_data);
     }
     catch (ExceptionInterface $e) {
       watchdog_exception('aggregator', $e);
       drupal_set_message(t('The feed from %site seems to be broken because of error "%error".', array('%site' => $feed->label(), '%error' => $e->getMessage())), 'error');
 
-      return FALSE;
+      return array();
     }
 
     $feed->setWebsiteUrl($channel->getLink());
@@ -48,7 +48,7 @@ public function parse(FeedInterface $feed) {
       $feed->setImage($image['uri']);
     }
     // Initialize items array.
-    $feed->items = array();
+    $items = array();
     foreach ($channel as $item) {
       // Reset the parsed item.
       $parsed_item = array();
@@ -65,14 +65,14 @@ public function parse(FeedInterface $feed) {
       if ($date = $item->getDateModified()) {
         $parsed_item['timestamp'] = $date->getTimestamp();
       }
-      // Store on $feed object. This is where processors will look for parsed items.
-      $feed->items[] = $parsed_item;
+      // Store the parsed item to the items array.
+      $items[] = $parsed_item;
     }
 
     // Clear the page and block caches.
     Cache::invalidateTags(array('content' => TRUE));
 
-    return TRUE;
+    return $items;
   }
 
 }
diff --git a/core/modules/aggregator/lib/Drupal/aggregator/Plugin/aggregator/processor/DefaultProcessor.php b/core/modules/aggregator/lib/Drupal/aggregator/Plugin/aggregator/processor/DefaultProcessor.php
index f5f4ebc..386e18f 100644
--- a/core/modules/aggregator/lib/Drupal/aggregator/Plugin/aggregator/processor/DefaultProcessor.php
+++ b/core/modules/aggregator/lib/Drupal/aggregator/Plugin/aggregator/processor/DefaultProcessor.php
@@ -160,11 +160,8 @@ public function submitConfigurationForm(array &$form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function process(FeedInterface $feed) {
-    if (!is_array($feed->items)) {
-      return;
-    }
-    foreach ($feed->items as $item) {
+  public function process(FeedInterface $feed, array &$items) {
+    foreach ($items as $item) {
       // @todo: The default entity view builder always returns an empty
       //   array, which is ignored in aggregator_save_item() currently. Should
       //   probably be fixed.
diff --git a/core/modules/aggregator/tests/modules/aggregator_test/lib/Drupal/aggregator_test/Plugin/aggregator/parser/TestParser.php b/core/modules/aggregator/tests/modules/aggregator_test/lib/Drupal/aggregator_test/Plugin/aggregator/parser/TestParser.php
index 053a9c9..92db9b4 100644
--- a/core/modules/aggregator/tests/modules/aggregator_test/lib/Drupal/aggregator_test/Plugin/aggregator/parser/TestParser.php
+++ b/core/modules/aggregator/tests/modules/aggregator_test/lib/Drupal/aggregator_test/Plugin/aggregator/parser/TestParser.php
@@ -29,7 +29,7 @@ class TestParser extends DefaultParser implements ParserInterface {
    *
    * @todo Actually test this.
    */
-  public function parse(FeedInterface $feed) {
-    return parent::parse($feed);
+  public function parse(FeedInterface $feed, $fetched_data) {
+    return parent::parse($feed, $fetched_data);
   }
 }
diff --git a/core/modules/aggregator/tests/modules/aggregator_test/lib/Drupal/aggregator_test/Plugin/aggregator/processor/TestProcessor.php b/core/modules/aggregator/tests/modules/aggregator_test/lib/Drupal/aggregator_test/Plugin/aggregator/processor/TestProcessor.php
index 28a71f8..5a8c2e3 100644
--- a/core/modules/aggregator/tests/modules/aggregator_test/lib/Drupal/aggregator_test/Plugin/aggregator/processor/TestProcessor.php
+++ b/core/modules/aggregator/tests/modules/aggregator_test/lib/Drupal/aggregator_test/Plugin/aggregator/processor/TestProcessor.php
@@ -98,8 +98,8 @@ public function submitConfigurationForm(array &$form, array &$form_state) {
   /**
    * {@inheritdoc}
    */
-  public function process(FeedInterface $feed) {
-    foreach ($feed->items as &$item) {
+  public function process(FeedInterface $feed, array &$items) {
+    foreach ($items as &$item) {
       // Prepend our test string.
       $item['title'] = 'testProcessor' . $item['title'];
     }
