From 9ddfb8b703b9c8be78aa7aacdf73e0a4f57a0383 Mon Sep 17 00:00:00 2001 From: Nikita Konev <3160384+nkonev@users.noreply.github.com> Date: Tue, 28 Jul 2020 20:18:33 +0300 Subject: [PATCH] fix double encoding websocket upgrade url (#1731) --- .../filter/WebsocketRoutingFilter.java | 7 ++++-- .../filter/WebsocketRoutingFilterTests.java | 22 +++++++++++++++++++ 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/spring-cloud-gateway-core/src/main/java/org/springframework/cloud/gateway/filter/WebsocketRoutingFilter.java b/spring-cloud-gateway-core/src/main/java/org/springframework/cloud/gateway/filter/WebsocketRoutingFilter.java index c1d793aa..b58b11fc 100644 --- a/spring-cloud-gateway-core/src/main/java/org/springframework/cloud/gateway/filter/WebsocketRoutingFilter.java +++ b/spring-cloud-gateway-core/src/main/java/org/springframework/cloud/gateway/filter/WebsocketRoutingFilter.java @@ -41,12 +41,14 @@ import org.springframework.web.util.UriComponentsBuilder; import static org.springframework.cloud.gateway.filter.headers.HttpHeadersFilter.filterRequest; import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR; +import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.containsEncodedParts; import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.isAlreadyRouted; import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.setAlreadyRouted; import static org.springframework.util.StringUtils.commaDelimitedListToStringArray; /** * @author Spencer Gibb + * @author Nikita Konev */ public class WebsocketRoutingFilter implements GlobalFilter, Ordered { @@ -132,7 +134,7 @@ public class WebsocketRoutingFilter implements GlobalFilter, Ordered { return this.headersFilters; } - private void changeSchemeIfIsWebSocketUpgrade(ServerWebExchange exchange) { + static void changeSchemeIfIsWebSocketUpgrade(ServerWebExchange exchange) { // Check the Upgrade URI requestUrl = exchange.getRequiredAttribute(GATEWAY_REQUEST_URL_ATTR); String scheme = requestUrl.getScheme().toLowerCase(); @@ -141,8 +143,9 @@ public class WebsocketRoutingFilter implements GlobalFilter, Ordered { if ("WebSocket".equalsIgnoreCase(upgrade) && ("http".equals(scheme) || "https".equals(scheme))) { String wsScheme = convertHttpToWs(scheme); + boolean encoded = containsEncodedParts(requestUrl); URI wsRequestUrl = UriComponentsBuilder.fromUri(requestUrl).scheme(wsScheme) - .build().toUri(); + .build(encoded).toUri(); exchange.getAttributes().put(GATEWAY_REQUEST_URL_ATTR, wsRequestUrl); if (log.isTraceEnabled()) { log.trace("changeSchemeTo:[" + wsRequestUrl + "]"); diff --git a/spring-cloud-gateway-core/src/test/java/org/springframework/cloud/gateway/filter/WebsocketRoutingFilterTests.java b/spring-cloud-gateway-core/src/test/java/org/springframework/cloud/gateway/filter/WebsocketRoutingFilterTests.java index a88c5e83..d8a59cfe 100644 --- a/spring-cloud-gateway-core/src/test/java/org/springframework/cloud/gateway/filter/WebsocketRoutingFilterTests.java +++ b/spring-cloud-gateway-core/src/test/java/org/springframework/cloud/gateway/filter/WebsocketRoutingFilterTests.java @@ -16,10 +16,19 @@ package org.springframework.cloud.gateway.filter; +import java.net.URI; + import org.junit.Test; +import org.springframework.mock.http.server.reactive.MockServerHttpRequest; +import org.springframework.mock.web.server.MockServerWebExchange; +import org.springframework.web.server.ServerWebExchange; + import static org.assertj.core.api.Assertions.assertThat; +import static org.springframework.cloud.gateway.filter.WebsocketRoutingFilter.changeSchemeIfIsWebSocketUpgrade; import static org.springframework.cloud.gateway.filter.WebsocketRoutingFilter.convertHttpToWs; +import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR; +import static org.springframework.http.HttpHeaders.UPGRADE; public class WebsocketRoutingFilterTests { @@ -32,4 +41,17 @@ public class WebsocketRoutingFilterTests { assertThat(convertHttpToWs("tcp")).isEqualTo("tcp"); } + @Test + public void testEncodedUrl() { + MockServerHttpRequest request = MockServerHttpRequest + .get("http://not-matters-that").header(UPGRADE, "WebSocket").build(); + ServerWebExchange exchange = MockServerWebExchange.from(request); + exchange.getAttributes().put(GATEWAY_REQUEST_URL_ATTR, + URI.create("http://microservice/my-service/websocket%20upgrade")); + changeSchemeIfIsWebSocketUpgrade(exchange); + URI wsRequestUrl = exchange.getAttribute(GATEWAY_REQUEST_URL_ATTR); + assertThat(wsRequestUrl).isEqualTo( + URI.create("ws://microservice/my-service/websocket%20upgrade")); + } + }