You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@httpd.apache.org by Thomas Eckert <th...@gmail.com> on 2013/04/03 09:52:07 UTC

ProxyPassReverseCookieDomain and non constant arguments

I'm trying to make ProxyPassReverseCookieDomain understand two things it
apparently does not understand at the moment: accept 1) balancer names and
2) variables as arguments. For the first problem I was able to come up with
a patch based on the code for the ProxyPassReverse directive (see below).

The second problem gives me headaches though. Suppose I would like to do
  ProxyPassReverseCookieDomain balancer://foobar/ %{HTTP_HOST}
so the %{HTTP_HOST} expression is translated to the http host field of the
original client request. This is required in case the reverse proxy is
reachable through multiple domains because the cookie must be set to the
correct domain - else it will not be transmitted by the client's agent in
the future.To achieve this I would have to carry this information from the
client->proxy request to the proxy->server request and their responses.
Obviously, this 'linking' of requests is already done be mod_proxy since it
could not function as a reveres proxy otherwise.

I would be grateful for some hints on this.


My preliminary patch for the balancer issue is located below

diff --git a/modules/proxy/proxy_util.c b/modules/proxy/proxy_util.c
index 5ab5d91..5345246 100644
--- a/modules/proxy/proxy_util.c
+++ b/modules/proxy/proxy_util.c
@@ -933,6 +933,29 @@ PROXY_DECLARE(const char *)
ap_proxy_location_reverse_map(
request_rec *r,
     return url;
 }

+/* Attempts to translate 'balancer_name' to a valid balancer, using the
'domain_name'
+ * to find the worker which matches to the domain. */
+PROXY_DECLARE(int) ap_proxy_balancer_matches_domain(request_rec *r, const
char* domain_name, const char *balancer_name)
+{
+  proxy_server_conf *sconf = (proxy_server_conf *)
ap_get_module_config(r->server->module_config, &proxy_module);
+
+  if (ap_proxy_valid_balancer_name((char *)balancer_name, 0) == 0)
+    return 0;
+
+  proxy_balancer *balancer = ap_proxy_get_balancer(r->pool, sconf,
balancer_name, 1);
+  if (balancer == NULL)
+    return 0;
+
+  int n;
+  proxy_worker **worker = (proxy_worker **)balancer->workers->elts;
+  for (n = 0; n < balancer->workers->nelts; n++) {
+    if (strcasecmp((*worker)->s->name, domain_name) == 0)
+      return 1;
+  }
+
+  return 0;
+}
+
 /*
  * Cookies are a bit trickier to match: we've got two substrings to worry
  * about, and we can't just find them with strstr 'cos of case.  Regexp
@@ -1003,7 +1026,8 @@ PROXY_DECLARE(const char *)
ap_proxy_cookie_reverse_map(request_rec *r,
         }
         for (i = 0; i < conf->cookie_domains->nelts; i++) {
             l2 = strlen(ent[i].fake);
-            if (l1 >= l2 && strncasecmp(ent[i].fake, domainp, l2) == 0) {
+            if ((ap_proxy_balancer_matches_domain(r, domainp, ent[i].fake)
== 1) ||
+                (l1 >= l2 && strncasecmp(ent[i].fake, domainp, l2) == 0)) {
                 newdomain = ent[i].real;
                 ddiff = strlen(newdomain) - l1;
                 break;

Re: ProxyPassReverseCookieDomain and non constant arguments

Posted by Thomas Eckert <th...@gmail.com>.
I'm getting the impression I did not state why these patches improve the
existing feature clearly enough, so I'll give it another shot.

1) The first patch addresses a scalability issue in mod_proxy. At present
an admin has to configure one ProxyPassReverseCookieDomain for every single
server he wants to reverse proxy. This does not scale well at all. Instead
of forcing admins to pollute their configuration files with repetitive
entries we can simply make use of the existing balancer names, which
themselves contain the server addresses. The resulting configuration files
look a lot better then without the patch and maintenance is not nearly as
inconvenient.

2) The second patch adds a currently missing feature. That is to allow the
configuration to reference a (specific) request-time value, just as many
configuration directives for other (or even the same!) modules already do.
Currently there is now way to have the directive adapt to each request
based on the request's (destination) hostname, which is necessary if you
want to rewrite the cookie to the _correct_ domain name. Remember, for the
client, the reverse proxy might be reachable via different hostnames so the
admin cannot know the value she has to put as the second argument. I added
this little feature so the directive can be used in this situation as well.
Otherwise an admin who wants to do this is out of luck. The second patch
might become obsolete with the implementation of a global interpolation
mechanism, as is discussed on the mailing list right now. But since I doubt
this is going to happen any time soon, we should see this added until then.

Combined, these two patches make the directive a lot easier to use and add
a degree of usability which I find sorely lacking right now.

Consider this configuration (which includes the suggested patches) :

<Proxy balancer://id1>
        BalancerMember http://server1.local
        BalancerMember http://server2.local
        BalancerMember http://server3.local <http://server1.local>
        BalancerMember http://server4.local <http://server2.local>
</Proxy>
<VirtualHost 10.10.10.10:80>
        ServerName reverseproxy.local
        <Location />
                ProxyPass balancer://id1/ lbmethod=bybusyness
                ProxyPassReverse balancer://id1/
                ProxyPassReverseCookieDomain balancer://id1/
        </Location>
</VirtualHost>

The above configuration is clearly easier to read and maintain then the one
below. And this is for 4 servers only. Just consider how this would look
like for 10+ servers, probably even spread over several VirtualHost entries.

<Proxy balancer://id1>
        BalancerMember http://server1.local
        BalancerMember http://server2.local
        BalancerMember http://server3.local <http://server1.local>
        BalancerMember http://server4.local <http://server2.local>
</Proxy>
<VirtualHost 10.10.10.10:80>
        ServerName reverseproxy.local
        <Location />
                ProxyPass balancer://id1/ lbmethod=bybusyness
                ProxyPassReverse balancer://id1/
                ProxyPassReverseCookieDomain
http://server1.localreverseproxy.local
                ProxyPassReverseCookieDomain http://server2.local
<http://server1.local>reverseproxy.local
                ProxyPassReverseCookieDomain http://server3.local
<http://server1.local>reverseproxy.local
                ProxyPassReverseCookieDomain http://server4.local
<http://server1.local>reverseproxy.local
        </Location>
</VirtualHost>


Now, if you also want to give your reverse proxy a ServerAlias, one would
do something like

<Proxy balancer://id1>
        BalancerMember http://server1.local
        BalancerMember http://server2.local
        BalancerMember http://server3.local <http://server1.local>
        BalancerMember http://server4.local <http://server2.local>
</Proxy>
<VirtualHost 10.10.10.10:80>
        ServerName reverseproxy.local
        ServerAlias other_name.local
        <Location />
                ProxyPass balancer://id1/ lbmethod=bybusyness
                ProxyPassReverse balancer://id1/
                ProxyPassReverseCookieDomain
http://server1.localreverseproxy.local      <--- problem !
                ProxyPassReverseCookieDomain http://server2.local
<http://server1.local>reverseproxy.local      <--- problem !
                ProxyPassReverseCookieDomain http://server3.local
<http://server1.local>reverseproxy.local      <--- problem !
                ProxyPassReverseCookieDomain http://server4.local
<http://server1.local>reverseproxy.local      <--- problem !
        </Location>
</VirtualHost>

The above marked lines will rewrite the cookies delivered to the client
_incorrectly_ if the client reached the reverse proxy through
"other_name.local". With the second patch we can just omit the last
argument to the directive (which really is redundant anyway) and have
mod_proxy insert the correct value by itself.


On Mon, Apr 22, 2013 at 10:33 AM, Thomas Eckert <thomas.r.w.eckert@gmail.com
> wrote:

> Any news here ? I would like this to get included since it fixes what I
> think is a real lack of usability - see my previous example as to the 'why'
> and 'how'.
>
>
> On Thu, Apr 4, 2013 at 11:34 AM, Thomas Eckert <
> thomas.r.w.eckert@gmail.com> wrote:
>
>> Suppose you have several balancers defined, each with multiple workers.
>> Now you want to rewrite all cookies from all servers, no matter the
>> hostname the client requested the content under.
>>
>> This means that - at time of configuration - you don't know the domain of
>> the content server you want to specify the directive for (1st argument to
>> ProxyPassReverseCookieDomain). This *might* be solved by iterating over all
>> domains and writing the directive for every single entry but this is surely
>> not considered 'good' style and absolutely not something users with large
>> setups want to do.
>>
>> The second problem is that - at time of configuration - you don't know
>> the hostname you have to rewrite the cookie to. It has to be the hostname
>> the client requested the content for, since only then will (or at least
>> should) it be transmitted by the client's agent in subsequent requests.
>> This would be solved by using %{HTTP_HOST} *if* that worked here. I
>> expected it to but after checking the code for rewriting the cookies I got
>> the impression the second argument to ProxyPassReverseCookieDomain would
>> simply be copied unchanged into the cookie without any previous
>> parsing/translation/substitution. I tried using %{HTTP_HOST} as second
>> argument - inside a <VirtualHost> - but it was not replaced by the
>> VirtualHost's ServerName or one of it's aliases and instead got printed
>> into the cookie as "Domain=%{HTTP_HOST}" (2.4.4 of course)
>>
>> The idea behind the patches is to be able to specify something like
>>
>> <Proxy balancer://cd107d9706d71153bafd4ab15f1c6b5d>
>>         BalancerMember http://server1.local
>>         BalancerMember http://server2.local
>> </Proxy>
>> <VirtualHost 10.10.10.10:80>
>>         ServerName reverseproxy.local
>>         <Location />
>>                 ProxyPass balancer://cd107d9706d71153bafd4ab15f1c6b5d/
>> lbmethod=bybusyness
>>                 ProxyPassReverse
>> balancer://cd107d9706d71153bafd4ab15f1c6b5d/
>>                 ProxyPassReverseCookieDomain
>> balancer://cd107d9706d71153bafd4ab15f1c6b5d/
>>         </Location>
>> </VirtualHost>
>>
>> With the suggested patches this is all it takes to rewrite all the
>> cookies to the correct domain names, independant of the number workers for
>> each balancer and the hostname of the client requests. I found no way to do
>> that with the existing code but I also feel like having missed something in
>> regards to using %{HTTP_HOST} - maybe some behind-the-scenes-magic I am
>> unaware of?
>>
>>
>>
>> On Thu, Apr 4, 2013 at 10:43 AM, Nick Kew <ni...@webthing.com> wrote:
>>
>>>
>>> On 3 Apr 2013, at 08:52, Thomas Eckert wrote:
>>>
>>> > I'm trying to make ProxyPassReverseCookieDomain understand two things
>>> it apparently does not understand at the moment: accept 1) balancer names
>>> and 2) variables as arguments. For the first problem I was able to come up
>>> with a patch based on the code for the ProxyPassReverse directive (see
>>> below).
>>> >
>>> > The second problem gives me headaches though. Suppose I would like to
>>> do
>>> >   ProxyPassReverseCookieDomain balancer://foobar/ %{HTTP_HOST}
>>>
>>> Why would you do that?  What backend application is setting cookies
>>> with such a broken domain parameter as that?
>>>
>>> > so the %{HTTP_HOST} expression is translated to the http host field of
>>> the original client request. This is
>>>
>>> The HTTP_HOST will always match the <VirtualHost> in which the reverse
>>> proxy
>>> is configured.  You can of course have as many virtualhosts as you want,
>>> but I'm not convinced you need even that.
>>>
>>> At a glance, your patch is unnecessary: you should get the same outcome
>>> by just adding a ProxyPassReverseCookieDomain directive for each Host:
>>> value you answer to.  Am I missing something?
>>>
>>> --
>>> Nick Kew
>>
>>
>>
>

Re: ProxyPassReverseCookieDomain and non constant arguments

Posted by Thomas Eckert <th...@gmail.com>.
Any news here ? I would like this to get included since it fixes what I
think is a real lack of usability - see my previous example as to the 'why'
and 'how'.


On Thu, Apr 4, 2013 at 11:34 AM, Thomas Eckert
<th...@gmail.com>wrote:

> Suppose you have several balancers defined, each with multiple workers.
> Now you want to rewrite all cookies from all servers, no matter the
> hostname the client requested the content under.
>
> This means that - at time of configuration - you don't know the domain of
> the content server you want to specify the directive for (1st argument to
> ProxyPassReverseCookieDomain). This *might* be solved by iterating over all
> domains and writing the directive for every single entry but this is surely
> not considered 'good' style and absolutely not something users with large
> setups want to do.
>
> The second problem is that - at time of configuration - you don't know the
> hostname you have to rewrite the cookie to. It has to be the hostname the
> client requested the content for, since only then will (or at least should)
> it be transmitted by the client's agent in subsequent requests. This would
> be solved by using %{HTTP_HOST} *if* that worked here. I expected it to but
> after checking the code for rewriting the cookies I got the impression the
> second argument to ProxyPassReverseCookieDomain would simply be copied
> unchanged into the cookie without any previous
> parsing/translation/substitution. I tried using %{HTTP_HOST} as second
> argument - inside a <VirtualHost> - but it was not replaced by the
> VirtualHost's ServerName or one of it's aliases and instead got printed
> into the cookie as "Domain=%{HTTP_HOST}" (2.4.4 of course)
>
> The idea behind the patches is to be able to specify something like
>
> <Proxy balancer://cd107d9706d71153bafd4ab15f1c6b5d>
>         BalancerMember http://server1.local
>         BalancerMember http://server2.local
> </Proxy>
> <VirtualHost 10.10.10.10:80>
>         ServerName reverseproxy.local
>         <Location />
>                 ProxyPass balancer://cd107d9706d71153bafd4ab15f1c6b5d/
> lbmethod=bybusyness
>                 ProxyPassReverse
> balancer://cd107d9706d71153bafd4ab15f1c6b5d/
>                 ProxyPassReverseCookieDomain
> balancer://cd107d9706d71153bafd4ab15f1c6b5d/
>         </Location>
> </VirtualHost>
>
> With the suggested patches this is all it takes to rewrite all the cookies
> to the correct domain names, independant of the number workers for each
> balancer and the hostname of the client requests. I found no way to do that
> with the existing code but I also feel like having missed something in
> regards to using %{HTTP_HOST} - maybe some behind-the-scenes-magic I am
> unaware of?
>
>
>
> On Thu, Apr 4, 2013 at 10:43 AM, Nick Kew <ni...@webthing.com> wrote:
>
>>
>> On 3 Apr 2013, at 08:52, Thomas Eckert wrote:
>>
>> > I'm trying to make ProxyPassReverseCookieDomain understand two things
>> it apparently does not understand at the moment: accept 1) balancer names
>> and 2) variables as arguments. For the first problem I was able to come up
>> with a patch based on the code for the ProxyPassReverse directive (see
>> below).
>> >
>> > The second problem gives me headaches though. Suppose I would like to do
>> >   ProxyPassReverseCookieDomain balancer://foobar/ %{HTTP_HOST}
>>
>> Why would you do that?  What backend application is setting cookies
>> with such a broken domain parameter as that?
>>
>> > so the %{HTTP_HOST} expression is translated to the http host field of
>> the original client request. This is
>>
>> The HTTP_HOST will always match the <VirtualHost> in which the reverse
>> proxy
>> is configured.  You can of course have as many virtualhosts as you want,
>> but I'm not convinced you need even that.
>>
>> At a glance, your patch is unnecessary: you should get the same outcome
>> by just adding a ProxyPassReverseCookieDomain directive for each Host:
>> value you answer to.  Am I missing something?
>>
>> --
>> Nick Kew
>
>
>

Re: ProxyPassReverseCookieDomain and non constant arguments

Posted by Thomas Eckert <th...@gmail.com>.
Suppose you have several balancers defined, each with multiple workers. Now
you want to rewrite all cookies from all servers, no matter the hostname
the client requested the content under.

This means that - at time of configuration - you don't know the domain of
the content server you want to specify the directive for (1st argument to
ProxyPassReverseCookieDomain). This *might* be solved by iterating over all
domains and writing the directive for every single entry but this is surely
not considered 'good' style and absolutely not something users with large
setups want to do.

The second problem is that - at time of configuration - you don't know the
hostname you have to rewrite the cookie to. It has to be the hostname the
client requested the content for, since only then will (or at least should)
it be transmitted by the client's agent in subsequent requests. This would
be solved by using %{HTTP_HOST} *if* that worked here. I expected it to but
after checking the code for rewriting the cookies I got the impression the
second argument to ProxyPassReverseCookieDomain would simply be copied
unchanged into the cookie without any previous
parsing/translation/substitution. I tried using %{HTTP_HOST} as second
argument - inside a <VirtualHost> - but it was not replaced by the
VirtualHost's ServerName or one of it's aliases and instead got printed
into the cookie as "Domain=%{HTTP_HOST}" (2.4.4 of course)

The idea behind the patches is to be able to specify something like

<Proxy balancer://cd107d9706d71153bafd4ab15f1c6b5d>
        BalancerMember http://server1.local
        BalancerMember http://server2.local
</Proxy>
<VirtualHost 10.10.10.10:80>
        ServerName reverseproxy.local
        <Location />
                ProxyPass balancer://cd107d9706d71153bafd4ab15f1c6b5d/
lbmethod=bybusyness
                ProxyPassReverse
balancer://cd107d9706d71153bafd4ab15f1c6b5d/
                ProxyPassReverseCookieDomain
balancer://cd107d9706d71153bafd4ab15f1c6b5d/
        </Location>
</VirtualHost>

With the suggested patches this is all it takes to rewrite all the cookies
to the correct domain names, independant of the number workers for each
balancer and the hostname of the client requests. I found no way to do that
with the existing code but I also feel like having missed something in
regards to using %{HTTP_HOST} - maybe some behind-the-scenes-magic I am
unaware of?



On Thu, Apr 4, 2013 at 10:43 AM, Nick Kew <ni...@webthing.com> wrote:

>
> On 3 Apr 2013, at 08:52, Thomas Eckert wrote:
>
> > I'm trying to make ProxyPassReverseCookieDomain understand two things it
> apparently does not understand at the moment: accept 1) balancer names and
> 2) variables as arguments. For the first problem I was able to come up with
> a patch based on the code for the ProxyPassReverse directive (see below).
> >
> > The second problem gives me headaches though. Suppose I would like to do
> >   ProxyPassReverseCookieDomain balancer://foobar/ %{HTTP_HOST}
>
> Why would you do that?  What backend application is setting cookies
> with such a broken domain parameter as that?
>
> > so the %{HTTP_HOST} expression is translated to the http host field of
> the original client request. This is
>
> The HTTP_HOST will always match the <VirtualHost> in which the reverse
> proxy
> is configured.  You can of course have as many virtualhosts as you want,
> but I'm not convinced you need even that.
>
> At a glance, your patch is unnecessary: you should get the same outcome
> by just adding a ProxyPassReverseCookieDomain directive for each Host:
> value you answer to.  Am I missing something?
>
> --
> Nick Kew

Re: ProxyPassReverseCookieDomain and non constant arguments

Posted by Nick Kew <ni...@webthing.com>.
On 3 Apr 2013, at 08:52, Thomas Eckert wrote:

> I'm trying to make ProxyPassReverseCookieDomain understand two things it apparently does not understand at the moment: accept 1) balancer names and 2) variables as arguments. For the first problem I was able to come up with a patch based on the code for the ProxyPassReverse directive (see below).
> 
> The second problem gives me headaches though. Suppose I would like to do
>   ProxyPassReverseCookieDomain balancer://foobar/ %{HTTP_HOST}

Why would you do that?  What backend application is setting cookies
with such a broken domain parameter as that?

> so the %{HTTP_HOST} expression is translated to the http host field of the original client request. This is

The HTTP_HOST will always match the <VirtualHost> in which the reverse proxy
is configured.  You can of course have as many virtualhosts as you want,
but I'm not convinced you need even that.

At a glance, your patch is unnecessary: you should get the same outcome
by just adding a ProxyPassReverseCookieDomain directive for each Host:
value you answer to.  Am I missing something?

-- 
Nick Kew