Index: .htaccess =================================================================== RCS file: /cvs/drupal/drupal/.htaccess,v retrieving revision 1.102 diff -u -u -p -r1.102 .htaccess --- .htaccess 9 Jun 2009 05:08:16 -0000 1.102 +++ .htaccess 15 Jun 2009 17:48:02 -0000 @@ -13,14 +13,23 @@ Options -Indexes # Follow symbolic links in this directory. Options +FollowSymLinks -# Make Drupal handle any 404 errors. +# Make Drupal handle any 404 errors by default. ErrorDocument 404 /index.php -# Force simple error message for requests for non-existent favicon.ico. - - # There is no end quote below, for compatibility with Apache 1.3. - ErrorDocument 404 "The requested file favicon.ico was not found. - +# Fast 404 response for static file types. +# +# The following lines prevent Drupal from handling 404 errors for specific +# types of static files (such as images and CSS), that are outside of a files +# directory. This fast response for these requests can help reduce server load. +# Note that all requests within a */files/* directory will continue to be +# handled by Drupal, to allow file generation/caching techniques. + +# If you do not use aliases ending in htm/html replace the above line with the +# commented line below. You need to make a similar change in the Rewrite +# section below. +# + ErrorDocument 404 "404 Not Found

Not Found

The requested URL was not found on this server.

+
# Set the default handler. DirectoryIndex index.php index.html index.htm @@ -84,10 +93,20 @@ DirectoryIndex index.php index.html inde # uncomment the following line: # RewriteBase / + # See "Fast 404 for static files" above. + RewriteCond %{REQUEST_FILENAME} !-f + RewriteCond %{REQUEST_URI} !files + RewriteCond %{REQUEST_URI} \.(txt|png|gif|jpe?g|shtml?|css|js|ico|swf|flv|cgi|bat|pl|dll|exe|asp)$ + # If you do not use aliases ending in htm/html replace the above line with + # the line below. You need to make a similar change in the FilesMatch + # section above. + # RewriteCond %{REQUEST_URI} \.(txt|png|gif|jpe?g|s?html?|css|js|ico|swf|flv|cgi|bat|pl|dll|exe|asp)$ + RewriteCond %{REQUEST_URI} !^404.%1$ + RewriteRule ^(.*)$ 404.%1 [L] + # Rewrite URLs of the form 'x' to the form 'index.php?q=x'. RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d - RewriteCond %{REQUEST_URI} !=/favicon.ico RewriteRule ^(.*)$ index.php?q=$1 [L,QSA] Index: modules/simpletest/tests/system_test.module =================================================================== RCS file: /cvs/drupal/drupal/modules/simpletest/tests/system_test.module,v retrieving revision 1.12 diff -u -u -p -r1.12 system_test.module --- modules/simpletest/tests/system_test.module 6 Jun 2009 15:43:05 -0000 1.12 +++ modules/simpletest/tests/system_test.module 15 Jun 2009 17:48:06 -0000 @@ -5,6 +5,7 @@ * Implement hook_menu(). */ function system_test_menu() { + global $db_prefix; $items['system-test/sleep/%'] = array( 'page callback' => 'system_test_sleep', 'page arguments' => array(2), @@ -50,7 +51,6 @@ function system_test_menu() { 'access arguments' => array('access content'), 'type' => MENU_CALLBACK, ); - $items['system-test/variable-get'] = array( 'title' => 'Variable Get', 'page callback' => 'variable_get', @@ -58,7 +58,22 @@ function system_test_menu() { 'access arguments' => array('access content'), 'type' => MENU_CALLBACK, ); - + // Register a path within the files directory, used to ensure we maintain + // Drupal's 404 handling within that directory even for specific fast 404 + // file types. + // The system_test module is enabled before the simpletest + // file_directory_path() is set, so we determine it using the db_prefix. + $items[file_directory_path() . '/' . $db_prefix . '/system-test/404-handling.jpg'] = array( + 'page callback' => 'system_test_404_handling', + 'access callback' => TRUE, + 'type' => MENU_CALLBACK, + ); + // Private files callback. + $items['system/files/system-test/404-handling.jpg'] = array( + 'page callback' => 'system_test_404_handling', + 'access callback' => TRUE, + 'type' => MENU_CALLBACK, + ); return $items; } @@ -105,6 +120,11 @@ function system_test_destination() { return 'The destination: ' . drupal_get_destination(); } +function system_test_404_handling() { + print 'This response was generated by Drupal.'; + exit; +} + /** * Implement hook_modules_installed(). */ Index: modules/system/system.admin.inc =================================================================== RCS file: /cvs/drupal/drupal/modules/system/system.admin.inc,v retrieving revision 1.156 diff -u -u -p -r1.156 system.admin.inc --- modules/system/system.admin.inc 13 Jun 2009 19:28:57 -0000 1.156 +++ modules/system/system.admin.inc 15 Jun 2009 17:48:06 -0000 @@ -1404,7 +1404,7 @@ function system_file_system_settings() { '#title' => t('File system path'), '#default_value' => file_directory_path(), '#maxlength' => 255, - '#description' => t('A file system path where the files will be stored. This directory must exist and be writable by Drupal. If the download method is set to public, this directory must be relative to the Drupal installation directory and be accessible over the web. If the download method is set to private, this directory should not be accessible over the web. Changing this location will modify all download paths and may cause unexpected problems on an existing site.'), + '#description' => t('A file system path where the files will be stored. This directory must exist, be writable by Drupal and contain the word \'files\' somewhere on the path. The word \'files\' on the path can allow the web server to serve fast 404 error responses for specific static file type requests outside the files directory, reducing server load. If the download method is set to public, this directory must be relative to the Drupal installation directory and be accessible over the web. If the download method is set to private, this directory should not be accessible over the web. Changing this location will modify all download paths and may cause unexpected problems on an existing site.'), '#after_build' => array('system_check_directory'), ); @@ -1429,6 +1429,15 @@ function system_file_system_settings() { } /** + * Validate the submitted file handling form. + */ +function system_file_system_settings_validate($form, &$form_state) { + if (strpos($form_state['values']['file_directory_path'], 'files') === FALSE) { + form_set_error('file_directory_path', t("The file system path must contain the word 'files' somewhere on the path.")); + } +} + +/** * Form builder; Configure site image toolkit usage. * * @ingroup forms Index: modules/system/system.test =================================================================== RCS file: /cvs/drupal/drupal/modules/system/system.test,v retrieving revision 1.50 diff -u -u -p -r1.50 system.test --- modules/system/system.test 13 Jun 2009 21:08:31 -0000 1.50 +++ modules/system/system.test 15 Jun 2009 17:48:06 -0000 @@ -566,7 +566,7 @@ class PageNotFoundTestCase extends Drupa * Implement setUp(). */ function setUp() { - parent::setUp(); + parent::setUp('system_test'); // Create an administrative user. $this->admin_user = $this->drupalCreateUser(array('administer site configuration')); @@ -606,6 +606,20 @@ class PageNotFoundTestCase extends Drupa $this->drupalGet($this->randomName(10)); $this->assertText(t('Page not found'), t('Found the default 404 page')); $this->assertNoText(t('User login'), t('Blocks are not shown on the default 404 page')); + + // Tests file directory requests are always handled by Drupal, but requests + // for specific file types outside of this directory are handled by the fast + // 404 response in .htaccess. + global $base_url; + $this->drupalGet($base_url . base_path() . $this->randomName(10) . '.ico'); + $this->assertRaw('404 Not Found

Not Found

The requested URL was not found on this server.

', t('404s for specific (fast 404) file types outside the files directory are returning without Drupal bootstrap.')); + if (variable_get('clean_url', 0)) { + $this->drupalGet(file_create_url('system-test/404-handling.jpg')); + $this->assertRaw('This response was generated by Drupal.', t('Drupal is handling requests for specific (fast 404) filetypes when within a public files directory.')); + } + variable_set('file_downloads', FILE_DOWNLOADS_PRIVATE); + $this->drupalGet(file_create_url('system-test/404-handling.jpg')); + $this->assertRaw('This response was generated by Drupal.', t('Drupal is handling requests for specific (fast 404) filetypes when within a private files directory.')); } }