001/* 002 * Copyright 2002-2017 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.web.socket.handler.WebSocketHandlerDecoratorFactory; 024 025/** 026 * Configure the processing of messages received from and sent to WebSocket clients. 027 * 028 * @author Rossen Stoyanchev 029 * @since 4.0.3 030 */ 031public class WebSocketTransportRegistration { 032 033 private Integer messageSizeLimit; 034 035 private Integer sendTimeLimit; 036 037 private Integer sendBufferSizeLimit; 038 039 private final List<WebSocketHandlerDecoratorFactory> decoratorFactories = 040 new ArrayList<WebSocketHandlerDecoratorFactory>(2); 041 042 043 /** 044 * Configure the maximum size for an incoming sub-protocol message. 045 * For example a STOMP message may be received as multiple WebSocket messages 046 * or multiple HTTP POST requests when SockJS fallback options are in use. 047 * <p>In theory a WebSocket message can be almost unlimited in size. 048 * In practice WebSocket servers impose limits on incoming message size. 049 * STOMP clients for example tend to split large messages around 16K 050 * boundaries. Therefore a server must be able to buffer partial content 051 * and decode when enough data is received. Use this property to configure 052 * the max size of the buffer to use. 053 * <p>The default value is 64K (i.e. 64 * 1024). 054 * <p><strong>NOTE</strong> that the current version 1.2 of the STOMP spec 055 * does not specifically discuss how to send STOMP messages over WebSocket. 056 * Version 2 of the spec will but in the mean time existing client libraries 057 * have already established a practice that servers must handle. 058 */ 059 public WebSocketTransportRegistration setMessageSizeLimit(int messageSizeLimit) { 060 this.messageSizeLimit = messageSizeLimit; 061 return this; 062 } 063 064 /** 065 * Protected accessor for internal use. 066 */ 067 protected Integer getMessageSizeLimit() { 068 return this.messageSizeLimit; 069 } 070 071 /** 072 * Configure a time limit (in milliseconds) for the maximum amount of a time 073 * allowed when sending messages to a WebSocket session or writing to an 074 * HTTP response when SockJS fallback option are in use. 075 * <p>In general WebSocket servers expect that messages to a single WebSocket 076 * session are sent from a single thread at a time. This is automatically 077 * guaranteed when using {@code @EnableWebSocketMessageBroker} configuration. 078 * If message sending is slow, or at least slower than rate of messages sending, 079 * subsequent messages are buffered until either the {@code sendTimeLimit} 080 * or the {@code sendBufferSizeLimit} are reached at which point the session 081 * state is cleared and an attempt is made to close the session. 082 * <p><strong>NOTE</strong> that the session time limit is checked only 083 * on attempts to send additional messages. So if only a single message is 084 * sent and it hangs, the session will not time out until another message is 085 * sent or the underlying physical socket times out. So this is not a 086 * replacement for WebSocket server or HTTP connection timeout but is rather 087 * intended to control the extent of buffering of unsent messages. 088 * <p><strong>NOTE</strong> that closing the session may not succeed in 089 * actually closing the physical socket and may also hang. This is true 090 * especially when using blocking IO such as the BIO connector in Tomcat 091 * that is used by default on Tomcat 7. Therefore it is recommended to ensure 092 * the server is using non-blocking IO such as Tomcat's NIO connector that 093 * is used by default on Tomcat 8. If you must use blocking IO consider 094 * customizing OS-level TCP settings, for example 095 * {@code /proc/sys/net/ipv4/tcp_retries2} on Linux. 096 * <p>The default value is 10 seconds (i.e. 10 * 10000). 097 * @param timeLimit the timeout value in milliseconds; the value must be 098 * greater than 0, otherwise it is ignored. 099 */ 100 public WebSocketTransportRegistration setSendTimeLimit(int timeLimit) { 101 this.sendTimeLimit = timeLimit; 102 return this; 103 } 104 105 /** 106 * Protected accessor for internal use. 107 */ 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 protected Integer getSendBufferSizeLimit() { 145 return this.sendBufferSizeLimit; 146 } 147 148 /** 149 * Configure one or more factories to decorate the handler used to process 150 * WebSocket messages. This may be useful in some advanced use cases, for 151 * example to allow Spring Security to forcibly close the WebSocket session 152 * when the corresponding HTTP session expires. 153 * @since 4.1.2 154 */ 155 public WebSocketTransportRegistration setDecoratorFactories(WebSocketHandlerDecoratorFactory... factories) { 156 if (factories != null) { 157 this.decoratorFactories.addAll(Arrays.asList(factories)); 158 } 159 return this; 160 } 161 162 /** 163 * Add a factory that to decorate the handler used to process WebSocket 164 * messages. This may be useful for some advanced use cases, for example 165 * to allow Spring Security to forcibly close the WebSocket session when 166 * the corresponding HTTP session expires. 167 * @since 4.1.2 168 */ 169 public WebSocketTransportRegistration addDecoratorFactory(WebSocketHandlerDecoratorFactory factory) { 170 this.decoratorFactories.add(factory); 171 return this; 172 } 173 174 protected List<WebSocketHandlerDecoratorFactory> getDecoratorFactories() { 175 return this.decoratorFactories; 176 } 177 178}