Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Reuse StandardWebSocketUpgradeStrategy as a base class for Tomcat etc
Includes non-reflective instantiation of well-known strategy classes. See gh-29436
- Loading branch information
Showing
14 changed files
with
379 additions
and
382 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
199 changes: 199 additions & 0 deletions
199
.../springframework/web/reactive/socket/server/upgrade/StandardWebSocketUpgradeStrategy.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,199 @@ | ||
/* | ||
* Copyright 2002-2022 the original author or authors. | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* https://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
package org.springframework.web.reactive.socket.server.upgrade; | ||
|
||
import java.util.Collections; | ||
import java.util.Map; | ||
import java.util.function.Supplier; | ||
|
||
import jakarta.servlet.http.HttpServletRequest; | ||
import jakarta.servlet.http.HttpServletResponse; | ||
import jakarta.websocket.Endpoint; | ||
import jakarta.websocket.server.ServerContainer; | ||
import jakarta.websocket.server.ServerEndpointConfig; | ||
import reactor.core.publisher.Mono; | ||
|
||
import org.springframework.core.io.buffer.DataBufferFactory; | ||
import org.springframework.http.server.reactive.ServerHttpRequest; | ||
import org.springframework.http.server.reactive.ServerHttpRequestDecorator; | ||
import org.springframework.http.server.reactive.ServerHttpResponse; | ||
import org.springframework.http.server.reactive.ServerHttpResponseDecorator; | ||
import org.springframework.lang.Nullable; | ||
import org.springframework.util.Assert; | ||
import org.springframework.web.reactive.socket.HandshakeInfo; | ||
import org.springframework.web.reactive.socket.WebSocketHandler; | ||
import org.springframework.web.reactive.socket.adapter.ContextWebSocketHandler; | ||
import org.springframework.web.reactive.socket.adapter.StandardWebSocketHandlerAdapter; | ||
import org.springframework.web.reactive.socket.adapter.TomcatWebSocketSession; | ||
import org.springframework.web.reactive.socket.server.RequestUpgradeStrategy; | ||
import org.springframework.web.server.ServerWebExchange; | ||
|
||
/** | ||
* A WebSocket {@code RequestUpgradeStrategy} for the Jakarta WebSocket API 2.1+. | ||
* | ||
* <p>This strategy serves as a fallback if no specific server has been detected. | ||
* It can also be used with Jakarta EE 10 level servers such as Tomcat 10.1 and | ||
* Undertow 2.3 directly, relying on their built-in Jakarta WebSocket 2.1 support. | ||
* | ||
* @author Juergen Hoeller | ||
* @author Violeta Georgieva | ||
* @author Rossen Stoyanchev | ||
* @since 6.0 | ||
* @see jakarta.websocket.server.ServerContainer#upgradeHttpToWebSocket | ||
*/ | ||
public class StandardWebSocketUpgradeStrategy implements RequestUpgradeStrategy { | ||
|
||
private static final String SERVER_CONTAINER_ATTR = "jakarta.websocket.server.ServerContainer"; | ||
|
||
|
||
@Nullable | ||
private Long asyncSendTimeout; | ||
|
||
@Nullable | ||
private Long maxSessionIdleTimeout; | ||
|
||
@Nullable | ||
private Integer maxTextMessageBufferSize; | ||
|
||
@Nullable | ||
private Integer maxBinaryMessageBufferSize; | ||
|
||
@Nullable | ||
private ServerContainer serverContainer; | ||
|
||
|
||
/** | ||
* Exposes the underlying config option on | ||
* {@link ServerContainer#setAsyncSendTimeout(long)}. | ||
*/ | ||
public void setAsyncSendTimeout(Long timeoutInMillis) { | ||
this.asyncSendTimeout = timeoutInMillis; | ||
} | ||
|
||
@Nullable | ||
public Long getAsyncSendTimeout() { | ||
return this.asyncSendTimeout; | ||
} | ||
|
||
/** | ||
* Exposes the underlying config option on | ||
* {@link ServerContainer#setDefaultMaxSessionIdleTimeout(long)}. | ||
*/ | ||
public void setMaxSessionIdleTimeout(Long timeoutInMillis) { | ||
this.maxSessionIdleTimeout = timeoutInMillis; | ||
} | ||
|
||
@Nullable | ||
public Long getMaxSessionIdleTimeout() { | ||
return this.maxSessionIdleTimeout; | ||
} | ||
|
||
/** | ||
* Exposes the underlying config option on | ||
* {@link ServerContainer#setDefaultMaxTextMessageBufferSize(int)}. | ||
*/ | ||
public void setMaxTextMessageBufferSize(Integer bufferSize) { | ||
this.maxTextMessageBufferSize = bufferSize; | ||
} | ||
|
||
@Nullable | ||
public Integer getMaxTextMessageBufferSize() { | ||
return this.maxTextMessageBufferSize; | ||
} | ||
|
||
/** | ||
* Exposes the underlying config option on | ||
* {@link ServerContainer#setDefaultMaxBinaryMessageBufferSize(int)}. | ||
*/ | ||
public void setMaxBinaryMessageBufferSize(Integer bufferSize) { | ||
this.maxBinaryMessageBufferSize = bufferSize; | ||
} | ||
|
||
@Nullable | ||
public Integer getMaxBinaryMessageBufferSize() { | ||
return this.maxBinaryMessageBufferSize; | ||
} | ||
|
||
@Override | ||
public Mono<Void> upgrade(ServerWebExchange exchange, WebSocketHandler handler, | ||
@Nullable String subProtocol, Supplier<HandshakeInfo> handshakeInfoFactory){ | ||
|
||
ServerHttpRequest request = exchange.getRequest(); | ||
ServerHttpResponse response = exchange.getResponse(); | ||
|
||
HttpServletRequest servletRequest = ServerHttpRequestDecorator.getNativeRequest(request); | ||
HttpServletResponse servletResponse = ServerHttpResponseDecorator.getNativeResponse(response); | ||
|
||
HandshakeInfo handshakeInfo = handshakeInfoFactory.get(); | ||
DataBufferFactory bufferFactory = response.bufferFactory(); | ||
|
||
// Trigger WebFlux preCommit actions and upgrade | ||
return exchange.getResponse().setComplete() | ||
.then(Mono.deferContextual(contextView -> { | ||
Endpoint endpoint = new StandardWebSocketHandlerAdapter( | ||
ContextWebSocketHandler.decorate(handler, contextView), | ||
session -> new TomcatWebSocketSession(session, handshakeInfo, bufferFactory)); | ||
|
||
String requestURI = servletRequest.getRequestURI(); | ||
DefaultServerEndpointConfig config = new DefaultServerEndpointConfig(requestURI, endpoint); | ||
config.setSubprotocols(subProtocol != null ? | ||
Collections.singletonList(subProtocol) : Collections.emptyList()); | ||
|
||
try { | ||
upgradeHttpToWebSocket(servletRequest, servletResponse, config, Collections.emptyMap()); | ||
} | ||
catch (Exception ex) { | ||
return Mono.error(ex); | ||
} | ||
return Mono.empty(); | ||
})); | ||
} | ||
|
||
|
||
protected void upgradeHttpToWebSocket(HttpServletRequest request, HttpServletResponse response, | ||
ServerEndpointConfig endpointConfig, Map<String,String> pathParams) throws Exception { | ||
|
||
getContainer(request).upgradeHttpToWebSocket(request, response, endpointConfig, pathParams); | ||
} | ||
|
||
protected ServerContainer getContainer(HttpServletRequest request) { | ||
if (this.serverContainer == null) { | ||
Object container = request.getServletContext().getAttribute(SERVER_CONTAINER_ATTR); | ||
Assert.state(container instanceof ServerContainer, | ||
"ServletContext attribute 'jakarta.websocket.server.ServerContainer' not found."); | ||
this.serverContainer = (ServerContainer) container; | ||
initServerContainer(this.serverContainer); | ||
} | ||
return this.serverContainer; | ||
} | ||
|
||
private void initServerContainer(ServerContainer serverContainer) { | ||
if (this.asyncSendTimeout != null) { | ||
serverContainer.setAsyncSendTimeout(this.asyncSendTimeout); | ||
} | ||
if (this.maxSessionIdleTimeout != null) { | ||
serverContainer.setDefaultMaxSessionIdleTimeout(this.maxSessionIdleTimeout); | ||
} | ||
if (this.maxTextMessageBufferSize != null) { | ||
serverContainer.setDefaultMaxTextMessageBufferSize(this.maxTextMessageBufferSize); | ||
} | ||
if (this.maxBinaryMessageBufferSize != null) { | ||
serverContainer.setDefaultMaxBinaryMessageBufferSize(this.maxBinaryMessageBufferSize); | ||
} | ||
} | ||
|
||
} |
Oops, something went wrong.