|
Home > Archive > Apache Mod-Python > February 2006 > How mod_python treats apache.OK/apache.DECLINED response from handlers.
You are viewing an archived Text-only version of the thread.
To view this thread in it's original format and/or if you want to reply to
this thread please [click here]
| Author |
How mod_python treats apache.OK/apache.DECLINED response from handlers.
|
|
| Graham Dumpleton 2006-02-17, 11:10 pm |
| Nicolas, Jim, Grisha (and others who might understand this issue)
When you get a chance, can you read through the JIRA issue:
http://issues.apache.org/jira/browse/MODPYTHON-129
and provide some feedback on whether you think my analysis is correct
and
thus whether mod_python really needs to be changed.
I would like to perhaps progress a fix for this issue sooner rather
than later as
part of changes addressing authentication. This would be MODPYTHON-124,
MODPYTHON-94 plus MODPYTHON-129.
If I can fix these, then feel I can give a proper solution to the SSL/
Basic auth
handler question on the main list at the moment. Bit frustrating that
functionality
is incomplete at the moment.
Thanks.
Graham
| |
| Deron Meranda 2006-02-19, 8:21 am |
| On 2/17/06, Graham Dumpleton <grahamd@dscpl.com.au> wrote:
> When you get a chance, can you read through the JIRA issue:
>
> http://issues.apache.org/jira/browse/MODPYTHON-129
>
> and provide some feedback on whether you think my analysis is correct
> and thus whether mod_python really needs to be changed.
Yes, I think your summary is pretty accurate. I never did
really understand why mod_python works the way it does
in this area (I'm sure there was a reason but I wasn't around
then).. I always thought the Apache logic was a lot more
useful.
I am one of those who do make somewhat-significant use of
the other apache phases. Actually what I've been doing is to
essentially write my own "looper" wrapper, which looks like
just one handler to mod_python, but which then implements
more of an Apache-style loop/dispatch itself in sub-handlers.
So at least in my case, I've been working around mod_python
rather than letting it work for me.
I guess the positive thing is that because of this I don't have
any existing code which actually uses multiple mod_python
handlers in the same phase; so this change in behavior is
only positive for me. So for me it's +1 on Graham's suggested
change in logic (but any incompatible change in behavior is
something to think hard about).
As for an example where this could even be benificial to the
content phase, consider having different content handlers, one
which outputs application/xhtml+xml+SVG+MathML and one
for text/html+GIF. Then the first handler would look at the
Accept header, etc, and if the user-agent can't support it,
it returns a defer and then the text/html handler gets a chance.
However, I still think even this new proposal is somewhat restrictive.
For example there's no way to interleave C and Python handlers
in the list-to-try (this is because to apache all the mod_python
handlers look just like one handler). Of course a necessary thing
to go along with this, would be a way to specify the hook order (one
of APR_HOOK_REALLY_FIRST, _FIRST, _MIDDLE,
_LAST, or _REALLY_LAST).
Perhaps mod_python can actually add multiple hooks to itself
in for each phase (at each order position), and then have a way
for the python-handlers to optionally specify a position. If
mod_python had no handlers for a particilar hook position it
would just by default return a decline.
--
Deron Meranda
| |
| Graham Dumpleton 2006-02-19, 8:21 am |
| Thanks for the feedback. At least I am not wacko. Further comments
below.
On 18/02/2006, at 5:44 PM, Deron Meranda wrote:
> I guess the positive thing is that because of this I don't have
> any existing code which actually uses multiple mod_python
> handlers in the same phase; so this change in behavior is
> only positive for me. So for me it's +1 on Graham's suggested
> change in logic (but any incompatible change in behavior is
> something to think hard about).
>
> As for an example where this could even be benificial to the
> content phase, consider having different content handlers, one
> which outputs application/xhtml+xml+SVG+MathML and one
> for text/html+GIF. Then the first handler would look at the
> Accept header, etc, and if the user-agent can't support it,
> it returns a defer and then the text/html handler gets a chance.
>
> However, I still think even this new proposal is somewhat restrictive.
> For example there's no way to interleave C and Python handlers
> in the list-to-try (this is because to apache all the mod_python
> handlers look just like one handler). Of course a necessary thing
> to go along with this, would be a way to specify the hook order (one
> of APR_HOOK_REALLY_FIRST, _FIRST, _MIDDLE,
> _LAST, or _REALLY_LAST).
>
> Perhaps mod_python can actually add multiple hooks to itself
> in for each phase (at each order position), and then have a way
> for the python-handlers to optionally specify a position. If
> mod_python had no handlers for a particilar hook position it
> would just by default return a decline.
Yeah, have thought in the past about how mod_python could be made
to register handlers as really first, first, last and really last.
Besides how
one would denote that in the configuration file, was concerned about
the overhead that might result. This is because mod_python would
need to register a permanent hook against every one of them and thus
no matter what the request is for, you get multiple calls into
mod_python
for each phase just so it can check its configuration to see if it
has to do
anything or not. Even if it decides not to do anything, it is an
overhead
on every request made to the server as far as I understand it.
In respect of interleaving and ordering of handlers within a phase,
am not sure that Apache provides much guarantees about order
within a section such as middle etc. Therefore the only way to ensure
that a handler is run in the right situation is not to have its
condition
check for running overlap with any other handler in that section.
Graham
| |
| Graham Dumpleton 2006-02-19, 8:21 am |
| I'll post more later when I have a chance to check a few things, but
I am
going to backtrack a bit. How far I don't know yet.
In short for now, mod_perl has a a concept called stacked handlers. You
have stacked handlers when you list more than one handler with the
handler directive on the same line. Mod_python equivalent would be:
PythonHandler page::header page::body page::footer
When handlers are stacked in this way, how status is treated would
probably
be like mod_python works now. Ie., keep going while OK, status of
last handler
is what is returned from the stack of handlers.
If you list the handlers on separate lines:
PythonAuthenHandler mysessionauth
PythonAuthenHandler mybasicauth
then the Apache rules for status would be applied against handlers
for each
separate handler directive as specified by Apache for that phase.
What I have to check is whether mod_python does use Apache rules in the
latter case or not or whether it is treating combination of all
across multiple
lines as stacked handlers.
If mod_python isn't quite doing it right, then what mod_perl does
seems to
be good way of doing it. That is stacked only if all listed on same
line.
Still need work out what should happen with req.add_handler().
Anyway, for information of stacked handlers in mod_perl, see:
http://www.oreilly.com/catalog/wrap.../ch04.html#3948
Note that don't need chained handlers from mod_perl as that is now
doable
using filters.
Graham
On 19/02/2006, at 2:16 AM, Jim Gallacher wrote:
[vbcol=seagreen]
> I agree with Deron's summary of your summary. 
>
> If we make this change (and that is a +1 from me) I suggest the
> following path, assuming that it is possible to control this
> behaviour with a PythonOption flag:
>
> 1. mp 3.3 - New behaviour is off by default, but can be turned on
> using a PythonOption. The old behaviour is deprecated and our user
> education phase begins. Perhaps we can log a message at Apache
> startup that the PythonOption whatever_we_call_it was not found?
>
> 2. mp 3.4 - New behaviour is *on* by default, but can still be
> turned off with the PythonOption. A deprecation warning goes into
> the Apache log if the new behaviour is turned off.
>
> 3. mp 3.5 - New behaviour only. The old way is deprecated and
> cannot be enabled.
>
> This means maintaining some cruft in the code during the
> transition, but I think this is a big enough change that we need to
> either jump the version to 4.0 or offer an easy transition path.
>
> Jim
>
> Deron Meranda wrote:
| |
| Graham Dumpleton 2006-02-19, 8:21 am |
| Sorry, long ramble to help me, more than anyone else, understand the
issues.
On 19/02/2006, at 7:44 AM, Graham Dumpleton wrote:
> I'll post more later when I have a chance to check a few things,
> but I am
> going to backtrack a bit. How far I don't know yet.
>
> In short for now, mod_perl has a a concept called stacked handlers.
> You
> have stacked handlers when you list more than one handler with the
> handler directive on the same line. Mod_python equivalent would be:
>
> PythonHandler page::header page::body page::footer
>
> When handlers are stacked in this way, how status is treated would
> probably
> be like mod_python works now. Ie., keep going while OK, status of
> last handler
> is what is returned from the stack of handlers.
>
> If you list the handlers on separate lines:
>
> PythonAuthenHandler mysessionauth
> PythonAuthenHandler mybasicauth
>
> then the Apache rules for status would be applied against handlers
> for each
> separate handler directive as specified by Apache for that phase.
>
> What I have to check is whether mod_python does use Apache rules in
> the
> latter case or not or whether it is treating combination of all
> across multiple
> lines as stacked handlers.
>
> If mod_python isn't quite doing it right, then what mod_perl does
> seems to
> be good way of doing it. That is stacked only if all listed on same
> line.
Now confirmed. In mod_python it treats all handlers for a phase as
stacked,
even when they are defined with distinct Python*Handler directives. I
would
thus suggest then that mod_python be changed so that it only treats
handlers
in stacked fashion as it does now when all on the same Python*Handler
line.
This would make it work like mod_perl which seems more sensible.
Taking content handlers as an example, when you have:
PythonHandler page::header page::body page::footer
if page::header returns OK, it will still then execute, page::body.
If page::body
returns OK, it will similarly execute page::footer. The result of
page::footer will
then be what is returned from the stacked handlers.
Obviously, if any of the stacked handlers returns an error, or DONE,
then the
whole request is ended.
If instead you were to have:
PythonHandler page::header page::body page::footer
PythonHandler alternatepage
if page::footer returns OK, then alternatepage is not run. If any of
the stacked
handlers returns DECLINED, the remainder of the stacked handlers would
be skipped and alternatepage run. Note that in practice it would only
make
sense for page::header to be returning DECLINED, and only prior to any
response content being generated else you might get a mess.
Thus, each Python*Handler directive as a whole is treated like Apache
treats
a handler. A stacked handler is a special case where within the list
of stacked
handlers mod_python uses its current rules.
If this approach is taken, no special option is needed to enable/disable
anything. If existing code is relying on stacked handlers type
behaviour and
they use multiple Python*Handler directives, they would change
configuration
to list all handlers to be stacked on the same Python*Handler line.
> Still need work out what should happen with req.add_handler().
For req.add_handler(), need to consider a few possible cases. First
consider
instead of having:
PythonHandler page::header page::body page::footer
having:
PythonHandler page::all
Where in page.py you have:
def all(req):
req.add_handler("PythonHandler","page::header")
req.add_handler("PythonHandler","page::body")
req.add_handler("PythonHandler","page::footer")
....
I haven't specified the return status yet as its value is significant.
If req.add_handler() adds the handlers onto the current handler list
to create a
stacked handler list, then the return status should be OK. This will
mean that it
will move on to calling in turn each of the stacked handlers just
added. Each of
those will have to also return OK.
If req.add_handler() does not add them onto the current handler list
to create a
stacked handler list, but creates them as distinct handlers, it must
return DECLINED,
but then since each of the three new handlers is distinct, it can't
behave like we
want it to without each of the new handlers fudging it by returning
DECLINED,
except for the last one. This is therefore no good.
At the same time though, adding them as stacked handlers stops us
from having:
def authenhandler(req):
req.add_handler("PythonAuthenHandler","mysessionauth")
req.add_handler("PythonAuthenHandler",",mybasicauth")
return apache.DECLINED
In this case the authehandler is being used to register a series of
alternate handlers
which must be treated as distinct. Adding them as stacked handlers
will not work
because as soon as one returns OK, we want this phase to be complete.
Thus depending on what you are doing, you need one or the other. To
make it
obvious, should perhaps use a distinct method name to add handlers as
stacked
handlers against the current handler list. Thus:
def all(req):
req.add_stacked_handler("PythonHandler","page::header")
req.add_stacked_handler("PythonHandler","page::body")
req.add_stacked_handler("PythonHandler","page::footer")
return apache.OK
Making req.add_handler() add each handler as a distinct one.
Okay, that is the end of the ramble. Hope someone understands what I
am raving
on about and can provide some useful feedback.
Graham
[vbcol=seagreen]
> Anyway, for information of stacked handlers in mod_perl, see:
>
> http://www.oreilly.com/catalog/wrap.../ch04.html#3948
>
> Note that don't need chained handlers from mod_perl as that is now
> doable
> using filters.
>
> Graham
>
> On 19/02/2006, at 2:16 AM, Jim Gallacher wrote:
>
| |
| Graham Dumpleton 2006-02-19, 8:21 am |
|
On 19/02/2006, at 3:24 PM, Graham Dumpleton wrote:
> Thus depending on what you are doing, you need one or the other. To
> make it
> obvious, should perhaps use a distinct method name to add handlers
> as stacked
> handlers against the current handler list. Thus:
>
> def all(req):
> req.add_stacked_handler("PythonHandler","page::header")
> req.add_stacked_handler("PythonHandler","page::body")
> req.add_stacked_handler("PythonHandler","page::footer")
> return apache.OK
Hmmm, adding a stacked handler probably only makes sense for the current
phase. Thus, perhaps just:
def all(req):
req.add_stacked_handler("page::header")
req.add_stacked_handler("page::body")
req.add_stacked_handler("page::footer")
return apache.OK
or if overloading is allowed:
def all(req):
req.add_handler(None,"page::header")
req.add_handler(None,"page::body")
req.add_handler(None,"page::footer")
return apache.OK
That no phase is listed means the current phase is used and it would
be stacked.
Too obscure???
If you allowed an independent handler stack to be added, maybe you
need to
allow a list as an alternative of just the handler string.
def all(req):
req.add_handler("PythonHandler",
["page::header","page::body","page::footer"])
return apache.DECLINED
Rather not use a single string and have to split it.
Graham
|
|
|
|
|