You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@httpd.apache.org by tv...@aventail.com on 1999/05/17 23:58:43 UTC

redirect in post-read phase

I apologize for the x-post (I sent this to apache-modules@covalent.net
yesterday), but I am just far too impatient. Not that a response is
guaranteed on this list, but my odds are at least better. 

<X-POST>
Anybody have any idea why something like this:

        if (cookie was found)
                return DECLINED;

        location = ap_psprintf(r->pool,
                               "%s://%s:%d%s?request=%s",
                               ap_http_method(r),
                               ap_get_server_name(r),
                               ap_get_server_port(r),
                               sconfig->authenticator,
                               r->unparsed_uri);

        ap_table_setn(r->headers_out, "Location", location);
        return REDIRECT;

would cause NOTHING to be sent to the client? Can a redirect be done in the 
post-read phase? I haven't traced this down all the way, but it appears
that apache is going through all the right motions to send the header out,
it's just that nothing is being write()'d.
</X-POST>

-Tom

-- 
Tom Vaughan <tvaughan at aventail dot com>

Re: redirect in post-read phase

Posted by tv...@aventail.com.
A quick grep of the source[1] reveals that every occurance of
ap_send_error_response() contains after it a call to ap_rflush(), except
the one located at the bottom of ap_die() which is the one called when
something other than an OK is returned by a module's post-read phase
handler.

Should perhaps the last call in ap_send_error_response() be a call to
ap_rflush()? Doing this solves my problem at least. Not sure about other
PRs. Sorry.

--- http_protocol.c.orig	Mon May 17 17:23:58 1999
+++ http_protocol.c	Mon May 17 17:24:41 1999
@@ -949,7 +949,6 @@
             ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r,
                          "request failed: URI too long");
             ap_send_error_response(r, 0);
-            ap_rflush(r);
             ap_log_transaction(r);
             return r;
         }
@@ -963,7 +962,6 @@
             ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r,
                          "request failed: error reading the headers");
             ap_send_error_response(r, 0);
-            ap_rflush(r);
             ap_log_transaction(r);
             return r;
         }
@@ -983,7 +981,6 @@
             r->header_only = 0;
             r->status = HTTP_BAD_REQUEST;
             ap_send_error_response(r, 0);
-            ap_rflush(r);
             ap_log_transaction(r);
             return r;
         }
@@ -1016,7 +1013,6 @@
                       "client sent HTTP/1.1 request without hostname "
                       "(see RFC2068 section 9, and 14.23): %s", r->uri);
         ap_send_error_response(r, 0);
-        ap_rflush(r);
         ap_log_transaction(r);
         return r;
     }
@@ -1037,7 +1033,6 @@
                           "client sent an unrecognized expectation value of "
                           "Expect: %s", expect);
             ap_send_error_response(r, 0);
-            ap_rflush(r);
             (void) ap_discard_request_body(r);
             ap_log_transaction(r);
             return r;
@@ -2613,4 +2608,5 @@
     }
     ap_kill_timeout(r);
     ap_finalize_request_protocol(r);
+    ap_rflush(r);
 }

-Tom

[1] [tvaughan@rehab apache_1.3.6]$ find . -name *.[ch] -print | xargs grep -n ap_send_error_response
./src/include/ap_compat.h:334:#define send_error_response            ap_send_error_response
./src/include/http_protocol.h:106:void ap_send_error_response(request_rec *r, int recursive_error);
./src/main/http_protocol.c:951:            ap_send_error_response(r, 0);
./src/main/http_protocol.c:965:            ap_send_error_response(r, 0);
./src/main/http_protocol.c:985:            ap_send_error_response(r, 0);
./src/main/http_protocol.c:1018:        ap_send_error_response(r, 0);
./src/main/http_protocol.c:1039:            ap_send_error_response(r, 0);
./src/main/http_protocol.c:2256:void ap_send_error_response(request_rec *r, int recursive_error)
./src/main/http_request.c:1050:    ap_send_error_response(r, recursive_error);
./src/modules/proxy/proxy_util.c:844:    /* Allow the "error-notes" string to be printed by ap_send_error_response() */

tvaughan@aventail.com writes:

> I apologize for the x-post (I sent this to apache-modules@covalent.net
> yesterday), but I am just far too impatient. Not that a response is
> guaranteed on this list, but my odds are at least better. 
> 
> <X-POST>
> Anybody have any idea why something like this:
> 
>         if (cookie was found)
>                 return DECLINED;
> 
>         location = ap_psprintf(r->pool,
>                                "%s://%s:%d%s?request=%s",
>                                ap_http_method(r),
>                                ap_get_server_name(r),
>                                ap_get_server_port(r),
>                                sconfig->authenticator,
>                                r->unparsed_uri);
> 
>         ap_table_setn(r->headers_out, "Location", location);
>         return REDIRECT;
> 
> would cause NOTHING to be sent to the client? Can a redirect be done in the 
> post-read phase? I haven't traced this down all the way, but it appears
> that apache is going through all the right motions to send the header out,
> it's just that nothing is being write()'d.
> </X-POST>
> 
> -Tom
> 
> -- 
> Tom Vaughan <tvaughan at aventail dot com>
> 

-- 
Tom Vaughan <tvaughan at aventail dot com>

Re: redirect in post-read phase

Posted by Valentin Bazavan <ba...@hpias.cup.hp.com>.
I had a similar need in a module I wrote some time ago, and I couldn't make
redirection to work from the post-read callback. I used a workaround instead.
Namely, I created a redirect handler, and in the post-read callback I set the
handler member of the request_rec structure to point to this handler.
It works pretty well, if you don't mind the extra step. E.g.:

static int hpac_redirect( request_rec *r )
{
    .
    .
    r->status = REDIRECT;
    ap_table_set( r->headers_out, "Location", <some URI> );
    return REDIRECT;
}

handler_rec hpac_handlers[ ] =
{
    { "hpac-redirect", hpac_redirect },
    .
    .
    { NULL }
};

static int control_hpac( request_rec *r )
{
    .
    .
    r->handler = "hpac-redirect";
    ap_table_setn( r->notes, "HPAC", "redirected"); /* for logging */
    return OK;

}

> would cause NOTHING to be sent to the client? Can a redirect be done in the
> post-read phase? I haven't traced this down all the way, but it appears
> that apache is going through all the right motions to send the header out,
> it's just that nothing is being write()'d.
> </X-POST>
>
> -Tom
>
> --
> Tom Vaughan <tvaughan at aventail dot com>
>-- End of excerpt from tvaughan@aventail.com



Re: redirect in post-read phase

Posted by Dean Gaudet <dg...@arctic.org>.

On 18 May 1999 tvaughan@aventail.com wrote:

> I can, but why waste the cycles if they can be avoided?

Correct vs. broken. 

Dean


Re: redirect in post-read phase

Posted by tv...@aventail.com.
Dean Gaudet <dg...@arctic.org> writes:

> Well I never intended post read request to be used that way... it was
> mostly intended for setting up environment variables.
> 
> Does your module do the right thing for subrequests?  See the XXX: comment
> in internal_internal_redirect in main/http_request.c.  I suggest that the
> phase is misnamed...

Not a clue. I'll take a look. Thanks.

> 
> Why can't you send your redirect in the same phase that mod_alias uses?

I can, but why waste the cycles if they can be avoided?

-Tom

-- 
Tom Vaughan <tvaughan at aventail dot com>

Re: redirect in post-read phase

Posted by Valentin Bazavan <ba...@hpias.cup.hp.com>.
On May 18,  2:00pm, Dean Gaudet wrote:
> Subject: Re: redirect in post-read phase
>
>
> On Tue, 18 May 1999, Valentin Bazavan wrote:
>
> > On May 18, 10:35am, Dean Gaudet wrote:
> > > Subject: Re: redirect in post-read phase

> Why don't the standard auth hooks work for you?

I didn't try the standard auth hooks. The post-read hook seemed to be the best
place for an admission controller, because it is called even before the
authentication phase. (The admission controller admits based on system load
and other considerations, it's not another authentication module.)

>
> Yeah I know how it works -- people hack together a solution that appears
> to work using the first thing they find... and generally don't find the
> right solution the first time... and then report bugs on things which

You are exactly right.

> they're using in ways we didn't intend... and then when we ask, "why
> didn't the standard way that module foobar uses work for you?"  they say

Maybe because when you do it the first time you don't realize what is the
"standard" way to do it?

> something like "oh, I didn't think of copying your examples"... to
> paraphrase things :)
>
> Yeah yeah there's no docs.  But there's a bunch of examples :)

Yes, indeed, there is plenty of code to look at. Reading the code is very
helpful in finding out how to do something, but it's not always obvious why
it is (or has to be) done that way.

Anyway, my comment was meant as a tribute, not a criticism. The fact that
something can be used in ways beyond the original intent is a "feature," not a
"bug." :-)

Valentin Bazavan

>
> Dean
>
>
>-- End of excerpt from Dean Gaudet



Re: redirect in post-read phase

Posted by Doug MacEachern <do...@cp.net>.
On 18 May 1999 tvaughan@aventail.com wrote:

> Consulting the index, _Writing Apache Modules with C and Perl, 1st ed._
> covers the post-read phase on pages 72, 332, and 512. There is never really
> any mention of what can and can't be done in this phase.
> 
> For example, on page 332:

true, it never says what can and can't be done, but the key word that is
used more than once is "initialize":
"The I<post_read_request> phase is a handy place to initialize
per-request data that will be available to other handlers in the
request chain. Because of its usefulness as an initialize ..."

and, the example modules discussed, mod_unique_id, mod_setenvif, etc.,
have nothing todo with a direct response the client.

if you read on to the description of header parser, it starts to talk
about doing what you want to do:
"... to take special action, perhaps altering the headers on the fly (as
we will do below to create an anonymous proxy server), or blocking 
unwanted transactions at an early stage. ..."

-Doug


Re: redirect in post-read phase

Posted by tv...@aventail.com.
Dean Gaudet <dg...@arctic.org> writes:

> Yeah I know how it works -- people hack together a solution that appears
> to work using the first thing they find... and generally don't find the
> right solution the first time... and then report bugs on things which
> they're using in ways we didn't intend... and then when we ask, "why
> didn't the standard way that module foobar uses work for you?"  they say
> something like "oh, I didn't think of copying your examples"... to
> paraphrase things :) 
> 
> Yeah yeah there's no docs.  But there's a bunch of examples :) 

Not sure to whom this was directed...

The modules in src/modules/standard/ do not all redirect the same way.

Fact is, before I sent my e-mail on this topic I read both _Apache The
Definitive Guide, 2nd ed._ and _Writing Apache Modules with C and Perl, 1st
ed._, *and* stepped through the code, *and* read the comments.

Consulting the index, _Writing Apache Modules with C and Perl, 1st ed._
covers the post-read phase on pages 72, 332, and 512. There is never really
any mention of what can and can't be done in this phase.

For example, on page 332:

        When a listening server receives an incoming request, it reads the
        HTTP request line and parses any HTTP headers sent along with
        it. Provided that what's been read is valid HTTP, Apache gives
        modules an early chance to step in during th _post_read_request_
        phase, known to the Perl API world as the
        _PerlPostReadRequestHandler_. This is the very first callback that
        Apache makes when serving an HTTP request, and it happens even
        before URI translation turns the requested URI into a physical
        pathname. 

_Apache The Definitive Guide, 2nd ed._ covers the post-read phase on page
303. This however would seem to indicate that a module could redirect in
this phase.

On page 303:

        This function is called immediately after the request headers have
        been read, or, in the case of an internal redirect, synthesized. It
        is not called on subrequests. It can return OK, DECLIENED, or a
        status code. If something other than DECLINED is returned, no
        further modules are called. This can be used to make decisions
        purely based on the header content. Currently the only standard
        Apache module to use this hook is the proxy module.

Especially when you step through he code and see this being run:

        ap_rvputs(r,
                  "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\n"
                  "<HTML><HEAD>\n<TITLE>", title,
                  "</TITLE>\n</HEAD><BODY>\n<H1>", h1, "</H1>\n",
                  NULL);

	switch (status) {
	case HTTP_MOVED_PERMANENTLY:
	case HTTP_MOVED_TEMPORARILY:
	case HTTP_TEMPORARY_REDIRECT:
	    ap_rvputs(r, "The document has moved <A HREF=\"",
		      ap_escape_html(r->pool, location), "\">here</A>.<P>\n",
		      NULL);
	    break;

If the post-read phase really isn't meant to be used like this, then I'd
say you need to revisit your use of ap_die() in ap_read_request(), and let
your colleagues know. 

-Tom

-- 
Tom Vaughan <tvaughan at aventail dot com>

Re: redirect in post-read phase

Posted by Dean Gaudet <dg...@arctic.org>.
p.s. and the reason I ask "why didn't you copy foo?" is because we also
want to know what deficiencies there are in the API... because that helps
us move forward. 

Dean

On Tue, 18 May 1999, Dean Gaudet wrote:

> 
> 
> On Tue, 18 May 1999, Valentin Bazavan wrote:
> 
> > On May 18, 10:35am, Dean Gaudet wrote:
> > > Subject: Re: redirect in post-read phase
> > > Well I never intended post read request to be used that way... it was
> > > mostly intended for setting up environment variables.
> > >
> > But you know how it works. You add a capablility for some purpose and people
> > discover many other ways it can be useful. I, for instance, use the post-read
> > hook to insert an admission control module into the server.
> 
> Why don't the standard auth hooks work for you? 
> 
> Yeah I know how it works -- people hack together a solution that appears
> to work using the first thing they find... and generally don't find the
> right solution the first time... and then report bugs on things which
> they're using in ways we didn't intend... and then when we ask, "why
> didn't the standard way that module foobar uses work for you?"  they say
> something like "oh, I didn't think of copying your examples"... to
> paraphrase things :) 
> 
> Yeah yeah there's no docs.  But there's a bunch of examples :) 
> 
> Dean
> 
> 
> 


Re: redirect in post-read phase

Posted by Dean Gaudet <dg...@arctic.org>.

On Tue, 18 May 1999, Valentin Bazavan wrote:

> On May 18, 10:35am, Dean Gaudet wrote:
> > Subject: Re: redirect in post-read phase
> > Well I never intended post read request to be used that way... it was
> > mostly intended for setting up environment variables.
> >
> But you know how it works. You add a capablility for some purpose and people
> discover many other ways it can be useful. I, for instance, use the post-read
> hook to insert an admission control module into the server.

Why don't the standard auth hooks work for you? 

Yeah I know how it works -- people hack together a solution that appears
to work using the first thing they find... and generally don't find the
right solution the first time... and then report bugs on things which
they're using in ways we didn't intend... and then when we ask, "why
didn't the standard way that module foobar uses work for you?"  they say
something like "oh, I didn't think of copying your examples"... to
paraphrase things :) 

Yeah yeah there's no docs.  But there's a bunch of examples :) 

Dean



Re: redirect in post-read phase

Posted by Valentin Bazavan <ba...@hpias.cup.hp.com>.
On May 18, 10:35am, Dean Gaudet wrote:
> Subject: Re: redirect in post-read phase
> Well I never intended post read request to be used that way... it was
> mostly intended for setting up environment variables.
>
But you know how it works. You add a capablility for some purpose and people
discover many other ways it can be useful. I, for instance, use the post-read
hook to insert an admission control module into the server.

Valentin Bazavan

Re: redirect in post-read phase

Posted by Dean Gaudet <dg...@arctic.org>.
Well I never intended post read request to be used that way... it was
mostly intended for setting up environment variables.

Does your module do the right thing for subrequests?  See the XXX: comment
in internal_internal_redirect in main/http_request.c.  I suggest that the
phase is misnamed...

Why can't you send your redirect in the same phase that mod_alias uses?

Dean

On 18 May 1999 tvaughan@aventail.com wrote:

> Dean Gaudet <dg...@arctic.org> writes:
> 
> > On 18 May 1999 tvaughan@aventail.com wrote:
> > 
> > > The problem still remains that ap_rflush is never called.
> > 
> > If that were the case, mod_alias wouldn't work.  So how does your module
> > differ?
> 
> mod_alias does its redirect in the filename translation, or fixups
> phase. Not sure which. My module does its redirect in the post-read
> phase. mod_alias does not even have such a hook. 
> 
> The problem is that everything other than the post-read phase is handled by
> ap_process_request. ap_process_request contains a call to ap_bhalfduplex,
> which calls ap_bflush. The post-read phase is handled by ap_read_request
> which does not have a 'flush' of any sort. 
> 
> -Tom
> 
> > 
> > Dean
> > 
> 
> -- 
> Tom Vaughan <tvaughan at aventail dot com>
> 


Re: redirect in post-read phase

Posted by tv...@aventail.com.
Dean Gaudet <dg...@arctic.org> writes:

> On 18 May 1999 tvaughan@aventail.com wrote:
> 
> > The problem still remains that ap_rflush is never called.
> 
> If that were the case, mod_alias wouldn't work.  So how does your module
> differ?

mod_alias does its redirect in the filename translation, or fixups
phase. Not sure which. My module does its redirect in the post-read
phase. mod_alias does not even have such a hook. 

The problem is that everything other than the post-read phase is handled by
ap_process_request. ap_process_request contains a call to ap_bhalfduplex,
which calls ap_bflush. The post-read phase is handled by ap_read_request
which does not have a 'flush' of any sort. 

-Tom

> 
> Dean
> 

-- 
Tom Vaughan <tvaughan at aventail dot com>

Re: redirect in post-read phase

Posted by Dean Gaudet <dg...@arctic.org>.

On 18 May 1999 tvaughan@aventail.com wrote:

> The problem still remains that ap_rflush is never called.

If that were the case, mod_alias wouldn't work.  So how does your module
differ?

Dean


Re: redirect in post-read phase

Posted by tv...@aventail.com.
Rodent of Unusual Size <Ke...@Golux.Com> writes:

> Try putting the "Location" field into r->err_headers_out instead
> of r->headers_out.  The contents of the former table are *always*
> sent, but there are conditions under which the latter are not.

Yup. One of the first things I tried. The r->err_headers_out are preserved,
and the r->headers_out are cleared. With one exception. The Location within
r->headers_out is preserved. So I guess it could be done either way. 

>From http_protocol.c:ap_send_error_response

    const char *location = ap_table_get(r->headers_out, "Location");

    [snip]

        table *tmp = r->headers_out;

        /* For all HTTP/1.x responses for which we generate the message,
         * we need to avoid inheriting the "normal status" header fields
         * that may have been set by the request handler before the
         * error or redirect, except for Location on external redirects.
         */
        r->headers_out = r->err_headers_out;
        r->err_headers_out = tmp;
        ap_clear_table(r->err_headers_out);

        if (location && *location
            && (ap_is_HTTP_REDIRECT(status) || status == HTTP_CREATED))
            ap_table_setn(r->headers_out, "Location", location);

The problem still remains that ap_rflush is never called.

-Tom

> -- 
> #ken    P-)}
> 
> Ken Coar                    <http://Web.Golux.Com/coar/>
> Apache Software Foundation  <http://www.apache.org/>
> "Apache Server for Dummies" <http://Web.Golux.Com/coar/ASFD/>
> 

-- 
Tom Vaughan <tvaughan at aventail dot com>

Re: redirect in post-read phase

Posted by Rodent of Unusual Size <Ke...@Golux.Com>.
Try putting the "Location" field into r->err_headers_out instead
of r->headers_out.  The contents of the former table are *always*
sent, but there are conditions under which the latter are not.
-- 
#ken    P-)}

Ken Coar                    <http://Web.Golux.Com/coar/>
Apache Software Foundation  <http://www.apache.org/>
"Apache Server for Dummies" <http://Web.Golux.Com/coar/ASFD/>