Re: Handling AP_FILTER_ERROR

2008-12-01 Thread Ruediger Pluem


On 12/01/2008 12:42 AM, Nick Kew wrote:
 On Sun, 30 Nov 2008 18:22:39 -0500
 Eric Covener [EMAIL PROTECTED] wrote:
 
 On Sun, Nov 30, 2008 at 5:20 PM, Nick Kew [EMAIL PROTECTED] wrote:
 In practice, the proposed fix looks good, and I want to
 vote +1.  I'm just a little concerned over whether we're
 in danger of an infinite loop if we feed an AP_FILTER_ERROR
 into ap_http_header_filter.  The filter will just return
 AP_FILTER_ERROR, and might get re-invoked with the error
 still there.
 This is my first real pass through the filters, so please correct me
 if something looks fishy.
 
 Something certainly looks fishy.  But it's not your analysis:
 it's the long-standing confusion over what a filter error looks like.
 
 If the filter is ever re-invoked, with the same brigade containing the
 error bucket, doesn't that mean an earlier filter (or handler) is
 looping over the same (uncleared) brigade?
 
 Sure, it means noone has cleared the brigade.  But it is customary
 to clear a brigade as we consume it, and it's possible something
 might be assuming that's happening.
 
 Looking at ap_http_header_filter, if we encounter an error,
 we first note it and continue.  If we subsequently encounter
 EOC, we'll return ap_pass_brigade and ignore the error
 altogether.  Otherwise we'll call ap_die (which is a no-op
 if passed AP_FILTER_ERROR) and then return AP_FILTER_ERROR
 up the stack, leaving the filter in place.
 Note that the ap_die() call in this context doesn't pass the filter
 chain rv (AP_FILTER_ERROR) but the stashed away HTTP error code that
 was pulled from the error bucket.
 
 Yes.  But in principle, that error could be AP_FILTER_ERROR, and will
 be if recursion ever happens.  How about, for example, a filter error
 in a subrequest returning AP_FILTER_ERROR.  What does the parent
 request see?

That depends on what the caller of ap_run_sub_req does with the result.
I guess no general statement is possible here.

 
This is the call that actually gets
 us the error response someone has queued up earlier (e.g.
 LimitRequestBody during the HTTP_IN filter)

 It's the later call to ap_die, back in ap_process_request, that should
 see AP_FILTER_ERROR and no-op.  This is the return code that the
 general fix for PR#31759 is catching as non-HTTP and changing to 500.

 
 Should is great; I'm worrying about edge-cases.
 
 To rephrase: I'd +1 the patch if either:
   (1) We do as I suggest, and remove the error bucket in
   ap_http_header_filter,
   or
   (2) Someone can convince me there is really no possibility,
   even in the event of a bug elsewhere, of this recursion.
 

Sorry, but now you confused ME :-).

So lets try to sort this out from the start.

1. The run_handler hook might return AP_FILTER_ERROR back to ap_invoke_handler.
   So AP_FILTER_ERROR might be the final result *after* the handler phase.
   With the current code ap_invoke_handler would transform AP_FILTER_ERROR into
   HTTP_INTERNAL_SERVER_ERROR and return this. After the patch
   ap_invoke_handler would return AP_FILTER_ERROR instead.

2. IMHO ap_invoke_handler is only called in three locations:

   ap_run_sub_req
   ap_process_request
   ap_internal_redirect

2.1 ap_run_sub_req
ap_run_sub_req will return HTTP_INTERNAL_SERVER_ERROR (now) or
AP_FILTER_ERROR (after the patch) to the caller. It cannot be
said what the caller does with this return code as subrequests
are done from many location and also by third party modules.

2.2 ap_process_request
ap_process_request sets r-status to HTTP_OK (to avoid error page recursion)
and calls ap_die with the return code (HTTP_INTERNAL_SERVER_ERROR / 
AP_FILTER_ERROR).
With the current code this produces an error page, after the patch this is 
a noop.
Afterwards the status is never used again.

2.3 ap_internal_redirect
Seems like the same case as ap_process_request to me.

I fail to see where a recursion could happen here after the patch and where
the error buckets come into the game. IMHO the worst case is that a
filter returns AP_FILTER_ERROR before any HTTP status code was sent, but does
nothing else (like sending an error bucket down the chain), the handler feeding
the chain does nothing but returning this code to ap_invoke_handler / 
ap_internal_redirect
and subsequently to ap_process_request after the patch which would cause us to 
not sent any
response at all (which would be also wrong).
So ap_die maybe should do the following:

if (type == AP_FILTER_ERROR) {
if [ap_http_header_filter is still in chain] {
   log this
   type = HTTP_INTERNAL_SERVER_ERROR;
}
else {
   return;
}
}


Regards

Rüdiger


Re: Handling AP_FILTER_ERROR

2008-12-01 Thread Nick Kew


On 1 Dec 2008, at 08:52, Ruediger Pluem wrote:


2. IMHO ap_invoke_handler is only called in three locations:


It's a public API, so could be called by any module.


So ap_die maybe should do the following:

if (type == AP_FILTER_ERROR) {
if [ap_http_header_filter is still in chain] {
   log this
   type = HTTP_INTERNAL_SERVER_ERROR;
}
else {
   return;
}
}


That looks good, too.

But do you see any objection to the (IMHO simpler) fix of
removing error buckets as we detect them?

--
Nick Kew


Re: Handling AP_FILTER_ERROR

2008-12-01 Thread Ruediger Pluem


On 12/01/2008 10:02 AM, Nick Kew wrote:
 
 On 1 Dec 2008, at 08:52, Ruediger Pluem wrote:

 2. IMHO ap_invoke_handler is only called in three locations:
 
 It's a public API, so could be called by any module.

Correct.

 
 So ap_die maybe should do the following:

 if (type == AP_FILTER_ERROR) {
 if [ap_http_header_filter is still in chain] {
log this
type = HTTP_INTERNAL_SERVER_ERROR;
 }
 else {
return;
 }
 }
 
 That looks good, too.
 
 But do you see any objection to the (IMHO simpler) fix of
 removing error buckets as we detect them?

Not directly. Could you please propose a concrete patch?
It makes discussion easier :-).

Regards

Rüdiger




Re: Handling AP_FILTER_ERROR

2008-12-01 Thread Nick Kew


On 1 Dec 2008, at 09:31, Ruediger Pluem wrote:


But do you see any objection to the (IMHO simpler) fix of
removing error buckets as we detect them?


Not directly. Could you please propose a concrete patch?
It makes discussion easier :-).


I think the one-liner should work, since we don't re-use the error  
bucket.

So against trunk, that's:

--- modules/http/http_filters.c (revision 722000)
+++ modules/http/http_filters.c (working copy)
@@ -1133,6 +1133,7 @@
 {
 if (AP_BUCKET_IS_ERROR(e)  !eb) {
 eb = e-data;
+apr_bucket_delete(e);
 continue;
 }
 /*

--
Nick Kew


Re: Handling AP_FILTER_ERROR

2008-12-01 Thread Ruediger Pluem


On 12/01/2008 11:01 AM, Nick Kew wrote:
 
 On 1 Dec 2008, at 09:31, Ruediger Pluem wrote:

 But do you see any objection to the (IMHO simpler) fix of
 removing error buckets as we detect them?

 Not directly. Could you please propose a concrete patch?
 It makes discussion easier :-).
 
 I think the one-liner should work, since we don't re-use the error bucket.
 So against trunk, that's:
 
 --- modules/http/http_filters.c (revision 722000)
 +++ modules/http/http_filters.c (working copy)
 @@ -1133,6 +1133,7 @@
  {
  if (AP_BUCKET_IS_ERROR(e)  !eb) {
  eb = e-data;
 +apr_bucket_delete(e);
  continue;
  }
  /*

I guess this could segfault (the status is in eb-status).
Why not cleaning up the whole brigade? IMHO it is of no use
anymore when we do an ap_die and afterwards return AP_FILTER_ERROR;

Index: modules/http/http_filters.c
===
--- modules/http/http_filters.c (Revision 721833)
+++ modules/http/http_filters.c (Arbeitskopie)
@@ -1145,7 +1145,11 @@
 }
 }
 if (eb) {
-ap_die(eb-status, r);
+int status;
+
+status = eb-status;
+apr_brigade_cleanup(b);
+ap_die(status, r);
 return AP_FILTER_ERROR;
 }



Regards

Rüdiger



Re: Handling AP_FILTER_ERROR

2008-12-01 Thread Nick Kew


On 1 Dec 2008, at 10:19, Ruediger Pluem wrote:


 if (eb) {
-ap_die(eb-status, r);
+int status;
+
+status = eb-status;
+apr_brigade_cleanup(b);
+ap_die(status, r);
 return AP_FILTER_ERROR;
 }


Good call.  +1 to that.

--
Nick Kew


Re: Handling AP_FILTER_ERROR

2008-12-01 Thread Eric Covener
On Mon, Dec 1, 2008 at 6:44 AM, Nick Kew [EMAIL PROTECTED] wrote:

 On 1 Dec 2008, at 10:19, Ruediger Pluem wrote:

 if (eb) {
 -ap_die(eb-status, r);
 +int status;
 +
 +status = eb-status;
 +apr_brigade_cleanup(b);
 +ap_die(status, r);
 return AP_FILTER_ERROR;
 }

 Good call.  +1 to that.

I'll revisit this afternoon, add to the backport, and reset the voting.

Thanks all.

-- 
Eric Covener
[EMAIL PROTECTED]


Re: Handling AP_FILTER_ERROR

2008-12-01 Thread Eric Covener
On Mon, Dec 1, 2008 at 7:33 AM, Eric Covener [EMAIL PROTECTED] wrote:
 On Mon, Dec 1, 2008 at 6:44 AM, Nick Kew [EMAIL PROTECTED] wrote:

 On 1 Dec 2008, at 10:19, Ruediger Pluem wrote:

 if (eb) {
 -ap_die(eb-status, r);
 +int status;
 +
 +status = eb-status;
 +apr_brigade_cleanup(b);
 +ap_die(status, r);
 return AP_FILTER_ERROR;
 }

 Good call.  +1 to that.

 I'll revisit this afternoon, add to the backport, and reset the voting.


Committed in r722081 with no change in perl framework.

-- 
Eric Covener
[EMAIL PROTECTED]


Re: Handling AP_FILTER_ERROR

2008-11-30 Thread Eric Covener
On Sun, Nov 30, 2008 at 5:20 PM, Nick Kew [EMAIL PROTECTED] wrote:
 In practice, the proposed fix looks good, and I want to
 vote +1.  I'm just a little concerned over whether we're
 in danger of an infinite loop if we feed an AP_FILTER_ERROR
 into ap_http_header_filter.  The filter will just return
 AP_FILTER_ERROR, and might get re-invoked with the error
 still there.

This is my first real pass through the filters, so please correct me
if something looks fishy.

If the filter is ever re-invoked, with the same brigade containing the
error bucket, doesn't that mean an earlier filter (or handler) is
looping over the same (uncleared) brigade?

 Looking at ap_http_header_filter, if we encounter an error,
 we first note it and continue.  If we subsequently encounter
 EOC, we'll return ap_pass_brigade and ignore the error
 altogether.  Otherwise we'll call ap_die (which is a no-op
 if passed AP_FILTER_ERROR) and then return AP_FILTER_ERROR
 up the stack, leaving the filter in place.

Note that the ap_die() call in this context doesn't pass the filter
chain rv (AP_FILTER_ERROR) but the stashed away HTTP error code that
was pulled from the error bucket.  This is the call that actually gets
us the error response someone has queued up earlier (e.g.
LimitRequestBody during the HTTP_IN filter)

It's the later call to ap_die, back in ap_process_request, that should
see AP_FILTER_ERROR and no-op.  This is the return code that the
general fix for PR#31759 is catching as non-HTTP and changing to 500.

-- 
Eric Covener
[EMAIL PROTECTED]


Re: Handling AP_FILTER_ERROR

2008-11-30 Thread Nick Kew
On Sun, 30 Nov 2008 18:22:39 -0500
Eric Covener [EMAIL PROTECTED] wrote:

 On Sun, Nov 30, 2008 at 5:20 PM, Nick Kew [EMAIL PROTECTED] wrote:
  In practice, the proposed fix looks good, and I want to
  vote +1.  I'm just a little concerned over whether we're
  in danger of an infinite loop if we feed an AP_FILTER_ERROR
  into ap_http_header_filter.  The filter will just return
  AP_FILTER_ERROR, and might get re-invoked with the error
  still there.
 
 This is my first real pass through the filters, so please correct me
 if something looks fishy.

Something certainly looks fishy.  But it's not your analysis:
it's the long-standing confusion over what a filter error looks like.

 If the filter is ever re-invoked, with the same brigade containing the
 error bucket, doesn't that mean an earlier filter (or handler) is
 looping over the same (uncleared) brigade?

Sure, it means noone has cleared the brigade.  But it is customary
to clear a brigade as we consume it, and it's possible something
might be assuming that's happening.

  Looking at ap_http_header_filter, if we encounter an error,
  we first note it and continue.  If we subsequently encounter
  EOC, we'll return ap_pass_brigade and ignore the error
  altogether.  Otherwise we'll call ap_die (which is a no-op
  if passed AP_FILTER_ERROR) and then return AP_FILTER_ERROR
  up the stack, leaving the filter in place.
 
 Note that the ap_die() call in this context doesn't pass the filter
 chain rv (AP_FILTER_ERROR) but the stashed away HTTP error code that
 was pulled from the error bucket.

Yes.  But in principle, that error could be AP_FILTER_ERROR, and will
be if recursion ever happens.  How about, for example, a filter error
in a subrequest returning AP_FILTER_ERROR.  What does the parent
request see?

 This is the call that actually gets
 us the error response someone has queued up earlier (e.g.
 LimitRequestBody during the HTTP_IN filter)
 
 It's the later call to ap_die, back in ap_process_request, that should
 see AP_FILTER_ERROR and no-op.  This is the return code that the
 general fix for PR#31759 is catching as non-HTTP and changing to 500.
 

Should is great; I'm worrying about edge-cases.

To rephrase: I'd +1 the patch if either:
  (1) We do as I suggest, and remove the error bucket in
  ap_http_header_filter,
  or
  (2) Someone can convince me there is really no possibility,
  even in the event of a bug elsewhere, of this recursion.

-- 
Nick Kew

Application Development with Apache - the Apache Modules Book
http://www.apachetutor.org/