Hello Stefan,

by spec / RFC, a HEAD request is not allowed to return any body.

Greetings,
Thomas

-----Ursprüngliche Nachricht-----
Von: Stefan Mayr <ste...@mayr-stefan.de> 
Gesendet: Montag, 14. Februar 2022 23:07
An: users@tomcat.apache.org
Betreff: Re: mod_jk interference with ErrorDocument/Alias on HEAD request

Hello again,

a self-compiled mod_jk 1.2.48 shows the same issue.

Am 13.02.2022 um 18:37 schrieb Stefan Mayr:
> Hi,
> 
> looking at the source code
> https://github.com/apache/tomcat-connectors/blob/main/native/apache-2.
> 0/mod_jk.c#L2954#L2973
> I did some more testing:
> 
> Variant 1: JkMount /demo/* ajp13_worker;use_server_errors=401
> Variant 2: JkMount /demo/* ajp13_worker
> 
> ignoring what variant 2 changes for regular request: reading the 
> source comment my understanding is, that for both variants a HEAD 
> request (by definition must have an empty response body) should let 
> Apache httpd handle the error code.
> 
> But the return code for jk_handler looks different:
> 
> Variant 1: s.http_response_status
> Variant 2: r->status

Although this looks different on the first glance it seems to be the same.

> The response only seems correct for variant 1 - which is configured to 
> let Apache httpd handle all responses for status codes >= 401. For 
> variant 2 mod_jk seems to handle the response itself - contrary to 
> what the comment explains.

This leads to the next assumption, that whenever there is a special handling 
for use_server_errors there should be something similar for the case with an 
empty/non-existing response body.

There is
https://github.com/apache/tomcat-connectors/blob/main/native/common/jk_ajp_common.c#L1991#L1993
with no corresponding (pseudo) code like

             if (!r->something_like_bodyct && r->http_response_status >= 
JK_HTTP_BAD_REQUEST){
                     r->response_blocked = JK_TRUE;
             }

Adding code like this (sorry, i could not find out how to determine if there is 
a response body) fixes the issue with the wrong response body for a HEAD 
request. But we miss the WWW-Authenticate header now.

Digging further we find
https://github.com/apache/tomcat-connectors/blob/main/native/apache-2.0/mod_jk.c#L331#L353
which has a special treatment for 401 HTTP Unauthorized. But again, only for 
use_server_errors.

This should be fixable by extending the condition like this

     if ((s->extension.use_server_error_pages &&
         status >= s->extension.use_server_error_pages) ||
         (!r->sent_bodyct && r->status >= HTTP_BAD_REQUEST)) {


But the WWW-Authenticate header is still missing. So i'm wrong, again. 
Although it feels like i'm close.

> Am 12.02.2022 um 14:24 schrieb Stefan Mayr:
>> Hello Tomcat users,
>>
>> this week we were debugging a strange connection issue which I 
>> tracked down to an interference between Apache httpd and mod_jk.
>>
>> For the full picture, the infrastructure setup contains
>>
>> 1. a Loadbalancer providing HTTPS, HTTP/1.1 and HTTP/2 for Clients.
>> 2. an Apache httpd 2.4 webserver (HTTP only) with mod_jk 3. a Tomcat 
>> mit AJP-Connector
>>
>> We have an application doing many different HEAD requests against an 
>> application running in the Tomcat server. The requests contain an 
>> Authorization header for Basic authentication. Expected response is a 
>> HTTP 200 OK or HTTP 401 if this particular user is not allowed to 
>> access that ressource. Because this is a HEAD request there must not 
>> be a response body according to RFC 2616.
>>
>> If there is a response body in the response to the HEAD request our 
>> loadbalancer does strange things: aborts the connection if the 
>> clients uses HTTP/2, SSL errors if using HTTP/1.1. But this is an 
>> issue on its own which we might have to solve with the vendor.
>>
>> Now comes the point where I need your help. We have a httpd 
>> configuration with mod_jk which generates these invalid response 
>> bodies on HEAD requests. I have a gut feeling this could be a bug 
>> with mod_jk.
>>
>> For demonstration purpose i created a minimal demo app which only is 
>> a WEB-INF/web.xml <?xml version="1.0" encoding="UTF-8"?> <web-app 
>> xmlns="https://jakarta.ee/xml/ns/jakartaee";
>>    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
>>    xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee
>>                        
>> https://jakarta.ee/xml/ns/jakartaee/web-app_5_0.xsd";
>>    version="5.0">
>>          <security-constraint>
>>                  <web-resource-collection>
>>                          <web-resource-name>Login</web-resource-name>
>>                          <url-pattern>/*</url-pattern>
>>                  </web-resource-collection>
>>                  <auth-constraint>
>>                          <role-name>manager</role-name>
>>                  </auth-constraint>
>>          </security-constraint>
>>          <security-role>
>>                  <role-name>manager</role-name>
>>          </security-role>
>>          <login-config>
>>                  <auth-method>BASIC</auth-method>
>>          </login-config>
>> </web-app>
>>
>> Then I place a JkMount in my Apache httpd configuration (+ minimal
>> worker.properties):
>>
>> JkMount /demo/* ajp13_worker
>>
>> Testing this with curl works like expected:
>>
>> root@1ae8973f1b6b:~# curl -I -v localhost/demo/
>> *   Trying 127.0.0.1:80...
>> * TCP_NODELAY set
>> * Connected to localhost (127.0.0.1) port 80 (#0)
>>  > HEAD /demo/ HTTP/1.1
>>  > Host: localhost
>>  > User-Agent: curl/7.68.0
>>  > Accept: */*
>>  >
>> * Mark bundle as not supporting multiuse < HTTP/1.1 401 401
>> HTTP/1.1 401 401
>> < Date: Sat, 12 Feb 2022 12:57:33 GMT
>> Date: Sat, 12 Feb 2022 12:57:33 GMT
>> < Server: Apache/2.4.41 (Ubuntu)
>> Server: Apache/2.4.41 (Ubuntu)
>> < Cache-Control: private
>> Cache-Control: private
>> < WWW-Authenticate: Basic realm="Authentication required"
>> WWW-Authenticate: Basic realm="Authentication required"
>> < Content-Language: en
>> Content-Language: en
>> < Content-Type: text/html;charset=utf-8
>> Content-Type: text/html;charset=utf-8
>>
>> <
>> * Connection #0 to host localhost left intact
>>
>> But our default setup always includes custom error pages:
>>
>> Alias /error/ "/usr/share/apache2/error/"
>> ErrorDocument 401 /error/HTTP_UNAUTHORIZED.html.var
>>
>> If both of those lines are added this results in a response body for 
>> the HEAD request.
>>
>> root@1ae8973f1b6b:~# curl -I -v localhost/demo/
>> *   Trying 127.0.0.1:80...
>> * TCP_NODELAY set
>> * Connected to localhost (127.0.0.1) port 80 (#0)
>>  > HEAD /demo/ HTTP/1.1
>>  > Host: localhost
>>  > User-Agent: curl/7.68.0
>>  > Accept: */*
>>  >
>> * Mark bundle as not supporting multiuse < HTTP/1.1 401 401
>> HTTP/1.1 401 401
>> < Date: Sat, 12 Feb 2022 12:56:27 GMT
>> Date: Sat, 12 Feb 2022 12:56:27 GMT
>> < Server: Apache/2.4.41 (Ubuntu)
>> Server: Apache/2.4.41 (Ubuntu)
>> < Cache-Control: private
>> Cache-Control: private
>> < WWW-Authenticate: Basic realm="Authentication required"
>> WWW-Authenticate: Basic realm="Authentication required"
>> < Content-Language: en
>> Content-Language: en
>> < Content-Type: text/html;charset=utf-8
>> Content-Type: text/html;charset=utf-8
>>
>> <
>> * Excess found: excess = 589 url = /demo/ (zero-length body)
>> * Connection #0 to host localhost left intact
>>
>> Checking with tcpdump on port 8009 we see the expected response 
>> without a body from the Tomcat AJP connector. The tcpdump von port 80 
>> reveals httpd is adding the configured ErrorDocument as response body.
>>
>> If we comment out either the Alias or ErrorDocument directive the 
>> response is correct again.
>>
>> Doing similar tests with CGI/PHP applications always show the correct 
>> response without a response body. This only affects requests which 
>> use mod_jk.
>>
>> So far I could reproduce this on SLES12 SP5 and SLES15 SP3 running 
>> Apache httpd 2.4.51 and a self compile mod_jk 1.2.46 (same with the 
>> included mod_jk 1.2.43) at work. At home the same happens on a stock 
>> openSUSE Leap 15.3 with Apache httpd 2.4.51 and mod_jk 1.2.43 as well 
>> as on Ubuntu 20.04 with httpd 2.4.41 and mod_jk 1.2.46.
>> I didn't try to compile the latest mod_jk version yet because I 
>> didn't spot a relevant point in the changelog.
>>
>> Can anyone confirm this behaviour or point me to a configuration 
>> directive i missed?
>>
--

Regards,

        Stefan Mayr

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

Reply via email to