Bug 41466 - NIO Connector: IllegalArgumentException: You can only write using the application write buffer provided by the handler
NIO Connector: IllegalArgumentException: You can only write using the applica...
Status: RESOLVED FIXED
Product: Tomcat 6
Classification: Unclassified
Component: Catalina
6.0.7
All Windows XP
: P2 major (vote)
: default
Assigned To: Tomcat Developers Mailing List
:
Depends on:
Blocks:
  Show dependency tree
 
Reported: 2007-01-25 09:12 UTC by Christophe Pierret
Modified: 2007-01-28 13:35 UTC (History)
0 users



Attachments
A patch fixing the issue, but not meant to be a definitive patch (824 bytes, patch)
2007-01-25 09:17 UTC, Christophe Pierret
Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Christophe Pierret 2007-01-25 09:12:11 UTC
Trying to use NIO connector instead of APR connector using Tomcat6 HEAD, I get
an IllegalArgumentException while in a call to sendAck.  

Looking at InternalNioOutputBuffer.sendAck(), it uses ByteBuffer.wrap() to
create a new ByteBuffer and uses this ByteBuffer in a call to writeToSocket.
There is a check in SecureNioChannel.write() that the ByteBuffer is the one
stored in the 

Commenting the line 372 in SecureNioChannel.java fixes the problem.
//if ( src != bufHandler.getWriteBuffer() ) throw new
IllegalArgumentException("You can only write using the application write buffer
provided by the handler.");
But I guess that the check is here for a valid reason, and a better fix would
very likely consist in fixing the sendAck or in adding an "or" condition to the
test for the case of sendAck().

GRAVE: Cannot find message associated with key standardWrapper.acknowledgeException
java.lang.IllegalArgumentException: You can only write using the application
write buffer provided by the handler.
	at org.apache.tomcat.util.net.SecureNioChannel.write(SecureNioChannel.java:372)
	at org.apache.tomcat.util.net.NioSelectorPool.write(NioSelectorPool.java:111)
	at
org.apache.coyote.http11.InternalNioOutputBuffer.writeToSocket(InternalNioOutputBuffer.java:434)
	at
org.apache.coyote.http11.InternalNioOutputBuffer.sendAck(InternalNioOutputBuffer.java:418)
	at org.apache.coyote.http11.Http11NioProcessor.action(Http11NioProcessor.java:1028)
	at org.apache.coyote.Response.action(Response.java:183)
	at org.apache.coyote.Response.acknowledge(Response.java:310)
	at org.apache.catalina.connector.Response.sendAcknowledgement(Response.java:1154)
	at
org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:169)
	at
org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:175)
	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:128)
	at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:105)
	at
org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:212)
	at org.apache.coyote.http11.Http11NioProcessor.process(Http11NioProcessor.java:888)
	at
org.apache.coyote.http11.Http11NioProtocol$Http11ConnectionHandler.process(Http11NioProtocol.java:624)
	at org.apache.tomcat.util.net.NioEndpoint$Worker.run(NioEndpoint.java:1467)
	at java.lang.Thread.run(Thread.java:595)
Comment 1 Christophe Pierret 2007-01-25 09:17:34 UTC
Created attachment 19460 [details]
A patch fixing the issue, but not meant to be a definitive patch

Should fix this differently since it removes a useful check that is not valid
in only one special case (sendAck call)
Comment 2 Filip Hanik 2007-01-28 13:28:23 UTC
Patch is invalid and would lead to invalid SSL data being sent, bug is
acknowledged and will be fixed.
Comment 3 Filip Hanik 2007-01-28 13:35:22 UTC
The following fix has been applied

Index: java/org/apache/tomcat/util/net/NioSelectorPool.java
===================================================================
--- java/org/apache/tomcat/util/net/NioSelectorPool.java        (revision 500888)
+++ java/org/apache/tomcat/util/net/NioSelectorPool.java        (working copy)
@@ -103,6 +103,10 @@
         boolean timedout = false;
         int keycount = 1; //assume we can write
         long time = System.currentTimeMillis(); //start the timeout timer
+        if ( socket.getBufHandler().getWriteBuffer()!= buf ) {
+            socket.getBufHandler().getWriteBuffer().put(buf);
+            buf = socket.getBufHandler().getWriteBuffer();
+        }
         try {
             while ( (!timedout) && buf.hasRemaining() ) {
                 if ( keycount > 0 ) { //only write if we were registered for a
write