Bug 32604 - Some httpHeaders can be lost in response
Summary: Some httpHeaders can be lost in response
Status: RESOLVED FIXED
Alias: None
Product: Tomcat 5
Classification: Unclassified
Component: Connector:Coyote (show other bugs)
Version: 5.0.30
Hardware: PC All
: P2 normal (vote)
Target Milestone: ---
Assignee: Tomcat Developers Mailing List
URL:
Keywords:
: 32688 36763 (view as bug list)
Depends on:
Blocks:
 
Reported: 2004-12-09 11:57 UTC by Touchard
Modified: 2005-09-21 15:29 UTC (History)
2 users (show)



Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Touchard 2004-12-09 11:57:58 UTC
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.
Comment 1 Remy Maucherat 2004-12-10 18:28:14 UTC
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).
Comment 2 Julian Reschke 2004-12-10 19:04:37 UTC
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?
Comment 3 william.barker 2004-12-10 19:26:13 UTC
(In reply to comment #2)
> Can you point to other portions of the spec that would allow that behaviour?

Section 5.5 bullet 2.
Comment 4 Julian Reschke 2004-12-10 19:44:41 UTC
(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>.
Comment 5 Touchard 2004-12-13 10:01:21 UTC
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. 
Comment 6 Remy Maucherat 2004-12-14 10:02:19 UTC
Please, don't waste your time. The specification is very clear.
Comment 7 Julian Reschke 2004-12-14 10:29:34 UTC
I agree that reopening bugs without any new points is a waste of time
(obviously). I disagree that the specification is very clear.
Comment 8 Remy Maucherat 2004-12-14 10:43:15 UTC
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.
Comment 9 Remy Maucherat 2004-12-14 11:05:07 UTC
*** Bug 32688 has been marked as a duplicate of this bug. ***
Comment 10 Jan Luehe 2005-01-12 02:35:03 UTC
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.
Comment 11 Julian Reschke 2005-01-12 14:52:56 UTC
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).
Comment 12 Jan Luehe 2005-04-25 18:07:20 UTC
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
Comment 13 william.barker 2005-09-21 23:29:59 UTC
*** Bug 36763 has been marked as a duplicate of this bug. ***