> I added some debug logging to see headers_out() before and after calling
> no_cache(1).  no_cache(1) appears to be setting the specified headers and
> internal_redirect() appears to be ignoring them.

alright, I think I see what's going on here.  I'll explain technically and
then try to explain the rationale I think is behind it.

the reason $r->no_cache(1) isn't affecting your code is that an
internal_redirect() is purposefully ignoring the headers_out table when it
issues the redirect.  to paraphrase the code, when you call
$r->internal_redirect apache creates a _new_ request and sends that request
through the standard request cycle, starting with uri translation.  when the
new request is created it copies various things from the current request,
one of which is _not_ the headers_out table.  here's the code from
http_request.c in 1.3:

    request_rec *new;
    ...
    new->headers_in      = r->headers_in;
    new->headers_out     = ap_make_table(r->pool, 12);

so, when you call $r->internal_redirect() you get the properties of the
incoming request, but inherit none of the properties of current response.

please note this is an apache thing, not a mod_perl thing, so it's nothing
that mod_perl is doing "wrong."  as with almost all that mod_perl does, the
API of internal_redirect() is an apache C one that mod_perl merely passes on
to you in perl.

ok, now for the rationale.  I can only suspect that the reason for this
behavior is that the point of internal_redirect() is to act just like a full
external redirect (ie returning REDIRECT with a Location header) except
you're not letting the browser know about it.  in other words,
internal_redirect() is a transparent replacement of the current content with
content from a different URI, cache headers and all.

in truth, I think the behavior you're observing is the desirable one for the
vast majority of cases of using an internal redirect.  for example, sending
the ETag header from the current request when calling internal_redirect() to
another URI would probably break the rules surrounding ETag, which is
supposed to be unique for each resource.

but of course, none of this helps your code.  hopefully it at least helps
your understanding :)

if you're just playing around I guess the workaround is to use a subrequest
instead of internal_redirect().  for example

  my $sub = $r->lookup_uri($lucky);
  $sub->no_cache(1);
  $sub->run;

if you really want to use internal_redirect() I have a rather complex
solution that _might_ work.  take this module:
  http://www.modperlcookbook.org/code/ch03/Cookbook-SimpleRequest-0.01.tar.gz

crack it open and s/assbackwards/no_local_copy/.  then from your code you
would call $r->no_local_copy(1) instead of $r->no_cache(1).  it's not
guaranteed to work but it probably will :)  of course, in mod_perl 2.0 you
get access to no_local_copy() without the acrobatics.

HTH

--Geoff

Reply via email to