> -----Ursprüngliche Nachricht-----
> Von: Yann Ylavic [mailto:[email protected]]
> Gesendet: Mittwoch, 14. Dezember 2016 01:42
> An: httpd-dev <[email protected]>
> Betreff: Re: svn commit: r1773865 -
> /httpd/httpd/trunk/modules/http/http_filters.c
> 
> On Tue, Dec 13, 2016 at 8:37 PM, Ruediger Pluem <[email protected]>
> wrote:
> >
> > On 12/13/2016 02:49 PM, Yann Ylavic wrote:
> >>
> >> The pros with this is indeed the reduced complexity (though the loop
> >> to walk the brigade already existed), the cons are that we rely on
> the
> >> caller/handler to not ignore ap_pass_brigade()'s return value and
> >
> > IMHO this would violate a principal and easy to follow design pattern.
> > I don't think that we can and want to protect module developers from
> > all errors they could make, especially if they are easy to spot
> > and understand. And if why catch this here?
> 
> I agree that defensive programming in not good (though the whole
> check_headers() patchset is nothing else after all...).
> 
> >
> > If someone in the the filter chain continues sending content even
> > after passing things down the chain caused an error weird things
> > can happen before us or if the source is after us after us.
> 
> Agreed, still.
> 
> >
> > This change is also unrelated to the bad header issue and I think
> > if there is interest to address this it should be done in a separate
> > patch set.
> 
> It is actually, we could eventually avoid reading/consuming the body
> of the original response (closing prematuraly any backend
> connection...), but in any case we need to eat the ap_die()'s one if
> we encounter a bad header on its generated response.
> That's because we want to generate a minimal 500 response in this
> case, with no body (even the ap_die(500)'s one not be related,
> ErrorDocument can be any redirection, including proxying).

We could do that easier in this case:

Index: http_filters.c
===================================================================
--- http_filters.c      (revision 1774129)
+++ http_filters.c      (working copy)
@@ -1248,11 +1248,6 @@
         }
     }
     if (ctx->headers_error) {
-        if (!eos) {
-            /* Eat body until EOS */
-            apr_brigade_cleanup(b);
-            return APR_SUCCESS;
-        }
 
         /* We may come back here from ap_die() below,
          * so clear anything from this response.
@@ -1271,14 +1266,16 @@
             ap_die(HTTP_INTERNAL_SERVER_ERROR, r);
             return AP_FILTER_ERROR;
         }
-        AP_DEBUG_ASSERT(APR_BUCKET_IS_EOS(e));
-        APR_BUCKET_REMOVE(e);
         apr_brigade_cleanup(b);
+        e =  apr_bucket_eoc_create(f->c->bucket_alloc);
         APR_BRIGADE_INSERT_TAIL(b, e);
+        e =  apr_bucket_eos_create(f->c->bucket_alloc);
+        APR_BRIGADE_INSERT_TAIL(b, e);
         r->status = HTTP_INTERNAL_SERVER_ERROR;
         r->content_type = r->content_encoding = NULL;
         r->content_languages = NULL;
         ap_set_content_length(r, 0);
+
     }
     else if (eb) {
         int status;

The ap_http_outerror_filter will then kill any further possible data
that gets down the chain.

> 
> Thus the eat-body code is needed anyway, let's also use it for the
> original response then.
> 
> >
> > Furthermore it causes a handler to continue generating content
> > in a properly resource intensive way that we drop directly. And the
> > handler has no chance to know this because we return APR_SUCCESS.
> 
> Hmm, we return AP_FILTER_ERROR right?

But only after we slurped all content. We return APR_SUCESS until we see EOS.
For the reasons above this is bad.

> 
> >>
> >> I'm even inclined to do the below changes, so that we are really safe
> >> (i.e. ignore any data) after EOS...
> >
> > After this patch we do the wrong thing with an EOC bucket.
> > The current contract is that an EOC bucket *anywhere* in the brigade
> causes the
> > header filter to go out of the way. After the patch this is broken if
> > a bad header is present. But as EOC tells us to get out of the way and
> do nothing,
> > we don't need to take care about bad headers. This breaks edge case
> with mod_proxy_http
> 
> OK, since we don't send the headers in the EOC case, I agree we should
> bypass check_headers().  But we may not be aware of an EOC unless it
> is part of the first brigade sent down the chain, and in this case
> check_headers() could trigger (that's fine I think, for late EOC
> cases, i.e. error while forwarding bodies, we need to send or block
> something already).
> 
> >
> > Albeit this would be fixable I see more negative points then positive
> points here
> > and I am -0.5 on that content slurping.
> 
> You mean, the one already backported to 2.4.x or the additional hunks
> I proposed above?

The code already in 2.4.x

> I think we should fix the EOC case in 2.4.x, but still eat ignored
> bodies in ap_http_header_filter().
> 
> For the EOC case, how about:
> 
> @@ -1227,13 +1224,6 @@ AP_CORE_DECLARE_NONSTD(apr_status_t)
> ap_http_heade
>           e != APR_BRIGADE_SENTINEL(b);
>           e = APR_BUCKET_NEXT(e))
>      {
> -        if (ctx->headers_error) {
> -            if (APR_BUCKET_IS_EOS(e)) {
> -                eos = 1;
> -                break;
> -            }
> -            continue;
> -        }
>          if (AP_BUCKET_IS_ERROR(e) && !eb) {
>              eb = e->data;
>              continue;
> @@ -1246,6 +1236,11 @@ AP_CORE_DECLARE_NONSTD(apr_status_t)
> ap_http_heade
>              ap_remove_output_filter(f);
>              return ap_pass_brigade(f->next, b);
>          }
> +
> +        if (ctx->headers_error && APR_BUCKET_IS_EOS(e)) {
> +            eos = 1;
> +            break;
> +        }
>      }
>      if (ctx->headers_error) {
>          if (!eos) {
> ?
> 

Looks good apart that I wouldn't do the break in the EOS case to catch EOC 
buckets after the EOS.
I guess in practice that will not add much or additional rounds in the loop at 
all, but it
Keeps the current expectation that EOC can be anywhere.

Regards

Rüdiger

Reply via email to