? boost-325813.patch Index: boost.install =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/boost/boost.install,v retrieving revision 1.3 diff -u -p -r1.3 boost.install --- boost.install 10 Oct 2010 05:01:46 -0000 1.3 +++ boost.install 14 Jan 2011 03:20:21 -0000 @@ -10,13 +10,13 @@ // Core API hooks /** - * Implementation of hook_enable(). + * Implements hook_enable(). */ function boost_enable() { } /** - * Implementation of hook_disable(). + * Implements hook_disable(). */ function boost_disable() { // Make sure that the static page cache is wiped when the module is disabled: @@ -25,13 +25,13 @@ function boost_disable() { } /** - * Implementation of hook_install(). + * Implements hook_install(). */ function boost_install() { } /** - * Implementation of hook_uninstall(). + * Implements hook_uninstall(). */ function boost_uninstall() { // Clear variables @@ -43,7 +43,7 @@ function boost_uninstall() { } /** - * Implementation of hook_requirements(). + * Implements hook_requirements(). */ function boost_requirements($phase) { } Index: boost.module =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/boost/boost.module,v retrieving revision 1.5 diff -u -p -r1.5 boost.module --- boost.module 10 Oct 2010 05:01:46 -0000 1.5 +++ boost.module 14 Jan 2011 03:20:21 -0000 @@ -3,14 +3,14 @@ /** * @file - * Caches text as static files + * Caches generated text as static files. */ define('BOOST_CACHEABILITY_PAGES', ''); define('BOOST_COOKIE', 'DRUPAL_UID'); /** - * Implementation of hook_menu(). + * Implements hook_menu(). */ function boost_menu() { $items['admin/config/development/performance/default'] = array( @@ -33,7 +33,7 @@ function boost_menu() { } /** - * Implementation of hook_init(). Performs page setup tasks if page not cached. + * Implements hook_init(). Performs page setup tasks if page not cached. */ function boost_init() { global $user, $_boost; @@ -42,39 +42,40 @@ function boost_init() { // contrib modules like ad module. $uid = isset($user->uid) ? $user->uid : 0; if (strpos($_SERVER['SCRIPT_FILENAME'], 'index.php') !== FALSE) { - // Remove Boost cookie at logout if it still exists + // Remove Boost cookie at logout if it still exists. if (isset($_COOKIE[BOOST_COOKIE]) && $uid == 0) { boost_set_cookie($uid, REQUEST_TIME - 86400); } - // Remove Boost cookie if set to -1 + // Remove Boost cookie if set to -1. elseif (isset($_COOKIE[BOOST_COOKIE]) && $_COOKIE[BOOST_COOKIE] == '-1') { boost_set_cookie($uid, REQUEST_TIME - 86400); } - // Set Boost cookie if it doesn't exists and user is logged in + // Set Boost cookie if it doesn't exists and user is logged in. elseif (!isset($_COOKIE[BOOST_COOKIE]) && $uid != 0) { boost_set_cookie($uid); } } $_boost = boost_transform_url(); - // Make sure the page is/should be cached according to our current configuration + // Make sure the page is/should be cached according to our current configuration. if ( strpos($_SERVER['SCRIPT_FILENAME'], 'index.php') === FALSE || variable_get('site_offline', 0) || ($_SERVER['REQUEST_METHOD'] != 'GET' && $_SERVER['REQUEST_METHOD'] != 'HEAD') || $_SERVER['SERVER_SOFTWARE'] === 'PHP CLI' || isset($_GET['nocache']) || $uid != 0 + || $_boost['menu_item']['status'] != 200 ) { $_boost['cache_this'] = FALSE; } } /** - * Implementation of boost_exit(). + * Implements boost_exit(). */ function boost_exit() { global $_boost; - // Bail out of caching + // Bail out of caching. if (!isset($_boost['cache_this'])) { if (!isset($_boost['is_cacheable'])) { return; @@ -89,20 +90,23 @@ function boost_exit() { elseif (!$_boost['is_cacheable']) { return; } + elseif ($_boost['menu_item']['status'] != 200) { + return; + } - // Get the important data + // Get the important data. $data = ob_get_contents(); $header_info = boost_get_header_info(); - // Get cache info + // Get cache info. $info = boost_match_header_attributes($header_info); if ($info['enabled'] === FALSE) { return; } - // attach extension to filename + // Attach extension to filename. $_boost['filename'] .= '.' . $info['extension']; - // Add note to bottom of content + // Add note to bottom of content. if ($info['commment_start'] && $info['commment_end']) { $expire = $info['lifetime_max']; $cached_at = date('Y-m-d H:i:s', REQUEST_TIME); @@ -110,9 +114,9 @@ function boost_exit() { $note = "\n" . $info['commment_start'] . 'Page cached by Boost @ ' . $cached_at . ', expires @ ' . $expires_at . ', lifetime ' . format_interval($expire) . $info['commment_end']; $data .= $note; } - // Write Info + // Write info to a file. if ($_boost['filename'] && !is_file($_boost['filename'])) { - if(!is_dir($_boost['directory'])) { + if (!is_dir($_boost['directory'])) { mkdir($_boost['directory'], 0777, TRUE); } file_put_contents($_boost['filename'], $data, LOCK_EX); @@ -120,10 +124,10 @@ function boost_exit() { } /** - * Implementation of hook_cron(). Performs periodic actions. + * Implements hook_cron(). Performs periodic actions. */ function boost_cron() { - // Remove expired files from the cache + // Remove expired files from the cache. global $_boost; if (isset($_boost['base_dir'])) { _boost_rmdir($_boost['base_dir'], FALSE); @@ -131,7 +135,7 @@ function boost_cron() { } /* - * Implementation of hook_flush_caches(). Deletes all static files. + * Implements hook_flush_caches(). Deletes all static files. */ function boost_flush_caches() { // Remove all files from the cache @@ -142,6 +146,15 @@ function boost_flush_caches() { return; } +/* + * Implements hook_page_delivery_callback_alter(). + */ +function boost_page_delivery_callback_alter(&$callback, $set = FALSE) { + if ($callback == 'drupal_deliver_html_page') { + $callback = 'boost_deliver_html_page'; + } +} + /** * Given a URL give back eveything we know * @@ -154,7 +167,7 @@ function boost_transform_url($url = NULL global $base_root, $base_path; $items = &drupal_static(__FUNCTION__); - // Set defaults if none passed in + // Set defaults if none passed in. if ($url === NULL) { $url = $base_root . request_uri(); } @@ -173,26 +186,26 @@ function boost_transform_url($url = NULL $parts['filename'] = $parts['base_dir'] . $parts['path'] . '_' . $parts['query']; $parts['directory'] = dirname($parts['filename']); - // Get the internal path (node/8) + // Get the internal path (node/8). if (drupal_is_front_page()) { $parts['normal_path'] = variable_get('site_frontpage', 'node'); } else { $parts['normal_path'] = drupal_get_normal_path($parts['path']); } - // Get the alias (content/about-us) + // Get the alias (content/about-us). $parts['path_alias'] = drupal_get_path_alias($parts['normal_path']); - // Get all args + // Get all args. $args = arg(NULL, $parts['normal_path']); - // Prevent array warnings + // Prevent array warnings. $args[0] = empty($args[0]) ? '' : $args[0]; $args[1] = empty($args[1]) ? '' : $args[1]; $args[2] = empty($args[2]) ? '' : $args[2]; $parts['args'] = $args; - // Get content type + // Get content type. $parts = _boost_get_menu_router($parts); - // See if url is cacheable + // See if url is cacheable. $parts = boost_is_cacheable($parts); $items[$hash] = $parts; } @@ -210,7 +223,7 @@ function boost_transform_url($url = NULL */ function boost_parse_url($url = NULL, $b_path = NULL) { global $base_root, $base_path; - // Set defaults + // Set defaults. if ($url === NULL) { $url = $base_root . request_uri(); } @@ -218,7 +231,7 @@ function boost_parse_url($url = NULL, $b $b_path = $base_path; } - // parse url + // Parse url. $parts = parse_url($url); if (empty($parts['host']) || empty($parts['path'])) { return FALSE; @@ -231,7 +244,7 @@ function boost_parse_url($url = NULL, $b $parts['query_array'] = array(); parse_str($parts['query'], $parts['query_array']); - // get page number and simple query for DB + // Get page number and info from the query string. if (!empty($parts['query_array'])) { $query = array(); foreach ($parts['query_array'] as $key => $val) { @@ -243,10 +256,10 @@ function boost_parse_url($url = NULL, $b } } ksort($query); - $parts['query_db'] = str_replace('&', '&', urldecode(http_build_query($query))); + $parts['query_extra'] = str_replace('&', '&', urldecode(http_build_query($query))); } - // Get fully decoded URL + // Get fully decoded URL. $decoded1 = urldecode($parts['base_path'] . $parts['path'] . '_' . $parts['query']); $decoded2 = urldecode($decoded1); while ($decoded1 != $decoded2) { @@ -274,7 +287,7 @@ function boost_parse_url($url = NULL, $b * @return $parts */ function boost_is_cacheable($parts) { - // Set local variables + // Set local variables. $path = $parts['path']; $query = $parts['query']; $full = $parts['url_full']; @@ -292,7 +305,7 @@ function boost_is_cacheable($parts) { // if incoming URL contains '..' or null bytes // if decoded URL contains :// outside of the host portion of the url // Limit the maximum directory nesting depth of the path - // Do not cache if destination is set + // Do not cache if destination is set. if ( $normal_path == 'user' || preg_match('!^user/(autocomplete|login|register|password|reset|logout)!', $normal_path) || preg_match('!^admin!', $normal_path) @@ -311,7 +324,7 @@ function boost_is_cacheable($parts) { return $parts; } - // Check for reserved characters if on windows + // Check for reserved characters if on windows. // http://en.wikipedia.org/wiki/Filename#Reserved_characters_and_words // " * : < > | $chars = '"*:<>|'; @@ -320,7 +333,7 @@ function boost_is_cacheable($parts) { return $parts; } - // Match the user's cacheability settings against the path + // Match the user's cacheability settings against the path. // See http://api.drupal.org/api/function/block_block_list_alter/7 $visibility = variable_get('boost_cacheability_option', BLOCK_VISIBILITY_NOTLISTED); $pages_setting = variable_get('boost_cacheability_pages', BOOST_CACHEABILITY_PAGES); @@ -329,7 +342,7 @@ function boost_is_cacheable($parts) { // with different case. Ex: /Page, /page, /PAGE. $pages = drupal_strtolower($pages_setting); if ($visibility < BLOCK_VISIBILITY_PHP) { - // Convert the alias to lowercase + // Convert the alias to lowercase. $path = drupal_strtolower($alias); // Compare the lowercase internal and lowercase path alias (if any). $page_match = drupal_match_path($path, $pages); @@ -357,7 +370,7 @@ function boost_is_cacheable($parts) { return $parts; } - // Invoke hook_boost_is_cacheable($path) + // Invoke hook_boost_is_cacheable($path). $modules = boost_module_implements('boost_is_cacheable', 'boost'); foreach ($modules as $module) { if (($result = module_invoke($module, 'boost_is_cacheable', $parts)) !== NULL) { @@ -367,7 +380,7 @@ function boost_is_cacheable($parts) { } /** - * Implementation of hook_boost_is_cacheable(). + * Implements hook_boost_is_cacheable(). * * TODO support for node types, etc. * @@ -402,9 +415,10 @@ function boost_set_cookie($uid, $expires } /** - * Gets menu router contex + * Gets menu router contex. * - * Allows for any content type to have it's own cache expiration among other things. + * Allows for any content type to have it's own cache expiration among + * other things. * * @param $parts * @@ -412,22 +426,40 @@ function boost_set_cookie($uid, $expires * */ function _boost_get_menu_router($parts) { - // Declare array keys + // Declare array keys. $router_item = array(); $router_item['page_type'] = ''; $router_item['page_id'] = ''; - // Load the menu item + // Load the menu item. $item = menu_get_item($parts['normal_path']); if (is_array($item)) { $router_item += $item; + if ($router_item['access']) { + $router_item['status'] = 200; + } + else { + $router_item['status'] = 403; + } + } + else { + $router_item['status'] = 404; } - // Get any extra arguments - $menu_args = arg(NULL, $router_item['path']); - $diff = array(); - foreach ($parts['args'] as $key => $value) { - if (!empty($value) && $value !== $menu_args[$key] && $menu_args[$key] !== '%') { - $diff[] = $value; + // Get any extra arguments. + if (!empty($router_item['path'])) { + $menu_args = arg(NULL, $router_item['path']); + $diff = array(); + foreach ($parts['args'] as $key => $value) { + if (!empty($value)) { + if (isset($menu_args[$key])) { + if ($value !== $menu_args[$key] && $menu_args[$key] !== '%') { + $diff[] = $value; + } + } + else { + $diff[] = $value; + } + } } } if (!empty($diff)) { @@ -438,7 +470,7 @@ function _boost_get_menu_router($parts) } $parts['menu_item'] = $router_item; - // Invoke hook_boost_menu_router($router_item) + // Invoke hook_boost_menu_router($router_item). $modules = boost_module_implements('boost_menu_router', 'boost'); foreach ($modules as $module) { if (($result = module_invoke($module, 'boost_menu_router', $parts)) !== NULL) { @@ -448,7 +480,7 @@ function _boost_get_menu_router($parts) } /** - * Implementation of hook_boost_menu_router(). + * Implements hook_boost_menu_router(). * * TODO Better support for arguments. * @@ -458,8 +490,7 @@ function _boost_get_menu_router($parts) * @return $parts */ function boost_boost_menu_router($parts) { - $router_item = $parts['menu_item']; - // Handle nodes + // Handle nodes. if ($parts['args'][0] == 'node' && is_numeric($parts['args'][1])) { $node = node_load($parts['args'][1]); $parts['menu_item']['page_callback'] = 'node'; @@ -469,7 +500,8 @@ function boost_boost_menu_router($parts) } return $parts; } - // Handle taxonomy + + // Handle taxonomy. if ($parts['args'][0] == 'taxonomy' && is_numeric($parts['args'][2])) { $term = taxonomy_term_load($parts['args'][2]); $parts['menu_item']['page_callback'] = 'taxonomy'; @@ -480,7 +512,8 @@ function boost_boost_menu_router($parts) } return $parts; } - // Handle users + + // Handle users. if ($parts['args'][0] == 'user' && is_numeric($parts['args'][1])) { $user = user_load($parts['args'][1]); $parts['menu_item']['page_callback'] = 'user'; @@ -490,11 +523,12 @@ function boost_boost_menu_router($parts) } return $parts; } - // Handle views - if ($router_item['page_callback'] == 'views_page') { + + // Handle views. + if (isset($parts['menu_item']['page_callback']) && $parts['menu_item']['page_callback'] == 'views_page') { $parts['menu_item']['page_callback'] = 'view'; - $parts['menu_item']['page_type'] = array_shift($router_item['page_arguments']); - $parts['menu_item']['page_id'] = array_shift($router_item['page_arguments']); + $parts['menu_item']['page_type'] = array_shift($parts['menu_item']['page_arguments']); + $parts['menu_item']['page_id'] = array_shift($parts['menu_item']['page_arguments']); // See http://drupal.org/node/651798 for the reason why this if is needed if (is_array($parts['menu_item']['page_id'])) { $parts['menu_item']['page_id'] = array_shift($parts['menu_item']['page_id']); @@ -502,8 +536,8 @@ function boost_boost_menu_router($parts) return $parts; } - // Handle panels - if ($parts['menu_item']['page_callback'] == 'page_manager_page_execute') { + // Handle panels. + if (isset($parts['menu_item']['page_callback']) && $parts['menu_item']['page_callback'] == 'page_manager_page_execute') { $subtask_id = array_shift($parts['menu_item']['page_arguments']); $page = page_manager_page_load($subtask_id); $task = page_manager_get_task($page->task); @@ -515,8 +549,8 @@ function boost_boost_menu_router($parts) return $parts; } - // Try to handle everything else - elseif (is_array($parts['menu_item']['page_arguments'])) { + // Try to handle everything else. + elseif (isset($parts['menu_item']['page_arguments']) && is_array($parts['menu_item']['page_arguments'])) { foreach ($parts['menu_item']['page_arguments'] as $string) { if (is_string($string) && empty($parts['menu_item']['page_type'])) { $parts['menu_item']['page_type'] = $string; @@ -526,6 +560,7 @@ function boost_boost_menu_router($parts) } } } + // If router doesn't hold the the arguments, get them from the URL. if (empty($parts['menu_item']['page_type'])) { $parts['menu_item']['page_type'] = $parts['menu_item']['extra_arguments']; @@ -534,24 +569,24 @@ function boost_boost_menu_router($parts) $parts['menu_item']['page_id'] = $parts['menu_item']['extra_arguments']; } - // Try populating with the query string - if (empty($parts['menu_item']['page_type']) && !empty($parts['query_db'])) { - $parts['menu_item']['page_type'] = $parts['query_db']; + // Try populating with the query string. + if (empty($parts['menu_item']['page_type']) && !empty($parts['query_extra'])) { + $parts['menu_item']['page_type'] = $parts['query_extra']; } - elseif (empty($router_item['page_id']) && !empty($parts['query_db'])) { - $parts['menu_item']['page_id'] = $parts['query_db']; + elseif (empty($parts['menu_item']['page_id']) && !empty($parts['query_extra'])) { + $parts['menu_item']['page_id'] = $parts['query_extra']; } return $parts; } /** - * Alters module_implements to set a hook to fire at the end + * Alters module_implements to set a hook to fire at the end. * * @param $hook - * name of hook + * Name of hook. * @param $name - * module name to shift to the end of the array + * Module name to shift to the end of the array. * * @return array */ @@ -573,7 +608,7 @@ function boost_module_implements($hook, * @see drupal_send_headers() * * @return array - * array contains info about the page that is about to be sent + * Contains info about the page that is about to be sent. */ function boost_get_header_info() { $headers = drupal_get_http_header(); @@ -654,7 +689,7 @@ function boost_match_header_attributes($ } /** - * Get the storage types for the boost cache + * Get the storage types for the boost cache. * * @return $types * array('title' => array('content-type' => $values)); @@ -721,7 +756,7 @@ function boost_get_storage_types() { } /** - * Implementation of hook_boost_storage_types(). + * Implements hook_boost_storage_types(). * * @return $types */ @@ -772,7 +807,7 @@ function boost_boost_storage_types() { * Recursive version of rmdir(); use with extreme caution. * * @param $dir - * the top-level directory that will be recursively removed + * The top-level directory that will be recursively removed. */ function _boost_rmdir($dir, $flush = TRUE) { static $lifetimes = array(); @@ -793,7 +828,7 @@ function _boost_rmdir($dir, $flush = TRU if ($object != "." && $object != "..") { $file = $dir . "/" . $object; if (is_dir($file)) { - rrmdir($file); + _boost_rmdir($file); } elseif ($flush) { unlink($file); @@ -830,3 +865,43 @@ function _boost_rmdir($dir, $flush = TRU function boost_file_get_age($filename) { return REQUEST_TIME - filemtime($filename); } + +/** + * Capture error conditions. + * + * @param $page_callback_result + * The result of a page callback. Can be one of: + * - NULL: to indicate no content. + * - An integer menu status constant: to indicate an error condition. + * - A string of HTML content. + * - A renderable array of content. + * + * @see drupal_deliver_html_page() + */ +function boost_deliver_html_page($page_callback_result) { + global $_boost; + + // Menu status constants are integers; page content is a string or array. + if (is_int($page_callback_result)) { + // @todo: Break these up into separate functions? + switch ($page_callback_result) { + case MENU_NOT_FOUND: + // 404 page. + $_boost['menu_item']['status'] = 404; + break; + + case MENU_ACCESS_DENIED: + // 403 page. + $_boost['menu_item']['status'] = 403; + break; + + case MENU_SITE_OFFLINE: + // 503 page. + $_boost['menu_item']['status'] = 503; + break; + } + } + + // Call original function + drupal_deliver_html_page($page_callback_result); +}