Null Response From Drupal 6

1st July 2009 - 5 minutes read time

I recently had some trouble with a Drupal 6 site I was updating. I wanted to create a local working copy of the site to test so I downloaded the files and backed up the database, but for some reason I couldn't get the site to run. In every browser I tried I would get "page cannot be displayed" or "host unresponsive". These messages were basically telling me that something on the site was causing it to fall over before it ever got around to producing any HTML, and so the browsers were treating it as best they could. I tried clearing the Drupal cache and disabling some modules but this didn't appear to do anything, or simply broke the site. Searching the internet for this problem yielded very few results, so I eventually had to track the problem down myself.

Adding a few echo statements to the index.php page told me that Drupal was bootstrapping fine, but the problem was somewhere down the line. Obviously, adding echo statements throughout the Drupal source code is a real pain, so a different approach was needed. Using a combination of Netbeans and xdebug I was able to run each line of code one by one until the problem occurred. Fortunately (or unfortunately) when the offending peice of code was run it caused the debugger to stop with no sign of where the issue occurred. But after a while I tracked it down to line 1966 in the file common.inc. Here is the code that was causing the issue.

if ($_optimize) {
  // Perform some safe CSS optimizations.
  $contents = preg_replace('<
    \s*([@{}:;,]|\)\s|\s\()\s* |  # Remove whitespace around separators, but keep space around parentheses.
    /\*([^*\\\\]|\*(?!/))+\*/ |   # Remove comments that are not CSS hacks.
    [\n\r]                        # Remove line breaks.
    >x', '\1', $contents);
}

So what is happening here? This piece of code has three functions, which are actually explained in the code, but work together to minimise the stylesheet as much as possible by removing comments, line breaks and white space. Let's take a real world example and run a stylesheet through this code to see what happens. Here is the original.

/**
 * Example CSS file
 *
 */
body{
    margin:100px;
}
 
/**
 * Make some paragraph tags large
 */
p#large{
    font-size:20px;
}

Here is the altered, or minimised, stylesheet.

body{margin:100px;}p#large{font-size:20px;}

The problem arises on some systems where trying to do too much with preg_replace() causes the PHP engine to fall over. To replicate this I created a long string and then tried to replace that string using preg_replace().

$contents = 'd' . str_repeat('a', 396) . 'b'; /// 397 breaks
$contents = preg_replace('/d(a)+b/', '\1', $contents);

On my test system (Windows XP, Apache 2.2, PHP 5.2) this code works fine, but increasing the str_repeat() parameter to 397 causes the system to display nothing upon refresh. Note that there will also be nothing in the error logs for PHP and Apache.

The solution to this problem is quite simple, just remove some of the comments in your CSS or try to reduce the size of it and then explicitly clear the CSS cache. This will force Drupal to fetch your CSS file again and attempt to minify it, and all being well your site will be back up again.

To explicitly clear the CSS cache open up the root index.php file and enter the following lines just after the bootstrap is called.

drupal_clear_css_cache();
exit();

Remove this code once you have accessed the page.

The optimise code is used when you use the optimize CSS files feature within Drupal, found within Site config > Performance. So if this feature is turned on it can cause Drupal to produce a null response on some systems if you have large CSS files. I say some systems because this is an architecture specific issue to do with available stack size, rather than a PHP bug.

Comments

Permalink

Impressive drill down of the problem. Is the number of CSS comments still an issue for Drupal 7 CSS optimization?

budda (Thu, 11/03/2011 - 23:53)

Permalink

The code appears to still be there in Drupal 7, although it has a different footprint, so I can only assume that it might still happen. I might give it a shot later.

Permalink

Ok, well it seems that this problem doesn't seem to be there anymore in D7. I added a large block of CSS comments to a CSS file in a test install and turned on caching and it didn't make the site fall over.

I recently discovered an interesting DoS attack vector using regular expressions called ReDoS (http://en.wikipedia.org/wiki/ReDoS) which this reminded me of.

Add new comment

The content of this field is kept private and will not be shown publicly.