You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@httpd.apache.org by Chris Darroch <ch...@pearsoncmg.com> on 2005/12/22 23:18:05 UTC

[PATCH 38019, 36908] make SetEnv run during post_read_req

Hi --

   Well, this may be a sore point, but I'll tackle it anyway,
so apologies in advance.  The fact that environment variables
created with SetEnv are applied during the fixups phase,
while SetEnvIf creates its variables during the post_read_request
and header_parser phases, does make my life a little more
painful.

   This has been raised in various bug reports, including #36908
and #35611.  These are marked "won't fix", with the explanation
that SetEnv is intended for use by content generators like CGI
scripts.

   However, as I've described in a new bug (sorry!), #38019,
I have a particular setup where what I'd like to do is reject all
requests that contain a particular HTTP header (in this case, a header
injected by hardware that means the request is coming from outside our
private network).  Here's what I thought I could do:

SetEnv FOO 1
SetEnvIf Http-X-Foo .+ !FOO
<Directory /foo>
    Allow from env=FOO
</Directory>

The logic being, set FOO=1, then unset FOO if the HTTP header is
present, and only allow access to a resource if FOO is still present.

   I attach a patch to the bug report in #38019 that simply moves
mod_env's handler up to the post_read_request phase, ahead of
mod_setenvif.

   Now, there may be historical reasons why this isn't desired,
and it might, I suppose, also cause existing users' configurations
to malfunction.  Still, I'd propose it as a 2.3/2.4 change, because
it does enable functionality like that I outlined above, and more
generally, it makes sense that all of the SetEnv* and PassEnv*, etc.,
directives would take effect at the same time.

   If this change isn't accepted, then I would strongly suggest
changing the documentation regarding environment variables to indicate
the order in which directives take effect; at the moment, that's not
clear.  In fact, the current documentation says the following, which
may be true for the special purpose environment variables listed on
the page, but isn't true in general for variables used in other ways
(e.g., in "Allow from env"):

  "To make these mechanisms as flexible as possible, they are invoked
   by defining environment variables, typically with BrowserMatch,
   though SetEnv and PassEnv could also be used, for example."

This section in particular, to my mind, clearly implies to the reader
that SetEnv and SetEnvIf take effect at the same time.  So does
the section on the Allow direction from mod_authz_host, which says:

  "The third format of the arguments to the Allow directive allows
   access to the server to be controlled based on the existence of an
   _environment_variable_. When Allow from env=env-variable is
   specified, then the request is allowed access if the environment
   variable env-variable exists. The server provides the ability to
   set environment variables in a flexible way based on characteristics
   of the client request using the directives provided by mod_setenvif."

The link to the "Environment Variables" page, and the wording,
imply that while mod_setenvif directives may be used to control
access based on request characteristics, that's not the only
way it could work, and other mechanisms for setting environment
variables should work too.

   If it's going to stay the way it is now for historical and
user support reasons, let me know and I'll try to write
something more obvious for docs/manual/env.xml, mod/mod_env.xml,
mod/mod_authz_host.xml, etc.

Thanks!

Chris.

-- 
GPG Key ID: 366A375B
GPG Key Fingerprint: 485E 5041 17E1 E2BB C263  E4DE C8E3 FA36 366A 375B


Re: [PATCH 38019, 36908] make SetEnv run during post_read_req

Posted by Nick Kew <ni...@webthing.com>.
On Thursday 22 December 2005 22:18, Chris Darroch wrote:

>    Well, this may be a sore point, but I'll tackle it anyway,
> so apologies in advance.  The fact that environment variables
> created with SetEnv are applied during the fixups phase,
> while SetEnvIf creates its variables during the post_read_request
> and header_parser phases, does make my life a little more
> painful.
>
>    This has been raised in various bug reports, including #36908
> and #35611.  These are marked "won't fix", with the explanation
> that SetEnv is intended for use by content generators like CGI
> scripts.

This looks a lot like the situation with mod_headers, that we solved
some time ago by introducing the "early" keyword.  AFAICS the same
solution would work for mod_env.  The number of bug reports you
cite evidences a demand for it.  That would be a very quick and
easy solution.

The solution you propose in your followup seems rather close to
folding mod_env into mod_setenvif in a manner designed to be
internally consistent.  That too makes sense to me, but would want
a little more thought.

Anyone else?

-- 
Nick Kew

Re: [PATCH 38019, 36908] make SetEnv run during post_read_req

Posted by Chris Darroch <ch...@pearsoncmg.com>.
Hi --

> I have a particular setup where what I'd like to do is reject all
> requests that contain a particular HTTP header (in this case, a header
> injected by hardware that means the request is coming from outside our
> private network).  Here's what I thought I could do:
> 
> SetEnv FOO 1
> SetEnvIf Http-X-Foo .+ !FOO
> <Directory /foo>
>     Allow from env=FOO
> </Directory>
> 
> The logic being, set FOO=1, then unset FOO if the HTTP header is
> present, and only allow access to a resource if FOO is still present.

   I thought a bit more about this last night, did some experimentation,
and have a different proposal now.  :-/  I found that for my
particular situation, I can use:

SetEnvIf Http-X-Foo ^$ FOO

which works because SetEnvIf matches an empty regex if either the
Http-X-Foo header is present and empty, or if it isn't present at all.
I find this somewhat counter-intuitive (albeit useful in this
particular case): how can a missing header match against anything?

   So, here's the proposal.  Alas, I am deeply short of "round tuits"
these days, but perhaps in a couple of months I can supply a patch.
Comments welcome beforehand, though.


1) Leave mod_env as-is for the moment, but document that it only
   functions for content generators, and not for any prior part
   of the request handling process.  In a future release (2.4? 3.0?)
   change the name of the directives to SetEnvCGI, etc.

2) Alter mod_setenvif so that SetEnvIf only matches if a header
   is present.  To my mind, this is simply the single-header
   equivalent of what you'd want to happen when using a regex
   to match header names, e.g.:

   SetEnvIf ^Http-X-.*$ ...

   I'd presumably want nothing to happen if no headers match the
   name regex.  In the case where I'm using a simple header name,
   like Http-X-Foo, that should be equivalent to using ^Http-X-Foo$,
   and thus follow the same logic; if no header is present that
   matches that name, nothing should happen (i.e., all value
   string regexs should fail to match, even for ^.*$ and other
   always-matching regexs).

3) Add to mod_setenvif a new directive, SetEnvPre, which works
   like this:

   SetEnvPre env-variable[=value]

   and simply sets env-variable to the given value (or an empty
   string if no value is supplied) before any SetEnvIf directives
   are applied.

4) Add to mod_setenvif another new directive, SetEnvExists, which
   works like this:

   SetEnvExists header|header-regex [!]env-variable[=value]
      [[!]env-variable[=value]] ...

   That is, just like SetEnvIf, but it only deals with headers
   (not other request attributes like Request_URI, etc.), and
   sets or unsets the env-variables based on whether any matching
   headers exist in the request.


   With these directives, one could set up something like:

SetEnvPre FOO=false
SetEnvExists ^Http-X-Foo-.*$ FOO=true

SetEnvPre FOO_IGNORE
SetEnvExists Http-X-Foo-Ignore FOO_IGNORE=all
SetEnvIfNoCase Http-X-Foo-Ignore ^header=(.*)$ FOO_IGNORE=$1

so that FOO is "false" unless at least one Http-X-Foo-* header
exists, in which case it's "true", and FOO_IGNORE is empty
unless the Http-X-Foo-Ignore header exists, in which case
FOO_IGNORE is "all", or if Http-X-Foo-Ignore has the form
header=foo then FOO_IGNORE is "foo".

   Does that all make sense?  As I said, comments welcome,
and flames also.  ("What's this?!  Santa flambé??")

Chris.

-- 
GPG Key ID: 366A375B
GPG Key Fingerprint: 485E 5041 17E1 E2BB C263  E4DE C8E3 FA36 366A 375B