2012/5/30  <ma...@apache.org>:
> Author: markt
> Date: Wed May 30 14:13:47 2012
> New Revision: 1344267
>
> URL: http://svn.apache.org/viewvc?rev=1344267&view=rev
> Log:
> Fix https://issues.apache.org/bugzilla/show_bug.cgi?id=53169
> Allow servlets to opt to avoid chunked encoding with a response of unknown 
> length by setting the Connection: close header.
> Based on a patch suggested by Philippe Marschall.
>
> Modified:
>    tomcat/tc7.0.x/trunk/   (props changed)
>    
> tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/AbstractHttp11Processor.java
>    
> tomcat/tc7.0.x/trunk/test/org/apache/coyote/http11/TestAbstractHttp11Processor.java
>    tomcat/tc7.0.x/trunk/webapps/docs/changelog.xml
>
> Propchange: tomcat/tc7.0.x/trunk/
> ------------------------------------------------------------------------------
>  Merged /tomcat/trunk:r1344266
>
> Modified: 
> tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/AbstractHttp11Processor.java
> URL: 
> http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/AbstractHttp11Processor.java?rev=1344267&r1=1344266&r2=1344267&view=diff
> ==============================================================================
> --- 
> tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/AbstractHttp11Processor.java
>  (original)
> +++ 
> tomcat/tc7.0.x/trunk/java/org/apache/coyote/http11/AbstractHttp11Processor.java
>  Wed May 30 14:13:47 2012
> @@ -1135,7 +1135,7 @@ public abstract class AbstractHttp11Proc
>         MimeHeaders headers = request.getMimeHeaders();
>
>         // Check connection header
> -        MessageBytes connectionValueMB = headers.getValue("connection");
> +        MessageBytes connectionValueMB = 
> headers.getValue(Constants.CONNECTION);
>         if (connectionValueMB != null) {
>             ByteChunk connectionValueBC = connectionValueMB.getByteChunk();
>             if (findBytes(connectionValueBC, Constants.CLOSE_BYTES) != -1) {
> @@ -1374,13 +1374,17 @@ public abstract class AbstractHttp11Proc
>         }
>
>         long contentLength = response.getContentLengthLong();
> +        boolean connectionClosePresent = false;
>         if (contentLength != -1) {
>             headers.setValue("Content-Length").setLong(contentLength);
>             getOutputBuffer().addActiveFilter
>                 (outputFilters[Constants.IDENTITY_FILTER]);
>             contentDelimitation = true;
>         } else {
> -            if (entityBody && http11) {
> +            // If the response code supports an entity body and we're on
> +            // HTTP 1.1 then we chunk unless we have a Connection: close 
> header
> +            connectionClosePresent = isConnectionClose(headers);
> +            if (entityBody && http11 && !connectionClosePresent) {
>                 getOutputBuffer().addActiveFilter
>                     (outputFilters[Constants.CHUNKED_FILTER]);
>                 contentDelimitation = true;
> @@ -1426,7 +1430,11 @@ public abstract class AbstractHttp11Proc
>         // Connection: close header.
>         keepAlive = keepAlive && !statusDropsConnection(statusCode);
>         if (!keepAlive) {
> -            
> headers.addValue(Constants.CONNECTION).setString(Constants.CLOSE);
> +            // Avoid adding the close header twice
> +            if (!connectionClosePresent) {
> +                headers.addValue(Constants.CONNECTION).setString(
> +                        Constants.CLOSE);
> +            }
>         } else if (!http11 && !error) {
>             
> headers.addValue(Constants.CONNECTION).setString(Constants.KEEPALIVE);
>         }
> @@ -1451,6 +1459,14 @@ public abstract class AbstractHttp11Proc
>
>     }
>
> +    private boolean isConnectionClose(MimeHeaders headers) {
> +        MessageBytes connection = headers.getValue(Constants.CONNECTION);
> +        if (connection == null) {
> +            return false;
> +        }
> +        return connection.equals(Constants.CLOSE);
> +    }

Just a note: The HTTP1.1 spec allows Connection header as

Connection = "Connection" ":" 1#(connection-token)

thus allowing it to have several values, separated by commas, or
several headers.

I agree though that for a response it does not make much sense to
expect something else if it is the "close" connection header.

In AbstractHttp11Processor#prepareRequest() the code that checks the
value of Constants.CONNECTION header is also not prepared to handle
several values or several headers. Though nobody complained and it
works a bit faster this way.

>  public class TestAbstractHttp11Processor extends TomcatBaseTest {
> (...)
>+    // flushes with no content-length set but sets Connection: close header
>+    // should no result in chunking on HTTP 1.1
>+    private static final class NoContentLengthConnectionCloseFlushingServlet
>+            extends HttpServlet {
>+
>+        private static final long serialVersionUID = 1L;
>+
>+        @Override
>+        protected void doGet(HttpServletRequest req, HttpServletResponse resp)
>+                throws ServletException, IOException {
>+            resp.setStatus(HttpServletResponse.SC_OK);
>+            resp.setContentType("text/event-stream");
>+            resp.addHeader("Connection", "close");

It could be resp.setHeader(..) in this test servlet here.

>+            resp.flushBuffer();
>+            resp.getWriter().write("OK");
>+            resp.flushBuffer();
>+        }
>+    }

Best regards,
Konstantin Kolinko

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org
For additional commands, e-mail: dev-h...@tomcat.apache.org

Reply via email to