Summary: | Incomplete html pages | ||
---|---|---|---|
Product: | Tomcat 8 | Reporter: | alexandre |
Component: | Catalina | Assignee: | Tomcat Developers Mailing List <dev> |
Status: | RESOLVED FIXED | ||
Severity: | normal | CC: | shaun |
Priority: | P2 | ||
Version: | 8.0.17 | ||
Target Milestone: | ---- | ||
Hardware: | PC | ||
OS: | All | ||
Attachments: | Buffer test .war as requested by Mark |
Description
alexandre
2015-01-21 15:29:30 UTC
Which connector are you using? Does the problem stop if you switch connectors? Is sendFile enabled? If yes, does the problem stop if sendFile is disabled? Thread dump (ideally 3, ~10s apart) when the application stops responding? Please provide the logs from the time the issue occurs. They may tell us something they don't tell you. Hello, same problem. After a last jsp:include in a jsp site the html content is not shown. No errors in tomcat log. Default Tomcat with port 8080. I have a single JSP running on 8.0.17 with 4 includes, and the page works just fine. Can you give more information about your environment? There's also a thread on the dev list if you want to discuss. I make a little test. I add a <%out.flush();%> at the end of the jsp file and the html content is correct. Without the <%out.flush();%> the html content is broken. I'm seeing similar issues with version 8.0.17 as well. Downgrading back to 8.0.15 made the problems go away for me, so it seems like something introduced between these versions is causing this. So far I've only noticed this problem with JSP files. Static content seems unaffected. Also, I'm seeing this happen through both HTTP and HTTPS. When the response is being truncated, the resulting size is always multiples of 8192 bytes. But this seems to only happen only if the resulting size is anything greater than 16KB. Examples of what I'm seeing: Expected size / Actual response size anything less than 16 KB -> the response is fine 17 KB -> 8 KB 25 KB -> 16 KB 39 KB -> 24 KB 44 KB -> 32 KB 50 KB -> 40 KB So it seems like the last remaining block (or 2?) isn't being written out... assuming the buffer size is 8 KB. And yes, when I call out.flush(), this problem goes away for me too. Here's some information about my environment: Java(TM) SE Runtime Environment (build 1.8.0_25-b17) Java HotSpot(TM) 64-Bit Server VM (build 25.25-b02, mixed mode) OS X Yosemite 10.10.1 I'm facing exactly the same issue. I've noticed that putting <% out.flush() %> at the end of the JSP file, everything was OK, but It's not good to assume that it's the goal to solve that. This still lacks a reproduction recipe. Thus far I tried the following simple tests with 8.0.17, and all of them are working (except a minor issue filed as bug 57481) - static files (Tomcat binaries) - examples webapp (mostly useless, as those pages are small) - simple jsp with a lot of text (200Kb) - jsp with jsp:include with a lot of text (200Kb, 800Kb) - simple jsp with EL (122Kn) - simple jsp with tags (164Kb) I tested HTTP + (bio,nio,apr) + (with Executor or without Executor) HTTPS + (bio,nio) + without Executor I am using JDK 7u72 (32-bit) on Windows 7. No truncations noted. Something else is needed to reproduce this. Okay, after some debugging, I think I found how to duplicate this rather easily. The original project where this was happening for me was a Spring MVC project. I wasn't able to duplicate it in a non-Spring MVC project at first, so I went back to my original project and followed the path from beginning to end to get more clues as to what was happening. I found that the bug seems to only occur when requests are forwarded. After realizing that, I was able to create a minimal example that shows the problem: 1. Download a fresh stock 8.0.17 build 2. Drop in two JSP files in webapps/ROOT (the Tomcat welcome screen project is perfectly fine). For example: page1.jsp and page2.jsp 3. Put <% request.getRequestDispatcher("page2.jsp").forward(request, response); %> in page1.jsp 4. Put a bunch of plain text (you don't need dynamic content) in page2.jsp so that the response will be over 16 KB. 5. Now visit localhost:8080/page1.jsp in your browser, and notice the content being truncated. Also, note that going to localhost:8080/page2.jsp directly does NOT truncate the data because there is no forwarding happen there. I was able to duplicate this on 2 separate machines (Mac and Windows). Thanks for the extra info. I (and I suspect a few other committers as well) am looking at this now... Reprodcued every time. Many thanks. Looking for the root cause at the moment... I've found the root cause. It was triggered by r1643210 but I think all that did was uncover a different bug. It is easier to see if you go back to Tomcat 6 as that is before async was added. If you look at StandardHostValve line 136 [1] you'll see that the response is unsuspended unconditionally although the comment suggests it is being unsuspended for error handling (which may need to write to the response). In r1643210 that code was modified so the response was only unsuspended if there was an error to handle. This triggered the problem because the RequestDispatcher did not flush the response before calling finish(). Calling finish() sets suspended to true. The sequence was: a) page 1 forwards to page 2 b) page 2 writes response leaving some data in buffer c) RD calls finish which suspends response d) StandardHostValve unsuspends response e) normal end handling for page 1 flushes and closes the response r1643210 removed step d) which in turn prevented the flush in step e). Section 9.4 of the Servlet 3.1 spec says: <quote> Before the forward method of the RequestDispatcher interface returns without exception, the response content must be sent and committed, and closed by the servlet container, unless the request was put into the asynchronous mode. </quote> My reading of the spec is that we should be calling response.flushBuffer() before we call finish() in the RequestDispatcher. I am going to apply a patch to that effect to trunk, 8.0.x and 7.0.x shortly. I then intend to start an 8.0.x release. [1] http://svn.eu.apache.org/viewvc/tomcat/tc6.0.x/trunk/java/org/apache/catalina/core/StandardHostValve.java?view=annotate#l136 Thank you! Reproduced based on recipe from Comment 8. My example: 1) webapps/examples2/numberwriter2.jsp: [[[ Forward to numberwriter.txt <jsp:forward page="numberwriter.txt" /> ]]] 2) webapps/examples2/numberwriter.txt: Copied output of numberwriter example (10000 lines with numbers from 00000000000000000001 up to 00000000000000010000, 210000 bytes total (EOL = LF)) I request /examples2/numberwriter2.jsp with wget. I observe the following pairs of requests in access log file: 127.0.0.1 - - [22/Jan/2015:14:32:00 +0300] "GET /examples2/numberwriter2.jsp HTTP/1.0" 200 204800 127.0.0.1 - - [22/Jan/2015:14:32:20 +0300] "GET /examples2/numberwriter2.jsp HTTP/1.0" 206 5200 That is the first GET request hangs after transferring 204800 bytes. After waiting for 20 seconds wget aborts connection. It repeats request asking for a range of bytes, and receives remaining 5200 bytes of the file. This happens in the same way for all connectors that I tested (those mentioned in Comment 7). Created attachment 32391 [details]
Buffer test .war as requested by Mark
Mark,
Just in case you still need a test .jsp for this issue.
rowsToPrint in index.jsp is set to break right now.
This has been fixed in trunk, 8.0.x (for 8.0.18 onwards) and in 7.0.x. Note that the fix that introduced this regression has not been included in a 7.0.x release so no 7.0.x release is affected by this bug. |