Fix https://issues.apache.org/bugzilla/show_bug.cgi?id=50496
authormarkt <markt@13f79535-47bb-0310-9956-ffa450edef68>
Fri, 7 Jan 2011 13:01:00 +0000 (13:01 +0000)
committermarkt <markt@13f79535-47bb-0310-9956-ffa450edef68>
Fri, 7 Jan 2011 13:01:00 +0000 (13:01 +0000)
Differentiate between content written (what the app writes to the output stream) and bytes written (what Tomcat writes to the socket) and use bytes for the access logs

git-svn-id: https://svn.apache.org/repos/asf/tomcat/trunk@1056298 13f79535-47bb-0310-9956-ffa450edef68

19 files changed:
java/org/apache/catalina/connector/Response.java
java/org/apache/catalina/valves/AccessLogValve.java
java/org/apache/catalina/valves/ErrorReportValve.java
java/org/apache/catalina/valves/JDBCAccessLogValve.java
java/org/apache/coyote/OutputBuffer.java
java/org/apache/coyote/RequestInfo.java
java/org/apache/coyote/Response.java
java/org/apache/coyote/ajp/AbstractAjpProcessor.java
java/org/apache/coyote/ajp/AjpAprProcessor.java
java/org/apache/coyote/ajp/AjpProcessor.java
java/org/apache/coyote/http11/AbstractOutputBuffer.java
java/org/apache/coyote/http11/InternalAprOutputBuffer.java
java/org/apache/coyote/http11/InternalNioOutputBuffer.java
java/org/apache/coyote/http11/InternalOutputBuffer.java
java/org/apache/coyote/http11/filters/ChunkedOutputFilter.java
java/org/apache/coyote/http11/filters/GzipOutputFilter.java
java/org/apache/coyote/http11/filters/IdentityOutputFilter.java
java/org/apache/coyote/http11/filters/VoidOutputFilter.java
webapps/docs/changelog.xml

index 98d05a3..3fdf46a 100644 (file)
@@ -308,12 +308,30 @@ public class Response
 
 
     /**
-     * Return the number of bytes actually written to the output stream.
+     * Return the number of bytes the application has actually written to the
+     * output stream. This excludes chunking, compression, etc. as well as
+     * headers.
      */
-    public long getContentCount() {
+    public long getContentWritten() {
         return outputBuffer.getContentWritten();
     }
 
+
+    /**
+     * Return the number of bytes the actually written to the socket. This
+     * includes chunking, compression, etc. but excludes headers.
+     */
+    public long getBytesWritten(boolean flush) {
+        if (flush) {
+            try {
+                outputBuffer.flush();
+            } catch (IOException ioe) {
+                // Ignore - the client has probably closed the connection
+            }
+        }
+        return coyoteResponse.getBytesWritten(flush);
+    }
+
     /**
      * Set the application commit flag.
      * 
@@ -330,7 +348,7 @@ public class Response
     public boolean isAppCommitted() {
         return (this.appCommitted || isCommitted() || isSuspended()
                 || ((getContentLength() > 0) 
-                    && (getContentCount() >= getContentLength())));
+                    && (getContentWritten() >= getContentLength())));
     }
 
 
index fe3bf39..9a03e16 100644 (file)
@@ -1049,7 +1049,7 @@ public class AccessLogValve extends ValveBase implements AccessLog {
         @Override
         public void addElement(StringBuilder buf, Date date, Request request,
                 Response response, long time) {
-            long length = response.getContentCount() ;
+            long length = response.getBytesWritten(true);
             if (length <= 0 && conversion) {
                 buf.append('-');
             } else {
index 335eb66..98a29db 100644 (file)
@@ -157,7 +157,7 @@ public class ErrorReportValve extends ValveBase {
 
         // Do nothing on a 1xx, 2xx and 3xx status
         // Do nothing if anything has been written already
-        if ((statusCode < 400) || (response.getContentCount() > 0))
+        if ((statusCode < 400) || (response.getContentWritten() > 0))
             return;
 
         String message = RequestUtil.filter(response.getMessage());
index 6601df2..d897774 100644 (file)
@@ -457,7 +457,7 @@ public final class JDBCAccessLogValve extends ValveBase implements AccessLog {
         String user = request.getRemoteUser();
         String query=request.getRequestURI();
         
-        long bytes = response.getContentCount() ;
+        long bytes = response.getBytesWritten(true);
         if(bytes < 0)
             bytes = 0;
         int status = response.getStatus();
index 09fe53a..2dfb588 100644 (file)
@@ -25,8 +25,8 @@ import org.apache.tomcat.util.buf.ByteChunk;
 /**
  * Output buffer.
  *
- * This class is used internally by the protocol implementation. All writes from higher level code should happen
- * via Resonse.doWrite().
+ * This class is used internally by the protocol implementation. All writes from
+ * higher level code should happen via Resonse.doWrite().
  * 
  * @author Remy Maucherat
  */
@@ -37,11 +37,18 @@ public interface OutputBuffer {
      * Write the response. The caller ( tomcat ) owns the chunks.
      *
      * @param chunk data to write
-     * @param response used to allow buffers that can be shared by multiple responses.
+     * @param response used to allow buffers that can be shared by multiple
+     *          responses.
      * @throws IOException
      */
     public int doWrite(ByteChunk chunk, Response response)
         throws IOException;
 
-
+    /**
+     * Bytes written to the underlying socket. This includes the effects of
+     * chunking, compression, etc.
+     * 
+     * @return  Bytes written for the current request
+     */
+    public long getBytesWritten();
 }
index ee8c0b3..c142cf6 100644 (file)
@@ -107,7 +107,7 @@ public class RequestInfo  {
     }
 
     public long getRequestBytesSent() {
-        return req.getResponse().getBytesWritten();
+        return req.getResponse().getContentWritten();
     }
 
     public long getRequestProcessingTime() {
@@ -140,7 +140,7 @@ public class RequestInfo  {
      */
     void updateCounters() {
         bytesReceived+=req.getBytesRead();
-        bytesSent+=req.getResponse().getBytesWritten();
+        bytesSent+=req.getResponse().getContentWritten();
 
         requestCount++;
         if( req.getResponse().getStatus() >=400 )
index f5ba643..88f1bbd 100644 (file)
@@ -97,7 +97,7 @@ public final class Response {
     private Locale locale = DEFAULT_LOCALE;
 
     // General informations
-    private long bytesWritten=0;
+    private long contentWritten = 0;
 
     /**
      * Holds request error exception.
@@ -531,7 +531,7 @@ public final class Response {
         throws IOException
     {
         outputBuffer.doWrite(chunk, this);
-        bytesWritten+=chunk.getLength();
+        contentWritten+=chunk.getLength();
     }
 
     // --------------------
@@ -551,10 +551,23 @@ public final class Response {
         headers.clear();
 
         // update counters
-        bytesWritten=0;
+        contentWritten=0;
     }
 
-    public long getBytesWritten() {
-        return bytesWritten;
+    /**
+     * Bytes written by application - i.e. before compression, chunking, etc.
+     */
+    public long getContentWritten() {
+        return contentWritten;
+    }
+    
+    /**
+     * Bytes written to socket - i.e. after compression, chunking, etc.
+     */
+    public long getBytesWritten(boolean flush) {
+        if (flush) {
+            action(ActionCode.CLIENT_FLUSH, this);
+        }
+        return outputBuffer.getBytesWritten();
     }
 }
index 0802b3d..44b00e1 100644 (file)
@@ -176,6 +176,12 @@ public abstract class AbstractAjpProcessor implements ActionHook, Processor {
      */
     protected AsyncStateMachine asyncStateMachine = new AsyncStateMachine(this);
 
+
+    /**
+     * Bytes written to client for the current request
+     */
+    protected long byteCount = 0;
+    
     
     // ------------------------------------------------------------- Properties
 
@@ -379,6 +385,7 @@ public abstract class AbstractAjpProcessor implements ActionHook, Processor {
        request.recycle();
        response.recycle();
        certificates.recycle();
+       byteCount = 0;
    }
    
    // ------------------------------------------------------ Connector Methods
index 815121a..d6926e5 100644 (file)
@@ -725,7 +725,13 @@ public class AjpAprProcessor extends AbstractAjpProcessor {
                 off += thisTime;
             }
 
+            byteCount += chunk.getLength();
             return chunk.getLength();
         }
+
+        @Override
+        public long getBytesWritten() {
+            return byteCount;
+        }
     }
 }
index 4f33a25..45b2fd8 100644 (file)
@@ -590,9 +590,7 @@ public class AjpProcessor extends AbstractAjpProcessor {
      * This class is an output buffer which will write data to an output
      * stream.
      */
-    protected class SocketOutputBuffer
-        implements OutputBuffer {
-
+    protected class SocketOutputBuffer implements OutputBuffer {
 
         /**
          * Write chunk.
@@ -631,7 +629,13 @@ public class AjpProcessor extends AbstractAjpProcessor {
                 off += thisTime;
             }
 
+            byteCount += chunk.getLength();
             return chunk.getLength();
         }
+
+        @Override
+        public long getBytesWritten() {
+            return byteCount;
+        }
     }
 }
index e5bef9d..6d5b2af 100644 (file)
@@ -88,6 +88,11 @@ public abstract class AbstractOutputBuffer implements OutputBuffer{
      */
     protected OutputBuffer outputStreamOutputBuffer;
 
+    /**
+     * Bytes written to client for the current request
+     */
+    protected long byteCount = 0;
+
     // -------------------------------------------------------------- Variables
 
 
@@ -185,7 +190,18 @@ public abstract class AbstractOutputBuffer implements OutputBuffer{
             return activeFilters[lastActiveFilter].doWrite(chunk, res);
 
     }
-    
+
+
+    @Override
+    public long getBytesWritten() {
+        if (lastActiveFilter == -1) {
+            return outputStreamOutputBuffer.getBytesWritten();
+        } else {
+            return activeFilters[lastActiveFilter].getBytesWritten();
+        }
+    }
+
+
     // --------------------------------------------------------- Public Methods
 
 
@@ -299,7 +315,7 @@ public abstract class AbstractOutputBuffer implements OutputBuffer{
         if (lastActiveFilter != -1)
             activeFilters[lastActiveFilter].end();
         finished = true;
-
+        byteCount = 0;
     }
     
     public abstract void sendAck() throws IOException;
index a2918b7..eabc110 100644 (file)
@@ -227,8 +227,7 @@ public class InternalAprOutputBuffer extends AbstractOutputBuffer {
      * This class is an output buffer which will write data to an output
      * stream.
      */
-    protected class SocketOutputBuffer 
-        implements OutputBuffer {
+    protected class SocketOutputBuffer implements OutputBuffer {
 
 
         /**
@@ -253,11 +252,14 @@ public class InternalAprOutputBuffer extends AbstractOutputBuffer {
                 len = len - thisTime;
                 start = start + thisTime;
             }
+            byteCount += chunk.getLength();
             return chunk.getLength();
-
         }
 
-
+        @Override
+        public long getBytesWritten() {
+            return byteCount;
+        }
     }
 
 
index 8f2bea2..410d090 100644 (file)
@@ -295,11 +295,14 @@ public class InternalNioOutputBuffer extends AbstractOutputBuffer {
             int start = chunk.getStart();
             byte[] b = chunk.getBuffer();
             addToBB(b, start, len);
+            byteCount += chunk.getLength();
             return chunk.getLength();
-
         }
 
-
+        @Override
+        public long getBytesWritten() {
+            return byteCount;
+        }
     }
 
 
index 6780583..27870fd 100644 (file)
@@ -74,6 +74,7 @@ public class InternalOutputBuffer extends AbstractOutputBuffer
      */
     protected boolean useSocketBuffer = false;    
     
+
     /**
      * Set the underlying socket output stream.
      */
@@ -255,11 +256,14 @@ public class InternalOutputBuffer extends AbstractOutputBuffer
                 outputStream.write(chunk.getBuffer(), chunk.getStart(), 
                                    length);
             }
-            return length;
-
+            byteCount += chunk.getLength();
+            return chunk.getLength();
         }
 
-
+        @Override
+        public long getBytesWritten() {
+            return byteCount;
+        }
     }
 
 
index 9dd0535..797f3e8 100644 (file)
@@ -126,6 +126,12 @@ public class ChunkedOutputFilter implements OutputFilter {
     }
 
 
+    @Override
+    public long getBytesWritten() {
+        return buffer.getBytesWritten();
+    }
+
+
     // --------------------------------------------------- OutputFilter Methods
 
 
index 81d5815..a7071f8 100644 (file)
@@ -82,6 +82,12 @@ public class GzipOutputFilter implements OutputFilter {
     }
 
 
+    @Override
+    public long getBytesWritten() {
+        return buffer.getBytesWritten();
+    }
+
+
     // --------------------------------------------------- OutputFilter Methods
 
     /**
index d10fd41..83912a4 100644 (file)
@@ -99,6 +99,12 @@ public class IdentityOutputFilter implements OutputFilter {
     }
 
 
+    @Override
+    public long getBytesWritten() {
+        return buffer.getBytesWritten();
+    }
+
+
     // --------------------------------------------------- OutputFilter Methods
 
 
index 9e1de7c..ce3eb72 100644 (file)
@@ -50,6 +50,12 @@ public class VoidOutputFilter implements OutputFilter {
     }
 
 
+    @Override
+    public long getBytesWritten() {
+        return 0;
+    }
+
+
     // --------------------------------------------------- OutputFilter Methods
 
 
index 2a89d92..e3cf8d0 100644 (file)
         (markt)
       </update>
       <fix>
+        <bug>50496</bug>: Bytes sent in the access log are now counted after
+        compression, chunking etc rather than before. (markt)
+      </fix>
+      <fix>
         <bug>50550</bug>: When a new directory is created (e.g. via WebDAV)
         ensure that a subsequent request for that directory does not result in a
         404 response. (markt)