If you set the content-length to a very small value before setting headers in the httpResponse, they are all lost. In my case: The following actions are done in my code (a proxy) .. handleResponse(HttpServletRequest request, HttpServletResponse response) .. response.setHeader("Host", "localhost"); response.setHeader("Pragma", "nocache"); response.setContentLength(0); response.setHeader("location", "http://www.apache.org"); ... I sniff the http strean and the location field is lost. It's lost because the response is considered committed after setting the conten- length to zero and the actual set of the header is only done when the response is not committed: in class org.apache.coyote.tomcat5.CoyoteResponse we have public void setHeader(String name, String value) { if (isCommitted()) return; // Ignore any call from an included servlet if (included) return; coyoteResponse.setHeader(name, value); } I deep into the code and found the following that isCommitted calls isAppCommitted: public boolean isAppCommitted() { return (this.appCommitted || isCommitted() || isSuspended() || ((getContentLength() != -1) && (getContentCount() >= getContentLength()))); } If the header has already been written (that's my case but i don't know why) the ((getContentLength() != -1) && (getContentCount() >= getContentLength())) predicate is returning true. I think this can also happens for example with a small text file in response with huge header and by settings the content-length at the beginning.
The spec requires that the request is committed after the amount of bytes specified in the content-length has been written. So setting content-length to 0 commits (sort of).
I'm reading sectio SRV.5.1 of servlet spec 2.4, and it doesn't seem to provide an exact definition for "committed" responses. On the other hand, it says...: "The isCommitted method returns a boolean value indicating whether any response bytes have been returned to the client." This doesn't seem to allow a behaviour where the engine commits the response without the servlet having explicitly written anything, though, Can you point to other portions of the spec that would allow that behaviour?
(In reply to comment #2) > Can you point to other portions of the spec that would allow that behaviour? Section 5.5 bullet 2.
(In reply to comment #3) > (In reply to comment #2) > > Can you point to other portions of the spec that would allow that behaviour? > > Section 5.5 bullet 2. > Understood, but seems to be very legalistic view; and I'd be surprised that this interpretation was intended. Following up with <mailto:servletapi-feedback@eng.sun.com>.
Remy Maucherat wrote > The spec requires that the request is committed after the amount of bytes > specified in the content-length has been written. So setting content-length to 0 > commits (sort of). the section 5.5 bullet 2 says • The amount of content specified in the setContentLength method of the response has been written to the response. We are talking headers not content here. I agree if it was body content, but not for http headers. I haven't seen either in the http rfc either in the servlet 2.4 any way to specify the http header length! After some thought it only appears in my case because the content-length is set to 0 and I write only http headers.
Please, don't waste your time. The specification is very clear.
I agree that reopening bugs without any new points is a waste of time (obviously). I disagree that the specification is very clear.
The sentence is very clear, actually. That it may or may not have consequences you feel are inappropriate or unintended, but this is not relevant at this point.
*** Bug 32688 has been marked as a duplicate of this bug. ***
I agree with Remy here that response.setContentLength(0) would cause the response to be closed, because it meets the condition that the amount of content specified in the setContentLength method of the response (in this case: zero) has been written to the response. Julian/Touchard, the reason the response is considered committed from the implementation point of view is because getContentCount() and getContentLength() are both zero in: public boolean isAppCommitted() { return (this.appCommitted || isCommitted() || isSuspended() || ((getContentLength() != -1) && (getContentCount() >= getContentLength()))); } Please notice that getContentCount() really only returns the number of bytes written to the response body (in this case: zero): it does not include any response header bytes, which - I agree with you - would be wrong.
Well, obviously different readers come to different conclusions. If this is really the intended meaning of the language in the servlet spec, I'd expect for a clarification in the spec (I did ask for it at <mailto:servletapi-feedback@eng.sun.com> over four weeks ago but so far didn't get any response).
One (probably unintended) side effect of SRV.5.5, 2nd bullet, is that even when response.setContentLength(0) is not called explicitly, but the response's content length is set to 0 via response.setHeader("Content-Length", "0"), as in the following code snippet: response.setHeader("Host", "localhost"); response.setHeader("Pragma", "nocache"); response.setHeader("Content-Length", "0"); response.setHeader("location", "http://www.apache.org"); any subsequently setHeader() calls are ignored. This is not intuitive, because HTTP response headers should be settable in any order. I suggest we amend SRV.5.5, 2nd bullet, in the upcoming Servlet Maintenance release, as follows: The amount of content specified in the setContentLength method of the response [ADD: has been greater than zero] and has been written to the response Unless there are any objections, I am going to apply the following patch: Index: Response.java =================================================================== RCS file: /home/cvs/jakarta-tomcat-catalina/catalina/src/share/org/apache/catalina/connector/Response.java,v retrieving revision 1.11 diff -u -r1.11 Response.java --- Response.java 31 Mar 2005 10:31:53 -0000 1.11 +++ Response.java 25 Apr 2005 16:03:48 -0000 @@ -315,7 +315,7 @@ */ public boolean isAppCommitted() { return (this.appCommitted || isCommitted() || isSuspended() - || ((getContentLength() != -1) + || ((getContentLength() > 0) && (getContentCount() >= getContentLength()))); } Please let me know. Jan
*** Bug 36763 has been marked as a duplicate of this bug. ***