|
Graham Dumpleton
grahamd at dscpl.com.au
Sat Apr 23 03:41:13 EDT 2005
There has been a few times on the list where questions have been asked
about
how to pass information through a "req.internal_redirect()" call. The
problem
is that any data which is stashed in the "req" object isn't available
to the
target of the internal redirect because Apache/mod_python constructs a
new
"req" object for the subsequent handler invocation.
Turns out there is actually a way of passing at least some information.
This
is done by adding new key/values to the "req.subprocess_env" table.
This table
is held within Apache data structures associated with the request and
contents
of it are propagated through to the target of the internal redirect.
The only
trick is that the key names get modified when the redirect occurs. You
also
can only store string values.
Take for example a handler which contains:
from mod_python import apache
import os
def handler(req):
req.subprocess_env.add("XXX","YYY")
req.internal_redirect(os.path.split(req.uri)[0]+'/page')
return apache.OK
and is accessed as:
/~grahamd/redirect/redirect
And a second handler which is triggered as the target of the redirect
which
contains:
from mod_python import apache
def handler(req):
req.content_type = "text/plain"
for key in req.subprocess_env.keys():
print >> req, key, "=", req.subprocess_env[key]
return apache.OK
That is, URL for this is:
/~grahamd/redirect/page
The result of making a request against the first URL is that
redirection to
the second occurs, with the output being:
REDIRECT_GATEWAY_INTERFACE = CGI/1.1
REDIRECT_SERVER_PROTOCOL = HTTP/1.1
REDIRECT_REQUEST_METHOD = GET
REDIRECT_QUERY_STRING =
REDIRECT_REQUEST_URI = /~grahamd/redirect/redirect
REDIRECT_SCRIPT_NAME = /~grahamd/redirect/redirect
REDIRECT_XXX = YYY
REDIRECT_STATUS = 200
GATEWAY_INTERFACE = CGI/1.1
SERVER_PROTOCOL = HTTP/1.1
REQUEST_METHOD = GET
QUERY_STRING =
REQUEST_URI = /~grahamd/redirect/redirect
SCRIPT_NAME = /~grahamd/redirect/page
As can be seen, the key/value pair of "XXX" and "YYY" have persisted,
although
the key name is now "REDIRECT_XXX". One can also see that other
preexisting
variables set by Apache for the original request are also propagated as
well,
with similar key name change.
That one can pass a newly created value would be useful where for
example a
initial handler had created a new session object as it could store the
session
ID in this table such that it is accessible to the second handler. In
the past
people have noticed how in redirects both handlers end up creating
separate
new session IDs if the first handler had to create one, because the new
session
ID is lost and not usable by the second handler.
The information propagated about the initial request is useful as well
for the
fact that the original URI is present. This could be used by the second
handler
in some way.
As an example, when using the ErrorDocument directive, Apache uses an
internal
redirect to redirect to the page when it is a local URI. As documented
in:
http://httpd.apache.org/docs-2.0/custom-error.html
the req.subprocess_env would contain the "REDIRECT_*" values shown
above. In
this case the internal redirect is being done in Apache itself, but
there is
no reason that you couldn't implement your own version of the
ErrorDocument
functionality in your own custom handler code.
Anyway, thought I would put together this ramble about this stuff when
I found
that this could be done since it may have been a solution to problems a
few
people had faced before, but that it could be done doesn't seem to have
ever
been mentioned on the mailing list before. At least now anyone
searching the
archives may find this. :-)
Enjoy.
Graham
|