Author: violetagg
Date: Mon Aug 29 16:31:46 2016
New Revision: 1758257
URL: http://svn.apache.org/viewvc?rev=1758257&view=rev
Log:
Introduce a new method org.apache.coyote.OutputBuffer.doWrite(ByteBuffer)
Modified:
tomcat/trunk/java/org/apache/coyote/OutputBuffer.java
tomcat/trunk/java/org/apache/coyote/ajp/AjpMessage.java
tomcat/trunk/java/org/apache/coyote/ajp/AjpProcessor.java
tomcat/trunk/java/org/apache/coyote/http11/Http11OutputBuffer.java
tomcat/trunk/java/org/apache/coyote/http11/filters/ChunkedOutputFilter.java
tomcat/trunk/java/org/apache/coyote/http11/filters/GzipOutputFilter.java
tomcat/trunk/java/org/apache/coyote/http11/filters/IdentityOutputFilter.java
tomcat/trunk/java/org/apache/coyote/http11/filters/VoidOutputFilter.java
tomcat/trunk/java/org/apache/coyote/http2/Stream.java
tomcat/trunk/test/org/apache/coyote/http11/filters/TesterOutputBuffer.java
Modified: tomcat/trunk/java/org/apache/coyote/OutputBuffer.java
URL:
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/OutputBuffer.java?rev=1758257&r1=1758256&r2=1758257&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/coyote/OutputBuffer.java (original)
+++ tomcat/trunk/java/org/apache/coyote/OutputBuffer.java Mon Aug 29 16:31:46
2016
@@ -17,6 +17,7 @@
package org.apache.coyote;
import java.io.IOException;
+import java.nio.ByteBuffer;
import org.apache.tomcat.util.buf.ByteChunk;
@@ -24,7 +25,7 @@ import org.apache.tomcat.util.buf.ByteCh
* Output buffer.
*
* This class is used internally by the protocol implementation. All writes
from
- * higher level code should happen via Resonse.doWrite().
+ * higher level code should happen via Response.doWrite().
*
* @author Remy Maucherat
*/
@@ -44,6 +45,19 @@ public interface OutputBuffer {
/**
+ * Write the given data to the response. The caller owns the chunks.
+ *
+ * @param chunk data to write
+ *
+ * @return The number of bytes written which may be less than available in
+ * the input chunk
+ *
+ * @throws IOException an underlying I/O error occurred
+ */
+ public int doWrite(ByteBuffer chunk) throws IOException;
+
+
+ /**
* Bytes written to the underlying socket. This includes the effects of
* chunking, compression, etc.
*
Modified: tomcat/trunk/java/org/apache/coyote/ajp/AjpMessage.java
URL:
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/ajp/AjpMessage.java?rev=1758257&r1=1758256&r2=1758257&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/coyote/ajp/AjpMessage.java (original)
+++ tomcat/trunk/java/org/apache/coyote/ajp/AjpMessage.java Mon Aug 29 16:31:46
2016
@@ -17,6 +17,8 @@
package org.apache.coyote.ajp;
+import java.nio.ByteBuffer;
+
import org.apache.juli.logging.Log;
import org.apache.juli.logging.LogFactory;
import org.apache.tomcat.util.buf.ByteChunk;
@@ -220,18 +222,47 @@ public class AjpMessage {
* @param numBytes The number of bytes to copy.
*/
public void appendBytes(byte[] b, int off, int numBytes) {
+ if (checkOverflow(numBytes)) {
+ return;
+ }
+ appendInt(numBytes);
+ System.arraycopy(b, off, buf, pos, numBytes);
+ pos += numBytes;
+ appendByte(0);
+ }
+
+
+ /**
+ * Copy a chunk of bytes into the packet, starting at the current
+ * write position. The chunk of bytes is encoded with the length
+ * in two bytes first, then the data itself, and finally a
+ * terminating \0 (which is <B>not</B> included in the encoded
+ * length).
+ *
+ * @param b The ByteBuffer from which to copy bytes.
+ */
+ public void appendBytes(ByteBuffer b) {
+ int numBytes = b.remaining();
+ if (checkOverflow(numBytes)) {
+ return;
+ }
+ appendInt(numBytes);
+ b.get(buf, pos, numBytes);
+ pos += numBytes;
+ appendByte(0);
+ }
+
+
+ private boolean checkOverflow(int numBytes) {
if (pos + numBytes + 3 > buf.length) {
log.error(sm.getString("ajpmessage.overflow", "" + numBytes, "" +
pos),
new ArrayIndexOutOfBoundsException());
if (log.isDebugEnabled()) {
dump("Overflow/coBytes");
}
- return;
+ return true;
}
- appendInt(numBytes);
- System.arraycopy(b, off, buf, pos, numBytes);
- pos += numBytes;
- appendByte(0);
+ return false;
}
Modified: tomcat/trunk/java/org/apache/coyote/ajp/AjpProcessor.java
URL:
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/ajp/AjpProcessor.java?rev=1758257&r1=1758256&r2=1758257&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/coyote/ajp/AjpProcessor.java (original)
+++ tomcat/trunk/java/org/apache/coyote/ajp/AjpProcessor.java Mon Aug 29
16:31:46 2016
@@ -21,6 +21,7 @@ import java.io.EOFException;
import java.io.IOException;
import java.io.InterruptedIOException;
import java.net.InetAddress;
+import java.nio.ByteBuffer;
import java.security.NoSuchProviderException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
@@ -1313,10 +1314,8 @@ public class AjpProcessor extends Abstra
// Write this chunk
while (len > 0) {
- int thisTime = len;
- if (thisTime > outputMaxChunkSize) {
- thisTime = outputMaxChunkSize;
- }
+ int thisTime = Math.min(len, outputMaxChunkSize);
+
responseMessage.reset();
responseMessage.appendByte(Constants.JK_AJP13_SEND_BODY_CHUNK);
responseMessage.appendBytes(chunk.getBytes(), chunk.getOffset() +
off, thisTime);
@@ -1332,6 +1331,32 @@ public class AjpProcessor extends Abstra
}
+ private void writeData(ByteBuffer chunk) throws IOException {
+ boolean blocking = (response.getWriteListener() == null);
+
+ int len = chunk.remaining();
+ int off = 0;
+
+ // Write this chunk
+ while (len > 0) {
+ int thisTime = Math.min(len, outputMaxChunkSize);
+
+ responseMessage.reset();
+ responseMessage.appendByte(Constants.JK_AJP13_SEND_BODY_CHUNK);
+ chunk.limit(chunk.position() + thisTime);
+ responseMessage.appendBytes(chunk);
+ responseMessage.end();
+ socketWrapper.write(blocking, responseMessage.getBuffer(), 0,
responseMessage.getLen());
+ socketWrapper.flush(blocking);
+
+ len -= thisTime;
+ off += thisTime;
+ }
+
+ bytesWritten += off;
+ }
+
+
private boolean hasDataToWrite() {
return responseMsgPos != -1 || socketWrapper.hasDataToWrite();
}
@@ -1397,6 +1422,27 @@ public class AjpProcessor extends Abstra
}
@Override
+ public int doWrite(ByteBuffer chunk) throws IOException {
+
+ if (!response.isCommitted()) {
+ // Validate and write response headers
+ try {
+ prepareResponse();
+ } catch (IOException e) {
+ setErrorState(ErrorState.CLOSE_CONNECTION_NOW, e);
+ }
+ }
+
+ int len = 0;
+ if (!swallowResponse) {
+ len = chunk.remaining();
+ writeData(chunk);
+ len -= chunk.remaining();
+ }
+ return len;
+ }
+
+ @Override
public long getBytesWritten() {
return bytesWritten;
}
Modified: tomcat/trunk/java/org/apache/coyote/http11/Http11OutputBuffer.java
URL:
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/http11/Http11OutputBuffer.java?rev=1758257&r1=1758256&r2=1758257&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/coyote/http11/Http11OutputBuffer.java
(original)
+++ tomcat/trunk/java/org/apache/coyote/http11/Http11OutputBuffer.java Mon Aug
29 16:31:46 2016
@@ -17,6 +17,7 @@
package org.apache.coyote.http11;
import java.io.IOException;
+import java.nio.ByteBuffer;
import org.apache.coyote.ActionCode;
import org.apache.coyote.OutputBuffer;
@@ -209,6 +210,24 @@ public class Http11OutputBuffer implemen
@Override
+ public int doWrite(ByteBuffer chunk) throws IOException {
+
+ if (!response.isCommitted()) {
+ // Send the connector a request for commit. The connector should
+ // then validate the headers, send them (using sendHeaders) and
+ // set the filters accordingly.
+ response.action(ActionCode.COMMIT, null);
+ }
+
+ if (lastActiveFilter == -1) {
+ return outputStreamOutputBuffer.doWrite(chunk);
+ } else {
+ return activeFilters[lastActiveFilter].doWrite(chunk);
+ }
+ }
+
+
+ @Override
public long getBytesWritten() {
if (lastActiveFilter == -1) {
return outputStreamOutputBuffer.getBytesWritten();
@@ -562,6 +581,18 @@ public class Http11OutputBuffer implemen
byteCount += len;
return len;
}
+
+ /**
+ * Write chunk.
+ */
+ @Override
+ public int doWrite(ByteBuffer chunk) throws IOException {
+ int len = chunk.remaining();
+ socketWrapper.write(isBlocking(), chunk);
+ len -= chunk.remaining();
+ byteCount += len;
+ return len;
+ }
@Override
public long getBytesWritten() {
Modified:
tomcat/trunk/java/org/apache/coyote/http11/filters/ChunkedOutputFilter.java
URL:
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/http11/filters/ChunkedOutputFilter.java?rev=1758257&r1=1758256&r2=1758257&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/coyote/http11/filters/ChunkedOutputFilter.java
(original)
+++ tomcat/trunk/java/org/apache/coyote/http11/filters/ChunkedOutputFilter.java
Mon Aug 29 16:31:46 2016
@@ -18,6 +18,7 @@
package org.apache.coyote.http11.filters;
import java.io.IOException;
+import java.nio.ByteBuffer;
import org.apache.coyote.OutputBuffer;
import org.apache.coyote.Response;
@@ -89,8 +90,7 @@ public class ChunkedOutputFilter impleme
// --------------------------------------------------- OutputBuffer Methods
@Override
- public int doWrite(ByteChunk chunk)
- throws IOException {
+ public int doWrite(ByteChunk chunk) throws IOException {
int result = chunk.getLength();
@@ -98,14 +98,32 @@ public class ChunkedOutputFilter impleme
return 0;
}
- // Calculate chunk header
- int pos = 7;
- int current = result;
- while (current > 0) {
- int digit = current % 16;
- current = current / 16;
- chunkLength[pos--] = HexUtils.getHex(digit);
+ int pos = calculateChunkHeader(result);
+
+ chunkHeader.setBytes(chunkLength, pos + 1, 9 - pos);
+ buffer.doWrite(chunkHeader);
+
+ buffer.doWrite(chunk);
+
+ chunkHeader.setBytes(chunkLength, 8, 2);
+ buffer.doWrite(chunkHeader);
+
+ return result;
+
+ }
+
+
+ @Override
+ public int doWrite(ByteBuffer chunk) throws IOException {
+
+ int result = chunk.remaining();
+
+ if (result <= 0) {
+ return 0;
}
+
+ int pos = calculateChunkHeader(result);
+
chunkHeader.setBytes(chunkLength, pos + 1, 9 - pos);
buffer.doWrite(chunkHeader);
@@ -119,6 +137,19 @@ public class ChunkedOutputFilter impleme
}
+ private int calculateChunkHeader(int len) {
+ // Calculate chunk header
+ int pos = 7;
+ int current = len;
+ while (current > 0) {
+ int digit = current % 16;
+ current = current / 16;
+ chunkLength[pos--] = HexUtils.getHex(digit);
+ }
+ return pos;
+ }
+
+
@Override
public long getBytesWritten() {
return buffer.getBytesWritten();
Modified:
tomcat/trunk/java/org/apache/coyote/http11/filters/GzipOutputFilter.java
URL:
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/http11/filters/GzipOutputFilter.java?rev=1758257&r1=1758256&r2=1758257&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/coyote/http11/filters/GzipOutputFilter.java
(original)
+++ tomcat/trunk/java/org/apache/coyote/http11/filters/GzipOutputFilter.java
Mon Aug 29 16:31:46 2016
@@ -19,6 +19,7 @@ package org.apache.coyote.http11.filters
import java.io.IOException;
import java.io.OutputStream;
+import java.nio.ByteBuffer;
import java.util.zip.GZIPOutputStream;
import org.apache.coyote.OutputBuffer;
@@ -73,6 +74,23 @@ public class GzipOutputFilter implements
}
+ @Override
+ public int doWrite(ByteBuffer chunk) throws IOException {
+ if (compressionStream == null) {
+ compressionStream = new GZIPOutputStream(fakeOutputStream, true);
+ }
+ int len = chunk.remaining();
+ if (chunk.hasArray()) {
+ compressionStream.write(chunk.array(), chunk.arrayOffset() +
chunk.position(), len);
+ } else {
+ byte[] bytes = new byte[len];
+ chunk.put(bytes);
+ compressionStream.write(bytes, 0, len);
+ }
+ return len;
+ }
+
+
@Override
public long getBytesWritten() {
return buffer.getBytesWritten();
Modified:
tomcat/trunk/java/org/apache/coyote/http11/filters/IdentityOutputFilter.java
URL:
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/http11/filters/IdentityOutputFilter.java?rev=1758257&r1=1758256&r2=1758257&view=diff
==============================================================================
---
tomcat/trunk/java/org/apache/coyote/http11/filters/IdentityOutputFilter.java
(original)
+++
tomcat/trunk/java/org/apache/coyote/http11/filters/IdentityOutputFilter.java
Mon Aug 29 16:31:46 2016
@@ -18,6 +18,7 @@
package org.apache.coyote.http11.filters;
import java.io.IOException;
+import java.nio.ByteBuffer;
import org.apache.coyote.OutputBuffer;
import org.apache.coyote.Response;
@@ -88,6 +89,44 @@ public class IdentityOutputFilter implem
}
return result;
+
+ }
+
+
+ @Override
+ public int doWrite(ByteBuffer chunk) throws IOException {
+
+ int result = -1;
+
+ if (contentLength >= 0) {
+ if (remaining > 0) {
+ result = chunk.remaining();
+ if (result > remaining) {
+ // The chunk is longer than the number of bytes remaining
+ // in the body; changing the chunk length to the number
+ // of bytes remaining
+ chunk.limit(chunk.position() + (int) remaining);
+ result = (int) remaining;
+ remaining = 0;
+ } else {
+ remaining = remaining - result;
+ }
+ buffer.doWrite(chunk);
+ } else {
+ // No more bytes left to be written : return -1 and clear the
+ // buffer
+ chunk.position(0);
+ chunk.limit(0);
+ result = -1;
+ }
+ } else {
+ // If no content length was set, just write the bytes
+ result = chunk.remaining();
+ buffer.doWrite(chunk);
+ result -= chunk.remaining();
+ }
+
+ return result;
}
Modified:
tomcat/trunk/java/org/apache/coyote/http11/filters/VoidOutputFilter.java
URL:
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/http11/filters/VoidOutputFilter.java?rev=1758257&r1=1758256&r2=1758257&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/coyote/http11/filters/VoidOutputFilter.java
(original)
+++ tomcat/trunk/java/org/apache/coyote/http11/filters/VoidOutputFilter.java
Mon Aug 29 16:31:46 2016
@@ -18,6 +18,7 @@
package org.apache.coyote.http11.filters;
import java.io.IOException;
+import java.nio.ByteBuffer;
import org.apache.coyote.OutputBuffer;
import org.apache.coyote.Response;
@@ -41,6 +42,12 @@ public class VoidOutputFilter implements
}
+ @Override
+ public int doWrite(ByteBuffer chunk) throws IOException {
+ return chunk.remaining();
+ }
+
+
@Override
public long getBytesWritten() {
return 0;
Modified: tomcat/trunk/java/org/apache/coyote/http2/Stream.java
URL:
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/http2/Stream.java?rev=1758257&r1=1758256&r2=1758257&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/coyote/http2/Stream.java (original)
+++ tomcat/trunk/java/org/apache/coyote/http2/Stream.java Mon Aug 29 16:31:46
2016
@@ -489,6 +489,35 @@ public class Stream extends AbstractStre
return offset;
}
+ @Override
+ public synchronized int doWrite(ByteBuffer chunk) throws IOException {
+ if (closed) {
+ throw new IllegalStateException(
+ sm.getString("stream.closed", getConnectionId(),
getIdentifier()));
+ }
+ if (!coyoteResponse.isCommitted()) {
+ coyoteResponse.sendHeaders();
+ }
+ int chunkLimit = chunk.limit();
+ int offset = 0;
+ while (chunk.remaining() > 0) {
+ int thisTime = Math.min(buffer.remaining(), chunk.remaining());
+ chunk.limit(chunk.position() + thisTime);
+ buffer.put(chunk);
+ chunk.limit(chunkLimit);
+ offset += thisTime;
+ if (chunk.remaining() > 0 && !buffer.hasRemaining()) {
+ // Only flush if we have more data to write and the buffer
+ // is full
+ if (flush(true, coyoteResponse.getWriteListener() ==
null)) {
+ break;
+ }
+ }
+ }
+ written += offset;
+ return offset;
+ }
+
public synchronized boolean flush(boolean block) throws IOException {
return flush(false, block);
}
Modified:
tomcat/trunk/test/org/apache/coyote/http11/filters/TesterOutputBuffer.java
URL:
http://svn.apache.org/viewvc/tomcat/trunk/test/org/apache/coyote/http11/filters/TesterOutputBuffer.java?rev=1758257&r1=1758256&r2=1758257&view=diff
==============================================================================
--- tomcat/trunk/test/org/apache/coyote/http11/filters/TesterOutputBuffer.java
(original)
+++ tomcat/trunk/test/org/apache/coyote/http11/filters/TesterOutputBuffer.java
Mon Aug 29 16:31:46 2016
@@ -18,6 +18,7 @@ package org.apache.coyote.http11.filters
import java.io.ByteArrayOutputStream;
import java.io.IOException;
+import java.nio.ByteBuffer;
import org.apache.coyote.OutputBuffer;
import org.apache.coyote.Response;
@@ -110,6 +111,11 @@ public class TesterOutputBuffer extends
}
@Override
+ public int doWrite(ByteBuffer chunk) throws IOException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
public long getBytesWritten() {
return byteCount;
}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]