Index: README.txt
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/cdn/README.txt,v
retrieving revision 1.43
diff -u -F '^f' -r1.43 README.txt
--- README.txt	19 Nov 2010 00:31:23 -0000	1.43
+++ README.txt	9 Dec 2010 17:50:59 -0000
@@ -53,6 +53,17 @@
   are also supported.
 
 
+Module compatibility
+--------------------
+This module has been verified to be compatible with the following modules:
+- CSS Gzip
+  (This module is obsolete when using Origin Pull mode with the Far Future
+  expiration setting enabled.)
+- ImageCache
+  (This module requires one of the patches that ships with the CDN module.)
+- Javascript Aggregator
+
+
 Installation
 ------------
 1) Note: skip this step if you want to rely on the fallback mechanism!
Index: cdn.admin.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/cdn/cdn.admin.inc,v
retrieving revision 1.30
diff -u -F '^f' -r1.30 cdn.admin.inc
--- cdn.admin.inc	19 Nov 2010 00:03:12 -0000	1.30
+++ cdn.admin.inc	9 Dec 2010 17:50:59 -0000
@@ -139,6 +139,40 @@ function cdn_admin_details_form(&$form_s
   // Basic mode settings.
   //
 
+  $farfuture_extensions  = variable_get(CDN_BASIC_FARFUTURE_EXTENSIONS_VARIABLE, CDN_BASIC_FARFUTURE_EXTENSIONS_DEFAULT);
+  $farfuture_variables = array(
+    '!extensions'             => "<code>." . implode("</code>, <code>.", explode("\n", $farfuture_extensions)) . "</code>",
+    '!extensions-compressed' => "<code>." . implode("</code>, <code>.", explode("\n", CDN_BASIC_FARFUTURE_GZIP_EXTENSIONS)) . "</code>",
+  );
+  $form['settings'][CDN_BASIC_FARFUTURE_VARIABLE] = array(
+    '#type' => 'checkbox',
+    '#title' => t('Far Future expiration'),
+    '#description' => t('<strong>Recommended for maximum performance boost!</strong>
+                         <br />
+                         Mark all files served from the CDN to expire in the
+                         far future (decades from now). This is the same as
+                         telling browsers to <em>always</em> use the cached
+                         files. This can significantly speed up page loads.
+                         Files are also automatically compressed (when the
+                         browser supports it), to speed up page loads even
+                         further.
+                         <br />
+                         Of course, you still want visitors to immediately get
+                         new versions of files when they change.  That is why
+                         unique filenames are generated automatically.
+                         <br />
+                         <strong>For the experts:</strong> the following HTTP
+                         headers are set: <code>Expires</code>,
+                         <code>Cache-Control</code>,
+                         <code>Last-Modified</code>, <code>Vary</code>, for
+                         files with one of the following extensions: !extensions
+                         and of these extensions, some will also be
+                         automatically compressed: !extensions-compressed.', $farfuture_variables
+                        ),
+    '#default_value' => variable_get(CDN_BASIC_FARFUTURE_VARIABLE, CDN_BASIC_FARFUTURE_DEFAULT),
+    '#process'       => array('ctools_dependent_process'),
+    '#dependency'    => array('radio:' . CDN_MODE_VARIABLE => array(CDN_MODE_BASIC)),
+  );
   $format_variables = array(
     '@format-url'        => '<' . t('URL') . '>',
     '@format-extensions' => '<' . t('extensions') . '>',
@@ -176,6 +210,7 @@ function cdn_admin_details_form(&$form_s
     '#dependency'    => array('radio:' . CDN_MODE_VARIABLE => array(CDN_MODE_BASIC)),
   );
 
+
   //
   // Advanced mode settings.
   //
@@ -236,7 +271,6 @@ function cdn_admin_other_settings_form(&
     '#type'          => 'checkbox',
     '#title'         => t('CDN supports HTTPS'),
     '#default_value' => variable_get(CDN_HTTPS_SUPPORT_VARIABLE, FALSE),
-    '#process'       => array('ctools_dependent_process'),
   );
 
   $path_explanation = t(
Index: cdn.basic.farfuture.inc
===================================================================
RCS file: cdn.basic.farfuture.inc
diff -N cdn.basic.farfuture.inc
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ cdn.basic.farfuture.inc	9 Dec 2010 17:51:00 -0000
@@ -0,0 +1,1112 @@
+<?php
+// $Id$
+
+/**
+ * @file
+ * Far Future expiration setting for basic mode.
+ */
+
+
+//----------------------------------------------------------------------------
+// Menu system callbacks.
+
+function cdn_basic_farfuture_download() {
+  $args = func_get_args();
+
+  // The first argument is the file's mtime. We don't need this anymore.
+  $mtime = array_shift($args);
+
+  // Reconstruct the path of the requested file.
+  $path  = implode('/', $args);
+
+  // Disallow downloading of files that are also not allowed to be downloaded
+  // by Drupal's .htaccess file.
+  if (preg_match("/\.(engine|inc|info|install|make|module|profile|test|po|sh|.*sql|theme|tpl(\.php)?|xtmpl)$|^(\..*|Entries.*|Repository|Root|Tag|Template)$/", $path)) {
+    drupal_access_denied();
+    exit();
+  }
+
+  if (!file_exists($path)) {
+    drupal_not_found();
+    exit();
+  }
+
+  // Remove some useless/unwanted headers.
+  $remove_headers = explode("\n", CDN_BASIC_FARFUTURE_REMOVE_HEADERS);
+  $current_headers = array();
+  foreach (headers_list() as $header) {
+    $parts = explode(':', $header);
+    $current_headers[] = $parts[0];
+  }
+  foreach ($remove_headers as $header) {
+    if (in_array($header, $current_headers)) {
+      // header_remove() only exists in PHP >=5.3
+      if (function_exists('header_remove')) {
+        header_remove($header);
+      }
+      else {
+        // In PHP <5.3, we cannot remove headers. At least shorten them to save
+        // every byte possible and to stop leaking information needlessly.
+        drupal_set_header($header . ':');
+      }
+    }
+  }
+
+  // Remove all previously set Cache-Control headers, because we're going to
+  // override it. Since multiple Cache-Control headers might have been set,
+  // simply setting a new, overriding header isn't enough: that would only
+  // override the *last* Cache-Control header. Yay for PHP!
+  if (function_exists('header_remove')) {
+    header_remove('Cache-Control');
+  }
+  else {
+    drupal_set_header("Cache-Control:");
+    drupal_set_header("Cache-Control:");
+  }
+
+  // Default caching rules: no caching/immediate expiration.
+  drupal_set_header("Cache-Control: private, must-revalidate, proxy-revalidate");
+  drupal_set_header("Expires: " . gmdate("D, d M Y H:i:s", time() - 86400) . "GMT");
+
+  // Instead of being powered by PHP, tell the world this resource was powered
+  // by the CDN module!
+  drupal_set_header("X-Powered-By: Drupal CDN module");
+  // Instruct intermediate HTTP caches to store both a compressed (gzipped)
+  // and uncompressed version of the resource.
+  drupal_set_header("Vary: Accept-Encoding");
+  // Determine the content type.
+  drupal_set_header("Content-Type: " . _cdn_basic_farfuture_get_mimetype(basename($path)));
+  // Support partial content requests.
+  drupal_set_header("Accept-Ranges: bytes");
+
+  // If the extension of the file that's being served is one of the far future
+  // extensions (by default: images, fonts and flash content), then cache it
+  // in the far future.
+  $farfuture_extensions  = variable_get(CDN_BASIC_FARFUTURE_EXTENSIONS_VARIABLE, CDN_BASIC_FARFUTURE_EXTENSIONS_DEFAULT);
+  $extension = strtolower(pathinfo($path, PATHINFO_EXTENSION));
+  if (in_array($extension, explode("\n", $farfuture_extensions))) {
+    // Remove all previously set Cache-Control headers, because we're going to
+    // override it. Since multiple Cache-Control headers might have been set,
+    // simply setting a new, overriding header isn't enough: that would only
+    // override the *last* Cache-Control header. Yay for PHP!
+    if (function_exists('header_remove')) {
+      header_remove('Cache-Control');
+    }
+    else {
+      drupal_set_header("Cache-Control:");
+      drupal_set_header("Cache-Control:");
+    }
+    // Set a far future Cache-Control header (480 weeks), which prevents
+    // intermediate caches from transforming the data and allows any
+    // intermediate cache to cache it, since it's marked as a public resource.
+    drupal_set_header("Cache-Control: max-age=290304000, no-transform, public");
+    // Set a far future Expires header. The maximum UNIX timestamp is somewhere
+    // in 2038. Set it to a date in 2037, just to be safe.
+    drupal_set_header("Expires: Tue, 20 Jan 2037 04:20:42 GMT");
+    // Pretend the file was last modified a long time ago in the past, this will
+    // prevent browsers that don't support Cache-Control nor Expires headers to
+    // still request a new version too soon (these browsers calculate a
+    // heuristic to determine when to request a new version, based on the last
+    // time the resource has been modified).
+    // Also see http://code.google.com/speed/page-speed/docs/caching.html.
+    drupal_set_header("Last-Modified: Wed, 20 Jan 1988 04:20:42 GMT");
+  }
+
+  // GET requests with an "Accept-Encoding" header that lists "gzip".
+  if (isset($_SERVER['HTTP_ACCEPT_ENCODING']) && strpos($_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip') !== FALSE) {
+    // Only send gzipped files for some file extensions (it doesn't make sense
+    // to gzip images, for example).
+    if (in_array($extension, explode("\n", CDN_BASIC_FARFUTURE_GZIP_EXTENSIONS))) {
+      // Ensure a gzipped version of the file is stored on disk, instead of
+      // gzipping the file on every request.
+      $gzip_path = file_directory_path() . '/' . CDN_BASIC_FARFUTURE_GZIP_DIRECTORY . "/$path.$mtime.gz";
+      if (!file_exists($gzip_path)) {
+        _cdn_basic_farfuture_create_directory_structure(dirname($gzip_path));
+        file_put_contents($gzip_path, gzencode(file_get_contents($path), 9));
+      }
+      // Make sure zlib.output_compression does not gzip our gzipped output.
+      ini_set('zlib.output_compression', '0');
+      // Prepare for gzipped output.
+      drupal_set_header("Content-Encoding: gzip");
+      $path = $gzip_path;
+    }
+  }
+
+  // Conditional GET requests (i.e. with If-Modified-Since header).
+  if (isset($_SERVER['HTTP_IF_MODIFIED_SINCE'])) {
+    // All files served by this function are designed to expire in the far
+    // future. Hence we can simply always tell the client the requested file
+    // was not modified.
+    drupal_set_header("HTTP/1.1 304 Not Modified");
+  }
+  // "Normal" GET requests.
+  else {
+    _cdn_transfer_file($path);
+  }
+
+  exit();
+}
+
+
+//----------------------------------------------------------------------------
+// Private functions.
+
+/**
+ * Variant of Drupal's file_transfer(), based on
+ *  http://www.thomthom.net/blog/2007/09/php-resumable-download-server/
+ * to support ranged requests as well.
+ *
+ * Note: ranged requests that request multiple ranges are not supported. They
+ * are responded to with a 416. See
+ * http://www.w3.org/Protocols/rfc2616/rfc2616-sec19.html
+ */
+function _cdn_transfer_file($path) {
+  $fp = @fopen($path, 'rb');
+
+  $size   = filesize($path); // File size
+  $length = $size;           // Content length
+  $start  = 0;               // Start byte
+  $end    = $size - 1;       // End byte
+
+  // In case of a range request, seek within the file to the correct location.
+  if (isset($_SERVER['HTTP_RANGE'])) {
+    $c_start = $start;
+    $c_end   = $end;
+
+    // Extract the string containing the requested range.
+    list(, $range) = explode('=', $_SERVER['HTTP_RANGE'], 2);
+
+    // If the client requested multiple ranges, repond with a 416.
+    if (strpos($range, ',') !== FALSE) {
+      header('HTTP/1.1 416 Requested Range Not Satisfiable');
+      header("Content-Range: bytes $start-$end/$size");
+      exit();
+    }
+
+    // Case "Range: -n": final n bytes are requested.
+    if ($range[0] == '-') {
+      $c_start = $size - substr($range, 1);
+    }
+    // Case "Range: m-n": bytes m through n are requested. When n is empty or
+    // non-numeric, n is the last byte.
+    else {
+      $range  = explode('-', $range);
+      $c_start = intval($range[0]);
+      $c_end   = (isset($range[1]) && is_numeric($range[1])) ? intval($range[1]) : $size;
+    }
+    // Minor normalization: end bytes can not be larger than $end.
+    $c_end = ($c_end > $end) ? $end : $c_end;
+
+    // If the requested range is not valid, respond with a 416.
+    if ($c_start > $c_end || $c_start > $end || $c_end > $end) {
+      header('HTTP/1.1 416 Requested Range Not Satisfiable');
+      header("Content-Range: bytes $start-$end/$size");
+      exit();
+    }
+
+    $start  = $c_start;
+    $end    = $c_end;
+    $length = $end - $start + 1;
+    fseek($fp, $start);
+
+    // The ranged request is valid and will be performed, respond with a 206.
+    header('HTTP/1.1 206 Partial Content');
+    header("Content-Range: bytes $start-$end/$size");
+  }
+  header("Content-Length: $length");
+
+  // Start buffered download. Prevent reading too far for a ranged request.
+  $buffer = 1024 * 8;
+  while (!feof($fp) && ($p = ftell($fp)) <= $end) {
+    if ($p + $buffer > $end) {
+      $buffer = $end - $p + 1;
+    }
+    set_time_limit(0); // Reset time limit for big files.
+    echo fread($fp, $buffer);
+    flush(); // Free up memory, to prevent triggering PHP's memory limit.
+  }
+  fclose($fp);
+}
+
+/**
+ * Determine an Internet Media Type, or MIME type from a filename.
+ * Borrowed from Drupal 7.
+ *
+ * @param $path
+ *   A string containing the file path.
+ * @return
+ *   The internet media type registered for the extension or
+ *   application/octet-stream for unknown extensions.
+ *
+ * @see file_default_mimetype_mapping()
+ */
+function _cdn_basic_farfuture_get_mimetype($path) {
+  static $mapping;
+
+  if (!isset($mapping)) {
+    $mapping = _cdn_basic_farfuture_mimetype_mapping();;
+  }
+
+  $extension = '';
+  $file_parts = explode('.', basename($path));
+
+  // Remove the first part: a full filename should not match an extension.
+  array_shift($file_parts);
+
+  // Iterate over the file parts, trying to find a match.
+  // For my.awesome.image.jpeg, we try:
+  //   - jpeg
+  //   - image.jpeg, and
+  //   - awesome.image.jpeg
+  while ($additional_part = array_pop($file_parts)) {
+    $extension = strtolower($additional_part . ($extension ? '.' . $extension : ''));
+    if (isset($mapping['extensions'][$extension])) {
+      return $mapping['mimetypes'][$mapping['extensions'][$extension]];
+    }
+  }
+
+  return 'application/octet-stream';
+}
+
+/**
+ * Default MIME extension mapping.
+ * Borrowed from Drupal 7.
+ *
+ * @return
+ *   Array of mimetypes correlated to the extensions that relate to them.
+ */
+function _cdn_basic_farfuture_mimetype_mapping() {
+  return array(
+    'mimetypes' => array(
+      0 => 'application/andrew-inset',
+      1 => 'application/atom',
+      2 => 'application/atomcat+xml',
+      3 => 'application/atomserv+xml',
+      4 => 'application/cap',
+      5 => 'application/cu-seeme',
+      6 => 'application/dsptype',
+      7 => 'application/hta',
+      8 => 'application/java-archive',
+      9 => 'application/java-serialized-object',
+      10 => 'application/java-vm',
+      11 => 'application/mac-binhex40',
+      12 => 'application/mathematica',
+      13 => 'application/msaccess',
+      14 => 'application/msword',
+      15 => 'application/octet-stream',
+      16 => 'application/oda',
+      17 => 'application/ogg',
+      18 => 'application/pdf',
+      19 => 'application/pgp-keys',
+      20 => 'application/pgp-signature',
+      21 => 'application/pics-rules',
+      22 => 'application/postscript',
+      23 => 'application/rar',
+      24 => 'application/rdf+xml',
+      25 => 'application/rss+xml',
+      26 => 'application/rtf',
+      27 => 'application/smil',
+      28 => 'application/vnd.cinderella',
+      29 => 'application/vnd.google-earth.kml+xml',
+      30 => 'application/vnd.google-earth.kmz',
+      31 => 'application/vnd.mozilla.xul+xml',
+      32 => 'application/vnd.ms-excel',
+      33 => 'application/vnd.ms-excel.addin.macroEnabled.12',
+      34 => 'application/vnd.ms-excel.sheet.binary.macroEnabled.12',
+      35 => 'application/vnd.ms-excel.sheet.macroEnabled.12',
+      36 => 'application/vnd.ms-excel.template.macroEnabled.12',
+      37 => 'application/vnd.ms-pki.seccat',
+      38 => 'application/vnd.ms-pki.stl',
+      39 => 'application/vnd.ms-powerpoint',
+      40 => 'application/vnd.ms-powerpoint.addin.macroEnabled.12',
+      41 => 'application/vnd.ms-powerpoint.presentation.macroEnabled.12',
+      42 => 'application/vnd.ms-powerpoint.slideshow.macroEnabled.12',
+      43 => 'application/vnd.ms-powerpoint.template.macroEnabled.12',
+      44 => 'application/vnd.ms-word.document.macroEnabled.12',
+      45 => 'application/vnd.ms-word.template.macroEnabled.12',
+      46 => 'application/vnd.ms-xpsdocument',
+      47 => 'application/vnd.oasis.opendocument.chart',
+      48 => 'application/vnd.oasis.opendocument.database',
+      49 => 'application/vnd.oasis.opendocument.formula',
+      50 => 'application/vnd.oasis.opendocument.graphics',
+      51 => 'application/vnd.oasis.opendocument.graphics-template',
+      52 => 'application/vnd.oasis.opendocument.image',
+      53 => 'application/vnd.oasis.opendocument.presentation',
+      54 => 'application/vnd.oasis.opendocument.presentation-template',
+      55 => 'application/vnd.oasis.opendocument.spreadsheet',
+      56 => 'application/vnd.oasis.opendocument.spreadsheet-template',
+      57 => 'application/vnd.oasis.opendocument.text',
+      58 => 'application/vnd.oasis.opendocument.text-master',
+      59 => 'application/vnd.oasis.opendocument.text-template',
+      60 => 'application/vnd.oasis.opendocument.text-web',
+      61 => 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
+      62 => 'application/vnd.openxmlformats-officedocument.presentationml.slideshow',
+      63 => 'application/vnd.openxmlformats-officedocument.presentationml.template',
+      64 => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
+      65 => 'application/vnd.openxmlformats-officedocument.spreadsheetml.template',
+      66 => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
+      67 => 'application/vnd.openxmlformats-officedocument.wordprocessingml.template',
+      68 => 'application/vnd.rim.cod',
+      69 => 'application/vnd.smaf',
+      70 => 'application/vnd.stardivision.calc',
+      71 => 'application/vnd.stardivision.chart',
+      72 => 'application/vnd.stardivision.draw',
+      73 => 'application/vnd.stardivision.impress',
+      74 => 'application/vnd.stardivision.math',
+      75 => 'application/vnd.stardivision.writer',
+      76 => 'application/vnd.stardivision.writer-global',
+      77 => 'application/vnd.sun.xml.calc',
+      78 => 'application/vnd.sun.xml.calc.template',
+      79 => 'application/vnd.sun.xml.draw',
+      80 => 'application/vnd.sun.xml.draw.template',
+      81 => 'application/vnd.sun.xml.impress',
+      82 => 'application/vnd.sun.xml.impress.template',
+      83 => 'application/vnd.sun.xml.math',
+      84 => 'application/vnd.sun.xml.writer',
+      85 => 'application/vnd.sun.xml.writer.global',
+      86 => 'application/vnd.sun.xml.writer.template',
+      87 => 'application/vnd.symbian.install',
+      88 => 'application/vnd.visio',
+      89 => 'application/vnd.wap.wbxml',
+      90 => 'application/vnd.wap.wmlc',
+      91 => 'application/vnd.wap.wmlscriptc',
+      92 => 'application/wordperfect',
+      93 => 'application/wordperfect5.1',
+      94 => 'application/x-123',
+      95 => 'application/x-7z-compressed',
+      96 => 'application/x-abiword',
+      97 => 'application/x-apple-diskimage',
+      98 => 'application/x-bcpio',
+      99 => 'application/x-bittorrent',
+      100 => 'application/x-cab',
+      101 => 'application/x-cbr',
+      102 => 'application/x-cbz',
+      103 => 'application/x-cdf',
+      104 => 'application/x-cdlink',
+      105 => 'application/x-chess-pgn',
+      106 => 'application/x-cpio',
+      107 => 'application/x-debian-package',
+      108 => 'application/x-director',
+      109 => 'application/x-dms',
+      110 => 'application/x-doom',
+      111 => 'application/x-dvi',
+      112 => 'application/x-flac',
+      113 => 'application/x-font',
+      114 => 'application/x-freemind',
+      115 => 'application/x-futuresplash',
+      116 => 'application/x-gnumeric',
+      117 => 'application/x-go-sgf',
+      118 => 'application/x-graphing-calculator',
+      119 => 'application/x-gtar',
+      120 => 'application/x-hdf',
+      121 => 'application/x-httpd-eruby',
+      122 => 'application/x-httpd-php',
+      123 => 'application/x-httpd-php-source',
+      124 => 'application/x-httpd-php3',
+      125 => 'application/x-httpd-php3-preprocessed',
+      126 => 'application/x-httpd-php4',
+      127 => 'application/x-ica',
+      128 => 'application/x-internet-signup',
+      129 => 'application/x-iphone',
+      130 => 'application/x-iso9660-image',
+      131 => 'application/x-java-jnlp-file',
+      132 => 'application/x-javascript',
+      133 => 'application/x-jmol',
+      134 => 'application/x-kchart',
+      135 => 'application/x-killustrator',
+      136 => 'application/x-koan',
+      137 => 'application/x-kpresenter',
+      138 => 'application/x-kspread',
+      139 => 'application/x-kword',
+      140 => 'application/x-latex',
+      141 => 'application/x-lha',
+      142 => 'application/x-lyx',
+      143 => 'application/x-lzh',
+      144 => 'application/x-lzx',
+      145 => 'application/x-maker',
+      146 => 'application/x-mif',
+      147 => 'application/x-ms-wmd',
+      148 => 'application/x-ms-wmz',
+      149 => 'application/x-msdos-program',
+      150 => 'application/x-msi',
+      151 => 'application/x-netcdf',
+      152 => 'application/x-ns-proxy-autoconfig',
+      153 => 'application/x-nwc',
+      154 => 'application/x-object',
+      155 => 'application/x-oz-application',
+      156 => 'application/x-pkcs7-certreqresp',
+      157 => 'application/x-pkcs7-crl',
+      158 => 'application/x-python-code',
+      159 => 'application/x-quicktimeplayer',
+      160 => 'application/x-redhat-package-manager',
+      161 => 'application/x-shar',
+      162 => 'application/x-shockwave-flash',
+      163 => 'application/x-stuffit',
+      164 => 'application/x-sv4cpio',
+      165 => 'application/x-sv4crc',
+      166 => 'application/x-tar',
+      167 => 'application/x-tcl',
+      168 => 'application/x-tex-gf',
+      169 => 'application/x-tex-pk',
+      170 => 'application/x-texinfo',
+      171 => 'application/x-trash',
+      172 => 'application/x-troff',
+      173 => 'application/x-troff-man',
+      174 => 'application/x-troff-me',
+      175 => 'application/x-troff-ms',
+      176 => 'application/x-ustar',
+      177 => 'application/x-wais-source',
+      178 => 'application/x-wingz',
+      179 => 'application/x-x509-ca-cert',
+      180 => 'application/x-xcf',
+      181 => 'application/x-xfig',
+      182 => 'application/x-xpinstall',
+      183 => 'application/xhtml+xml',
+      184 => 'application/xml',
+      185 => 'application/zip',
+      186 => 'audio/basic',
+      187 => 'audio/midi',
+      346 => 'audio/mp4',
+      188 => 'audio/mpeg',
+      189 => 'audio/ogg',
+      190 => 'audio/prs.sid',
+      191 => 'audio/x-aiff',
+      192 => 'audio/x-gsm',
+      193 => 'audio/x-mpegurl',
+      194 => 'audio/x-ms-wax',
+      195 => 'audio/x-ms-wma',
+      196 => 'audio/x-pn-realaudio',
+      197 => 'audio/x-realaudio',
+      198 => 'audio/x-scpls',
+      199 => 'audio/x-sd2',
+      200 => 'audio/x-wav',
+      201 => 'chemical/x-alchemy',
+      202 => 'chemical/x-cache',
+      203 => 'chemical/x-cache-csf',
+      204 => 'chemical/x-cactvs-binary',
+      205 => 'chemical/x-cdx',
+      206 => 'chemical/x-cerius',
+      207 => 'chemical/x-chem3d',
+      208 => 'chemical/x-chemdraw',
+      209 => 'chemical/x-cif',
+      210 => 'chemical/x-cmdf',
+      211 => 'chemical/x-cml',
+      212 => 'chemical/x-compass',
+      213 => 'chemical/x-crossfire',
+      214 => 'chemical/x-csml',
+      215 => 'chemical/x-ctx',
+      216 => 'chemical/x-cxf',
+      217 => 'chemical/x-embl-dl-nucleotide',
+      218 => 'chemical/x-galactic-spc',
+      219 => 'chemical/x-gamess-input',
+      220 => 'chemical/x-gaussian-checkpoint',
+      221 => 'chemical/x-gaussian-cube',
+      222 => 'chemical/x-gaussian-input',
+      223 => 'chemical/x-gaussian-log',
+      224 => 'chemical/x-gcg8-sequence',
+      225 => 'chemical/x-genbank',
+      226 => 'chemical/x-hin',
+      227 => 'chemical/x-isostar',
+      228 => 'chemical/x-jcamp-dx',
+      229 => 'chemical/x-kinemage',
+      230 => 'chemical/x-macmolecule',
+      231 => 'chemical/x-macromodel-input',
+      232 => 'chemical/x-mdl-molfile',
+      233 => 'chemical/x-mdl-rdfile',
+      234 => 'chemical/x-mdl-rxnfile',
+      235 => 'chemical/x-mdl-sdfile',
+      236 => 'chemical/x-mdl-tgf',
+      237 => 'chemical/x-mmcif',
+      238 => 'chemical/x-mol2',
+      239 => 'chemical/x-molconn-Z',
+      240 => 'chemical/x-mopac-graph',
+      241 => 'chemical/x-mopac-input',
+      242 => 'chemical/x-mopac-out',
+      243 => 'chemical/x-mopac-vib',
+      244 => 'chemical/x-ncbi-asn1-ascii',
+      245 => 'chemical/x-ncbi-asn1-binary',
+      246 => 'chemical/x-ncbi-asn1-spec',
+      247 => 'chemical/x-pdb',
+      248 => 'chemical/x-rosdal',
+      249 => 'chemical/x-swissprot',
+      250 => 'chemical/x-vamas-iso14976',
+      251 => 'chemical/x-vmd',
+      252 => 'chemical/x-xtel',
+      253 => 'chemical/x-xyz',
+      254 => 'image/gif',
+      255 => 'image/ief',
+      256 => 'image/jpeg',
+      257 => 'image/pcx',
+      258 => 'image/png',
+      259 => 'image/svg+xml',
+      260 => 'image/tiff',
+      261 => 'image/vnd.djvu',
+      262 => 'image/vnd.microsoft.icon',
+      263 => 'image/vnd.wap.wbmp',
+      264 => 'image/x-cmu-raster',
+      265 => 'image/x-coreldraw',
+      266 => 'image/x-coreldrawpattern',
+      267 => 'image/x-coreldrawtemplate',
+      268 => 'image/x-corelphotopaint',
+      269 => 'image/x-jg',
+      270 => 'image/x-jng',
+      271 => 'image/x-ms-bmp',
+      272 => 'image/x-photoshop',
+      273 => 'image/x-portable-anymap',
+      274 => 'image/x-portable-bitmap',
+      275 => 'image/x-portable-graymap',
+      276 => 'image/x-portable-pixmap',
+      277 => 'image/x-rgb',
+      278 => 'image/x-xbitmap',
+      279 => 'image/x-xpixmap',
+      280 => 'image/x-xwindowdump',
+      281 => 'message/rfc822',
+      282 => 'model/iges',
+      283 => 'model/mesh',
+      284 => 'model/vrml',
+      285 => 'text/calendar',
+      286 => 'text/css',
+      287 => 'text/csv',
+      288 => 'text/h323',
+      289 => 'text/html',
+      290 => 'text/iuls',
+      291 => 'text/mathml',
+      292 => 'text/plain',
+      293 => 'text/richtext',
+      294 => 'text/scriptlet',
+      295 => 'text/tab-separated-values',
+      296 => 'text/texmacs',
+      297 => 'text/vnd.sun.j2me.app-descriptor',
+      298 => 'text/vnd.wap.wml',
+      299 => 'text/vnd.wap.wmlscript',
+      300 => 'text/x-bibtex',
+      301 => 'text/x-boo',
+      302 => 'text/x-c++hdr',
+      303 => 'text/x-c++src',
+      304 => 'text/x-chdr',
+      305 => 'text/x-component',
+      306 => 'text/x-csh',
+      307 => 'text/x-csrc',
+      308 => 'text/x-diff',
+      309 => 'text/x-dsrc',
+      310 => 'text/x-haskell',
+      311 => 'text/x-java',
+      312 => 'text/x-literate-haskell',
+      313 => 'text/x-moc',
+      314 => 'text/x-pascal',
+      315 => 'text/x-pcs-gcd',
+      316 => 'text/x-perl',
+      317 => 'text/x-python',
+      318 => 'text/x-setext',
+      319 => 'text/x-sh',
+      320 => 'text/x-tcl',
+      321 => 'text/x-tex',
+      322 => 'text/x-vcalendar',
+      323 => 'text/x-vcard',
+      324 => 'video/3gpp',
+      325 => 'video/dl',
+      326 => 'video/dv',
+      327 => 'video/fli',
+      328 => 'video/gl',
+      329 => 'video/mp4',
+      330 => 'video/mpeg',
+      331 => 'video/ogg',
+      332 => 'video/quicktime',
+      333 => 'video/vnd.mpegurl',
+      347 => 'video/x-flv',
+      334 => 'video/x-la-asf',
+      335 => 'video/x-mng',
+      336 => 'video/x-ms-asf',
+      337 => 'video/x-ms-wm',
+      338 => 'video/x-ms-wmv',
+      339 => 'video/x-ms-wmx',
+      340 => 'video/x-ms-wvx',
+      341 => 'video/x-msvideo',
+      342 => 'video/x-sgi-movie',
+      343 => 'x-conference/x-cooltalk',
+      344 => 'x-epoc/x-sisx-app',
+      345 => 'x-world/x-vrml',
+    ),
+
+    // Extensions added to this list MUST be lower-case.
+    'extensions' => array(
+      'ez' => 0,
+      'atom' => 1,
+      'atomcat' => 2,
+      'atomsrv' => 3,
+      'cap' => 4,
+      'pcap' => 4,
+      'cu' => 5,
+      'tsp' => 6,
+      'hta' => 7,
+      'jar' => 8,
+      'ser' => 9,
+      'class' => 10,
+      'hqx' => 11,
+      'nb' => 12,
+      'mdb' => 13,
+      'dot' => 14,
+      'doc' => 14,
+      'bin' => 15,
+      'oda' => 16,
+      'ogg' => 17,
+      'ogx' => 17,
+      'pdf' => 18,
+      'key' => 19,
+      'pgp' => 20,
+      'prf' => 21,
+      'eps' => 22,
+      'ai' => 22,
+      'ps' => 22,
+      'rar' => 23,
+      'rdf' => 24,
+      'rss' => 25,
+      'rtf' => 26,
+      'smi' => 27,
+      'smil' => 27,
+      'cdy' => 28,
+      'kml' => 29,
+      'kmz' => 30,
+      'xul' => 31,
+      'xlb' => 32,
+      'xlt' => 32,
+      'xls' => 32,
+      'xlam' => 33,
+      'xlsb' => 34,
+      'xlsm' => 35,
+      'xltm' => 36,
+      'cat' => 37,
+      'stl' => 38,
+      'pps' => 39,
+      'ppt' => 39,
+      'ppam' => 40,
+      'pptm' => 41,
+      'ppsm' => 42,
+      'potm' => 43,
+      'docm' => 44,
+      'dotm' => 45,
+      'xps' => 46,
+      'odc' => 47,
+      'odb' => 48,
+      'odf' => 49,
+      'odg' => 50,
+      'otg' => 51,
+      'odi' => 52,
+      'odp' => 53,
+      'otp' => 54,
+      'ods' => 55,
+      'ots' => 56,
+      'odt' => 57,
+      'odm' => 58,
+      'ott' => 59,
+      'oth' => 60,
+      'pptx' => 61,
+      'ppsx' => 62,
+      'potx' => 63,
+      'xlsx' => 64,
+      'xltx' => 65,
+      'docx' => 66,
+      'dotx' => 67,
+      'cod' => 68,
+      'mmf' => 69,
+      'sdc' => 70,
+      'sds' => 71,
+      'sda' => 72,
+      'sdd' => 73,
+      'sdw' => 75,
+      'sgl' => 76,
+      'sxc' => 77,
+      'stc' => 78,
+      'sxd' => 79,
+      'std' => 80,
+      'sxi' => 81,
+      'sti' => 82,
+      'sxm' => 83,
+      'sxw' => 84,
+      'sxg' => 85,
+      'stw' => 86,
+      'sis' => 87,
+      'vsd' => 88,
+      'wbxml' => 89,
+      'wmlc' => 90,
+      'wmlsc' => 91,
+      'wpd' => 92,
+      'wp5' => 93,
+      'wk' => 94,
+      '7z' => 95,
+      'abw' => 96,
+      'dmg' => 97,
+      'bcpio' => 98,
+      'torrent' => 99,
+      'cab' => 100,
+      'cbr' => 101,
+      'cbz' => 102,
+      'cdf' => 103,
+      'vcd' => 104,
+      'pgn' => 105,
+      'cpio' => 106,
+      'udeb' => 107,
+      'deb' => 107,
+      'dir' => 108,
+      'dxr' => 108,
+      'dcr' => 108,
+      'dms' => 109,
+      'wad' => 110,
+      'dvi' => 111,
+      'flac' => 112,
+      'pfa' => 113,
+      'pfb' => 113,
+      'pcf' => 113,
+      'gsf' => 113,
+      'pcf.z' => 113,
+      'mm' => 114,
+      'spl' => 115,
+      'gnumeric' => 116,
+      'sgf' => 117,
+      'gcf' => 118,
+      'taz' => 119,
+      'gtar' => 119,
+      'tgz' => 119,
+      'hdf' => 120,
+      'rhtml' => 121,
+      'phtml' => 122,
+      'pht' => 122,
+      'php' => 122,
+      'phps' => 123,
+      'php3' => 124,
+      'php3p' => 125,
+      'php4' => 126,
+      'ica' => 127,
+      'ins' => 128,
+      'isp' => 128,
+      'iii' => 129,
+      'iso' => 130,
+      'jnlp' => 131,
+      'js' => 132,
+      'jmz' => 133,
+      'chrt' => 134,
+      'kil' => 135,
+      'skp' => 136,
+      'skd' => 136,
+      'skm' => 136,
+      'skt' => 136,
+      'kpr' => 137,
+      'kpt' => 137,
+      'ksp' => 138,
+      'kwd' => 139,
+      'kwt' => 139,
+      'latex' => 140,
+      'lha' => 141,
+      'lyx' => 142,
+      'lzh' => 143,
+      'lzx' => 144,
+      'maker' => 145,
+      'frm' => 145,
+      'frame' => 145,
+      'fm' => 145,
+      'book' => 145,
+      'fb' => 145,
+      'fbdoc' => 145,
+      'mif' => 146,
+      'wmd' => 147,
+      'wmz' => 148,
+      'dll' => 149,
+      'bat' => 149,
+      'exe' => 149,
+      'com' => 149,
+      'msi' => 150,
+      'nc' => 151,
+      'pac' => 152,
+      'nwc' => 153,
+      'o' => 154,
+      'oza' => 155,
+      'p7r' => 156,
+      'crl' => 157,
+      'pyo' => 158,
+      'pyc' => 158,
+      'qtl' => 159,
+      'rpm' => 160,
+      'shar' => 161,
+      'swf' => 162,
+      'swfl' => 162,
+      'sitx' => 163,
+      'sit' => 163,
+      'sv4cpio' => 164,
+      'sv4crc' => 165,
+      'tar' => 166,
+      'gf' => 168,
+      'pk' => 169,
+      'texi' => 170,
+      'texinfo' => 170,
+      'sik' => 171,
+      '~' => 171,
+      'bak' => 171,
+      '%' => 171,
+      'old' => 171,
+      't' => 172,
+      'roff' => 172,
+      'tr' => 172,
+      'man' => 173,
+      'me' => 174,
+      'ms' => 175,
+      'ustar' => 176,
+      'src' => 177,
+      'wz' => 178,
+      'crt' => 179,
+      'xcf' => 180,
+      'fig' => 181,
+      'xpi' => 182,
+      'xht' => 183,
+      'xhtml' => 183,
+      'xml' => 184,
+      'xsl' => 184,
+      'zip' => 185,
+      'au' => 186,
+      'snd' => 186,
+      'mid' => 187,
+      'midi' => 187,
+      'kar' => 187,
+      'mpega' => 188,
+      'mpga' => 188,
+      'm4a' => 188,
+      'mp3' => 188,
+      'mp2' => 188,
+      'oga' => 189,
+      'spx' => 189,
+      'sid' => 190,
+      'aif' => 191,
+      'aiff' => 191,
+      'aifc' => 191,
+      'gsm' => 192,
+      'm3u' => 193,
+      'wax' => 194,
+      'wma' => 195,
+      'rm' => 196,
+      'ram' => 196,
+      'ra' => 197,
+      'pls' => 198,
+      'sd2' => 199,
+      'wav' => 200,
+      'alc' => 201,
+      'cac' => 202,
+      'cache' => 202,
+      'csf' => 203,
+      'cascii' => 204,
+      'cbin' => 204,
+      'ctab' => 204,
+      'cdx' => 205,
+      'cer' => 206,
+      'c3d' => 207,
+      'chm' => 208,
+      'cif' => 209,
+      'cmdf' => 210,
+      'cml' => 211,
+      'cpa' => 212,
+      'bsd' => 213,
+      'csml' => 214,
+      'csm' => 214,
+      'ctx' => 215,
+      'cxf' => 216,
+      'cef' => 216,
+      'emb' => 217,
+      'embl' => 217,
+      'spc' => 218,
+      'gam' => 219,
+      'inp' => 219,
+      'gamin' => 219,
+      'fchk' => 220,
+      'fch' => 220,
+      'cub' => 221,
+      'gau' => 222,
+      'gjf' => 222,
+      'gjc' => 222,
+      'gal' => 223,
+      'gcg' => 224,
+      'gen' => 225,
+      'hin' => 226,
+      'istr' => 227,
+      'ist' => 227,
+      'dx' => 228,
+      'jdx' => 228,
+      'kin' => 229,
+      'mcm' => 230,
+      'mmd' => 231,
+      'mmod' => 231,
+      'mol' => 232,
+      'rd' => 233,
+      'rxn' => 234,
+      'sdf' => 235,
+      'sd' => 235,
+      'tgf' => 236,
+      'mcif' => 237,
+      'mol2' => 238,
+      'b' => 239,
+      'gpt' => 240,
+      'mopcrt' => 241,
+      'zmt' => 241,
+      'mpc' => 241,
+      'dat' => 241,
+      'mop' => 241,
+      'moo' => 242,
+      'mvb' => 243,
+      'prt' => 244,
+      'aso' => 245,
+      'val' => 245,
+      'asn' => 246,
+      'ent' => 247,
+      'pdb' => 247,
+      'ros' => 248,
+      'sw' => 249,
+      'vms' => 250,
+      'vmd' => 251,
+      'xtel' => 252,
+      'xyz' => 253,
+      'gif' => 254,
+      'ief' => 255,
+      'jpeg' => 256,
+      'jpe' => 256,
+      'jpg' => 256,
+      'pcx' => 257,
+      'png' => 258,
+      'svgz' => 259,
+      'svg' => 259,
+      'tif' => 260,
+      'tiff' => 260,
+      'djvu' => 261,
+      'djv' => 261,
+      'ico' => 262,
+      'wbmp' => 263,
+      'ras' => 264,
+      'cdr' => 265,
+      'pat' => 266,
+      'cdt' => 267,
+      'cpt' => 268,
+      'art' => 269,
+      'jng' => 270,
+      'bmp' => 271,
+      'psd' => 272,
+      'pnm' => 273,
+      'pbm' => 274,
+      'pgm' => 275,
+      'ppm' => 276,
+      'rgb' => 277,
+      'xbm' => 278,
+      'xpm' => 279,
+      'xwd' => 280,
+      'eml' => 281,
+      'igs' => 282,
+      'iges' => 282,
+      'silo' => 283,
+      'msh' => 283,
+      'mesh' => 283,
+      'icz' => 285,
+      'ics' => 285,
+      'css' => 286,
+      'csv' => 287,
+      '323' => 288,
+      'html' => 289,
+      'htm' => 289,
+      'shtml' => 289,
+      'uls' => 290,
+      'mml' => 291,
+      'txt' => 292,
+      'pot' => 292,
+      'text' => 292,
+      'asc' => 292,
+      'rtx' => 293,
+      'wsc' => 294,
+      'sct' => 294,
+      'tsv' => 295,
+      'ts' => 296,
+      'tm' => 296,
+      'jad' => 297,
+      'wml' => 298,
+      'wmls' => 299,
+      'bib' => 300,
+      'boo' => 301,
+      'hpp' => 302,
+      'hh' => 302,
+      'h++' => 302,
+      'hxx' => 302,
+      'cxx' => 303,
+      'cc' => 303,
+      'cpp' => 303,
+      'c++' => 303,
+      'h' => 304,
+      'htc' => 305,
+      'csh' => 306,
+      'c' => 307,
+      'patch' => 308,
+      'diff' => 308,
+      'd' => 309,
+      'hs' => 310,
+      'java' => 311,
+      'lhs' => 312,
+      'moc' => 313,
+      'pas' => 314,
+      'p' => 314,
+      'gcd' => 315,
+      'pm' => 316,
+      'pl' => 316,
+      'py' => 317,
+      'etx' => 318,
+      'sh' => 319,
+      'tk' => 320,
+      'tcl' => 320,
+      'cls' => 321,
+      'ltx' => 321,
+      'sty' => 321,
+      'tex' => 321,
+      'vcs' => 322,
+      'vcf' => 323,
+      '3gp' => 324,
+      'dl' => 325,
+      'dif' => 326,
+      'dv' => 326,
+      'fli' => 327,
+      'gl' => 328,
+      'mp4' => 329,
+      'f4v' => 329,
+      'f4p' => 329,
+      'mpe' => 330,
+      'mpeg' => 330,
+      'mpg' => 330,
+      'ogv' => 331,
+      'qt' => 332,
+      'mov' => 332,
+      'mxu' => 333,
+      'lsf' => 334,
+      'lsx' => 334,
+      'mng' => 335,
+      'asx' => 336,
+      'asf' => 336,
+      'wm' => 337,
+      'wmv' => 338,
+      'wmx' => 339,
+      'wvx' => 340,
+      'avi' => 341,
+      'movie' => 342,
+      'ice' => 343,
+      'sisx' => 344,
+      'wrl' => 345,
+      'vrm' => 345,
+      'vrml' => 345,
+      'f4a' => 346,
+      'f4b' => 346,
+      'flv' => 347,
+    ),
+  );
+}
+
+/**
+ * file_check_directory() doesn't support creating directory trees.
+ */
+function _cdn_basic_farfuture_create_directory_structure($path) {
+  // Create the directory structure in which the file will be stored. Because
+  // it's nested, file_check_directory() can't do this in one run.
+  $parts = explode('/', $path);
+  for ($i = 0; $i < count($parts); $i++) {
+    $directory = implode('/', array_slice($parts, 0, $i + 1));
+    file_check_directory(file_create_path($directory), FILE_CREATE_DIRECTORY | FILE_MODIFY_PERMISSIONS);
+  }
+}
Index: cdn.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/cdn/cdn.module,v
retrieving revision 1.76
diff -u -F '^f' -r1.76 cdn.module
--- cdn.module	23 Nov 2010 14:44:59 -0000	1.76
+++ cdn.module	9 Dec 2010 17:51:00 -0000
@@ -39,6 +39,13 @@
 
 // Variables for basic mode.
 define('CDN_BASIC_MAPPING_VARIABLE', 'cdn_basic_mapping');
+define('CDN_BASIC_FARFUTURE_VARIABLE', 'cdn_farfuture_status');
+define('CDN_BASIC_FARFUTURE_DEFAULT', TRUE);
+define('CDN_BASIC_FARFUTURE_EXTENSIONS_VARIABLE', "cdn_farfuture_extensions");
+define('CDN_BASIC_FARFUTURE_EXTENSIONS_DEFAULT', "css\njs\nsvg\nico\ngif\njpg\njpeg\npng\notf\nttf\neot\nwoff\nflv\nswf");
+define('CDN_BASIC_FARFUTURE_GZIP_EXTENSIONS', "css\njs\nico\nsvg\notf\nttf\neot");
+define('CDN_BASIC_FARFUTURE_GZIP_DIRECTORY', "cdn/farfuture/gzip");
+define('CDN_BASIC_FARFUTURE_REMOVE_HEADERS', "Set-Cookie");
 
 // Variables for advanced mode.
 define('CDN_ADVANCED_SYNCED_FILES_DB_VARIABLE', 'cdn_advanced_synced_files_db');
@@ -59,6 +66,7 @@
 function cdn_file_url_alter(&$path) {
   $status                = variable_get(CDN_STATUS_VARIABLE, CDN_DISABLED);
   $mode                  = variable_get(CDN_MODE_VARIABLE, CDN_MODE_BASIC);
+  $farfuture             = variable_get(CDN_BASIC_FARFUTURE_VARIABLE, CDN_BASIC_FARFUTURE_DEFAULT);
   $stats                 = variable_get(CDN_STATS_VARIABLE, FALSE) && user_access(CDN_PERM_ACCESS_STATS);
   $file_path_blacklist   = variable_get(CDN_EXCEPTION_FILE_PATH_BLACKLIST_VARIABLE, CDN_EXCEPTION_FILE_PATH_BLACKLIST_DEFAULT);
   $file_path_whitelist   = variable_get(CDN_EXCEPTION_FILE_PATH_WHITELIST_VARIABLE, CDN_EXCEPTION_FILE_PATH_WHITELIST_DEFAULT);
@@ -90,7 +98,7 @@ function cdn_file_url_alter(&$path) {
         return;
       }
     }
-  
+
     // If the current Drupal path matches one of the blacklisted Drupal paths,
     // return immediately.
     if (drupal_match_path($_GET['q'], $drupal_path_blacklist)) {
@@ -107,6 +115,13 @@ function cdn_file_url_alter(&$path) {
       $start = microtime();
     }
 
+    // Alter the file path when using Origin Pull mode and using that mode's
+    // Far Future setting.
+    if ($mode == CDN_MODE_BASIC && $farfuture) {
+      $path_before_farfuture = $path;
+      $path = 'cdn/farfuture/' . filemtime($path) . '/' . $path;
+    }
+
     // Load the include file that contains the logic for the mode that's
     // currently enabled.
     cdn_load_include(($mode == CDN_MODE_BASIC) ? 'basic' : 'advanced');
@@ -152,7 +167,8 @@ function cdn_file_url_alter(&$path) {
     // If the user can access it, add this to the per-page statistics.
     if ($stats) {
       $end = microtime();
-      _cdn_devel_page_stats($path, $cdn_url, $server, $end - $start);
+      $source_path = ($mode == CDN_MODE_BASIC && $farfuture) ? $path_before_farfuture : $path;
+      _cdn_devel_page_stats($source_path, $cdn_url, $server, $end - $start);
     }
 
     // Override the path with the corresponding CDN URL, *if* the file is
@@ -160,6 +176,14 @@ function cdn_file_url_alter(&$path) {
     if ($cdn_url !== FALSE) {
       $path = $cdn_url;
     }
+    else {
+      // If the file is not available on the CDN and Origin Pull mode's Far
+      // Future setting is enabled, then don't serve it using CDN module's
+      // non-scalable Far Future functionality, but using Drupal's default.
+      if ($mode == CDN_MODE_BASIC && $farfuture) {
+        $path = $path_before_farfuture;
+      }
+    }
   }
 }
 
@@ -215,6 +239,14 @@ function cdn_menu() {
     'file'             => 'cdn.stats.inc',
   );
 
+  $items['cdn/farfuture'] = array(
+    'title'            => 'Download a far futured file',
+    'access callback'  => TRUE,
+    'page callback'    => 'cdn_basic_farfuture_download',
+    'type'             => MENU_CALLBACK,
+    'file'             => 'cdn.basic.farfuture.inc',
+  );
+
   return $items;
 }
 
@@ -252,7 +284,6 @@ function cdn_nodeapi(&$node, $op, $a3 = 
   }
 }
 
-
 /**
  * Implementation of hook_theme().
  */
