From: markt Date: Fri, 7 Jan 2011 13:01:00 +0000 (+0000) Subject: Fix https://issues.apache.org/bugzilla/show_bug.cgi?id=50496 X-Git-Url: https://git.internetallee.de/?a=commitdiff_plain;h=0a8fee1a70b26130f50a6458db215f5f55d34ac4;p=tomcat7.0 Fix https://issues.apache.org/bugzilla/show_bug.cgi?id=50496 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 --- diff --git a/java/org/apache/catalina/connector/Response.java b/java/org/apache/catalina/connector/Response.java index 98d05a3d1..3fdf46afe 100644 --- a/java/org/apache/catalina/connector/Response.java +++ b/java/org/apache/catalina/connector/Response.java @@ -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()))); } diff --git a/java/org/apache/catalina/valves/AccessLogValve.java b/java/org/apache/catalina/valves/AccessLogValve.java index fe3bf3935..9a03e166d 100644 --- a/java/org/apache/catalina/valves/AccessLogValve.java +++ b/java/org/apache/catalina/valves/AccessLogValve.java @@ -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 { diff --git a/java/org/apache/catalina/valves/ErrorReportValve.java b/java/org/apache/catalina/valves/ErrorReportValve.java index 335eb6667..98a29db86 100644 --- a/java/org/apache/catalina/valves/ErrorReportValve.java +++ b/java/org/apache/catalina/valves/ErrorReportValve.java @@ -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()); diff --git a/java/org/apache/catalina/valves/JDBCAccessLogValve.java b/java/org/apache/catalina/valves/JDBCAccessLogValve.java index 6601df209..d897774dd 100644 --- a/java/org/apache/catalina/valves/JDBCAccessLogValve.java +++ b/java/org/apache/catalina/valves/JDBCAccessLogValve.java @@ -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(); diff --git a/java/org/apache/coyote/OutputBuffer.java b/java/org/apache/coyote/OutputBuffer.java index 09fe53adc..2dfb58805 100644 --- a/java/org/apache/coyote/OutputBuffer.java +++ b/java/org/apache/coyote/OutputBuffer.java @@ -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(); } diff --git a/java/org/apache/coyote/RequestInfo.java b/java/org/apache/coyote/RequestInfo.java index ee8c0b362..c142cf65a 100644 --- a/java/org/apache/coyote/RequestInfo.java +++ b/java/org/apache/coyote/RequestInfo.java @@ -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 ) diff --git a/java/org/apache/coyote/Response.java b/java/org/apache/coyote/Response.java index f5ba64329..88f1bbd03 100644 --- a/java/org/apache/coyote/Response.java +++ b/java/org/apache/coyote/Response.java @@ -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(); } } diff --git a/java/org/apache/coyote/ajp/AbstractAjpProcessor.java b/java/org/apache/coyote/ajp/AbstractAjpProcessor.java index 0802b3dac..44b00e13b 100644 --- a/java/org/apache/coyote/ajp/AbstractAjpProcessor.java +++ b/java/org/apache/coyote/ajp/AbstractAjpProcessor.java @@ -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 diff --git a/java/org/apache/coyote/ajp/AjpAprProcessor.java b/java/org/apache/coyote/ajp/AjpAprProcessor.java index 815121a20..d6926e57b 100644 --- a/java/org/apache/coyote/ajp/AjpAprProcessor.java +++ b/java/org/apache/coyote/ajp/AjpAprProcessor.java @@ -725,7 +725,13 @@ public class AjpAprProcessor extends AbstractAjpProcessor { off += thisTime; } + byteCount += chunk.getLength(); return chunk.getLength(); } + + @Override + public long getBytesWritten() { + return byteCount; + } } } diff --git a/java/org/apache/coyote/ajp/AjpProcessor.java b/java/org/apache/coyote/ajp/AjpProcessor.java index 4f33a25d0..45b2fd820 100644 --- a/java/org/apache/coyote/ajp/AjpProcessor.java +++ b/java/org/apache/coyote/ajp/AjpProcessor.java @@ -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; + } } } diff --git a/java/org/apache/coyote/http11/AbstractOutputBuffer.java b/java/org/apache/coyote/http11/AbstractOutputBuffer.java index e5bef9d6c..6d5b2afe2 100644 --- a/java/org/apache/coyote/http11/AbstractOutputBuffer.java +++ b/java/org/apache/coyote/http11/AbstractOutputBuffer.java @@ -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; diff --git a/java/org/apache/coyote/http11/InternalAprOutputBuffer.java b/java/org/apache/coyote/http11/InternalAprOutputBuffer.java index a2918b712..eabc11086 100644 --- a/java/org/apache/coyote/http11/InternalAprOutputBuffer.java +++ b/java/org/apache/coyote/http11/InternalAprOutputBuffer.java @@ -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; + } } diff --git a/java/org/apache/coyote/http11/InternalNioOutputBuffer.java b/java/org/apache/coyote/http11/InternalNioOutputBuffer.java index 8f2bea296..410d090d6 100644 --- a/java/org/apache/coyote/http11/InternalNioOutputBuffer.java +++ b/java/org/apache/coyote/http11/InternalNioOutputBuffer.java @@ -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; + } } diff --git a/java/org/apache/coyote/http11/InternalOutputBuffer.java b/java/org/apache/coyote/http11/InternalOutputBuffer.java index 678058384..27870fda7 100644 --- a/java/org/apache/coyote/http11/InternalOutputBuffer.java +++ b/java/org/apache/coyote/http11/InternalOutputBuffer.java @@ -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; + } } diff --git a/java/org/apache/coyote/http11/filters/ChunkedOutputFilter.java b/java/org/apache/coyote/http11/filters/ChunkedOutputFilter.java index 9dd0535ae..797f3e830 100644 --- a/java/org/apache/coyote/http11/filters/ChunkedOutputFilter.java +++ b/java/org/apache/coyote/http11/filters/ChunkedOutputFilter.java @@ -126,6 +126,12 @@ public class ChunkedOutputFilter implements OutputFilter { } + @Override + public long getBytesWritten() { + return buffer.getBytesWritten(); + } + + // --------------------------------------------------- OutputFilter Methods diff --git a/java/org/apache/coyote/http11/filters/GzipOutputFilter.java b/java/org/apache/coyote/http11/filters/GzipOutputFilter.java index 81d581532..a7071f88e 100644 --- a/java/org/apache/coyote/http11/filters/GzipOutputFilter.java +++ b/java/org/apache/coyote/http11/filters/GzipOutputFilter.java @@ -82,6 +82,12 @@ public class GzipOutputFilter implements OutputFilter { } + @Override + public long getBytesWritten() { + return buffer.getBytesWritten(); + } + + // --------------------------------------------------- OutputFilter Methods /** diff --git a/java/org/apache/coyote/http11/filters/IdentityOutputFilter.java b/java/org/apache/coyote/http11/filters/IdentityOutputFilter.java index d10fd4190..83912a44b 100644 --- a/java/org/apache/coyote/http11/filters/IdentityOutputFilter.java +++ b/java/org/apache/coyote/http11/filters/IdentityOutputFilter.java @@ -99,6 +99,12 @@ public class IdentityOutputFilter implements OutputFilter { } + @Override + public long getBytesWritten() { + return buffer.getBytesWritten(); + } + + // --------------------------------------------------- OutputFilter Methods diff --git a/java/org/apache/coyote/http11/filters/VoidOutputFilter.java b/java/org/apache/coyote/http11/filters/VoidOutputFilter.java index 9e1de7c35..ce3eb7270 100644 --- a/java/org/apache/coyote/http11/filters/VoidOutputFilter.java +++ b/java/org/apache/coyote/http11/filters/VoidOutputFilter.java @@ -50,6 +50,12 @@ public class VoidOutputFilter implements OutputFilter { } + @Override + public long getBytesWritten() { + return 0; + } + + // --------------------------------------------------- OutputFilter Methods diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml index 2a89d92d6..e3cf8d02f 100644 --- a/webapps/docs/changelog.xml +++ b/webapps/docs/changelog.xml @@ -189,6 +189,10 @@ (markt) + 50496: Bytes sent in the access log are now counted after + compression, chunking etc rather than before. (markt) + + 50550: 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)