You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by re...@apache.org on 2019/05/16 17:10:19 UTC

[tomcat] branch master updated: Handle write error when flushing internal buffer

This is an automated email from the ASF dual-hosted git repository.

remm pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/tomcat.git


The following commit(s) were added to refs/heads/master by this push:
     new a49ee3d  Handle write error when flushing internal buffer
a49ee3d is described below

commit a49ee3debf58774e0ca4f738bb72953c57ce522e
Author: remm <re...@apache.org>
AuthorDate: Thu May 16 19:10:03 2019 +0200

    Handle write error when flushing internal buffer
    
    Checking for a negative result wasn't done, so do that now for NIO and
    NIO2. Fix outdated comments for cut & paste. Remove read sync for NIO2,
    it's most likely not useful.
---
 java/org/apache/tomcat/util/net/Nio2Endpoint.java | 41 ++++++++++++++---------
 java/org/apache/tomcat/util/net/NioEndpoint.java  |  9 +++--
 2 files changed, 32 insertions(+), 18 deletions(-)

diff --git a/java/org/apache/tomcat/util/net/Nio2Endpoint.java b/java/org/apache/tomcat/util/net/Nio2Endpoint.java
index c5a3328..748c929 100644
--- a/java/org/apache/tomcat/util/net/Nio2Endpoint.java
+++ b/java/org/apache/tomcat/util/net/Nio2Endpoint.java
@@ -1011,18 +1011,24 @@ public class Nio2Endpoint extends AbstractJsseEndpoint<Nio2Channel,AsynchronousS
             }
 
             @Override
+            protected void end() {
+                // Restore regular notifications
+                if (read) {
+                    readNotify = false;
+                } else {
+                    writeNotify = false;
+                }
+            }
+
+            @Override
             public void run() {
                 if (read) {
                     long nBytes = 0;
-                    // Read from main buffer first
+                    // If there is still data inside the main read buffer, it needs to be read first
                     if (!socketBufferHandler.isReadBufferEmpty()) {
-                        // There is still data inside the main read buffer, it needs to be read first
-                        synchronized (readCompletionHandler) {
-                            // Note: It is not necessary to put this code in the completion handler
-                            socketBufferHandler.configureReadBufferForRead();
-                            for (int i = 0; i < length && !socketBufferHandler.isReadBufferEmpty(); i++) {
-                                nBytes += transfer(socketBufferHandler.getReadBuffer(), buffers[offset + i]);
-                            }
+                        socketBufferHandler.configureReadBufferForRead();
+                        for (int i = 0; i < length && !socketBufferHandler.isReadBufferEmpty(); i++) {
+                            nBytes += transfer(socketBufferHandler.getReadBuffer(), buffers[offset + i]);
                         }
                         if (nBytes > 0) {
                             completion.completed(Long.valueOf(nBytes), this);
@@ -1032,24 +1038,27 @@ public class Nio2Endpoint extends AbstractJsseEndpoint<Nio2Channel,AsynchronousS
                         getSocket().read(buffers, offset, length, timeout, unit, this, completion);
                     }
                 } else {
-                    // Write from main buffer first
+                    // If there is still data inside the main write buffer, it needs to be written first
                     if (!socketBufferHandler.isWriteBufferEmpty()) {
-                        // There is still data inside the main write buffer, it needs to be written first
                         socketBufferHandler.configureWriteBufferForRead();
                         getSocket().write(socketBufferHandler.getWriteBuffer(), null, new CompletionHandler<Integer, Void>() {
                             @Override
-                            public void completed(Integer result, Void attachment) {
-                                run();
+                            public void completed(Integer nBytes, Void attachment) {
+                                if (nBytes.intValue() < 0) {
+                                    failed(new EOFException(), null);
+                                } else {
+                                    // Continue until everything is written
+                                    run();
+                                }
                             }
                             @Override
                             public void failed(Throwable exc, Void attachment) {
-                                handler.failed(exc, Nio2OperationState.this.attachment);
+                                completion.failed(exc, Nio2OperationState.this);
                             }
                         });
-                        return;
+                    } else {
+                        getSocket().write(buffers, offset, length, timeout, unit, this, completion);
                     }
-                    // It should be less necessary to check the buffer state as it is easy to flush before
-                    getSocket().write(buffers, offset, length, timeout, unit, this, completion);
                 }
             }
         }
diff --git a/java/org/apache/tomcat/util/net/NioEndpoint.java b/java/org/apache/tomcat/util/net/NioEndpoint.java
index b3f1f2f..6b7a9fa 100644
--- a/java/org/apache/tomcat/util/net/NioEndpoint.java
+++ b/java/org/apache/tomcat/util/net/NioEndpoint.java
@@ -1456,11 +1456,16 @@ public class NioEndpoint extends AbstractJsseEndpoint<NioChannel,SocketChannel>
                                 if (!socketBufferHandler.isWriteBufferEmpty()) {
                                     // There is still data inside the main write buffer, it needs to be written first
                                     socketBufferHandler.configureWriteBufferForRead();
-                                    getSocket().write(socketBufferHandler.getWriteBuffer());
-                                    // Start operation only if the main write buffer is now empty
+                                    do {
+                                        nBytes = getSocket().write(socketBufferHandler.getWriteBuffer());
+                                    } while (!socketBufferHandler.isWriteBufferEmpty() && nBytes > 0);
                                     if (!socketBufferHandler.isWriteBufferEmpty()) {
                                         doWrite = false;
                                     }
+                                    // Preserve a negative value since it is an error
+                                    if (nBytes > 0) {
+                                        nBytes = 0;
+                                    }
                                 }
                                 if (doWrite) {
                                     nBytes = getSocket().write(buffers, offset, length);


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