This is an automated email from the ASF dual-hosted git repository.
rcordier pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/james-project.git
The following commit(s) were added to refs/heads/master by this push:
new 84ac44e020 JAMES-4184 POP3 TOP msg 0 - only read headers (#2965)
84ac44e020 is described below
commit 84ac44e020787d34e3d2df6c79d0428e4d25676b
Author: Benoit TELLIER <[email protected]>
AuthorDate: Mon Mar 9 04:25:15 2026 +0100
JAMES-4184 POP3 TOP msg 0 - only read headers (#2965)
---
.../james/protocols/pop3/core/TopCmdHandler.java | 9 +++--
.../james/protocols/pop3/mailbox/Mailbox.java | 9 +++++
.../mailbox/DistributedMailboxAdapter.java | 18 ++++++++++
.../james/pop3server/mailbox/MailboxAdapter.java | 24 +++++++++++---
.../apache/james/pop3server/POP3ServerTest.java | 38 ++++++++++++++++++++++
5 files changed, 91 insertions(+), 7 deletions(-)
diff --git
a/protocols/pop3/src/main/java/org/apache/james/protocols/pop3/core/TopCmdHandler.java
b/protocols/pop3/src/main/java/org/apache/james/protocols/pop3/core/TopCmdHandler.java
index bf15a77b7c..4e08416d1b 100644
---
a/protocols/pop3/src/main/java/org/apache/james/protocols/pop3/core/TopCmdHandler.java
+++
b/protocols/pop3/src/main/java/org/apache/james/protocols/pop3/core/TopCmdHandler.java
@@ -60,8 +60,9 @@ public class TopCmdHandler extends AbstractPOP3CommandHandler
implements CapaCap
if (args.getLineCount().isEmpty()) {
return handleSyntaxError();
}
- InputStream content = getMessageContent(session, data);
- InputStream in = new CountingBodyInputStream(new
CRLFTerminatedInputStream(new ExtraDotInputStream(content)),
args.getLineCount().get());
+ int lineCount = args.getLineCount().get();
+ InputStream content = lineCount == 0 ?
getMessageHeaders(session, data) : getMessageContent(session, data);
+ InputStream in = new CountingBodyInputStream(new
CRLFTerminatedInputStream(new ExtraDotInputStream(content)), lineCount);
return new POP3StreamResponse(POP3Response.OK_RESPONSE,
"Message follows", in);
}
@@ -95,6 +96,10 @@ public class TopCmdHandler extends
AbstractPOP3CommandHandler implements CapaCap
return session.getUserMailbox().getMessage(data.getUid());
}
+ protected InputStream getMessageHeaders(POP3Session session,
MessageMetaData data) throws IOException {
+ return session.getUserMailbox().getMessageHeaders(data.getUid());
+ }
+
@Override
public Set<String> getImplementedCapabilities(POP3Session session) {
if (session.getHandlerState() == POP3Session.TRANSACTION) {
diff --git
a/protocols/pop3/src/main/java/org/apache/james/protocols/pop3/mailbox/Mailbox.java
b/protocols/pop3/src/main/java/org/apache/james/protocols/pop3/mailbox/Mailbox.java
index 38b5fbb7cc..6f61cf4963 100644
---
a/protocols/pop3/src/main/java/org/apache/james/protocols/pop3/mailbox/Mailbox.java
+++
b/protocols/pop3/src/main/java/org/apache/james/protocols/pop3/mailbox/Mailbox.java
@@ -33,6 +33,15 @@ public interface Mailbox {
*/
InputStream getMessage(String uid) throws IOException;
+ /**
+ * Return only the headers as {@link InputStream} for the given
<code>uid</code>.
+ * Implementations may override this for better performance (e.g. using
FetchGroup.HEADERS).
+ * @exception IOException If message can not be found or is inaccessible
+ */
+ default InputStream getMessageHeaders(String uid) throws IOException {
+ return getMessage(uid);
+ }
+
/**
* Return a immutable {@link List} which holds the {@link MessageMetaData}
* for all messages in the {@link Mailbox}
diff --git
a/server/protocols/protocols-pop3-distributed/src/main/java/org/apache/james/pop3server/mailbox/DistributedMailboxAdapter.java
b/server/protocols/protocols-pop3-distributed/src/main/java/org/apache/james/pop3server/mailbox/DistributedMailboxAdapter.java
index baee0734f5..3a6a36b231 100644
---
a/server/protocols/protocols-pop3-distributed/src/main/java/org/apache/james/pop3server/mailbox/DistributedMailboxAdapter.java
+++
b/server/protocols/protocols-pop3-distributed/src/main/java/org/apache/james/pop3server/mailbox/DistributedMailboxAdapter.java
@@ -113,6 +113,24 @@ public class DistributedMailboxAdapter implements Mailbox {
}
}
+ @Override
+ public InputStream getMessageHeaders(String uid) throws IOException {
+ try {
+ MessageId messageId = messageIdFactory.fromString(uid);
+ Iterator<MessageResult> messages =
messageIdManager.getMessage(messageId, FetchGroup.HEADERS, session).iterator();
+ if (messages.hasNext()) {
+ return messages.next().getHeaders().getInputStream();
+ } else {
+ LOGGER.warn("Removing {} from {} POP3 projection for user {}
as it is not backed by a MailboxMessage",
+ uid, mailbox.getId().serialize(),
session.getUser().asString());
+ Mono.from(metadataStore.remove(mailbox.getId(),
messageId)).block();
+ throw new IOException("Message does not exist for uid " + uid);
+ }
+ } catch (MailboxException e) {
+ throw new IOException("Unable to retrieve message headers for uid
" + uid, e);
+ }
+ }
+
@Override
public List<MessageMetaData> getMessages() {
return Flux.from(metadataStore.stat(mailbox.getId()))
diff --git
a/server/protocols/protocols-pop3/src/main/java/org/apache/james/pop3server/mailbox/MailboxAdapter.java
b/server/protocols/protocols-pop3/src/main/java/org/apache/james/pop3server/mailbox/MailboxAdapter.java
index e6de9b79f1..f582ab61b1 100644
---
a/server/protocols/protocols-pop3/src/main/java/org/apache/james/pop3server/mailbox/MailboxAdapter.java
+++
b/server/protocols/protocols-pop3/src/main/java/org/apache/james/pop3server/mailbox/MailboxAdapter.java
@@ -40,9 +40,6 @@ import
org.apache.james.protocols.pop3.mailbox.MessageMetaData;
import com.google.common.collect.ImmutableList;
public class MailboxAdapter implements Mailbox {
- private static final FetchGroup FULL_GROUP = FetchGroup.FULL_CONTENT;
- private static final FetchGroup METADATA_GROUP = FetchGroup.MINIMAL;
-
private final MessageManager manager;
private final MailboxSession session;
@@ -58,7 +55,7 @@ public class MailboxAdapter implements Mailbox {
public InputStream getMessage(String uid) throws IOException {
try {
mailboxManager.startProcessingRequest(session);
- Iterator<MessageResult> results =
manager.getMessages(MessageUid.of(Long.parseLong(uid)).toRange(), FULL_GROUP,
session);
+ Iterator<MessageResult> results =
manager.getMessages(MessageUid.of(Long.parseLong(uid)).toRange(),
FetchGroup.FULL_CONTENT, session);
if (results.hasNext()) {
return results.next().getFullContent().getInputStream();
} else {
@@ -71,11 +68,28 @@ public class MailboxAdapter implements Mailbox {
}
}
+ @Override
+ public InputStream getMessageHeaders(String uid) throws IOException {
+ try {
+ mailboxManager.startProcessingRequest(session);
+ Iterator<MessageResult> results =
manager.getMessages(MessageUid.of(Long.parseLong(uid)).toRange(),
FetchGroup.HEADERS, session);
+ if (results.hasNext()) {
+ return results.next().getHeaders().getInputStream();
+ } else {
+ throw new IOException("Message does not exist for uid " + uid);
+ }
+ } catch (MailboxException e) {
+ throw new IOException("Unable to retrieve message headers for uid
" + uid, e);
+ } finally {
+ mailboxManager.endProcessingRequest(session);
+ }
+ }
+
@Override
public List<MessageMetaData> getMessages() throws IOException {
try {
mailboxManager.startProcessingRequest(session);
- Iterator<MessageResult> results =
manager.getMessages(MessageRange.all(), METADATA_GROUP, session);
+ Iterator<MessageResult> results =
manager.getMessages(MessageRange.all(), FetchGroup.MINIMAL, session);
List<MessageMetaData> mList = new ArrayList<>();
while (results.hasNext()) {
MessageResult result = results.next();
diff --git
a/server/protocols/protocols-pop3/src/test/java/org/apache/james/pop3server/POP3ServerTest.java
b/server/protocols/protocols-pop3/src/test/java/org/apache/james/pop3server/POP3ServerTest.java
index d0e091e41f..00f12a6359 100644
---
a/server/protocols/protocols-pop3/src/test/java/org/apache/james/pop3server/POP3ServerTest.java
+++
b/server/protocols/protocols-pop3/src/test/java/org/apache/james/pop3server/POP3ServerTest.java
@@ -544,6 +544,44 @@ public class POP3ServerTest {
mailboxManager.deleteMailbox(mailboxPath, session);
}
+ @Test
+ void topWithZeroLinesShouldReturnOnlyHeaders() throws Exception {
+ finishSetUp(pop3Configuration);
+
+ pop3Client = new POP3Client();
+ InetSocketAddress bindedAddress = new
ProtocolServerUtils(pop3Server).retrieveBindedAddress();
+ pop3Client.connect(bindedAddress.getAddress().getHostAddress(),
bindedAddress.getPort());
+
+ Username username = Username.of("topzero");
+ usersRepository.addUser(username, "password");
+
+ MailboxPath mailboxPath = MailboxPath.inbox(username);
+ MailboxSession session = mailboxManager.authenticate(username,
"password").withoutDelegation();
+ mailboxManager.createMailbox(mailboxPath, session);
+ setupTestMails(session, mailboxManager.getMailbox(mailboxPath,
session));
+
+ pop3Client.login("topzero", "password");
+ POP3MessageInfo[] entries = pop3Client.listMessages();
+
+ Reader reader = pop3Client.retrieveMessageTop(entries[0].number, 0);
+ assertThat(reader).isNotNull();
+
+ StringBuilder responseBody = new StringBuilder();
+ char[] buffer = new char[1024];
+ int n;
+ while ((n = reader.read(buffer)) != -1) {
+ responseBody.append(buffer, 0, n);
+ }
+ reader.close();
+
+ String response = responseBody.toString();
+ assertThat(response).contains("Return-path: [email protected]");
+ assertThat(response).contains("Subject: test");
+ assertThat(response).doesNotContain("Body Text
POP3ServerTest.setupTestMails");
+
+ mailboxManager.deleteMailbox(mailboxPath, session);
+ }
+
@Test
void pop3SessionShouldTolerateConcurrentDeletes() throws Exception {
finishSetUp(pop3Configuration);
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]