Fix processing of early messages.

1. Eliminated any possibility of infinite recursion.
2. Handle the fact that you can have multiple 'early contents' for a
   single message.
This commit is contained in:
Greyson Parrelli 2020-05-09 12:18:09 -04:00
parent 618b1b5ace
commit a83ccc18bb
2 changed files with 26 additions and 11 deletions

View File

@ -240,6 +240,17 @@ public final class PushProcessMessageJob extends BaseJob {
if (messageState == MessageState.DECRYPTED_OK) { if (messageState == MessageState.DECRYPTED_OK) {
SignalServiceContent content = SignalServiceContent.deserialize(serializedPlaintextContent); SignalServiceContent content = SignalServiceContent.deserialize(serializedPlaintextContent);
handleMessage(content, optionalSmsMessageId); handleMessage(content, optionalSmsMessageId);
Optional<List<SignalServiceContent>> earlyContent = ApplicationDependencies.getEarlyMessageCache()
.retrieve(Recipient.externalPush(context, content.getSender()).getId(),
content.getTimestamp());
if (earlyContent.isPresent()) {
Log.i(TAG, "Found " + earlyContent.get().size() + " dependent item(s) that were retrieved earlier. Processing.");
for (SignalServiceContent earlyItem : earlyContent.get()) {
handleMessage(earlyItem, Optional.absent());
}
}
} else { } else {
//noinspection ConstantConditions //noinspection ConstantConditions
handleExceptionMessage(exceptionMetadata, optionalSmsMessageId); handleExceptionMessage(exceptionMetadata, optionalSmsMessageId);
@ -332,14 +343,6 @@ public final class PushProcessMessageJob extends BaseJob {
} }
resetRecipientToPush(Recipient.externalPush(context, content.getSender())); resetRecipientToPush(Recipient.externalPush(context, content.getSender()));
Optional<SignalServiceContent> earlyContent = ApplicationDependencies.getEarlyMessageCache()
.retrieve(Recipient.externalPush(context, content.getSender()).getId(),
content.getTimestamp());
if (earlyContent.isPresent()) {
Log.i(TAG, "Found dependent content that was retrieved earlier. Processing.");
handleMessage(earlyContent.get(), Optional.absent());
}
} catch (StorageFailedException e) { } catch (StorageFailedException e) {
Log.w(TAG, e); Log.w(TAG, e);
handleCorruptMessage(e.getSender(), e.getSenderDevice(), timestamp, smsMessageId); handleCorruptMessage(e.getSender(), e.getSenderDevice(), timestamp, smsMessageId);
@ -1363,6 +1366,7 @@ public final class PushProcessMessageJob extends BaseJob {
.incrementReadReceiptCount(id, content.getTimestamp()); .incrementReadReceiptCount(id, content.getTimestamp());
if (!handled) { if (!handled) {
Log.w(TAG, "[handleReadReceipt] Could not find matching message! timestamp: " + timestamp + " author: " + sender.getId());
ApplicationDependencies.getEarlyMessageCache().store(sender.getId(), timestamp, content); ApplicationDependencies.getEarlyMessageCache().store(sender.getId(), timestamp, content);
} }
} }

View File

@ -6,6 +6,8 @@ import org.thoughtcrime.securesms.recipients.RecipientId;
import org.whispersystems.libsignal.util.guava.Optional; import org.whispersystems.libsignal.util.guava.Optional;
import org.whispersystems.signalservice.api.messages.SignalServiceContent; import org.whispersystems.signalservice.api.messages.SignalServiceContent;
import java.util.LinkedList;
import java.util.List;
import java.util.Objects; import java.util.Objects;
/** /**
@ -15,14 +17,23 @@ import java.util.Objects;
*/ */
public final class EarlyMessageCache { public final class EarlyMessageCache {
private final LRUCache<MessageId, SignalServiceContent> cache = new LRUCache<>(100); private final LRUCache<MessageId, List<SignalServiceContent>> cache = new LRUCache<>(100);
/** /**
* @param targetSender The sender of the message this message depends on. * @param targetSender The sender of the message this message depends on.
* @param targetSentTimestamp The sent timestamp of the message this message depends on. * @param targetSentTimestamp The sent timestamp of the message this message depends on.
*/ */
public void store(@NonNull RecipientId targetSender, long targetSentTimestamp, @NonNull SignalServiceContent content) { public void store(@NonNull RecipientId targetSender, long targetSentTimestamp, @NonNull SignalServiceContent content) {
cache.put(new MessageId(targetSender, targetSentTimestamp), content); MessageId messageId = new MessageId(targetSender, targetSentTimestamp);
List<SignalServiceContent> contentList = cache.get(messageId);
if (contentList == null) {
contentList = new LinkedList<>();
}
contentList.add(content);
cache.put(messageId, contentList);
} }
/** /**
@ -30,7 +41,7 @@ public final class EarlyMessageCache {
* @param sender The sender of the message in question. * @param sender The sender of the message in question.
* @param sentTimestamp The sent timestamp of the message in question. * @param sentTimestamp The sent timestamp of the message in question.
*/ */
public Optional<SignalServiceContent> retrieve(@NonNull RecipientId sender, long sentTimestamp) { public Optional<List<SignalServiceContent>> retrieve(@NonNull RecipientId sender, long sentTimestamp) {
return Optional.fromNullable(cache.remove(new MessageId(sender, sentTimestamp))); return Optional.fromNullable(cache.remove(new MessageId(sender, sentTimestamp)));
} }