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]