> -----Original Message-----
> From: William A. Rowe, Jr.
> Sent: Montag, 13. Juli 2009 23:58
> To: [email protected]
> Subject: Re: mod_deflate DoS using HEAD
>
> Nick Kew wrote:
> > Eric Covener wrote:
> >
> >> /* For a 304 response, only change the headers */
> >> - if (r->status == HTTP_NOT_MODIFIED) {
> >> + if (r->status == HTTP_NOT_MODIFIED || r->header_only) {
> >
> > Technically speaking, screws up the protocol.
> >
> > IMHO it would be acceptable provided:
> > (a) it's an option for the admin, rather than enforced
> > (b) it's documented
> > (c) the headers are correct: either Content-Encoding is
> > unset (uncompressed response) or Content-Length is
> > unset. Probably the former.
>
> Agreed. It's not a DoS. If the admin wants to conserve CPU
> resources, they must either;
>
> * cache the deflated pages (avoid user-agent header if there
> are multiples, which reminds me we need a module to unset the
> accept deflate trigger on non-compliant browsers running
> very-first in the quick_handler.)
>
> * create gzip'ed content, navigate the choice of content through
> multiviews.
>
> * do not do server-side deflation (it is expensive).
>
All very true. But how about the following patch. It should do no
harm and should solve the issue in at least some cases (I think
in most cases):
Index: modules/filters/mod_deflate.c
===================================================================
--- modules/filters/mod_deflate.c (revision 793927)
+++ modules/filters/mod_deflate.c (working copy)
@@ -629,6 +629,19 @@
apr_bucket *b;
apr_size_t len;
+ /*
+ * Optimization: If we are a HEAD request and bytes_sent is not zero
+ * it means that we have passed the content-length filter once and
+ * have more data to sent. This means that the content-length filter
+ * could not determine our content-length for the response to the
+ * HEAD request anyway (the associated GET request would deliver the
+ * body in chunked encoding) and we can stop compressing.
+ */
+ if (r->header_only && r->bytes_sent) {
+ ap_remove_output_filter(f);
+ return ap_pass_brigade(f->next, bb);
+ }
+
e = APR_BRIGADE_FIRST(bb);
if (APR_BUCKET_IS_EOS(e)) {
Regards
Rüdiger