Closed Bug 364556 Opened 19 years ago Closed 9 years ago

304 response followed by empty content packet is interpretted as 200 and then waits for content which never comes, until the socket is closed.

Categories

(Core :: Networking: HTTP, defect)

1.8 Branch
x86
Linux
defect
Not set
normal

Tracking

()

RESOLVED FIXED

People

(Reporter: jed, Unassigned)

Details

User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1) Gecko/20060601 Firefox/2.0 (Ubuntu-edgy) Build Identifier: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1) Gecko/20060601 Firefox/2.0 (Ubuntu-edgy) Under certain circumstances on some application servers (this was observed on WebLogic 8.1), a 304 response can be closely followed by an empty content packet: "0000\r\n\r\n". For some reason, sometimes - not always, but reproducibly often enough - this gets interpretted as a 200 (as shown in LiveHeaders), and the browser then waits for the rest of the content. There is no further content coming and eventually the server closes the socket, leaving the browser displaying the following (the bit in between the lines): ---------------------------- 0000 HTTP/1.1 304 Not Modified Date: Wed, 20 Dec 2006 06:24:02 GMT 0000 ---------------------------- The server response is made up of two TCP packets, the first containing the 304 and the second containing the empty content. If they are a single packet, the problem cannot be reproduced. Turning off keep-alive and switching to HTTP 1.0 also appear to fix this (at least make it no longer visible!) BTW. I tried to file this on Mozilla core, but couldn't find the Bugzilla product. Please move over to there and to the Network:HTTP component if possible. I am going on holiday over christmas, any urgent follow up should be cc'd to dylan@atlassian.com Reproducible: Sometimes Steps to Reproduce: 1. make request to dodgy web-server. 2. web-server responds with 304 and then empty content packet. Actual Results: Client waits for server until socket is closed (20+ seconds), then shows the 304 and content responses and as though they were the page content. If the request were for an image or javascript, the server tries to interpret them as such. Expected Results: Client properly uses cached version of resource. This was initially found in Firefox 2 on Ubuntu and Red Hat, confirmed on Windows in both version 2 and Minefield 3.0a1. The following Java class acts as a very simple web-server hanging on port 8070 and reproduces the problem. To use, point the browser to this port and then refresh. For my Windows browser in VMWare, this could be reproduced after only a couple of refreshes, on the Ubuntu host, it took up to 20 refreshes before being seen, but was still always reproducible. --------------- /** * Simple server that returns an HTTP Response 200 on a socket and subsequently returns 304s with a follow-up empty * chunk. This reproduces a bug in Firefox that is seen with some content served from WebLogic. */ public class WebServerTest { public static void main(String[] args) throws Exception { new WebServerTest().run(); } static String getResponse() { StringBuilder builder = new StringBuilder("HTTP/1.1 200 OK\r\nDate: Wed, 20 Dec 2006 06:24:02 GMT\r\nContent-Length: "); String content = "<html><head><title>Test Page</title></head><body><h1>Some Content</h1>This is content</body></html>"; builder.append(content.length()); builder.append("\r\nLast-Modified: Tue, 19 Dec 2006 00:37:34 GMT\r\n\r\n"); builder.append(content); builder.append("\r\n\r\n"); return builder.toString(); } static void copy(String string, OutputStream stream) throws IOException { final int bufferSize = 8 * 1024; final Reader input = new StringReader(string); final Writer output = new OutputStreamWriter(stream); final char[] buffer = new char[bufferSize]; int n = 0; while (-1 != (n = input.read(buffer))) { output.write(buffer, 0, n); } output.flush(); } private final Executor executor = Executors.newCachedThreadPool(); private final ServerSocket serverSocket; private final String response = getResponse(); private final String notModified = "HTTP/1.1 304 Not Modified\r\nDate: Wed, 20 Dec 2006 06:24:02 GMT\r\n\r\n"; private final String emptyContent = "0000\r\n\r\n"; public WebServerTest() { try { this.serverSocket = new ServerSocket(8070); } catch (UnknownHostException e) { throw new RuntimeException(e); } catch (IOException e) { throw new RuntimeException(e); } } public void run() { while (true) { try { executor.execute(new RequestHandler(serverSocket.accept())); } catch (IOException e) { throw new RuntimeException(e); } } } class RequestHandler implements Runnable { private final Socket socket; boolean newSocket = true; RequestHandler(Socket socket) { this.socket = socket; } public void run() { while (true) { try { getInput(socket); } catch (TimeoutException e) { try { socket.close(); } catch (IOException ignore) {} return; } try { final OutputStream outputStream = socket.getOutputStream(); if (newSocket) { copy(response, outputStream); newSocket = false; } else { copy(notModified, outputStream); // send a second chunk, an empty content packet that fools firefox // into thinking more is on the way copy(emptyContent, outputStream); } outputStream.flush(); } catch (IOException e) { throw new RuntimeException(e); } } } String getInput(Socket socket) throws TimeoutException { final int WAIT_TIME = 10; final int TEN_SECONDS = 10000; int waitedFor = 0; StringBuilder buffer; try { final InputStream inputStream = socket.getInputStream(); while (inputStream.available() == 0) { Thread.sleep(WAIT_TIME); waitedFor = waitedFor + WAIT_TIME; if (waitedFor > TEN_SECONDS) { socket.close(); throw new TimeoutException(); } } buffer = new StringBuilder(inputStream.available()); while (inputStream.available() > 0) { buffer.append((char) inputStream.read()); } } catch (IOException e) { throw new RuntimeException(e); } catch (InterruptedException e) { throw new RuntimeException(e); } return buffer.toString(); } } }
Component: General → Networking: HTTP
Product: Firefox → Core
QA Contact: general → networking.http
Version: unspecified → 1.8 Branch
Please note, this is recognised as a server bug as the RFC states that there MUST NOT be a message body for 304 responses. BUT, if there are servers responding like this, it would be better to disregard the subsequent message body packet. See: http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.3.5 If we can get a WebLogic bug submitted, we'll crossref here.
And causes strange effects. For me it looks like it tries to parse the response like a normal 200 response, but with bad data. For me the HTML reponse contains referenced files (script src, link rel, etc.) in the <head> tag to javascripts and cascaded stylesheets. Firefox 2.0.0.11 tried to parse the javascripts in the header but with a stupid data from the <head> node instead of the javascript itself. And then shows javascript errors or misinterpreted css. So it looks like it has some buffer problem here, maybe a security bug also.
Reporter: Is this still an issue ?
we're at the point where we can call this invalid, because 304's can't have bodies and its now rare to see this mistake, but there is also considerable logic added that tries to disambiguate this sitaution.. so I'm going to call it fixed
Status: UNCONFIRMED → RESOLVED
Closed: 9 years ago
Resolution: --- → FIXED
You need to log in before you can comment on or make changes to this bug.