Bug 50413 - Tomcat returns 304 instead of 404 response for static custom 404 error file
Tomcat returns 304 instead of 404 response for static custom 404 error file
Status: RESOLVED FIXED
Product: Tomcat 5
Classification: Unclassified
Component: Catalina
5.5.31
PC Windows XP
: P2 minor (vote)
: ---
Assigned To: Tomcat Developers Mailing List
:
Depends on:
Blocks:
  Show dependency tree
 
Reported: 2010-12-05 07:34 UTC by Konstantin Preißer
Modified: 2011-01-20 14:23 UTC (History)
0 users



Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Konstantin Preißer 2010-12-05 07:34:55 UTC
When using a static html file for 404 errors and the client sends a request to a file whoch doesn't exist, and adds a "If-Modified-Since" header with a date that is newer than the modification date of the static error file, then Tomcat returns "302 Not Modofied" instead of "404 Not Found".

Steps to reproduce:
1) Make a simple webapp that uses a static html file as custom error page for 404 errors, like this (web.xml):

  <error-page>
    <error-code>404</error-code>
    <location>/errorpages/404.html</location>
  </error-page>

2) Do a GET request to a URL which points to a file that doesn't exist, and add a "If-Modified-Since" header with a date that is newer than the modification date of the 404 error file (the date may also be in the future), e.g.

GET /MyWebApp/AUrlToAFileWhichDoesNotExist.gif HTTP/1.1
Host: localhost
Keep-Alive: 115
Connection: keep-alive
If-Modified-Since: Tue, 08 Nov 2015 15:07:52 GMT 

(replace "MyWebApp" with your webapp's name)

3) Tomcat returns "HTTP/1.1 302 Not Modified" instead of "HTTP/1.1 404 Not Found".


Actual Results: Tomcat returns a "302 Not Modified" response, because it seems to compare the date of the "If-Modified-Header" with the date of the static 404 error file.

Expected Results: Tomcat returns a "404 Not Found" response, because the requested file does not exist.


If you omit the "If-Modified-Since" header or use a date that is older than the date of the error file, Tomcat correctly returns "404 Not Found", but adds an "Last-Modified" header with the modification date of the 404 file.


This behavior caused invalid 302 responses to be sent over the ISAPI redirector (bug 50363, with enabled chunked encoding support) when I was viewing my site in Firefox and pressed F5 to refresh it, because I think as of bug 49591, Tomcat uses chunked encoding for this response, which the ISAPI redirector didn't check.

I tested on Tomcat 7.0.5 on 32-Bit Windows XP, with Tomcat Native 1.1.20, on Java 1.6.0_22.
Comment 1 Konstantin Preißer 2010-12-05 07:41:06 UTC
Sorry, when I wrote "302 Not Modified" I actually ment "304 Not Modified".
Comment 2 Mark Thomas 2010-12-10 05:11:55 UTC
Thanks for the report. This has been fixed in 7.0.x and will be included in 7.0.6 onwards.
Comment 3 Konstantin Preißer 2010-12-10 10:57:33 UTC
(In reply to comment #2)
> Thanks for the report. This has been fixed in 7.0.x and will be included in
> 7.0.6 onwards.

Thanks :)

I would like to note that the same behavior/bug exists in Tomcat 6.0.29 and 5.5.31 as well (I just tested it on these versions). Sorry I didn't that before. Maybe the fix needs to be backported?

Cheers
Konstantin
Comment 4 Mark Thomas 2010-12-12 16:30:43 UTC
Re-open against 5.5.x so it gets fixed in 5.5.x and 6.0.x
Comment 5 Mark Thomas 2011-01-08 14:27:55 UTC
Fixed in 6.0.x and will be included in 6.0.30 onwards.
Comment 6 Konstantin Kolinko 2011-01-08 16:13:19 UTC
One minor glitch with the current fix for this issue:
(regards 7.0, 6.0 and proposed patch for 5.5)


In DefaultServlet#serveResource(..) there is the following condition:
        if ( (cacheEntry.context != null) 
                || ( ((ranges == null) || (ranges.isEmpty()))
                        && (request.getHeader("Range") == null) )
                || (ranges == FULL) ) {

Note the following part of it:
 (ranges == null || ranges.isEmpty()) && (request.getHeader("Range") == null)

With the current fix for this issue a "parseRange(request, response, cacheEntry.attributes)" call is skipped and thus "ranges" remains to be null, but request.getHeader("Range") still returns the original header.

==============================================================================
Using MyWebApp with a custom 404.html page, as described by OP, I now get:

In current 7.0.x (at rev.1056780)
-- Request:
GET /MyWebApp/AUrlToAFileWhichDoesNotExist.gif HTTP/1.1
Host: localhost
Keep-Alive: 115
Connection: keep-alive
Range: bytes=0-499
-- Response:
HTTP/1.1 404 Not Found
Server: Apache-Coyote/1.1
Transfer-Encoding: chunked
Date: Sat, 08 Jan 2011 20:49:46 GMT

0
-- Request: (without the "Range" header)
GET /MyWebApp/AUrlToAFileWhichDoesNotExist.gif HTTP/1.1
Host: localhost
Keep-Alive: 115
Connection: keep-alive
--
HTTP/1.1 404 Not Found
Server: Apache-Coyote/1.1
Content-Type: text/html
Content-Length: 17
Date: Sat, 08 Jan 2011 20:51:02 GMT

Error 404.html!
--

I.e., if "Range" header was specified, the custom error page is not used at all.


It is not a show stopper, as it is still better than it was before, because e.g. in 5.5.31 the response is the following:

-- Request:
GET /MyWebApp/AUrlToAFileWhichDoesNotExist.gif HTTP/1.1
Host: localhost
Keep-Alive: 115
Connection: keep-alive
Range: bytes=0-499
-- Response:
HTTP/1.1 206 Partial Content
Server: Apache-Coyote/1.1
Accept-Ranges: bytes
ETag: W/"17-1294518367875"
Last-Modified: Sat, 08 Jan 2011 20:26:07 GMT
Content-Range: bytes 0-16/17
Content-Type: text/html
Content-Length: 17
Date: Sat, 08 Jan 2011 21:01:35 GMT

Error 404.html!
--
which is wrong, because it is successful "206 Partial Content", while "404 Not Found" was expected instead.
Comment 7 Konstantin Kolinko 2011-01-09 03:17:24 UTC
(In reply to comment #6)
This is fixed by r1056889 in 7.0 - will be in 7.0.6.
Proposed as an additional patch for this issue for 6.0 and 5.5.
Comment 8 Mark Thomas 2011-01-20 12:09:12 UTC
fixed in 6.0.x and will be in 6.0.31 onwards
Comment 9 Jim Jagielski 2011-01-20 14:23:11 UTC
Will be in 5.5.32