Index: includes/common.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/common.inc,v
retrieving revision 1.611.2.15
diff -u -F^f -r1.611.2.15 common.inc
--- includes/common.inc	22 Jan 2008 09:36:49 -0000	1.611.2.15
+++ includes/common.inc	26 Jan 2008 22:08:15 -0000
@@ -1379,6 +1379,56 @@ function base_path() {
 }
 
 /**
+ * Returns a rewritten file URL. Allows you to serve files from different
+ * servers than the server on which Drupal is hosted.
+ *
+ * @param $file_path
+ *   Path to a file, relative to the root directory. E.g.: "misc/jquery.js".
+ * @param $absolute_url
+ *   Whether to generate an absolute URL or not.
+ * @return
+ *   A valid file URL.
+ */
+function file_url($file_path, $absolute_url = FALSE) {
+  static $modules;
+  $file_url = FALSE;
+
+  if (!isset($modules)) {
+    $modules = array();
+    foreach (module_implements('file_server') as $module) {
+      $modules[] = array(
+        'module' => $module,
+        'weight' => variable_get("file_server_{$module}_weight", 0),
+      );
+    }
+
+    // Sort file server types by weight.
+    uasort($modules, create_function('$a, $b', 'return $a["weight"] > $b["weight"];'));
+  }
+  
+  // Try the first preferred file server to check if it can serve the file.
+  // Then try the second, and so on.
+  foreach ($modules as $module) {
+    $file_url = module_invoke($module['module'], 'file_server', 'url', $file_path, $absolute_url);
+
+    // If the URL rewriting function sucesfully generated a URL, we can stop
+    // trying to find a server that can serve the file.
+    if ($file_url) {
+      break;
+    }
+  }
+  
+  // Always fall back to Drupal's default file server, to guarantee a working
+  // file URL.
+  if (!$file_url) {
+    $prefix = ($absolute_url) ? $GLOBALS['base_url'] .'/' : base_path();
+    $file_url = $prefix . $file_path;
+  }
+
+  return $file_url;
+}
+
+/**
  * Provide a substitute clone() function for PHP4.
  */
 function drupal_clone($object) {
@@ -1474,15 +1524,15 @@ function drupal_get_css($css = NULL) {
           // If a CSS file is not to be preprocessed and it's a module CSS file, it needs to *always* appear at the *top*,
           // regardless of whether preprocessing is on or off.
           if (!$preprocess && $type == 'module') {
-            $no_module_preprocess .= '<style type="text/css" media="'. $media .'">@import "'. base_path() . $file .'";</style>' ."\n";
+            $no_module_preprocess .= '<style type="text/css" media="'. $media .'">@import "'. file_url($file) .'";</style>' ."\n";
           }
           // If a CSS file is not to be preprocessed and it's a theme CSS file, it needs to *always* appear at the *bottom*,
           // regardless of whether preprocessing is on or off.
           else if (!$preprocess && $type == 'theme') {
-            $no_theme_preprocess .= '<style type="text/css" media="'. $media .'">@import "'. base_path() . $file .'";</style>' ."\n";
+            $no_theme_preprocess .= '<style type="text/css" media="'. $media .'">@import "'. file_url($file) .'";</style>' ."\n";
           }
           else {
-            $output .= '<style type="text/css" media="'. $media .'">@import "'. base_path() . $file .'";</style>' ."\n";
+            $output .= '<style type="text/css" media="'. $media .'">@import "'. file_url($file) .'";</style>' ."\n";
           }
         }
       }
@@ -1491,7 +1541,7 @@ function drupal_get_css($css = NULL) {
     if ($is_writable && $preprocess_css) {
       $filename = md5(serialize($types)) .'.css';
       $preprocess_file = drupal_build_css_cache($types, $filename);
-      $output .= '<style type="text/css" media="'. $media .'">@import "'. base_path() . $preprocess_file .'";</style>'. "\n";
+      $output .= '<style type="text/css" media="'. $media .'">@import "'. file_url($preprocess_file) .'";</style>'. "\n";
     }
   }
 
@@ -1526,7 +1576,7 @@ function drupal_build_css_cache($types, 
           // Return the path to where this CSS file originated from, stripping off the name of the file at the end of the path.
           $path = base_path() . substr($file, 0, strrpos($file, '/')) .'/';
           // Wraps all @import arguments in url().
-          $contents = preg_replace('/@import\s+(?!url)[\'"]?(\S*)\b[\'"]?/i', '@import url("\1")', $contents);
+          $contents = preg_replace('/@import\s+(?!url)[\'"]?(\S*)\b[\'"]?/i', '@import url("\1")', $contents);          
           // Fix all paths within this CSS file, ignoring absolute paths.
           $data .= preg_replace('/url\(([\'"]?)(?![a-z]+:)/i', 'url(\1'. $path . '\2', $contents);
         }
@@ -1685,7 +1735,7 @@ function drupal_get_js($scope = 'header'
         break;
       default:
         foreach ($data as $path => $info) {
-          $output .= '<script type="text/javascript"'. ($info['defer'] ? ' defer="defer"' : '') .' src="'. check_url(base_path() . $path) . ($info['cache'] ? '' : '?'. time()) ."\"></script>\n";
+          $output .= '<script type="text/javascript"'. ($info['defer'] ? ' defer="defer"' : '') .' src="'. check_url(file_url($path)) . ($info['cache'] ? '' : '?'. time()) ."\"></script>\n";
         }
     }
   }
Index: includes/file.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/file.inc,v
retrieving revision 1.90.2.3
diff -u -F^f -r1.90.2.3 file.inc
--- includes/file.inc	7 Jan 2008 01:00:22 -0000	1.90.2.3
+++ includes/file.inc	26 Jan 2008 22:08:16 -0000
@@ -33,7 +33,7 @@ function file_create_url($path) {
   }
   switch (variable_get('file_downloads', FILE_DOWNLOADS_PUBLIC)) {
     case FILE_DOWNLOADS_PUBLIC:
-      return $GLOBALS['base_url'] .'/'. file_directory_path() .'/'. str_replace('\\', '/', $path);
+      return file_url(file_directory_path() .'/'. str_replace('\\', '/', $path), TRUE);
     case FILE_DOWNLOADS_PRIVATE:
       return url('system/files/'. $path, NULL, NULL, TRUE);
   }
Index: includes/theme.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/theme.inc,v
retrieving revision 1.337.2.2
diff -u -F^f -r1.337.2.2 theme.inc
--- includes/theme.inc	31 May 2007 05:52:42 -0000	1.337.2.2
+++ includes/theme.inc	26 Jan 2008 22:08:16 -0000
@@ -322,24 +322,24 @@ function theme_get_setting($setting_name
 
     if ($settings['toggle_logo']) {
       if ($settings['default_logo']) {
-        $settings['logo'] = base_path() . dirname($theme_object->filename) .'/logo.png';
+        $settings['logo'] = file_url(dirname($theme_object->filename) .'/logo.png');
       }
       elseif ($settings['logo_path']) {
-        $settings['logo'] = base_path() . $settings['logo_path'];
+        $settings['logo'] = file_url($settings['logo_path']);
       }
     }
 
     if ($settings['toggle_favicon']) {
       if ($settings['default_favicon']) {
         if (file_exists($favicon = dirname($theme_object->filename) .'/favicon.ico')) {
-          $settings['favicon'] = base_path() . $favicon;
+          $settings['favicon'] = file_url($favicon);
         }
         else {
-          $settings['favicon'] = base_path() . 'misc/favicon.ico';
+          $settings['favicon'] = file_url('misc/favicon.ico');
         }
       }
       elseif ($settings['favicon_path']) {
-        $settings['favicon'] = base_path() . $settings['favicon_path'];
+        $settings['favicon'] = file_url($settings['favicon_path']);
       }
       else {
         $settings['toggle_favicon'] = FALSE;
@@ -613,8 +613,7 @@ function theme_links($links, $attributes
 function theme_image($path, $alt = '', $title = '', $attributes = NULL, $getsize = TRUE) {
   if (!$getsize || (is_file($path) && (list($width, $height, $type, $image_attributes) = @getimagesize($path)))) {
     $attributes = drupal_attributes($attributes);
-    $url = (url($path) == $path) ? $path : (base_path() . $path);
-    return '<img src="'. check_url($url) .'" alt="'. check_plain($alt) .'" title="'. check_plain($title) .'" '. $image_attributes . $attributes .' />';
+    return '<img src="'. check_url(file_url($path)) .'" alt="'. check_plain($alt) .'" title="'. check_plain($title) .'" '. $image_attributes . $attributes .' />';
   }
 }
 
Index: modules/system/system.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/system/system.module,v
retrieving revision 1.440.2.28
diff -u -F^f -r1.440.2.28 system.module
--- modules/system/system.module	11 Jan 2008 00:47:17 -0000	1.440.2.28
+++ modules/system/system.module	26 Jan 2008 22:08:18 -0000
@@ -738,9 +738,69 @@ function system_file_system_settings() {
     '#description' => t('If you want any sort of access control on the downloading of files, this needs to be set to <em>private</em>. You can change this at any time, however all download URLs will change and there may be unexpected problems so it is not recommended.')
   );
 
+  $form['file_servers'] = array(
+    '#tree' => TRUE,
+    '#type' => 'fieldset',
+    '#title' => t('File servers'),
+    '#description' => t(
+      '<strong>This setting is for advanced users</strong>.<br />
+      Enables Drupal to serve files from any kind of file server. Drupal will
+      automatically fall back to file servers that are lower in the list.
+      <br />The web server Drupal is running on will always be used as the
+      default file server.'),
+    '#collapsible' => FALSE,
+  );
+
+  $modules = array();
+  foreach (module_implements('file_server', TRUE) as $module) {
+    $info = _module_parse_info_file(drupal_get_path('module', $module) ."/$module.info");
+    $file_server_info = module_invoke($module, 'file_server', 'info');
+
+    $modules[$module] = array(
+      'type' => $file_server_info['type'],
+      'module' => (!isset($file_server_info['configuration_page'])) ? $info['name'] : l($info['name'], $file_server_info['configuration_page']),
+      'weight' => variable_get("file_server_{$module}_weight", 0),
+    );
+  }
+
+  // Sort file server types by weight.
+  uasort($modules, create_function('$a, $b', 'return $a["weight"] > $b["weight"];'));
+
+  foreach ($modules as $module => $settings) {
+    $form['file_servers']['types'][$module] = array('#value' => $settings['type']);
+    $form['file_servers']['modules'][$module] = array('#value' => $settings['module']);
+    $form['file_servers']['weights']["file_server_{$module}_weight"] = array('#type' => 'weight', '#default_value' => $settings['weight']);
+  }
+
+  // The web server Drupal is running on is always available, and it's the
+  // default server, i.e. a server we can always fall back to. So it must
+  // always be at the bottom of the list and don't have a configurable weight.
+  $form['file_servers']['types']['drupal'] = array('#value' => t('Web server'));
+  $form['file_servers']['modules']['drupal'] = array('#value' => 'Drupal');
+  $form['file_servers']['weights']['file_server_drupal_weight'] = array('#value' => t('Default server'));
+
   return system_settings_form($form);
 }
 
+function theme_system_file_system_settings($form) {
+  $header = array(t('Type'), t('Module'), t('Weight'));
+  $rows = array();
+  foreach (element_children($form['file_servers']['modules']) as $module) {
+    // Don't take form control structures
+    if (is_array($form['file_servers']['modules'][$module])) {
+      $rows[] = array(
+        drupal_render($form['file_servers']['types'][$module]),
+        drupal_render($form['file_servers']['modules'][$module]),
+        drupal_render($form['file_servers']['weights']["file_server_{$module}_weight"]),
+      );
+    }
+  }
+
+  $form['file_servers']['#value'] = theme('table', $header, $rows);
+
+  return drupal_render($form);
+}
+
 function system_image_toolkit_settings() {
   $toolkits_available = image_get_available_toolkits();
   if (count($toolkits_available) > 1) {
