diff --git a/libraries/http_request.inc b/libraries/http_request.inc
index 1ed19c2..4b4e8a8 100644
--- a/libraries/http_request.inc
+++ b/libraries/http_request.inc
@@ -109,27 +109,42 @@ function http_request_get($url, $username = NULL, $password = NULL, $accept_inva
 
   // Only download and parse data if really needs refresh.
   // Based on "Last-Modified" and "If-Modified-Since".
-  $headers = array();
+  $headers = array('User-Agent' => 'Drupal (+http://drupal.org/)');
   if ($cache = cache_get('feeds_http_download_' . md5($url))) {
-    $last_result = $cache->data;
-    $last_headers = array_change_key_case($last_result->headers);
 
-    if (!empty($last_headers['etag'])) {
-      if ($curl) {
-        $headers[] = 'If-None-Match: ' . $last_headers['etag'];
-      }
-      else {
-        $headers['If-None-Match'] = $last_headers['etag'];
+    $last_result = $cache->data;
+    $last_result->headers = http_request_normalize_headers($last_result->headers);
+    $last_headers = $last_result->headers;
+
+    // Cache-Control headers take precedence over Expires headers.
+    $freshness_lifetime = FALSE;
+    $no_cache = FALSE;
+    if ($last_headers['cache-control']) {
+      $cache_settings = http_request_parse_cache_control($last_headers['cache-control']);
+      $no_cache = $cache_settings['no-cache'];
+
+      if ($cache_settings['max-age'] !== FALSE) {
+        $freshness_lifetime = (int) $cache_settings['max-age'];
       }
     }
-    if (!empty($last_headers['last-modified'])) {
-      if ($curl) {
-        $headers[] = 'If-Modified-Since: ' . $last_headers['last-modified'];
-      }
-      else {
-        $headers['If-Modified-Since'] = $last_headers['last-modified'];
-      }
+
+    if ($last_headers['expires'] && $freshness_lifetime === FALSE) {
+      $freshness_lifetime = strtotime($last_headers['expires']) - $last_result->date_value;
+    }
+
+    // Skip download if the cache is fresh.
+    $current_age = $last_result->corrected_initial_age + time() - $last_result->response_time;
+    if (!$no_cache && $freshness_lifetime > $current_age) {
+      return $last_result;
+    }
+
+    if ($last_headers['etag']) {
+      $headers['If-None-Match'] = $last_headers['etag'];
+    }
+    if ($last_headers['last-modified']) {
+      $headers['If-Modified-Since'] = $last_headers['last-modified'];
     }
+
     if (!empty($username) && !$curl) {
       $headers['Authorization'] = 'Basic ' . base64_encode("$username:$password");
     }
@@ -139,7 +154,6 @@ function http_request_get($url, $username = NULL, $password = NULL, $accept_inva
   $url = strtr($url, array('feed://' => 'http://', 'webcal://' => 'http://'));
 
   if ($curl) {
-    $headers[] = 'User-Agent: Drupal (+http://drupal.org/)';
     $result = new stdClass();
     $result->headers = array();
 
@@ -173,7 +187,11 @@ function http_request_get($url, $username = NULL, $password = NULL, $accept_inva
         curl_setopt($download, CURLOPT_USERPWD, "{$username}:{$password}");
         curl_setopt($download, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
       }
-      curl_setopt($download, CURLOPT_HTTPHEADER, $headers);
+      $curl_headers = array();
+      foreach ($headers as $key => $value) {
+        $curl_headers[] = "$key: $value";
+      }
+      curl_setopt($download, CURLOPT_HTTPHEADER, $curl_headers);
       curl_setopt($download, CURLOPT_HEADER, TRUE);
       curl_setopt($download, CURLOPT_RETURNTRANSFER, TRUE);
       curl_setopt($download, CURLOPT_ENCODING, '');
@@ -182,7 +200,9 @@ function http_request_get($url, $username = NULL, $password = NULL, $accept_inva
         curl_setopt($download, CURLOPT_SSL_VERIFYPEER, 0);
       }
       $header = '';
+      $request_time = time();
       $data = curl_exec($download);
+      $response_time = time();
       if (curl_error($download)) {
         throw new HRCurlException(
           t('cURL error (@code) @error for @url', array(
@@ -221,7 +241,9 @@ function http_request_get($url, $username = NULL, $password = NULL, $accept_inva
     }
   }
   else {
+    $request_time = time();
     $result = drupal_http_request($url, array('headers' => $headers, 'timeout' => $request_timeout));
+    $response_time = time();
     $result->headers = isset($result->headers) ? $result->headers : array();
   }
 
@@ -231,7 +253,6 @@ function http_request_get($url, $username = NULL, $password = NULL, $accept_inva
   if ($result->code == 304) {
 
     if (isset($last_result)) {
-      $last_result->from_cache = TRUE;
       return $last_result;
     }
     else {
@@ -243,7 +264,25 @@ function http_request_get($url, $username = NULL, $password = NULL, $accept_inva
   }
 
   // Set caches.
-  cache_set('feeds_http_download_' . md5($url), $result);
+  $response_headers = http_request_normalize_headers($result->headers);
+
+  if ($response_headers['cache-control']) {
+    $cache_settings = http_request_parse_cache_control($response_headers['cache-control']);
+    $no_store = $cache_settings['no-store'];
+  }
+
+  // Should we keep the in-memory cache here?
+  if (empty($no_store)) {
+    $now = time();
+    $corrected_received_age = max($now - strtotime($response_headers['date']), $response_headers['age'], 0);
+    $result->corrected_initial_age = $corrected_received_age + ($now - $request_time);
+
+    $result->response_time = $response_time;
+    $result->date_value = $response_headers['date'] ? strtotime($response_headers['date']) : $response_time;
+
+    $result->from_cache = TRUE;
+    cache_set('feeds_http_download_' . md5($url), $result);
+  }
   $download_cache[$url] = $result;
 
   return $result;
@@ -413,3 +452,61 @@ function http_request_create_absolute_url($url, $base_url) {
   }
   return FALSE;
 }
+
+/**
+ * Parses an HTTP Cache-Control header string.
+ *
+ * @param string $cache_control
+ *   A Cache-Control header string.
+ *
+ * @return array
+ *   An array with keys set to Cache-Control keys. If the key has a
+ *   corresponding value, it will be set as the array's value, otherwise the
+ *   key will be set to TRUE.
+ */
+function http_request_parse_cache_control($cache_control) {
+  $cache_control = array_map('trim', explode(',', $cache_control));
+  $cache_settings = array(
+    'no-store' => FALSE,
+    'no-cache' => FALSE,
+    'must-revalidate' => FALSE,
+    'max-age' => FALSE,
+  );
+
+  foreach ($cache_control as $cache_rule) {
+    $cache_rule = strtolower($cache_rule);
+    if (strpos($cache_rule, '=') !== FALSE) {
+      list($key, $value) = explode('=', $cache_rule, 2);
+      $cache_settings[$key] = is_numeric($value) ? (int) $value : $value;
+    }
+    else {
+      $cache_settings[$cache_rule] = TRUE;
+    }
+  }
+
+  return $cache_settings;
+}
+
+/**
+ * Normalizes HTTP response headers.
+ *
+ * @param array $headers
+ *   An HTTP header array.
+ *
+ * @return array
+ *   The same headers as input, but with the keys lowercased, and default values
+ *   filled in.
+ */
+function http_request_normalize_headers(array $headers) {
+  $headers = array_change_key_case($headers);
+  $headers += array(
+    'etag' => FALSE,
+    'last-modified' => FALSE,
+    'cache-control' => FALSE,
+    'expires' => FALSE,
+    'date' => FALSE,
+    'age' => FALSE,
+  );
+
+  return $headers;
+}
