Skip to content

Commit 29158aa

Browse files
committed
Expose timeToFirstMessage in Java/XML config
Issue: SPR-16531
1 parent 18854ee commit 29158aa

File tree

8 files changed

+102
-26
lines changed

8 files changed

+102
-26
lines changed

spring-websocket/src/main/java/org/springframework/web/socket/config/MessageBrokerBeanDefinitionParser.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -308,6 +308,9 @@ private RuntimeBeanReference registerStompHandler(Element element, RuntimeBeanRe
308308
if (transportElem.hasAttribute("send-buffer-size")) {
309309
handlerDef.getPropertyValues().add("sendBufferSizeLimit", transportElem.getAttribute("send-buffer-size"));
310310
}
311+
if (transportElem.hasAttribute("time-to-first-message")) {
312+
handlerDef.getPropertyValues().add("timeToFirstMessage", transportElem.getAttribute("time-to-first-message"));
313+
}
311314
Element factoriesElement = DomUtils.getChildElementByTagName(transportElem, "decorator-factories");
312315
if (factoriesElement != null) {
313316
ManagedList<Object> factories = extractBeanSubElements(factoriesElement, context);

spring-websocket/src/main/java/org/springframework/web/socket/config/annotation/WebMvcStompEndpointRegistry.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2017 the original author or authors.
2+
* Copyright 2002-2018 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -77,6 +77,9 @@ public WebMvcStompEndpointRegistry(WebSocketHandler webSocketHandler,
7777
if (transportRegistration.getSendBufferSizeLimit() != null) {
7878
this.subProtocolWebSocketHandler.setSendBufferSizeLimit(transportRegistration.getSendBufferSizeLimit());
7979
}
80+
if (transportRegistration.getTimeToFirstMessage() != null) {
81+
this.subProtocolWebSocketHandler.setTimeToFirstMessage(transportRegistration.getTimeToFirstMessage());
82+
}
8083

8184
this.stompHandler = new StompSubProtocolHandler();
8285
if (transportRegistration.getMessageSizeLimit() != null) {

spring-websocket/src/main/java/org/springframework/web/socket/config/annotation/WebSocketTransportRegistration.java

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2017 the original author or authors.
2+
* Copyright 2002-2018 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -40,6 +40,9 @@ public class WebSocketTransportRegistration {
4040
@Nullable
4141
private Integer sendBufferSizeLimit;
4242

43+
@Nullable
44+
private Integer timeToFirstMessage;
45+
4346
private final List<WebSocketHandlerDecoratorFactory> decoratorFactories = new ArrayList<>(2);
4447

4548

@@ -151,6 +154,34 @@ protected Integer getSendBufferSizeLimit() {
151154
return this.sendBufferSizeLimit;
152155
}
153156

157+
/**
158+
* Set the maximum time allowed in milliseconds after the WebSocket
159+
* connection is established and before the first sub-protocol message is
160+
* received.
161+
*
162+
* <p>This handler is for WebSocket connections that use a sub-protocol.
163+
* Therefore, we expect the client to send at least one sub-protocol message
164+
* in the beginning, or else we assume the connection isn't doing well, e.g.
165+
* proxy issue, slow network, and can be closed.
166+
*
167+
* <p>By default this is set to {@code 60,000} (1 minute).
168+
*
169+
* @param timeToFirstMessage the maximum time allowed in milliseconds
170+
* @since 5.1
171+
*/
172+
public WebSocketTransportRegistration setTimeToFirstMessage(int timeToFirstMessage) {
173+
this.timeToFirstMessage = timeToFirstMessage;
174+
return this;
175+
}
176+
177+
/**
178+
* Protected accessor for internal use.
179+
*/
180+
@Nullable
181+
protected Integer getTimeToFirstMessage() {
182+
return this.timeToFirstMessage;
183+
}
184+
154185
/**
155186
* Configure one or more factories to decorate the handler used to process
156187
* WebSocket messages. This may be useful in some advanced use cases, for

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

Lines changed: 35 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -68,13 +68,8 @@
6868
public class SubProtocolWebSocketHandler
6969
implements WebSocketHandler, SubProtocolCapable, MessageHandler, SmartLifecycle {
7070

71-
/**
72-
* Sessions connected to this handler use a sub-protocol. Hence we expect to
73-
* receive some client messages. If we don't receive any within a minute, the
74-
* connection isn't doing well (proxy issue, slow network?) and can be closed.
75-
* @see #checkSessions()
76-
*/
77-
private static final int TIME_TO_FIRST_MESSAGE = 60 * 1000;
71+
/** The default value for {@link #setTimeToFirstMessage(int) timeToFirstMessage}. */
72+
private static final int DEFAULT_TIME_TO_FIRST_MESSAGE = 60 * 1000;
7873

7974

8075
private final Log logger = LogFactory.getLog(SubProtocolWebSocketHandler.class);
@@ -98,6 +93,8 @@ public class SubProtocolWebSocketHandler
9893

9994
private int sendBufferSizeLimit = 512 * 1024;
10095

96+
private int timeToFirstMessage = DEFAULT_TIME_TO_FIRST_MESSAGE;
97+
10198
private volatile long lastSessionCheckTime = System.currentTimeMillis();
10299

103100
private final ReentrantLock sessionCheckLock = new ReentrantLock();
@@ -224,6 +221,35 @@ public int getSendBufferSizeLimit() {
224221
return this.sendBufferSizeLimit;
225222
}
226223

224+
/**
225+
* Set the maximum time allowed in milliseconds after the WebSocket
226+
* connection is established and before the first sub-protocol message is
227+
* received.
228+
*
229+
* <p>This handler is for WebSocket connections that use a sub-protocol.
230+
* Therefore, we expect the client to send at least one sub-protocol message
231+
* in the beginning, or else we assume the connection isn't doing well, e.g.
232+
* proxy issue, slow network, and can be closed.
233+
*
234+
* <p>By default this is set to {@code 60,000} (1 minute).
235+
*
236+
* @param timeToFirstMessage the maximum time allowed in milliseconds
237+
* @since 5.1
238+
* @see #checkSessions()
239+
*/
240+
public void setTimeToFirstMessage(int timeToFirstMessage) {
241+
this.timeToFirstMessage = timeToFirstMessage;
242+
}
243+
244+
/**
245+
* Return the maximum time allowed after the WebSocket connection is
246+
* established and before the first sub-protocol message.
247+
* @since 5.1
248+
*/
249+
public int getTimeToFirstMessage() {
250+
return this.timeToFirstMessage;
251+
}
252+
227253
/**
228254
* Return a String describing internal state and counters.
229255
*/
@@ -457,7 +483,7 @@ private String resolveSessionId(Message<?> message) {
457483
*/
458484
private void checkSessions() {
459485
long currentTime = System.currentTimeMillis();
460-
if (!isRunning() || (currentTime - this.lastSessionCheckTime < TIME_TO_FIRST_MESSAGE)) {
486+
if (!isRunning() || (currentTime - this.lastSessionCheckTime < getTimeToFirstMessage())) {
461487
return;
462488
}
463489

@@ -468,7 +494,7 @@ private void checkSessions() {
468494
continue;
469495
}
470496
long timeSinceCreated = currentTime - holder.getCreateTime();
471-
if (timeSinceCreated < TIME_TO_FIRST_MESSAGE) {
497+
if (timeSinceCreated < getTimeToFirstMessage()) {
472498
continue;
473499
}
474500
WebSocketSession session = holder.getSession();

spring-websocket/src/main/resources/org/springframework/web/socket/config/spring-websocket.xsd

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -683,6 +683,22 @@
683683
@param sendBufferSizeLimit the maximum number of bytes to buffer when
684684
sending messages; if the value is less than or equal to 0 then buffering
685685
is effectively disabled.
686+
]]></xsd:documentation>
687+
</xsd:annotation>
688+
</xsd:attribute>
689+
<xsd:attribute name="time-to-first-message" type="xsd:string">
690+
<xsd:annotation>
691+
<xsd:documentation><![CDATA[
692+
Set the maximum time allowed in milliseconds after the WebSocket
693+
connection is established and before the first sub-protocol message is
694+
received.
695+
696+
This handler is for WebSocket connections that use a sub-protocol.
697+
Therefore, we expect the client to send at least one sub-protocol message
698+
in the beginning, or else we assume the connection isn't doing well, e.g.
699+
proxy issue, slow network, and can be closed.
700+
701+
By default this is set to 60,000 (1 minute).
686702
]]></xsd:documentation>
687703
</xsd:annotation>
688704
</xsd:attribute>

spring-websocket/src/test/java/org/springframework/web/socket/config/MessageBrokerBeanDefinitionParserTests.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -94,8 +94,8 @@
9494
import static org.junit.Assert.*;
9595

9696
/**
97-
* Test fixture for MessageBrokerBeanDefinitionParser.
98-
* See test configuration files websocket-config-broker-*.xml.
97+
* Test fixture for {@link MessageBrokerBeanDefinitionParser}.
98+
* Also see test configuration files websocket-config-broker-*.xml.
9999
*
100100
* @author Brian Clozel
101101
* @author Artem Bilan
@@ -147,6 +147,7 @@ public void simpleBroker() throws Exception {
147147
assertEquals(Arrays.asList("v10.stomp", "v11.stomp", "v12.stomp"), subProtocolWsHandler.getSubProtocols());
148148
assertEquals(25 * 1000, subProtocolWsHandler.getSendTimeLimit());
149149
assertEquals(1024 * 1024, subProtocolWsHandler.getSendBufferSizeLimit());
150+
assertEquals(30 * 1000, subProtocolWsHandler.getTimeToFirstMessage());
150151

151152
Map<String, SubProtocolHandler> handlerMap = subProtocolWsHandler.getProtocolHandlerMap();
152153
StompSubProtocolHandler stompHandler = (StompSubProtocolHandler) handlerMap.get("v12.stomp");

spring-websocket/src/test/java/org/springframework/web/socket/config/annotation/WebSocketMessageBrokerConfigurationSupportTests.java

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2015 the original author or authors.
2+
* Copyright 2002-2018 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -48,7 +48,6 @@
4848
import org.springframework.stereotype.Controller;
4949
import org.springframework.web.servlet.HandlerMapping;
5050
import org.springframework.web.servlet.handler.SimpleUrlHandlerMapping;
51-
import org.springframework.web.socket.TextMessage;
5251
import org.springframework.web.socket.WebSocketHandler;
5352
import org.springframework.web.socket.WebSocketSession;
5453
import org.springframework.web.socket.config.WebSocketMessageBrokerStats;
@@ -61,16 +60,11 @@
6160
import org.springframework.web.socket.messaging.SubProtocolWebSocketHandler;
6261
import org.springframework.web.socket.server.support.WebSocketHttpRequestHandler;
6362

64-
import static org.junit.Assert.assertArrayEquals;
65-
import static org.junit.Assert.assertEquals;
66-
import static org.junit.Assert.assertFalse;
67-
import static org.junit.Assert.assertNotNull;
68-
import static org.junit.Assert.assertTrue;
69-
import static org.mockito.Mockito.mock;
63+
import static org.junit.Assert.*;
64+
import static org.mockito.Mockito.*;
7065

7166
/**
72-
* Test fixture for
73-
* {@link org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurationSupport}.
67+
* Test fixture for {@link WebSocketMessageBrokerConfigurationSupport}.
7468
*
7569
* @author Rossen Stoyanchev
7670
*/
@@ -100,8 +94,8 @@ public void clientInboundChannelSendMessage() throws Exception {
10094
session.setOpen(true);
10195
webSocketHandler.afterConnectionEstablished(session);
10296

103-
TextMessage textMessage = StompTextMessageBuilder.create(StompCommand.SEND).headers("destination:/foo").build();
104-
webSocketHandler.handleMessage(session, textMessage);
97+
webSocketHandler.handleMessage(session,
98+
StompTextMessageBuilder.create(StompCommand.SEND).headers("destination:/foo").build());
10599

106100
Message<?> message = channel.messages.get(0);
107101
StompHeaderAccessor accessor = StompHeaderAccessor.getAccessor(message, StompHeaderAccessor.class);
@@ -145,6 +139,7 @@ public void webSocketHandler() {
145139

146140
assertEquals(1024 * 1024, subWsHandler.getSendBufferSizeLimit());
147141
assertEquals(25 * 1000, subWsHandler.getSendTimeLimit());
142+
assertEquals(30 * 1000, subWsHandler.getTimeToFirstMessage());
148143

149144
Map<String, SubProtocolHandler> handlerMap = subWsHandler.getProtocolHandlerMap();
150145
StompSubProtocolHandler protocolHandler = (StompSubProtocolHandler) handlerMap.get("v12.stomp");
@@ -240,6 +235,7 @@ public void configureWebSocketTransport(WebSocketTransportRegistration registrat
240235
registration.setMessageSizeLimit(128 * 1024);
241236
registration.setSendTimeLimit(25 * 1000);
242237
registration.setSendBufferSizeLimit(1024 * 1024);
238+
registration.setTimeToFirstMessage(30 * 1000);
243239
}
244240

245241
@Override

spring-websocket/src/test/resources/org/springframework/web/socket/config/websocket-config-broker-simple.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
path-helper="urlPathHelper">
1111

1212
<!-- message-size=128*1024, send-buffer-size=1024*1024 -->
13-
<websocket:transport message-size="131072" send-timeout="25000" send-buffer-size="1048576">
13+
<websocket:transport message-size="131072" send-timeout="25000" send-buffer-size="1048576" time-to-first-message="30000">
1414
<websocket:decorator-factories>
1515
<bean class="org.springframework.web.socket.config.TestWebSocketHandlerDecoratorFactory" />
1616
</websocket:decorator-factories>

0 commit comments

Comments
 (0)