Index: includes/common.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/common.inc,v
retrieving revision 1.945
diff -u -F^f -r1.945 common.inc
--- includes/common.inc 29 Jul 2009 06:39:33 -0000 1.945
+++ includes/common.inc 29 Jul 2009 18:04:47 -0000
@@ -2496,15 +2496,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 .= '' . "\n";
+ $no_module_preprocess .= '' . "\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.
elseif (!$preprocess && $type == 'theme') {
- $no_theme_preprocess .= '' . "\n";
+ $no_theme_preprocess .= '' . "\n";
}
else {
- $output .= '' . "\n";
+ $output .= '' . "\n";
}
}
}
@@ -2516,7 +2516,7 @@ function drupal_get_css($css = NULL) {
// starting with "ad*".
$filename = 'css_' . md5(serialize($types) . $query_string) . '.css';
$preprocess_file = drupal_build_css_cache($types, $filename);
- $output .= '' . "\n";
+ $output .= '' . "\n";
}
}
if (!empty($no_inline_preprocess)) {
@@ -2962,7 +2962,7 @@ function drupal_get_js($scope = 'header'
case 'file':
if (!$item['preprocess'] || !$is_writable || !$preprocess_js) {
- $no_preprocess .= '\n";
+ $no_preprocess .= '\n";
}
else {
$files[$item['data']] = $item;
@@ -2982,7 +2982,7 @@ function drupal_get_js($scope = 'header'
// starting with "ad*".
$filename = 'js_' . md5(serialize($files) . $query_string) . '.js';
$preprocess_file = drupal_build_js_cache($files, $filename);
- $preprocessed .= '' . "\n";
+ $preprocessed .= '' . "\n";
}
// Keep the order of JS files consistent as some are preprocessed and others are not.
Index: includes/file.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/file.inc,v
retrieving revision 1.178
diff -u -F^f -r1.178 file.inc
--- includes/file.inc 27 Jul 2009 19:53:17 -0000 1.178
+++ includes/file.inc 29 Jul 2009 18:04:48 -0000
@@ -301,18 +301,60 @@ function file_stream_wrapper_get_instanc
/**
* Create the download path to a file.
*
- * @param $path A string containing the path of the file to generate URL for.
- * @return A string containing a URL that can be used to download the file.
+ * There are two kinds of files:
+ * - "created files", i.e. those in the files directory (which is stored in
+ * the file_directory_path variable and can be retrieved using
+ * file_directory_path()). These are files that have either been uploaded by
+ * users or were generated automatically (for example through CSS
+ * aggregation).
+ * - "shipped files", i.e. those outside of the files directory, which ship as
+ * part of Drupal core or contributed modules or themes.
+ * When a hook_file_url_alter() function is defined and overrides the path,
+ * then that rewritten path is used instead of creating a URL for the file at
+ * the given path.
+ *
+ * @param $path
+ * A string containing the Drupal path (i.e. path relative to the Drupal
+ * root directory) of the file to generate the URL for.
+ * @return
+ * A string containing a URL that can be used to download the file.
*/
function file_create_url($path) {
- // Strip file_directory_path from $path. We only include relative paths in
- // URLs.
- $path = file_directory_strip($path);
- switch (variable_get('file_downloads', FILE_DOWNLOADS_PUBLIC)) {
- case FILE_DOWNLOADS_PUBLIC:
- return $GLOBALS['base_url'] . '/' . file_directory_path() . '/' . str_replace('\\', '/', $path);
- case FILE_DOWNLOADS_PRIVATE:
- return url('system/files/' . $path, array('absolute' => TRUE));
+ // Clean up Windows paths.
+ $old_path = $path = str_replace('\\', '/', $path);
+
+ drupal_alter('file_url', $path);
+
+ // If any module has altered the path, then return the alteration.
+ if ($path != $old_path) {
+ return $path;
+ }
+
+ // Otherwise serve the file from Drupal's web server. This point will only
+ // be reached when either no custom_file_url_rewrite() function has been
+ // defined, or when that function returned FALSE, thereby indicating that it
+ // cannot (or doesn't wish to) rewrite the URL. This is typically because
+ // the file doesn't match some conditions to be served from a CDN or static
+ // file server, or because the file has not yet been synced to the CDN or
+ // static file server.
+
+ // Shipped files.
+ if (strpos($path, file_directory_path() . '/') !== 0) {
+ return base_path() . $path;
+ }
+ // Created files.
+ else {
+ switch (variable_get('file_downloads', FILE_DOWNLOADS_PUBLIC)) {
+ case FILE_DOWNLOADS_PUBLIC:
+ return $GLOBALS['base_url'] . '/' . $path;
+ case FILE_DOWNLOADS_PRIVATE:
+ // Strip file_directory_path from $path. Private downloads' URLs are
+ // rewritten to be served relatively to system/files (which is a menu
+ // callback that streams the file) instead of relatively to the file
+ // directory path.
+ $path = file_directory_strip($path);
+ return url('system/files/' . $path, array('absolute' => TRUE));
+ }
}
}
Index: includes/form.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/form.inc,v
retrieving revision 1.354
diff -u -F^f -r1.354 form.inc
--- includes/form.inc 28 Jul 2009 12:13:46 -0000 1.354
+++ includes/form.inc 29 Jul 2009 18:04:50 -0000
@@ -2452,7 +2452,7 @@ function theme_image_button($element) {
(!empty($element['#value']) ? ('value="' . check_plain($element['#value']) . '" ') : '') .
'id="' . $element['#id'] . '" ' .
drupal_attributes($element['#attributes']) .
- ' src="' . base_path() . $element['#src'] . '" ' .
+ ' src="' . file_create_url($element['#src']) . '" ' .
(!empty($element['#title']) ? 'alt="' . check_plain($element['#title']) . '" title="' . check_plain($element['#title']) . '" ' : '' ) .
"/>\n";
}
Index: includes/theme.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/theme.inc,v
retrieving revision 1.500
diff -u -F^f -r1.500 theme.inc
--- includes/theme.inc 27 Jul 2009 18:38:35 -0000 1.500
+++ includes/theme.inc 29 Jul 2009 18:04:52 -0000
@@ -1097,24 +1097,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_create_url(dirname($theme_object->filename) . '/logo.png');
}
elseif ($settings['logo_path']) {
- $settings['logo'] = base_path() . $settings['logo_path'];
+ $settings['logo'] = file_create_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_create_url($favicon);
}
else {
- $settings['favicon'] = base_path() . 'misc/favicon.ico';
+ $settings['favicon'] = file_create_url('misc/favicon.ico');
}
}
elseif ($settings['favicon_path']) {
- $settings['favicon'] = base_path() . $settings['favicon_path'];
+ $settings['favicon'] = file_create_url($settings['favicon_path']);
}
else {
$settings['toggle_favicon'] = FALSE;
@@ -1338,7 +1338,7 @@ function theme_links($links, $attributes
function theme_image($path, $alt = '', $title = '', $attributes = array(), $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);
+ $url = (url($path) == $path) ? $path : file_create_url($path);
return '
';
}
}
Index: modules/simpletest/tests/file.test
===================================================================
RCS file: /cvs/drupal/drupal/modules/simpletest/tests/file.test,v
retrieving revision 1.37
diff -u -F^f -r1.37 file.test
--- modules/simpletest/tests/file.test 27 Jul 2009 19:53:18 -0000 1.37
+++ modules/simpletest/tests/file.test 29 Jul 2009 18:04:54 -0000
@@ -1913,6 +1913,25 @@ function file_test_file_scan_callback_re
}
/**
+ * Test the generating of public file URLs.
+ */
+ function testPublicFileURL() {
+ // Set file downloads to public.
+ variable_set('file_downloads', FILE_DOWNLOADS_PUBLIC);
+
+ // Test generating an URL to a created file.
+ $file = $this->createFile();
+ $url = file_create_url($file->filepath);
+ $this->assertEqual($GLOBALS['base_url'] . '/' . file_directory_path() . '/' . $file->filename, $url, t('Correctly generated a URL for a created file.'));
+
+ // Test generating an URL to a shipped file (i.e. a file that is part of
+ // Drupal core, a module or a theme, for example a JavaScript file).
+ $file = 'misc/jquery.js';
+ $url = file_create_url($file);
+ $this->assertEqual(base_path() . $file, $url, t('Correctly generated a URL for a shipped file.'));
+ }
+
+ /**
* Test the private file transfer system.
*/
function testPrivateFileTransfer() {
@@ -1921,7 +1940,7 @@ function file_test_file_scan_callback_re
// Create a file.
$file = $this->createFile();
- $url = file_create_url($file->filename);
+ $url = file_create_url($file->filepath);
// Set file_test access header to allow the download.
file_test_set_return('download', array('x-foo' => 'Bar'));
@@ -1943,6 +1962,45 @@ function file_test_file_scan_callback_re
}
/**
+ * Tests for file URL rewriting.
+ */
+class FileURLRewritingTest extends FileDownloadTest {
+ public static function getInfo() {
+ return array(
+ 'name' => t('File URL rewriting'),
+ 'description' => t('Tests for file URL rewriting.'),
+ 'group' => t('File'),
+ );
+ }
+
+ function setUp() {
+ DrupalWebTestCase::setUp('file_test', 'file_url_test');
+ }
+
+ /**
+ * Test the generating of rewritten public file URLs.
+ */
+ function testPublicFileURL() {
+ // Set file downloads to public.
+ variable_set('file_downloads', FILE_DOWNLOADS_PUBLIC);
+
+ // Test generating an URL to a created file.
+ $file = $this->createFile();
+ $url = file_create_url($file->filepath);
+ $this->assertEqual(FILE_URL_TEST_CDN_1 . '/' . $file->filepath, $url, t('Correctly generated a URL for a created file.'));
+
+ // Test generating an URL to a shipped file (i.e. a file that is part of
+ // Drupal core, a module or a theme, for example a JavaScript file).
+ $file = 'misc/jquery.js';
+ $url = file_create_url($file);
+ $this->assertEqual(FILE_URL_TEST_CDN_1 . '/' . $file, $url, t('Correctly generated a URL for a shipped file.'));
+ $file = 'misc/favicon.ico';
+ $url = file_create_url($file);
+ $this->assertEqual(FILE_URL_TEST_CDN_2 . '/' . $file, $url, t('Correctly generated a URL for a shipped file.'));
+ }
+}
+
+/**
* Tests for file_munge_filename() and file_unmunge_filename().
*/
class FileNameMungingTest extends FileTestCase {
Index: modules/simpletest/tests/file_url_test.info
===================================================================
RCS file: modules/simpletest/tests/file_url_test.info
diff -N modules/simpletest/tests/file_url_test.info
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ modules/simpletest/tests/file_url_test.info 29 Jul 2009 18:04:54 -0000
@@ -0,0 +1,8 @@
+; $Id$
+name = "File URL test"
+description = "Support module for file URL rewrite tests."
+package = Testing
+version = VERSION
+core = 7.x
+files[] = file_url_test.module
+hidden = TRUE
Index: modules/simpletest/tests/file_url_test.module
===================================================================
RCS file: modules/simpletest/tests/file_url_test.module
diff -N modules/simpletest/tests/file_url_test.module
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ modules/simpletest/tests/file_url_test.module 29 Jul 2009 18:04:55 -0000
@@ -0,0 +1,37 @@
+uid == 1) {
+ return;
+ }
+
+ $cdn1 = 'http://cdn1.example.com';
+ $cdn2 = 'http://cdn2.example.com';
+ $cdn_extensions = array('css', 'js', 'gif', 'jpg', 'jpeg', 'png');
+
+ // Most CDN's don't support private file transfers without a lot of hassle,
+ // so don't support this in the common case.
+ if (variable_get('file_downloads', FILE_DOWNLOADS_PUBLIC) == FILE_DOWNLOADS_PRIVATE) {
+ return;
+ }
+
+ // Serve files without extension and files with one of the CDN extensions
+ // from CDN 1, all others from CDN 2.
+ $pathinfo = pathinfo($path);
+ if (!array_key_exists('extension', $pathinfo) || in_array($pathinfo['extension'], $cdn_extensions)) {
+ $path = $cdn1 . '/' . $path;
+ }
+ else {
+ $path = $cdn2 . '/' . $path;
+ }
+}
+
+/**
* Load additional information into file objects.
*
* file_load_multiple() calls this hook to allow modules to load
Index: themes/garland/template.php
===================================================================
RCS file: /cvs/drupal/drupal/themes/garland/template.php,v
retrieving revision 1.23
diff -u -F^f -r1.23 template.php
--- themes/garland/template.php 28 Jul 2009 10:09:25 -0000 1.23
+++ themes/garland/template.php 29 Jul 2009 18:04:56 -0000
@@ -79,9 +79,9 @@ function garland_node_submitted($node) {
function garland_get_ie_styles() {
global $language;
- $ie_styles = '' . "\n";
+ $ie_styles = '' . "\n";
if ($language->direction == LANGUAGE_RTL) {
- $ie_styles .= ' ' . "\n";
+ $ie_styles .= ' ' . "\n";
}
return $ie_styles;