tomcat-users mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From André Warnier ...@ice-sa.com>
Subject Re: mod_jk how to add JK_WORKER_NAME to http-header
Date Wed, 27 Feb 2013 11:16:08 GMT
Jochen Wißmann wrote:
> On 27.02.2013 09:59, André Warnier wrote:
>> Rainer Jung wrote:
>>> On 26.02.2013 19:41, Jochen Wißmann wrote:
>>>> Hello,
>>>>
>>>> i am trying to find an easy way to determine from the http-client side,
>>>> which  AJP13-worker handled my request.
>>>> So my basic idea is to use mod_header to add mod_jk`s env-variable
>>>> JK_WORKER_NAME to the Header of the http-response.
>>>> I tried to get something like this working:
>>>>
>>>> httpd.conf:
>>>> ...
>>>> Header add TC-Server "%{JK_WORKER_NAME}e"
>>>> ...
>>>>
>>>> All my previous attempts resulted in http-responses looking like this:
>>>>
>>>> < HTTP/1.1 200 OK
>>>> < Set-Cookie: ARPT=LRWQXVS110.160.11.26CKMLQ; path=/
>>>> < Date: Tue, 26 Feb 2013 18:25:31 GMT
>>>> < Server: Apache/2.2.22 (Unix) mod_jk/1.2.36 mod_ssl/2.2.22
>>>> OpenSSL/0.9.8x DAV/2
>>>> < Set-Cookie: JSESSIONID=A4052BF60BA2007F0B0F47E2699AFDE.liferay0; 
>>>> Path=/
>>>> < Set-Cookie: GUEST_LANGUAGE_ID=en_US; Expires=Wed, 26-Feb-2014 
>>>> 18:25:31
>>>> GMT; Path=/
>>>> < Set-Cookie: COOKIE_SUPPORT=true; Expires=Wed, 26-Feb-2014 18:25:31
>>>> GMT; Path=/
>>>> < Liferay-Portal: Liferay Portal Community Edition 6.0.6 CE (Bunyan /
>>>> Build 6006 / February 17, 2011)
>>>> < ETag: "838b4ae2"
>>>> < Content-Length: 8043
>>>> < X-Server-Ip: 110.160.11.26
>>>> < TC-Server: (null)
>>>> < Content-Type: text/html;charset=utf-8
>>>>
>>>> Why do i get "TC-Server: (null)" ?
>>>> Using the Variable JK_WORKER_NAME to log the worker's name via
>>>> mod_log_config works fine.
>>>>
>>>> Am i missing something? Is it even possible to access the env-variable
>>>> JK_WORKER_NAME with module mod_header?
>>>> Could anyone please help?
>>>> Thanks!
>>>
>>> mod_jk respects the environment variable JK_WORKER_NAME when choosing a
>>> target worker, but it does not set it.
>>>
>>> mod_jk only sets a note with name JK_WORKER_NAME, which is different
>>> from an env var. The "n" in your log format means "note".
>>>
>>> Unfortunately most variable use supported in Apache config is for env
>>> vars, not for notes, so you can't directly set the header from a note.
>>>
>>> There are two things you can experiment with:
>>>
>>> a) using an undocumented mod_rewrite feature to try to copy the note
>>> into an env var and then using that env var to set the header
>>>
>>> or
>>>
>>> b) not using the normal JkMount or uriworkermap.properties way of
>>> defining the workers responsible for handling the URIs, but instead
>>> using mod_rewrite via setting the env var JK:WORKER_NAME
>>>
>>> Ad a)
>>>
>>> Works roughly like that (untested):
>>>
>>> RewriteCond %{ENV:JK_WORKER_NAME} (.*)
>>> RewriteRule . - [ENV=WORKER:%1]
>>>
>>> Note 1: the undocumented feature of mod_rewrite is, that
>>> %{ENV:JK_WORKER_NAME} first looks for a note named "JK_WORKER_NAME" and
>>> only if it doesn't find it for an env var.
>>>
>>> Note 2: The RewriteRule now sets a new env var "WORKER" to the captured
>>> value of the note. lease choose a new variable name here, not
>>> "JK_WORER_NAME".
>>>
>>> Now we add
>>>
>>> Header add TC-Server-Ip "%{WORKER}e"
>>>
>>> If you choose another name as "WORKER" for the new env var in the
>>> RewriteRule, please adjust here as well.
>>>
>>> Finally: if it doesn't work, try again by placing the Rewrite lines in a
>>> <Directory></Directory> block. Don't forget to switch
>>>
>>> RewriteEngine On
>>>
>>> Ad b)
>>>
>>> You can use mod_rewrite to set the env var JK_WORKER_NAME (now it is
>>> important to use that name). mod_jk will then route the request to that
>>> worker and since you had set the env var yourself, you can also copy it
>>> to a header.
>>>
>>> RewriteRule ^/c - [ENV=JK_WORKER_NAME:liferay]
>>> RewriteRule ^/c/.* - [ENV=JK_WORKER_NAME:liferay]
>>> RewriteRule ^/group - [ENV=JK_WORKER_NAME:liferay]
>>> RewriteRule ^/group/.* - [ENV=JK_WORKER_NAME:liferay]
>>>
>>> etc.
>>>
>>> and then
>>>
>>> Header add TC-Server-Ip "%{JK_WORKER_NAME}e"
>>>
>>> Final remarks:
>>>
>>> Your config does not really warrant this effort: you only have one
>>> worker name, so what do you expect in the header? I'm asking, because if
>>> you are using a load balancer worker (assumed name "lb") in your real
>>> config, and it has sub workers for example "node1" and "node2" then
>>> JK_WORKER_NAME will always be "lb". To actually get the chosen sub
>>> worker, only recipe 1 has a chance to work. You would there replace
>>> JK_WORJER_NAME in the RewriteCond by JK_WORKER_ROUTE. Unfortunately I
>>> think that the route note is not set before the request actually gets
>>> forwarded and that is to late for mod_rewrite to be able to copy it in
>>> an env var.
>>>
>>> In that case (load balancer and you want to know the chosen lb sub
>>> worker) we would either need to add something to mod_jk, or allow
>>> mod_headers to also support notes, or write a special small module.
>>>
>>> Having written all that, I think the following patch to mod_headers
>>> would be best. It simply adds support for notes to mod_headers (%{xxx}n
>>> notation):
>>>
>>> Index: modules/metadata/mod_headers.c
>>> ===================================================================
>>> --- modules/metadata/mod_headers.c      (revision 1449529)
>>> +++ modules/metadata/mod_headers.c      (working copy)
>>> @@ -200,6 +200,16 @@
>>>          return "(null)";
>>>  }
>>>
>>> +static const char *header_request_note(request_rec *r, char *a)
>>> +{
>>> +    const char *s = apr_table_get(r->notes,a);
>>> +
>>> +    if (s)
>>> +        return unwrap_header(r->pool, s);
>>> +    else
>>> +        return "(null)";
>>> +}
>>> +
>>>  static const char *header_request_ssl_var(request_rec *r, char *name)
>>>  {
>>>      if (header_ssl_lookup) {
>>> @@ -853,6 +863,7 @@
>>>      register_format_tag_handler("D", (const void
>>> *)header_request_duration);
>>>      register_format_tag_handler("t", (const void 
>>> *)header_request_time);
>>>      register_format_tag_handler("e", (const void 
>>> *)header_request_env_var);
>>> +    register_format_tag_handler("n", (const void 
>>> *)header_request_note);
>>>      register_format_tag_handler("s", (const void 
>>> *)header_request_ssl_var);
>>>
>>>      return OK;
>>>
>>> You should be able to apply it to a 2.2 mod_headers, recompile and be
>>> done. Not a standard feature though.
>>>
>>> Regards,
>>>
>>> Rainer
>>>
>>> P.S.: Grüße von Bonn nach Bonn
>>>
>>
>> And from Schwaben too...
>> I feel a bit naive after all the sophisticated technical stuff above, 
>> in suggesting the following, but how about :
>> If I understand the original post correctly, the whole point would be 
>> to know, at the httpd level, which "worker" (Tomcat) actually 
>> processed this request, right ?
>> If so, why not have the desired response header added at the Tomcat 
>> level ?
>> The more or less standard workhorsse URLRewriteFilter could be used 
>> here for that.
>>     <rule>
>>         <from>.*</from>
>>         <set type="response-header" name="TC-worker">name of this 
>> tomcat</set>
>>     </rule>
>> and then check this on the way back in Apache..
>> That would also overcome Rainer's note about load-balancing above.
>> As a matter of fact, I am quite sure that Tomcat itself already adds 
>> some kind of response header to indicate that it was involved in this, 
>> so it might just be a matter of proper Tomcat configuration.
>>
>> ---------------------------------------------------------------------
>> To unsubscribe, e-mail: users-unsubscribe@tomcat.apache.org
>> For additional commands, e-mail: users-help@tomcat.apache.org
>>
> 
> Hi André,
> 
> thanks for that hint. I initially tried a similar approach as the 
> URLRewriteFilter, by writing my own Filter-class.
> The reason i would like to see, which ajp-worker handled my requests is, 
> that i am working on an automated cluster-test, which should be able to 
> detect failover-events between workers. So changing the web.xml will 
> work, i am sure. But it would alter my test-subject (something i'd like 
> to avoid), and i would have to add the filter to approximately 30 
> web.xmls (something i would also like to avoid, i am lazy) ...
> I will try both approaches (Filter vs. mod_rewrite) and let you know my 
> results.
> 

Hi. Before you do that, you may want to have another look at this page :
http://tomcat.apache.org/connectors-doc/reference/apache.html
and in particular the section at the end labeled : Using SetHandler and Environment Variables

I use this way of configuring the proxy-ing of requests via mod_jk, rather than the 
JkMount and uriworkermap style, for some (purely personal) reasons :
- it keeps things "in one place" (the httpd config file)
- I believe that it "fits better" in the Apache httpd configuration style, allowing you to

use the classical Apache <Location>, <LocationMatch> etc.. to decide which URLs
are being 
proxied
- I find it easier that way, to mentally see where and when what happens at the Apache 
level when you use mod_jk + Tomcat, as in fact an Apache "response handler".

For example, in your case, you could set up the following section in Apache, to replace 
your external uri map :

<LocationMatch "^\/(c|group|html|image|language|layouttpl|...)\/">
   # in principle, for all those, pass them on to Tomcat..
   SetHandler jakarta-servlet
   SetEnv JK_WORKER_NAME liferay-1

   # but for some subset, do not pass them on, and let Apache itself handle them
   SetEnvIf REQUEST_URI (some condition) no-jk
   ...
   (set other filters, variables, headers, whatever)
   ...
</LocationMatch>

Just so that you would know about it.


---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@tomcat.apache.org
For additional commands, e-mail: users-help@tomcat.apache.org


Mime
View raw message