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}