Message broker skips messages with user destination
When a broker message handler is not configured with any prefixes, it will process all messages by default, but user destination messages should be pre-processed by the userDestinationMessageHandler first. This change protects against that. Closes gh-26474
This commit is contained in:
@@ -19,6 +19,7 @@ package org.springframework.messaging.simp.broker;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
|
||||
@@ -58,6 +59,9 @@ public abstract class AbstractBrokerMessageHandler
|
||||
|
||||
private final Collection<String> destinationPrefixes;
|
||||
|
||||
@Nullable
|
||||
private Predicate<String> userDestinationPredicate;
|
||||
|
||||
private boolean preservePublishOrder = false;
|
||||
|
||||
@Nullable
|
||||
@@ -135,6 +139,21 @@ public abstract class AbstractBrokerMessageHandler
|
||||
return this.destinationPrefixes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure a Predicate to identify messages with a user destination. When
|
||||
* no {@link #getDestinationPrefixes() destination prefixes} are configured,
|
||||
* this helps to recognize and skip user destination messages that need to
|
||||
* be pre-processed by the
|
||||
* {@link org.springframework.messaging.simp.user.UserDestinationMessageHandler}
|
||||
* before they reach the broker.
|
||||
* @param predicate the predicate to identify user messages with a non-null
|
||||
* destination as messages with a user destinations.
|
||||
* @since 5.3.4
|
||||
*/
|
||||
public void setUserDestinationPredicate(@Nullable Predicate<String> predicate) {
|
||||
this.userDestinationPredicate = predicate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether the client must receive messages in the order of publication.
|
||||
* <p>By default messages sent to the {@code "clientOutboundChannel"} may
|
||||
@@ -265,10 +284,27 @@ public abstract class AbstractBrokerMessageHandler
|
||||
protected abstract void handleMessageInternal(Message<?> message);
|
||||
|
||||
|
||||
/**
|
||||
* Whether a message with the given destination should be processed. This is
|
||||
* the case if one of the following conditions is true:
|
||||
* <ol>
|
||||
* <li>The destination starts with one of the configured
|
||||
* {@link #getDestinationPrefixes() destination prefixes}.
|
||||
* <li>No prefixes are configured and the destination isn't matched
|
||||
* by the {@link #setUserDestinationPredicate(Predicate)
|
||||
* userDestinationPredicate}.
|
||||
* <li>The message has no destination.
|
||||
* </ol>
|
||||
* @param destination the destination to check
|
||||
* @return whether to process (true) or skip (false) the destination
|
||||
*/
|
||||
protected boolean checkDestinationPrefix(@Nullable String destination) {
|
||||
if (destination == null || CollectionUtils.isEmpty(this.destinationPrefixes)) {
|
||||
if (destination == null) {
|
||||
return true;
|
||||
}
|
||||
if (CollectionUtils.isEmpty(this.destinationPrefixes)) {
|
||||
return !isUserDestination(destination);
|
||||
}
|
||||
for (String prefix : this.destinationPrefixes) {
|
||||
if (destination.startsWith(prefix)) {
|
||||
return true;
|
||||
@@ -277,6 +313,10 @@ public abstract class AbstractBrokerMessageHandler
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean isUserDestination(String destination) {
|
||||
return (this.userDestinationPredicate != null && this.userDestinationPredicate.test(destination));
|
||||
}
|
||||
|
||||
protected void publishBrokerAvailableEvent() {
|
||||
boolean shouldPublish = this.brokerAvailable.compareAndSet(false, true);
|
||||
if (this.eventPublisher != null && shouldPublish) {
|
||||
|
||||
@@ -64,6 +64,7 @@ import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.MimeTypeUtils;
|
||||
import org.springframework.util.PathMatcher;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.validation.Errors;
|
||||
import org.springframework.validation.Validator;
|
||||
|
||||
@@ -346,15 +347,21 @@ public abstract class AbstractMessageBrokerConfiguration implements ApplicationC
|
||||
if (handler == null) {
|
||||
return null;
|
||||
}
|
||||
updateUserDestinationResolver(handler, userDestinationResolver);
|
||||
updateUserDestinationResolver(handler, userDestinationResolver, registry.getUserDestinationPrefix());
|
||||
return handler;
|
||||
}
|
||||
|
||||
private void updateUserDestinationResolver(AbstractBrokerMessageHandler handler, UserDestinationResolver userDestinationResolver) {
|
||||
private void updateUserDestinationResolver(
|
||||
AbstractBrokerMessageHandler handler, UserDestinationResolver userDestinationResolver,
|
||||
@Nullable String userDestinationPrefix) {
|
||||
|
||||
Collection<String> prefixes = handler.getDestinationPrefixes();
|
||||
if (!prefixes.isEmpty() && !prefixes.iterator().next().startsWith("/")) {
|
||||
((DefaultUserDestinationResolver) userDestinationResolver).setRemoveLeadingSlash(true);
|
||||
}
|
||||
if (StringUtils.hasText(userDestinationPrefix)) {
|
||||
handler.setUserDestinationPredicate(destination -> destination.startsWith(userDestinationPrefix));
|
||||
}
|
||||
}
|
||||
|
||||
@Bean
|
||||
@@ -379,7 +386,7 @@ public abstract class AbstractMessageBrokerConfiguration implements ApplicationC
|
||||
subscriptions.put(destination, userRegistryMessageHandler);
|
||||
}
|
||||
handler.setSystemSubscriptions(subscriptions);
|
||||
updateUserDestinationResolver(handler, userDestinationResolver);
|
||||
updateUserDestinationResolver(handler, userDestinationResolver, registry.getUserDestinationPrefix());
|
||||
return handler;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user