001/*
002 * Copyright 2002-2018 the original author or authors.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *      https://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017package org.springframework.web.socket.config.annotation;
018
019import java.util.ArrayList;
020import java.util.Arrays;
021import java.util.List;
022
023import org.springframework.lang.Nullable;
024import org.springframework.web.socket.handler.WebSocketHandlerDecoratorFactory;
025
026/**
027 * Configure the processing of messages received from and sent to WebSocket clients.
028 *
029 * @author Rossen Stoyanchev
030 * @since 4.0.3
031 */
032public class WebSocketTransportRegistration {
033
034        @Nullable
035        private Integer messageSizeLimit;
036
037        @Nullable
038        private Integer sendTimeLimit;
039
040        @Nullable
041        private Integer sendBufferSizeLimit;
042
043        @Nullable
044        private Integer timeToFirstMessage;
045
046        private final List<WebSocketHandlerDecoratorFactory> decoratorFactories = new ArrayList<>(2);
047
048
049        /**
050         * Configure the maximum size of an inbound sub-protocol message, such as
051         * a STOMP frame which may be aggregated from multiple WebSocket messages.
052         * <p>The default value is 64K (i.e. 64 * 1024).
053         * <p><strong>Note:</strong> This is not the same as the size of an
054         * individual WebSocket message which needs to be configured at the WebSocket
055         * server level instead. See the reference documentation for details.
056         */
057        public WebSocketTransportRegistration setMessageSizeLimit(int messageSizeLimit) {
058                this.messageSizeLimit = messageSizeLimit;
059                return this;
060        }
061
062        /**
063         * Protected accessor for internal use.
064         */
065        @Nullable
066        protected Integer getMessageSizeLimit() {
067                return this.messageSizeLimit;
068        }
069
070        /**
071         * Configure a time limit (in milliseconds) for the maximum amount of a time
072         * allowed when sending messages to a WebSocket session or writing to an
073         * HTTP response when SockJS fallback option are in use.
074         * <p>In general WebSocket servers expect that messages to a single WebSocket
075         * session are sent from a single thread at a time. This is automatically
076         * guaranteed when using {@code @EnableWebSocketMessageBroker} configuration.
077         * If message sending is slow, or at least slower than rate of messages sending,
078         * subsequent messages are buffered until either the {@code sendTimeLimit}
079         * or the {@code sendBufferSizeLimit} are reached at which point the session
080         * state is cleared and an attempt is made to close the session.
081         * <p><strong>NOTE</strong> that the session time limit is checked only
082         * on attempts to send additional messages. So if only a single message is
083         * sent and it hangs, the session will not time out until another message is
084         * sent or the underlying physical socket times out. So this is not a
085         * replacement for WebSocket server or HTTP connection timeout but is rather
086         * intended to control the extent of buffering of unsent messages.
087         * <p><strong>NOTE</strong> that closing the session may not succeed in
088         * actually closing the physical socket and may also hang. This is true
089         * especially when using blocking IO such as the BIO connector in Tomcat
090         * that is used by default on Tomcat 7. Therefore it is recommended to ensure
091         * the server is using non-blocking IO such as Tomcat's NIO connector that
092         * is used by default on Tomcat 8. If you must use blocking IO consider
093         * customizing OS-level TCP settings, for example
094         * {@code /proc/sys/net/ipv4/tcp_retries2} on Linux.
095         * <p>The default value is 10 seconds (i.e. 10 * 10000).
096         * @param timeLimit the timeout value in milliseconds; the value must be
097         * greater than 0, otherwise it is ignored.
098         */
099        public WebSocketTransportRegistration setSendTimeLimit(int timeLimit) {
100                this.sendTimeLimit = timeLimit;
101                return this;
102        }
103
104        /**
105         * Protected accessor for internal use.
106         */
107        @Nullable
108        protected Integer getSendTimeLimit() {
109                return this.sendTimeLimit;
110        }
111
112        /**
113         * Configure the maximum amount of data to buffer when sending messages
114         * to a WebSocket session, or an HTTP response when SockJS fallback
115         * option are in use.
116         * <p>In general WebSocket servers expect that messages to a single WebSocket
117         * session are sent from a single thread at a time. This is automatically
118         * guaranteed when using {@code @EnableWebSocketMessageBroker} configuration.
119         * If message sending is slow, or at least slower than rate of messages sending,
120         * subsequent messages are buffered until either the {@code sendTimeLimit}
121         * or the {@code sendBufferSizeLimit} are reached at which point the session
122         * state is cleared and an attempt is made to close the session.
123         * <p><strong>NOTE</strong> that closing the session may not succeed in
124         * actually closing the physical socket and may also hang. This is true
125         * especially when using blocking IO such as the BIO connector in Tomcat
126         * configured by default on Tomcat 7. Therefore it is recommended to ensure
127         * the server is using non-blocking IO such as Tomcat's NIO connector used
128         * by default on Tomcat 8. If you must use blocking IO consider customizing
129         * OS-level TCP settings, for example {@code /proc/sys/net/ipv4/tcp_retries2}
130         * on Linux.
131         * <p>The default value is 512K (i.e. 512 * 1024).
132         * @param sendBufferSizeLimit the maximum number of bytes to buffer when
133         * sending messages; if the value is less than or equal to 0 then buffering
134         * is effectively disabled.
135         */
136        public WebSocketTransportRegistration setSendBufferSizeLimit(int sendBufferSizeLimit) {
137                this.sendBufferSizeLimit = sendBufferSizeLimit;
138                return this;
139        }
140
141        /**
142         * Protected accessor for internal use.
143         */
144        @Nullable
145        protected Integer getSendBufferSizeLimit() {
146                return this.sendBufferSizeLimit;
147        }
148
149        /**
150         * Set the maximum time allowed in milliseconds after the WebSocket connection
151         * is established and before the first sub-protocol message is received.
152         * <p>This handler is for WebSocket connections that use a sub-protocol.
153         * Therefore, we expect the client to send at least one sub-protocol message
154         * in the beginning, or else we assume the connection isn't doing well, e.g.
155         * proxy issue, slow network, and can be closed.
156         * <p>By default this is set to {@code 60,000} (1 minute).
157         * @param timeToFirstMessage the maximum time allowed in milliseconds
158         * @since 5.1
159         */
160        public WebSocketTransportRegistration setTimeToFirstMessage(int timeToFirstMessage) {
161                this.timeToFirstMessage = timeToFirstMessage;
162                return this;
163        }
164
165        /**
166         * Protected accessor for internal use.
167         */
168        @Nullable
169        protected Integer getTimeToFirstMessage() {
170                return this.timeToFirstMessage;
171        }
172
173        /**
174         * Configure one or more factories to decorate the handler used to process
175         * WebSocket messages. This may be useful in some advanced use cases, for
176         * example to allow Spring Security to forcibly close the WebSocket session
177         * when the corresponding HTTP session expires.
178         * @since 4.1.2
179         */
180        public WebSocketTransportRegistration setDecoratorFactories(WebSocketHandlerDecoratorFactory... factories) {
181                this.decoratorFactories.addAll(Arrays.asList(factories));
182                return this;
183        }
184
185        /**
186         * Add a factory that to decorate the handler used to process WebSocket
187         * messages. This may be useful for some advanced use cases, for example
188         * to allow Spring Security to forcibly close the WebSocket session when
189         * the corresponding HTTP session expires.
190         * @since 4.1.2
191         */
192        public WebSocketTransportRegistration addDecoratorFactory(WebSocketHandlerDecoratorFactory factory) {
193                this.decoratorFactories.add(factory);
194                return this;
195        }
196
197        protected List<WebSocketHandlerDecoratorFactory> getDecoratorFactories() {
198                return this.decoratorFactories;
199        }
200
201}