Skip to content

Commit b3fa1b4

Browse files
committed
Synchronized updates of STOMP header key cache
Issue: SPR-14901
1 parent 9b76dc2 commit b3fa1b4

File tree

2 files changed

+47
-36
lines changed

2 files changed

+47
-36
lines changed

spring-messaging/src/main/java/org/springframework/messaging/simp/stomp/StompEncoder.java

+26-12
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import java.util.List;
2626
import java.util.Map;
2727
import java.util.Map.Entry;
28+
import java.util.concurrent.ConcurrentHashMap;
2829

2930
import org.apache.commons.logging.Log;
3031
import org.apache.commons.logging.LogFactory;
@@ -53,15 +54,26 @@ public class StompEncoder {
5354

5455
private static final int HEADER_KEY_CACHE_LIMIT = 32;
5556

57+
58+
private final Map<String, byte[]> headerKeyAccessCache =
59+
new ConcurrentHashMap<>(HEADER_KEY_CACHE_LIMIT);
60+
5661
@SuppressWarnings("serial")
57-
private final Map<String, byte[]> headerKeyCache =
62+
private final Map<String, byte[]> headerKeyUpdateCache =
5863
new LinkedHashMap<String, byte[]>(HEADER_KEY_CACHE_LIMIT, 0.75f, true) {
5964
@Override
6065
protected boolean removeEldestEntry(Map.Entry<String, byte[]> eldest) {
61-
return size() > HEADER_KEY_CACHE_LIMIT;
66+
if (size() > HEADER_KEY_CACHE_LIMIT) {
67+
headerKeyAccessCache.remove(eldest.getKey());
68+
return true;
69+
}
70+
else {
71+
return false;
72+
}
6273
}
6374
};
6475

76+
6577
/**
6678
* Encodes the given STOMP {@code message} into a {@code byte[]}
6779
* @param message the message to encode
@@ -160,21 +172,23 @@ private void writeHeaders(StompCommand command, Map<String, Object> headers, byt
160172

161173
private byte[] encodeHeaderKey(String input, boolean escape) {
162174
String inputToUse = (escape ? escape(input) : input);
163-
if (headerKeyCache.containsKey(inputToUse)) {
164-
return headerKeyCache.get(inputToUse);
175+
if (this.headerKeyAccessCache.containsKey(inputToUse)) {
176+
return this.headerKeyAccessCache.get(inputToUse);
177+
}
178+
synchronized (this.headerKeyUpdateCache) {
179+
byte[] bytes = this.headerKeyUpdateCache.get(inputToUse);
180+
if (bytes == null) {
181+
bytes = inputToUse.getBytes(StandardCharsets.UTF_8);
182+
this.headerKeyAccessCache.put(inputToUse, bytes);
183+
this.headerKeyUpdateCache.put(inputToUse, bytes);
184+
}
185+
return bytes;
165186
}
166-
byte[] bytes = encodeHeaderString(inputToUse);
167-
headerKeyCache.put(inputToUse, bytes);
168-
return bytes;
169187
}
170188

171189
private byte[] encodeHeaderValue(String input, boolean escape) {
172190
String inputToUse = (escape ? escape(input) : input);
173-
return encodeHeaderString(inputToUse);
174-
}
175-
176-
private byte[] encodeHeaderString(String input) {
177-
return input.getBytes(StandardCharsets.UTF_8);
191+
return inputToUse.getBytes(StandardCharsets.UTF_8);
178192
}
179193

180194
/**

spring-websocket/src/main/java/org/springframework/web/socket/messaging/StompSubProtocolHandler.java

+21-24
Original file line numberDiff line numberDiff line change
@@ -88,13 +88,14 @@ public class StompSubProtocolHandler implements SubProtocolHandler, ApplicationE
8888

8989
private static final byte[] EMPTY_PAYLOAD = new byte[0];
9090

91+
9192
private StompSubProtocolErrorHandler errorHandler;
9293

9394
private int messageSizeLimit = 64 * 1024;
9495

95-
private StompEncoder stompEncoder;
96+
private StompEncoder stompEncoder = new StompEncoder();
9697

97-
private StompDecoder stompDecoder;
98+
private StompDecoder stompDecoder = new StompDecoder();
9899

99100
private final Map<String, BufferingStompDecoder> decoders = new ConcurrentHashMap<>();
100101

@@ -106,10 +107,6 @@ public class StompSubProtocolHandler implements SubProtocolHandler, ApplicationE
106107

107108
private final Stats stats = new Stats();
108109

109-
public StompSubProtocolHandler() {
110-
setEncoder(new StompEncoder());
111-
setDecoder(new StompDecoder());
112-
}
113110

114111
/**
115112
* Configure a handler for error messages sent to clients which allows
@@ -129,24 +126,6 @@ public StompSubProtocolErrorHandler getErrorHandler() {
129126
return this.errorHandler;
130127
}
131128

132-
/**
133-
* Configure a {@link StompEncoder} for encoding STOMP frames
134-
* @param encoder the encoder
135-
* @since 4.3.5
136-
*/
137-
public void setEncoder(StompEncoder encoder) {
138-
this.stompEncoder = encoder;
139-
}
140-
141-
/**
142-
* Configure a {@link StompDecoder} for decoding STOMP frames
143-
* @param decoder the decoder
144-
* @since 4.3.5
145-
*/
146-
public void setDecoder(StompDecoder decoder) {
147-
this.stompDecoder = decoder;
148-
}
149-
150129
/**
151130
* Configure the maximum size allowed for an incoming STOMP message.
152131
* Since a STOMP message can be received in multiple WebSocket messages,
@@ -167,6 +146,24 @@ public int getMessageSizeLimit() {
167146
return this.messageSizeLimit;
168147
}
169148

149+
/**
150+
* Configure a {@link StompEncoder} for encoding STOMP frames
151+
* @param encoder the encoder
152+
* @since 4.3.5
153+
*/
154+
public void setEncoder(StompEncoder encoder) {
155+
this.stompEncoder = encoder;
156+
}
157+
158+
/**
159+
* Configure a {@link StompDecoder} for decoding STOMP frames
160+
* @param decoder the decoder
161+
* @since 4.3.5
162+
*/
163+
public void setDecoder(StompDecoder decoder) {
164+
this.stompDecoder = decoder;
165+
}
166+
170167
/**
171168
* Configure a {@link MessageHeaderInitializer} to apply to the headers of all
172169
* messages created from decoded STOMP frames and other messages sent to the

0 commit comments

Comments
 (0)