Skip to content
Commits on Source (23)
// $Id$
REQUIREMENTS
------------
......
// $Id$
NOTE: this module is currently in an alpha state. Come back in a bit unless
you're an experienced user and don't mind figuring things out on your own.
DESCRIPTION
-----------
......@@ -18,7 +14,6 @@ FEATURES
site, reducing web server load and boosting your site's scalability.
* On-demand page caching (static file created after first page request).
* Full support for multi-site Drupal installations.
* Command line administration support (requires the drush module).
INSTALLATION
------------
......@@ -135,7 +130,7 @@ LIMITATIONS
* At the moment, Windows users are S.O.L. due to the use of symlinks and
Unix-specific shell commands. The author has no personal interest in
supporting Windows but will accept well-documented, non-detrimental
patches to that effect.
patches to that effect (see http://drupal.org/node/174380).
BUG REPORTS
-----------
......@@ -146,4 +141,5 @@ CREDITS
-------
Developed and maintained by Arto Bendiken <http://bendiken.net/>
Ported to Drupal 5.x by Alexander I. Grafov <http://drupal.ru/>
Miscellaneous contributions by: Jacob Peddicord, Justin Miller.
Miscellaneous contributions by: Jacob Peddicord, Justin Miller, Barry
Jaspan.
// $Id$
This is a listing of known bugs, features that mostly work but are still
somewhat in progress, features that are being considered or planned for
......
// $Id$
This lists some of the users of Boost, describing the setup of the website
in question as well as providing rationale on how Boost benefits the site.
It is hoped that the cases described here may serve as useful guides for new
Boost users evaluating how to best implement static caching on their site.
If you would like to add your website to this list, please contact the
author at http://drupal.org/user/26089/contact, describing your site and
setup. Try to keep the description to a paragraph or two, and don't forget
to include your name and the URL to your website. Note that additions to
this list are posted at the author's sole discretion, and submissions may be
abridged or edited for grammar.
Stand Against Poverty <http://www.standagainstpoverty.org>
United Nations campaign website used to organize events and report event
attendance for events at which nearly 117 million people worldwide
participated. The events seek to raise awareness about poverty and
highlight effort around the United Nations Millennium Development Goals
that seek toward reducing global poverty. The website runs on a cluster
of 4 load-balanced Apache web servers and a single database server.
Boost is used to reduce the overall resource usage consumed by anonymous
visitors on the site in order to devote more infrastructure resources
toward event organizers who sign in as authenticated users to create
events and report event attendance tallies. The Stand Against Poverty
site is is 4 languages, and uses the i18n module. Boost was used with
this patch http://drupal.org/node/174380#comment-663794 to allow for the
use of Boost on i18n sites. While there is still a substantial amount of
traffic on the website during the 3 day campaign, the impact of
anonymous traffic (which includes all traffic, until users sign in) is
greatly reduced.
Hosting infrastructure for StandAgainstPoverty.org provided by the good
folks at http://www.advomatic.com
Development Seed writes more about the campaign on their blog at:
http://www.developmentseed.org/blog/2008/oct/22/united-nations-uses-drupal-huge-anti-poverty-event
http://www.developmentseed.org/blog/2008/oct/23/improving-drupals-performance-boost-module-uns-millennium-campaign
Environmental Working Group <http://www.ewg.org/>
The Environmental Working Group (EWG) uses the power of public
information to protect public health and the environment. Boost is used
to cache all public-facing pages on the site (13,000+ and counting) and
has been critical in sustaining EWG's large amounts of traffic since the
site relaunched using Drupal in early 2007. EWG frequently receives
traffic from multiple press outlets on a given day and Boost allows EWG
to manage its infrastructure in-house and at a fraction of the price
that would otherwise be required.
Arto Bendiken <http://bendiken.net/>
Personal website of the author. Boost is used to cache virtually every
page on the site, quite significantly improving response times despite
the sometimes sluggish shared hosting the site runs on. An additional
......@@ -22,3 +55,10 @@ abridged or edited for grammar.
such as posting comments obviously don't work until MySQL access is
restored, however).
If you would like to add your website to this list, please contact the
author at http://drupal.org/user/26089/contact, describing your site and
setup. Try to keep the description to a paragraph or two, and don't forget
to include your name and the URL to your website. Note that additions to
this list are posted at the author's sole discretion, and submissions may be
abridged or edited for grammar.
<?php
// $Id$
/**
* @file
......@@ -52,10 +51,10 @@ function boost_settings_form($form = array()) {
//_boost_check_htaccess(); // TODO
$options = array(t('Cache every page except the listed pages.'), t('Cache only the listed pages.'));
$description = t("Enter one page per line as Drupal paths. The '*' character is a wildcard. Example paths are '%blog' for the blog page and %blog-wildcard for every personal blog. %front is the front page.", array('%blog' => theme('placeholder', 'blog'), '%blog-wildcard' => theme('placeholder', 'blog/*'), '%front' => theme('placeholder', '<front>')));
$description = t("Enter one page per line as Drupal paths. The '*' character is a wildcard. Example paths are %blog for the blog page and %blog-wildcard for every personal blog. %front is the front page.", array('%blog' => 'blog', '%blog-wildcard' => 'blog/*', '%front' => '<front>'));
if (user_access('use PHP for block visibility')) {
$options[] = t('Cache pages for which the following PHP code returns <code>TRUE</code> (PHP-mode, experts only).');
$description .= t('If the PHP-mode is chosen, enter PHP code between %php. Note that executing incorrect PHP-code can severely break your Drupal site.', array('%php' => theme('placeholder', '<?php ?>')));
$description .= t(' If the PHP-mode is chosen, enter PHP code between %php. Note that executing incorrect PHP-code can severely break your Drupal site.', array('%php' => '<?php ?>'));
}
$form['cacheability'] = array(
'#type' => 'fieldset',
......
<?php
// $Id$
/**
* @file
......@@ -177,12 +176,17 @@ function boost_file_path($path) {
$path = 'index'; // special handling for Drupal's front page
}
// Compose the full file system path to the static file
$cache_dir = boost_cache_directory();
$cache_file = implode('/', array($cache_dir, $path)) . BOOST_FILE_EXTENSION;
// Under no circumstances should the incoming path contain '..' or null
// bytes; we also limit the maximum directory nesting depth of the path
if (strpos($path, '..') !== FALSE || strpos($path, "\0") !== FALSE ||
count(explode('/', $path)) > BOOST_MAX_PATH_DEPTH) {
return FALSE;
}
// Convert any other undesirable characters in the path to underscores
$path = preg_replace('@[^/a-z0-9_-]@i', '_', $path);
// Security check to make sure the file actually is where it should be
return file_check_location($cache_file, $cache_dir);
return boost_cache_directory() . '/' . $path . BOOST_FILE_EXTENSION;
}
/**
......
<?php
// $Id$
/**
* @file
* Actions for managing the static page cache provided by the Boost module.
*/
//////////////////////////////////////////////////////////////////////////////
/**
* Lists all files currently in the Boost static file system cache.
*/
function drush_boost_list() {
// TODO: implementation.
}
/**
* Expires all files, or all files matching a given path, from the static page cache.
*/
function drush_boost_expire($path = NULL) {
drush_op('boost_cache_expire', $path, TRUE);
if (DRUSH_VERBOSE) {
drush_print(empty($key) ? t('Boost static page cache fully cleared.') :
t("Boost cached pages like `%path' expired.", array('%path' => $path)));
}
}
/**
* Enables the Boost static page cache.
*/
function drush_boost_enable() {
drush_op('variable_set', 'boost', CACHE_ENABLED);
if (DRUSH_VERBOSE) {
drush_print(t('Boost static page cache enabled.'));
}
}
/**
* Disables the Boost static page cache.
*/
function drush_boost_disable() {
drush_op('variable_set', 'boost', CACHE_DISABLED);
if (DRUSH_VERBOSE) {
drush_print(t('Boost static page cache disabled.'));
}
}
//////////////////////////////////////////////////////////////////////////////
<?php
// $Id$
/**
* @file
......
; $Id$
name = Boost
description = Provides a performance and scalability boost through caching Drupal pages as static HTML files.
package = Caching
<?php
// $Id$
/**
* @file
......
<?php
// $Id$
/**
* @file
......@@ -15,6 +14,7 @@ define('BOOST_FRONTPAGE', drupal_get_normal_path(variable_get('site_f
define('BOOST_ENABLED', variable_get('boost', CACHE_DISABLED));
define('BOOST_FILE_PATH', variable_get('boost_file_path', 'cache'));
define('BOOST_FILE_EXTENSION', variable_get('boost_file_extension', '.html'));
define('BOOST_MAX_PATH_DEPTH', 10);
define('BOOST_CACHEABILITY_OPTION', variable_get('boost_cacheability_option', 0));
define('BOOST_CACHEABILITY_PAGES', variable_get('boost_cacheability_pages', ''));
define('BOOST_FETCH_METHOD', variable_get('boost_fetch_method', 'php'));
......@@ -94,7 +94,7 @@ function boost_menu($may_cache) {
*/
function boost_init() {
// Stop right here unless we're being called for an ordinary page request
if (strpos($_SERVER['PHP_SELF'], 'index.php') === FALSE)
if (strpos($_SERVER['SCRIPT_FILENAME'], 'index.php') === FALSE)
return;
// TODO: check interaction with other modules that use ob_start(); this
......@@ -105,8 +105,14 @@ function boost_init() {
if (empty($user->uid) && $_SERVER['REQUEST_METHOD'] == 'GET') {
// Make sure no query string (in addition to ?q=) was set, and that
// the page is cacheable according to our current configuration:
if (count($_GET) == 1 && boost_is_cacheable($_GET['q']))
if (count($_GET) == 1 && boost_is_cacheable($_GET['q'])) {
// In the event of errors such as drupal_not_found(), GET['q'] is
// changed before _boost_ob_handler() is called. Apache is going to
// look in the cache for the original path, however, so we need to
// preserve it.
$GLOBALS['_boost_path'] = $_GET['q'];
ob_start('_boost_ob_handler');
}
}
}
......@@ -151,16 +157,16 @@ function boost_exit($destination = NULL) {
global $user;
if (empty($user->uid) && ($messages = drupal_set_message())) {
// Check that the page we're redirecting to has been cached by Boost
// and really necessitates special handling:
// Check that the page we're redirecting to really necessitates
// special handling, i.e. it doesn't have a query string:
extract(parse_url($destination));
$path = ($path == base_path() ? '' : substr($path, strlen(base_path())));
if (boost_is_cached($path) && empty($query)) {
// FIXME: call any remaining exit hooks since we're about to terminate.
if (empty($query)) {
// FIXME: call any remaining exit hooks since we're about to terminate?
// Add a query string to ensure we don't serve a static copy of
// the page we're redirecting to, which would prevent the session
// messages from showing up:
// If no query string was previously set, add one just to ensure we
// don't serve a static copy of the page we're redirecting to, which
// would prevent the session messages from showing up:
$destination = url($path, 't=' . time(), $fragment, TRUE);
// Do what drupal_goto() would do if we were to return to it:
......@@ -206,6 +212,12 @@ function boost_comment($comment, $op) {
if (!empty($comment['nid']))
boost_cache_expire('node/' . $comment['nid'], TRUE);
break;
case 'publish':
case 'unpublish':
case 'delete':
if (!empty($comment->nid))
boost_cache_expire('node/' . $comment->nid, TRUE);
break;
}
}
......@@ -293,9 +305,9 @@ function _boost_ob_handler($buffer) {
chdir(dirname($_SERVER['SCRIPT_FILENAME']));
// Check the currently set content type; at present we can't deal with anything else than HTML.
if (_boost_get_content_type() == 'text/html') {
if (_boost_get_content_type() == 'text/html' && _boost_get_http_status() == 200) {
if (strlen($buffer) > 0) { // Sanity check
boost_cache_set($_GET['q'], $buffer);
boost_cache_set($GLOBALS['_boost_path'], $buffer);
}
}
......@@ -311,14 +323,27 @@ function _boost_ob_handler($buffer) {
* has overridden the content type.
*/
function _boost_get_content_type($default = NULL) {
static $regex = '/^Content-Type:\s*([\w\d\/\-]+)/i';
static $regex = '!^Content-Type:\s*([\w\d\/\-]+)!i';
return _boost_get_http_header($regex, $default);
}
// The last Content-Type header is the one that counts:
/**
* Determines the HTTP response code that the current page request will be
* returning by examining the HTTP headers that have been output so far.
*/
function _boost_get_http_status($default = 200) {
static $regex = '!^HTTP/1.1\s+(\d+)!';
return (int)_boost_get_http_header($regex, $default);
}
function _boost_get_http_header($regex, $default = NULL) {
// The last header is the one that counts:
$headers = preg_grep($regex, explode("\n", drupal_set_header()));
if (!empty($headers) && preg_match($regex, array_pop($headers), $matches))
if (!empty($headers) && preg_match($regex, array_pop($headers), $matches)) {
return $matches[1]; // found it
return $default;
}
return $default; // no such luck
}
//////////////////////////////////////////////////////////////////////////////
......@@ -138,4 +138,3 @@ DirectoryIndex index.php
RewriteRule ^(.*)$ index.php?q=$1 [L,QSA]
</IfModule>
# $Id$
......@@ -104,4 +104,3 @@ DirectoryIndex index.php
RewriteRule ^(.*)$ index.php?q=$1 [L,QSA]
</IfModule>
# $Id$