diff --git a/modules/aggregator/aggregator.api.php b/modules/aggregator/aggregator.api.php
index 5fc07778d5eb072c5523533eeea40852023ad661..cfdac8f168e01bf0b3b3387fc26bf5b3d653e4db 100644
--- a/modules/aggregator/aggregator.api.php
+++ b/modules/aggregator/aggregator.api.php
@@ -28,6 +28,9 @@
  *   $feed->url 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.
+ *
  * @see hook_aggregator_fetch_info()
  * @see hook_aggregator_parse()
  * @see hook_aggregator_process()
@@ -82,12 +85,12 @@ function hook_aggregator_fetch_info() {
  *   $feed->source_string contains the raw feed data as a string. Parse data
  *   from $feed->source_string and expose it to other modules as an array of
  *   data items on $feed->items.
- * 
+ *
  *   Feed format:
  *   - $feed->description (string) - description of the feed
  *   - $feed->image (string) - image for the feed
  *   - $feed->etag (string) - value of feed's entity tag header field
- *   - $feed->modified (UNIX timestamp) - value of feed's last modified header 
+ *   - $feed->modified (UNIX timestamp) - value of feed's last modified header
  *     field
  *   - $feed->items (Array) - array of feed items.
  *
@@ -101,8 +104,8 @@ function hook_aggregator_fetch_info() {
  *   AUTHOR (string) - the feed item's author
  *   GUID (string) - RSS/Atom global unique identifier
  *   LINK (string) - the feed item's URL
- * 
- * @return 
+ *
+ * @return
  *   TRUE if parsing was successful, FALSE otherwise.
  *
  * @see hook_aggregator_parse_info()
@@ -116,7 +119,7 @@ function hook_aggregator_parse($feed) {
     $feed->items = $items;
     return TRUE;
   }
-  return FALSE;  
+  return FALSE;
 }
 
 /**
diff --git a/modules/aggregator/aggregator.fetcher.inc b/modules/aggregator/aggregator.fetcher.inc
index 7c697052c9019825d4c3edc2eb9c13cddfc9f18d..0974a6926e7f49588aa435819086838a9774f7fb 100644
--- a/modules/aggregator/aggregator.fetcher.inc
+++ b/modules/aggregator/aggregator.fetcher.inc
@@ -37,11 +37,6 @@ function aggregator_aggregator_fetch($feed) {
   // Process HTTP response code.
   switch ($result->code) {
     case 304:
-      db_update('aggregator_feed')
-        ->fields(array('checked' => REQUEST_TIME))
-        ->condition('fid', $feed->fid)
-        ->execute();
-      drupal_set_message(t('There is no new syndicated content from %site.', array('%site' => $feed->title)));
       break;
     case 301:
       $feed->url = $result->redirect_url;
@@ -49,25 +44,12 @@ function aggregator_aggregator_fetch($feed) {
     case 200:
     case 302:
     case 307:
-      // We store the md5 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.
       if (!isset($result->data)) {
         $result->data = '';
       }
       if (!isset($result->headers)) {
         $result->headers = array();
       }
-      $md5 = md5($result->data);
-      if ($feed->hash == $md5) {
-        db_update('aggregator_feed')
-          ->condition('fid', $feed->fid)
-          ->fields(array('checked' => REQUEST_TIME))
-          ->execute();
-        drupal_set_message(t('There is no new syndicated content from %site.', array('%site' => $feed->title)));
-        break;
-      }
-
       $feed->source_string = $result->data;
       $feed->http_headers = $result->headers;
       break;
@@ -75,4 +57,6 @@ function aggregator_aggregator_fetch($feed) {
       watchdog('aggregator', 'The feed from %site seems to be broken, due to "%error".', array('%site' => $feed->title, '%error' => $result->code . ' ' . $result->error), WATCHDOG_WARNING);
       drupal_set_message(t('The feed from %site seems to be broken, because of error "%error".', array('%site' => $feed->title, '%error' => $result->code . ' ' . $result->error)));
   }
+
+  return $feed->source_string === FALSE ? FALSE : TRUE;
 }
diff --git a/modules/aggregator/aggregator.module b/modules/aggregator/aggregator.module
index 44290d19f2a9747ce6e0c343d87617d17f0a9ba9..3812ed3c9cf9553f64d65f3978fd5bdce19f4cb4 100644
--- a/modules/aggregator/aggregator.module
+++ b/modules/aggregator/aggregator.module
@@ -599,9 +599,14 @@ function aggregator_refresh($feed) {
 
   // Fetch the feed.
   list($fetcher, $parser, $processors) = _aggregator_get_variables();
-  module_invoke($fetcher, 'aggregator_fetch', $feed);
+  $success = module_invoke($fetcher, 'aggregator_fetch', $feed);
 
-  if ($feed->source_string !== FALSE) {
+  // We store the md5 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.
+  $md5 = md5($feed->source_string);
+
+  if ($success && ($feed->hash != $md5)) {
     // Parse the feed.
     if (module_invoke($parser, 'aggregator_parse', $feed)) {
       // Update feed with parsed data.
@@ -613,7 +618,7 @@ function aggregator_refresh($feed) {
           'link' => empty($feed->link) ? $feed->url : $feed->link,
           'description' => empty($feed->description) ? '' : $feed->description,
           'image' => empty($feed->image) ? '' : $feed->image,
-          'hash' => md5($feed->source_string),
+          'hash' => $md5,
           'etag' => empty($feed->etag) ? '' : $feed->etag,
           'modified' => empty($feed->modified) ? 0 : $feed->modified,
         ))
@@ -636,6 +641,14 @@ function aggregator_refresh($feed) {
       }
     }
   }
+  else {
+    db_update('aggregator_feed')
+      ->fields(array('checked' => REQUEST_TIME))
+      ->condition('fid', $feed->fid)
+      ->execute();
+
+    drupal_set_message(t('There is no new syndicated content from %site.', array('%site' => $feed->title)));
+  }
 
   // Expire old feed items.
   if (function_exists('aggregator_expire')) {