WP-Cache does not preserve any headers in cached output — not even known headers such as Content-Type. (Among other things, this causes feeds to be delivered as text/html.)
There are two reasons why the headers are dropped.
Cause #1
In some environments, such as FastCGI (an Apache extension, which TextDrive uses by default), apache_response_headers is not available. WP-Cache relies on this function to get the headers in order to cache them.
Fix
PHP 5 provides headers_list, but it returns an ordered array instead of an associative array. Still, something is better than nothing; when apache_response_headers is not available; headers_list should be used.
Cause #2
WP-Cache registers two callbacks:
- An output buffer callback, wp_cache_ob_callback.
- A shutdown callback, wp_callback_ob_end.
Contrary to the name of the shutdown callback, it has nothing to do with the output buffer. It is called when php finishes executing, and calls ob_end_clean (or ob_end_flush), causing the output buffer callback to be called. Thus, “*_ob_end” is called before “*_ob_callback”.
That part is cosmetic, however; it doesn't directly cause any bugs. What does is the fact that *_ob_end relies on the $meta_object object, but this object is not created until *_ob_callback. *_ob_end dutifully sets up all the headers into the meta object, but since the meta object is undefined until ob_end_flush is called, none of that has any effect, so the headers have in fact not been put into anything.
Fix
Move the creation of $meta_object from *_ob_callback to *_ob_end, and for clarity's sake, rename *_ob_end to *_shutdown_callback.
The attached patch addresses both causes by implementing both fixes. I include a function, of my own creation, which tries apache_response_headers first, followed by headers_list (gathering the headers therefrom into a new associative array), followed by returning null. The opposite order of preference may be desired. headers_list will only be tried if it exists, which preserves workingness on PHP versions before 5.