On 09. okt. 2015 21:32, Torstein Tauno Svendsen wrote:

Hi! I tried using James (3.0.0-beta5-SNAPSHOT) behind a perdition proxy
(http://horms.net/projects/perdition/), and noted that this makes IMAP
login-requests hang.

Seems that when peridtion forwards the "LOGIN" request request it ends
up sending something like:

A LOGIN {3}
foo {3}
bar

And this does not work with James - I see the expected "+" resonse after
"LOGIN {3}", but there is no response to "foo {3}".

Sending only the password as a literal  - i.e.

"LOGIN foo {3}
bar"

works as expected .

Is this a bug in James or a misfeature in perdition? Sending all the
arguments like literals works fine with dovecot.

I tried digging into this - looks like there are two issues preventing this from working:

1) AbstractNettyImapRequestLineReader uses a boolean ("retry") to determine if it should write continuation requests or not, so it can only support one literal argument

2) ImapRequestFrameDecoder starts with "buffer.markReaderIndex()" and does a "buffer.resetReaderIndex()" to reset the reader index if it does not have enough data. But if a literal argument has been read, NettyImapRequestLineReader does this:

InputStream in = new BoundedInputStream(new ChannelBufferInputStream(buffer), size);

And the ChannelBufferInputStream constructor ends up doing "buffer.markReaderIndex()", so the reader-index ImapRequestFrameDecoder should reset to has been overwritten.

Attaching a patch that seems to work for me.


--
Torstein Tauno Svendsen                [email protected]
Seniorutvikler                              +47 932 95 901
Visena AS                           http://www.visena.com/
Index: server/protocols/protocols-imap4/src/main/java/org/apache/james/imapserver/netty/AbstractNettyImapRequestLineReader.java
===================================================================
--- server/protocols/protocols-imap4/src/main/java/org/apache/james/imapserver/netty/AbstractNettyImapRequestLineReader.java	(revision 1707433)
+++ server/protocols/protocols-imap4/src/main/java/org/apache/james/imapserver/netty/AbstractNettyImapRequestLineReader.java	(working copy)
@@ -27,11 +27,12 @@
 public abstract class AbstractNettyImapRequestLineReader extends ImapRequestLineReader {
     private final Channel channel;
     private final ChannelBuffer cRequest = ChannelBuffers.wrappedBuffer("+\r\n".getBytes());
-    private final boolean retry;
+    private final int alreadyWrittenContinuationRequestCount;
+    private int cRequestCounter = 0;
 
-    public AbstractNettyImapRequestLineReader(Channel channel, boolean retry) {
+    public AbstractNettyImapRequestLineReader(Channel channel, int alreadyWrittenContinuationRequestCount) {
         this.channel = channel;
-        this.retry = retry;
+        this.alreadyWrittenContinuationRequestCount = alreadyWrittenContinuationRequestCount;
 
     }
 
@@ -41,10 +42,15 @@
      */
     protected void commandContinuationRequest() throws DecodingException {
         // only write the request out if this is not a retry to process the
-        // request..
+        // request and the request has not already been written
+        cRequestCounter++;
 
-        if (!retry)
+        if( cRequestCounter > alreadyWrittenContinuationRequestCount)
             channel.write(cRequest);
     }
 
+    public int continuationRequestsWritten() {
+        return cRequestCounter;
+    }
+
 }
Index: server/protocols/protocols-imap4/src/main/java/org/apache/james/imapserver/netty/ImapRequestFrameDecoder.java
===================================================================
--- server/protocols/protocols-imap4/src/main/java/org/apache/james/imapserver/netty/ImapRequestFrameDecoder.java	(revision 1707433)
+++ server/protocols/protocols-imap4/src/main/java/org/apache/james/imapserver/netty/ImapRequestFrameDecoder.java	(working copy)
@@ -55,6 +55,7 @@
     private final static String STORED_DATA = "STORED_DATA";
     private final static String WRITTEN_DATA = "WRITTEN_DATA";
     private final static String OUTPUT_STREAM = "OUTPUT_STREAM";
+    private final static String CR_REQUESTS_SENT_COUNT ="CR_COUNT";
 
     public ImapRequestFrameDecoder(ImapDecoder decoder, int inMemorySizeLimit, int literalSizeLimit) {
         this.decoder = decoder;
@@ -75,9 +76,13 @@
      */
     @SuppressWarnings("unchecked")
     protected Object decode(ChannelHandlerContext ctx, Channel channel, ChannelBuffer buffer) throws Exception {
-        buffer.markReaderIndex();
-        boolean retry = false;
 
+
+        // using buffer.markReaderIndex does not work if we have mulitiple literal arguments.
+        // NettyImapRequestLineReader ends up calling markReaderIndex in read()
+
+        int originalReaderIndex = buffer.readerIndex();
+
         ImapRequestLineReader reader;
         // check if we failed before and if we already know how much data we
         // need to sucess next run
@@ -84,7 +89,11 @@
         Map<String, Object> attachment = (Map<String, Object>) ctx.getAttachment();
         int size = -1;
         if (attachment.containsKey(NEEDED_DATA)) {
-            retry = true;
+            int cRequestSent = 0;
+            if( attachment.containsKey(CR_REQUESTS_SENT_COUNT)) {
+                cRequestSent = (Integer) attachment.get(CR_REQUESTS_SENT_COUNT);
+            }
+
             size = (Integer) attachment.get(NEEDED_DATA);
             // now see if the buffer hold enough data to process.
             if (size != NettyImapRequestLineReader.NotEnoughDataException.UNKNOWN_SIZE && size > buffer.readableBytes()) {
@@ -138,23 +147,23 @@
                                 FileUtils.forceDelete(f);
                             }
 
-                        }, retry);
+                        }, cRequestSent);
                     } else {
-                        attachment.put(WRITTEN_DATA, written);
+                        attachment.put(WRITTEN_DATA, written);
                         return null;
                     }
 
                 } else {
-                    buffer.resetReaderIndex();
+                    buffer.readerIndex(originalReaderIndex);
                     return null;
                 }
 
             } else {
 
-                reader = new NettyImapRequestLineReader(channel, buffer, retry, literalSizeLimit);
+                reader = new NettyImapRequestLineReader(channel, buffer, cRequestSent, literalSizeLimit);
             }
         } else {
-            reader = new NettyImapRequestLineReader(channel, buffer, retry, literalSizeLimit);
+            reader = new NettyImapRequestLineReader(channel, buffer, 0, literalSizeLimit);
         }
 
         ImapSession session = (ImapSession) attributes.get(channel);
@@ -202,8 +211,9 @@
                 // SwitchableDelimiterBasedFrameDecoder added further to JAMES-1436.
                 final SwitchableDelimiterBasedFrameDecoder framer = (SwitchableDelimiterBasedFrameDecoder) pipeline.get(FRAMER);
                 framer.disableFraming(framerContext);
+                attachment.put(CR_REQUESTS_SENT_COUNT, e.getcRequestsWritten());
                 
-                buffer.resetReaderIndex();
+                buffer.readerIndex(originalReaderIndex);
                 return null;
             }
         } else {
Index: server/protocols/protocols-imap4/src/main/java/org/apache/james/imapserver/netty/NettyImapRequestLineReader.java
===================================================================
--- server/protocols/protocols-imap4/src/main/java/org/apache/james/imapserver/netty/NettyImapRequestLineReader.java	(revision 1707433)
+++ server/protocols/protocols-imap4/src/main/java/org/apache/james/imapserver/netty/NettyImapRequestLineReader.java	(working copy)
@@ -42,8 +42,8 @@
     private int read = 0;
     private final int maxLiteralSize;
 
-    public NettyImapRequestLineReader(Channel channel, ChannelBuffer buffer, boolean retry, int maxLiteralSize) {
-        super(channel, retry);
+    public NettyImapRequestLineReader(Channel channel, ChannelBuffer buffer, int alreadyWrittenContinuationRequestCount, int maxLiteralSize) {
+        super(channel, alreadyWrittenContinuationRequestCount);
         this.buffer = buffer;
         this.maxLiteralSize  = maxLiteralSize;
     }
@@ -65,7 +65,7 @@
                 next = buffer.readByte();
                 read++;
             } else {
-                throw new NotEnoughDataException();
+                throw new NotEnoughDataException(continuationRequestsWritten());
             }
             nextSeen = true;
             nextChar = (char) next;
@@ -91,7 +91,7 @@
         if (size + crlf > buffer.readableBytes()) {
             // ok let us throw a exception which till the decoder how many more
             // bytes we need
-            throw new NotEnoughDataException(size + read + crlf);
+            throw new NotEnoughDataException(size + read + crlf,continuationRequestsWritten());
         }
 
         // Unset the next char.
@@ -118,13 +118,15 @@
 
         public final static int UNKNOWN_SIZE = -1;
         private final int size;
+        private final int cRequestsWritten;
 
-        public NotEnoughDataException(int size) {
+        public NotEnoughDataException(int size,int cRequestsWritten) {
             this.size = size;
+            this.cRequestsWritten = cRequestsWritten;
         }
 
-        public NotEnoughDataException() {
-            this(UNKNOWN_SIZE);
+        public NotEnoughDataException(int cRequestsWritten) {
+            this(UNKNOWN_SIZE,cRequestsWritten);
         }
 
         /**
@@ -135,6 +137,18 @@
         public int getNeededSize() {
             return size;
         }
-    }
 
+        /**
+         * Returns the number of continuation requests written
+         *
+         * @return cRequestsWritten
+         */
+
+
+
+        public int getcRequestsWritten() {
+            return cRequestsWritten;
+        }
+    }
+
 }
Index: server/protocols/protocols-imap4/src/main/java/org/apache/james/imapserver/netty/NettyStreamImapRequestLineReader.java
===================================================================
--- server/protocols/protocols-imap4/src/main/java/org/apache/james/imapserver/netty/NettyStreamImapRequestLineReader.java	(revision 1707433)
+++ server/protocols/protocols-imap4/src/main/java/org/apache/james/imapserver/netty/NettyStreamImapRequestLineReader.java	(working copy)
@@ -31,8 +31,8 @@
 
     private final InputStream in;
 
-    public NettyStreamImapRequestLineReader(Channel channel, InputStream in, boolean retry) {
-        super(channel, retry);
+    public NettyStreamImapRequestLineReader(Channel channel, InputStream in, int alreadyWrittenContinuationRequestCount) {
+        super(channel, alreadyWrittenContinuationRequestCount);
         this.in = in;
     }
 

---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to