Content type unknown after upgrading Tomcat 10.1.39 => 10.1.40
Hi all, long time Tomcat user, but first time I'm posting, so hi to you all :-) I'm suffering a strange phenomenon after I upgraded Tomcat on one of our virtual machines from 10.1.39 to 10.1.40: When I open the link to an application being served by Tomcat my browser (Firefox) now downloads a file instead of displaying the (generated) HTML page. With the network inspector I discovered that the content-type in the response is set to "content/unknown;charset=UTF-8". When reverting back to 10.1.39 everything works; the content-type in the response is (as expected) "text/html;charset=UTF-8". In the changelog I haven't seen anything regarding this. The configuration files used to start Tomcat are exactly the same in both scenarios, and the application isn't changed. Can anyone explain what's happening? Tomcat: 10.1.39 / 40 Java: openjdk-21.0.6 OS: Ubuntu 24.04.2 LTS Best regards Thorsten - To unsubscribe, e-mail: users-unsubscr...@tomcat.apache.org For additional commands, e-mail: users-h...@tomcat.apache.org
Re: Content type unknown after upgrading Tomcat 10.1.39 => 10.1.40
Hi Chris, That definitely sounds odd. Do you have anything on the network between the client (browser) and the server (Tomcat)? Specifically, anything like a load-balancer, proxy, or similar? I just want to remove other possible causes before diving into Tomcat (but from your description, Tomcat does seem to be the suspicious component, here). No, there's nothing in between me and Tomcat. It's reproducible also by directly using curl on the command line: "curl -v --insecure --noproxy '*' https://.../"; gives me the following on 10.1.39 (private data replaced for security): Note: Using embedded CA bundle (233263 bytes) Note: Using embedded CA bundle, for proxies (233263 bytes) % Total% Received % Xferd Average Speed TimeTime Time Current Dload Upload Total SpentLeft Speed 0 00 00 0 0 0 --:--:-- --:--:-- --:--:-- 0* Host myhost.example.com:8448 was resolved. * IPv6: 2a02:5a0:f019:1:4448:4350:a9b4:9022 * IPv4: 10.192.141.7 * Trying [2a02:5a0:f019:1:4448:4350:a9b4:9022]:8448... * ALPN: curl offers h2,http/1.1 * TLSv1.3 (OUT), TLS handshake, Client hello (1): } [317 bytes data] * TLSv1.3 (IN), TLS handshake, Server hello (2): { [122 bytes data] * TLSv1.3 (IN), TLS handshake, Unknown (8): { [41 bytes data] * TLSv1.3 (IN), TLS handshake, Certificate (11): { [5210 bytes data] * TLSv1.3 (IN), TLS handshake, CERT verify (15): { [520 bytes data] * TLSv1.3 (IN), TLS handshake, Finished (20): { [52 bytes data] * TLSv1.3 (OUT), TLS handshake, Finished (20): } [52 bytes data] * SSL connection using TLSv1.3 / TLS_AES_256_GCM_SHA384 / [blank] / UNDEF * ALPN: server accepted h2 * Server certificate: * subject: ... * start date: May 6 10:01:48 2024 GMT * expire date: Dec 26 10:01:48 2048 GMT * issuer: ... * SSL certificate verify result: self signed certificate in certificate chain (19), continuing anyway. * Certificate level 0: Public key type ? (4096/128 Bits/secBits), signed using sha256WithRSAEncryption * Certificate level 1: Public key type ? (4096/128 Bits/secBits), signed using sha256WithRSAEncryption * Certificate level 2: Public key type ? (4096/128 Bits/secBits), signed using sha512WithRSAEncryption * Connected to myhost.example.com (2a02:5a0:f019:1:4448:4350:a9b4:9022) port 8448 * using HTTP/2 * [HTTP/2] [1] OPENED stream for https://myhost.example.com:8448/my/servlet/app?version=!!1.22.32-4-g8a3c060!! * [HTTP/2] [1] [:method: GET] * [HTTP/2] [1] [:scheme: https] * [HTTP/2] [1] [:authority: myhost.example.com:8448] * [HTTP/2] [1] [:path: /my/servlet/app?version=!!1.22.32-4-g8a3c060!!] * [HTTP/2] [1] [user-agent: curl/8.12.1] * [HTTP/2] [1] [accept: */*] > GET /my/servlet/app?version=!!1.22.32-4-g8a3c060!! HTTP/2 > Host: myhost.example.com:8448 > User-Agent: curl/8.12.1 > Accept: */* > * Request completely sent off 0 00 00 0 0 0 --:--:-- --:--:-- --:--:-- 0< HTTP/2 200 < cache-control: max-age=0 < expires: Wed, 16 Apr 2025 16:22:16 GMT < content-type: text/html;charset=UTF-8 < content-length: 7999 < date: Wed, 16 Apr 2025 16:22:16 GMT < { [7999 bytes data] 100 7999 100 79990 0 31126 0 --:--:-- --:--:-- --:--:-- 31246 * Connection #0 to host myhost.example.com left intact With 10.1.40 using exactly the same command the result is the same apart from the content-type: (...) * Request completely sent off 0 00 00 0 0 0 --:--:-- --:--:-- --:--:-- 0< HTTP/2 200 < cache-control: max-age=0 < expires: Wed, 16 Apr 2025 16:19:48 GMT < content-type: content/unknown;charset=UTF-8 < content-length: 7999 < date: Wed, 16 Apr 2025 16:19:48 GMT < { [7999 bytes data] 100 7999 100 79990 0 32015 0 --:--:-- --:--:-- --:--:-- 32124 This is what's puzzling me... BTW, I'm using a system-wide Tomcat installation under /usr/local/share and a user installation with its own ./conf directory; basically the same what Ubuntu is offering via the packages "tomcat10-common" and "tomcat10-user". This way I can switch the Tomcat version to be used by simply changing the CATALINA_HOME variable in the startup script. But I guess this shouldn't matter... Regards Thorsten - To unsubscribe, e-mail: users-unsubscr...@tomcat.apache.org For additional commands, e-mail: users-h...@tomcat.apache.org
Re: Content type unknown after upgrading Tomcat 10.1.39 => 10.1.40
Hi Mark, That looks like the result of fixing this bug: https://bz.apache.org/bugzilla/show_bug.cgi?id=69623 A little more digging suggests that MIME type is only set for a resource when it is served via the default servlet. I suspect that lookup needs to be moved so MIME type is also available when the default servlet is not used. I should be able to put together a test case for what I think the problem is but I'd like to be sure it is fixing the problem you are seeing. There are a couple of options: 1. You test a SNAPSHOT build of Tomcat 10.1.x from the CI system that contains the fix once I have implemented what I think is the fix. 2. You provide the simplest possible web application that reproduces the issue and I use that to test. Thanks for your answer. I see whether I can create a minimal reproducer. Regards Thorsten - To unsubscribe, e-mail: users-unsubscr...@tomcat.apache.org For additional commands, e-mail: users-h...@tomcat.apache.org
Re: Content type unknown after upgrading Tomcat 10.1.39 => 10.1.40
Hi Chris, please excuse the long delay in answering (unplanned holidays...) Tomcat is never going to figure out what MIME type should be used for a request like "/my/servlet/app?version=!!1.22.32-4-g8a3c060!!" So I think Mark is probably right (well, he's right like 99.999% of the time, so...) about this being related to https://bz.apache.org/bugzilla/ show_bug.cgi?id=69623 but I suspect your servlet is not explicitly setting a content-type. It took quite some time debugging into our application to find out the place where the output difference happens between Tomcat 10.1.39 and 10.1.40: We're using our own template engine that renders the HTML output, depending on the actual state of the application for the (logged-in) user. Basically the code is working the same way as this minimal reproducer: package com.example; import java.io.ByteArrayOutputStream; import java.io.IOException; import jakarta.servlet.ServletException; import jakarta.servlet.annotation.WebServlet; import jakarta.servlet.http.HttpServlet; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; @WebServlet("/HelloWorld") public class HelloWorld extends HttpServlet { @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html; charset=UTF-8"); var resource = request.getServletContext().getResource("HelloWorld.html"); var connection = resource.openConnection(); String contentType = connection.getContentType(); if (null == contentType) { contentType = "text/html"; } var length = connection.getContentLength(); var baos = new ByteArrayOutputStream(); try (var is = connection.getInputStream()) { is.transferTo(baos); } var output = baos.toByteArray(); response.setContentLength(length); response.setContentType(contentType); try (var os = response.getOutputStream()) { os.write(output, 0, output.length); } } } web.xml: http://xmlns.jcp.org/xml/ns/javaee"; xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"; xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"; version="3.1" metadata-complete="true"> Hello World Web Application HelloWorld com.example.HelloWorld HelloWorld /* HelloWorld.html: Hello World! Hello World! With Tomcat 10.1.39 I'm getting the following result with curl: %> curl -v http://localhost:8080/hello (...) * Request completely sent off < HTTP/1.1 200 < Content-Type: text/html;charset=UTF-8 < Content-Length: 212 (...) With Tomcat 10.1.40: (...) * Request completely sent off < HTTP/1.1 200 < Content-Type: content/unknown;charset=UTF-8 < Content-Length: 212 (...) The reason is exactly what you assumed and the change that Mark mentioned: Since 10.1.40 the class CachedResource$CachedResourceURLConnection now has a new method "public String getContentType()" that is causing this difference... Ok, we could change our code so that in case the content type is set to "content/unknown" we're replacing that by "text/html". OTOH with respect to our customers this isn't really a good solution: On the one hand they partly have older releases that would have to be patched. On the other hand we normally don't have control about their environment; we could only give advises, especially in this case don't upgrade to Tomcat 10.1.40... WDYT? Thorsten - To unsubscribe, e-mail: users-unsubscr...@tomcat.apache.org For additional commands, e-mail: users-h...@tomcat.apache.org