2017-03-09 22:47 GMT+01:00 Luca Toscano <[email protected]>:
>
>
> 2017-02-24 23:27 GMT+01:00 Luca Toscano <[email protected]>:
>
>> Hi everybody,
>>
>> the following users@ question is interesting in my opinion:
>>
>> 2017-02-20 18:17 GMT+01:00 Mike Schlottman <[email protected]>:
>>
>>>
>>> The problem comes when I combine these 2 so that all users except those
>>> coming from 127.*.*.* or 192.168.*.* see the nice error page.
>>>
>>> <If "! %{HTTP:X-Real-IP} -ipmatch '127.0.0.0/8' ">
>>>
>>> <If "! %{HTTP:X-Real-IP} -ipmatch '192.168.0.0/16' ">
>>>
>>> ErrorDocument 404 /errors/404
>>>
>>> </If>
>>>
>>> </If>
>>>
>>> The user from 172.28.1.84 does not get the nice 404 page, but the
>>> default 404 page. The IP does not match either of the ranges as observed
>>> when using the ranges individually, but when combined in this way it does
>>> not work as expected.
>>>
>>>
>>>
>>> Any ideas why this is?
>>>
>>>
>>>
>>
>> He ended up using a single if with an expression composed by the two
>> conditions in && to solve the problem, but I started to wonder why this
>> configuration does not work. I tested the "nested ifs" config with trace8
>> logging and it seem that only the outermost <If> expression gets evaluated.
>>
>> Is there a specific reason why this happens? I'd expect two possible
>> outcomes from this configuration, namely either a syntax error while
>> parsing the config (preferred imho) or a context merge, but not a no-op.
>>
>> Any pointers/suggestions about where to look?
>>
>>
> I tried to investigate a bit the problem to write a good explanation in
> the docs (and also to better understand the httpd internals for fun) but I
> am still far from a satisfactory result.
>
> I tried the following config (inside other containers like Location too):
>
> <If "true">
> ErrorDocument 503 "This is a custom 503 inside the outer IF!"
> <If "true">
> ErrorDocument 503 "This is a custom 503 inside the inner IF!"
> </If>
> </If>
>
> Each time that 503 is generated, I get the "outer IF" 503 response, never
> the inner one.
>
> With gdb it is easy to see that when ap_if_walk is executed,
> dconf->sec_if->nelts is 1, so only one of the Ifs is evaluated.
>
> So I checked how the if sections are parsed and built
> with
> ap_process_config_tree->ap_walk_config->ap_walk_config_sub->invoke_cmd->ifsection
> and eventually ap_add_if, but I only got that the parent/child relationship
> is set up correctly.
>
> My only goal is to figure out if nested Ifs are not evaluated on purpose
> and if so why they are allowed by the syntax checker. Eventually it would
> be really great to update the docs (regular user docs and also
> https://httpd.apache.org/docs/trunk/developer/request.html).
>
>
This time (hopefully) I think I found what I was looking for, namely why
nested <If> blocks are definitely not going to work.
The ap_if_walk (request.c) function gets the core_dir_config settings
via ap_get_core_module_config(r->per_dir_config), retrieving all the <If>
containers using the sec_if field, and then iterating through them to
evaluate their (apr_expr) conditions.
In order to be able to use nested <If> blocks ap_if_walk would need to
check, for each sec_if->elts element of the core's r->per_dir_config, if it
contains a sec_if blocks too (and restart the process of checking its
condition etc..). Something like:
AP_DECLARE(int) ap_if_walk(request_rec *r) {
[..]
/* Go through the if entries, and check for matches */
for (sec_idx = 0; sec_idx < num_sec; ++sec_idx) {
core_dir_config *entry_core;
entry_core = ap_get_core_module_config(sec_ent[sec_idx]);
if(entry_core->sec_if->nelts > 0) { .. /* handling nested <If>s */
.. }
[..]
In this way we would allow arbitrary nesting of <If> blocks in the httpd
config. I am not advocating for this solution but we should either allow
nested <If> blocks or explicitly warn the users when httpd checks its
config that a nested configuration will be silently ignored (emitting an
explicit configuration error while parsing the config would be even better
but probably too invasive for 2.4.x releases).
Thoughts?
Luca