Browse Source

Move URL transform methods from ServerHttpResponse to ServerWebExchange

This commit moves `encodeUrl` and `registerUrlEncoder` from
ServerHttpResponse to ServerWebExchange.

It also renames `encodeUrl` to `transformUrl` and `registerUrlEncoder`
to `addUrlTransformer` to make it clearer that these methods do not
perform actual URL encodings (i.e. they do not replaceinvalid
characters).
The `add` prefix (instead of `register`) makes it clearer that each
function is added in addition to the previous one.

Issue: SPR-15924
pull/1507/merge
Arjen Poutsma 8 years ago
parent
commit
02a2c400c7
  1. 14
      spring-web/src/main/java/org/springframework/http/server/reactive/AbstractServerHttpResponse.java
  2. 20
      spring-web/src/main/java/org/springframework/http/server/reactive/ServerHttpResponse.java
  3. 11
      spring-web/src/main/java/org/springframework/http/server/reactive/ServerHttpResponseDecorator.java
  4. 18
      spring-web/src/main/java/org/springframework/web/server/ServerWebExchange.java
  5. 12
      spring-web/src/main/java/org/springframework/web/server/ServerWebExchangeDecorator.java
  6. 15
      spring-web/src/main/java/org/springframework/web/server/adapter/DefaultServerWebExchange.java
  7. 26
      spring-web/src/test/java/org/springframework/http/server/reactive/ServerHttpResponseTests.java
  8. 60
      spring-web/src/test/java/org/springframework/web/server/adapter/ServerWebExchangeTests.java
  9. 4
      spring-webflux/src/main/java/org/springframework/web/reactive/result/view/RedirectView.java
  10. 4
      spring-webflux/src/main/java/org/springframework/web/reactive/result/view/RequestContext.java

14
spring-web/src/main/java/org/springframework/http/server/reactive/AbstractServerHttpResponse.java

@ -19,7 +19,6 @@ package org.springframework.http.server.reactive; @@ -19,7 +19,6 @@ package org.springframework.http.server.reactive;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collectors;
@ -69,9 +68,6 @@ public abstract class AbstractServerHttpResponse implements ServerHttpResponse { @@ -69,9 +68,6 @@ public abstract class AbstractServerHttpResponse implements ServerHttpResponse {
private final MultiValueMap<String, ResponseCookie> cookies;
@Nullable
private Function<String, String> urlEncoder = url -> url;
private final AtomicReference<State> state = new AtomicReference<>(State.NEW);
private final List<Supplier<? extends Mono<Void>>> commitActions = new ArrayList<>(4);
@ -136,16 +132,6 @@ public abstract class AbstractServerHttpResponse implements ServerHttpResponse { @@ -136,16 +132,6 @@ public abstract class AbstractServerHttpResponse implements ServerHttpResponse {
}
}
@Override
public String encodeUrl(String url) {
return (this.urlEncoder != null ? this.urlEncoder.apply(url) : url);
}
@Override
public void registerUrlEncoder(Function<String, String> encoder) {
this.urlEncoder = (this.urlEncoder != null ? this.urlEncoder.andThen(encoder) : encoder);
}
@Override
public void beforeCommit(Supplier<? extends Mono<Void>> action) {
this.commitActions.add(action);

20
spring-web/src/main/java/org/springframework/http/server/reactive/ServerHttpResponse.java

@ -16,8 +16,6 @@ @@ -16,8 +16,6 @@
package org.springframework.http.server.reactive;
import java.util.function.Function;
import org.springframework.http.HttpStatus;
import org.springframework.http.ReactiveHttpOutputMessage;
import org.springframework.http.ResponseCookie;
@ -59,22 +57,4 @@ public interface ServerHttpResponse extends ReactiveHttpOutputMessage { @@ -59,22 +57,4 @@ public interface ServerHttpResponse extends ReactiveHttpOutputMessage {
*/
void addCookie(ResponseCookie cookie);
/**
* A mechanism for URL rewriting that applications and libraries such as
* HTML template libraries to use consistently for all URLs emitted by
* the application. Doing so enables the registration of URL encoders via
* {@link #registerUrlEncoder} that can insert an id for authentication,
* a nonce for CSRF protection, or other.
* @param url the URL to encode
* @return the encoded URL or the same
*/
String encodeUrl(String url);
/**
* Register a URL rewriting function for use with {@link #encodeUrl}.
* The function must return an encoded URL or the same URL.
* @param encoder a URL encoding function to use
*/
void registerUrlEncoder(Function<String, String> encoder);
}

11
spring-web/src/main/java/org/springframework/http/server/reactive/ServerHttpResponseDecorator.java

@ -15,7 +15,6 @@ @@ -15,7 +15,6 @@
*/
package org.springframework.http.server.reactive;
import java.util.function.Function;
import java.util.function.Supplier;
import org.reactivestreams.Publisher;
@ -80,16 +79,6 @@ public class ServerHttpResponseDecorator implements ServerHttpResponse { @@ -80,16 +79,6 @@ public class ServerHttpResponseDecorator implements ServerHttpResponse {
getDelegate().addCookie(cookie);
}
@Override
public String encodeUrl(String url) {
return getDelegate().encodeUrl(url);
}
@Override
public void registerUrlEncoder(Function<String, String> encoder) {
getDelegate().registerUrlEncoder(encoder);
}
@Override
public DataBufferFactory bufferFactory() {
return getDelegate().bufferFactory();

18
spring-web/src/main/java/org/springframework/web/server/ServerWebExchange.java

@ -20,6 +20,7 @@ import java.security.Principal; @@ -20,6 +20,7 @@ import java.security.Principal;
import java.time.Instant;
import java.util.Map;
import java.util.function.Consumer;
import java.util.function.Function;
import reactor.core.publisher.Mono;
@ -177,6 +178,23 @@ public interface ServerWebExchange { @@ -177,6 +178,23 @@ public interface ServerWebExchange {
*/
boolean checkNotModified(@Nullable String etag, Instant lastModified);
/**
* Transform the given url according to the registered transformation function(s).
* By default, this method returns the given {@code url}, though additional
* transformation functions can by registered with {@link #addUrlTransformer}
* @param url the URL to transform
* @return the transformed URL
*/
String transformUrl(String url);
/**
* Register an additional URL transformation function for use with {@link #transformUrl}.
* The given function can be used to insert an id for authentication, a nonce for CSRF
* protection, etc.
* <p>Note that the given function is applied after any previously registered functions.
* @param transformer a URL transformation function to add
*/
void addUrlTransformer(Function<String, String> transformer);
/**
* Return a builder to mutate properties of this exchange by wrapping it

12
spring-web/src/main/java/org/springframework/web/server/ServerWebExchangeDecorator.java

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* Copyright 2002-2016 the original author or authors.
* Copyright 2002-2017 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.
@ -18,6 +18,7 @@ package org.springframework.web.server; @@ -18,6 +18,7 @@ package org.springframework.web.server;
import java.security.Principal;
import java.time.Instant;
import java.util.Map;
import java.util.function.Function;
import reactor.core.publisher.Mono;
@ -120,6 +121,15 @@ public class ServerWebExchangeDecorator implements ServerWebExchange { @@ -120,6 +121,15 @@ public class ServerWebExchangeDecorator implements ServerWebExchange {
return getDelegate().checkNotModified(etag, lastModified);
}
@Override
public String transformUrl(String url) {
return getDelegate().transformUrl(url);
}
@Override
public void addUrlTransformer(Function<String, String> transformer) {
getDelegate().addUrlTransformer(transformer);
}
@Override
public String toString() {

15
spring-web/src/main/java/org/springframework/web/server/adapter/DefaultServerWebExchange.java

@ -24,6 +24,7 @@ import java.util.Collections; @@ -24,6 +24,7 @@ import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import reactor.core.publisher.Mono;
@ -91,6 +92,8 @@ public class DefaultServerWebExchange implements ServerWebExchange { @@ -91,6 +92,8 @@ public class DefaultServerWebExchange implements ServerWebExchange {
private volatile boolean notModified;
private Function<String, String> urlTransformer = url -> url;
public DefaultServerWebExchange(ServerHttpRequest request, ServerHttpResponse response,
WebSessionManager sessionManager, ServerCodecConfigurer codecConfigurer, LocaleContextResolver localeContextResolver) {
@ -322,4 +325,16 @@ public class DefaultServerWebExchange implements ServerWebExchange { @@ -322,4 +325,16 @@ public class DefaultServerWebExchange implements ServerWebExchange {
return true;
}
@Override
public String transformUrl(String url) {
return this.urlTransformer.apply(url);
}
@Override
public void addUrlTransformer(Function<String, String> transformer) {
Assert.notNull(transformer, "'encoder' must not be null");
this.urlTransformer = this.urlTransformer.andThen(transformer);
}
}

26
spring-web/src/test/java/org/springframework/http/server/reactive/ServerHttpResponseTests.java

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* Copyright 2002-2016 the original author or authors.
* Copyright 2002-2017 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.
@ -32,9 +32,7 @@ import org.springframework.core.io.buffer.DefaultDataBufferFactory; @@ -32,9 +32,7 @@ import org.springframework.core.io.buffer.DefaultDataBufferFactory;
import org.springframework.http.ResponseCookie;
import static junit.framework.TestCase.assertTrue;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.*;
/**
* @author Rossen Stoyanchev
@ -42,26 +40,6 @@ import static org.junit.Assert.assertSame; @@ -42,26 +40,6 @@ import static org.junit.Assert.assertSame;
*/
public class ServerHttpResponseTests {
@Test
public void encodeUrlDefault() throws Exception {
TestServerHttpResponse response = new TestServerHttpResponse();
assertEquals("/foo", response.encodeUrl("/foo"));
}
@Test
public void encodeUrlWithEncoder() throws Exception {
TestServerHttpResponse response = new TestServerHttpResponse();
response.registerUrlEncoder(s -> s + "?nonce=123");
assertEquals("/foo?nonce=123", response.encodeUrl("/foo"));
}
@Test
public void encodeUrlWithMultipleEncoders() throws Exception {
TestServerHttpResponse response = new TestServerHttpResponse();
response.registerUrlEncoder(s -> s + ";p=abc");
response.registerUrlEncoder(s -> s + "?q=123");
assertEquals("/foo;p=abc?q=123", response.encodeUrl("/foo"));
}
@Test
public void writeWith() throws Exception {

60
spring-web/src/test/java/org/springframework/web/server/adapter/ServerWebExchangeTests.java

@ -0,0 +1,60 @@ @@ -0,0 +1,60 @@
/*
* Copyright 2002-2017 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
*
* http://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.server.adapter;
import org.junit.Before;
import org.junit.Test;
import org.springframework.mock.http.server.reactive.test.MockServerHttpRequest;
import org.springframework.mock.http.server.reactive.test.MockServerWebExchange;
import org.springframework.web.server.ServerWebExchange;
import static org.junit.Assert.*;
/**
* @author Arjen Poutsma
*/
public class ServerWebExchangeTests {
private ServerWebExchange exchange;
@Before
public void createExchange() {
MockServerHttpRequest request = MockServerHttpRequest.get("http://example.com").build();
this.exchange = new MockServerWebExchange(request);
}
@Test
public void transformUrlDefault() throws Exception {
assertEquals("/foo", this.exchange.transformUrl("/foo"));
}
@Test
public void transformUrlWithEncoder() throws Exception {
this.exchange.addUrlTransformer(s -> s + "?nonce=123");
assertEquals("/foo?nonce=123", this.exchange.transformUrl("/foo"));
}
@Test
public void transformUrlWithMultipleEncoders() throws Exception {
this.exchange.addUrlTransformer(s -> s + ";p=abc");
this.exchange.addUrlTransformer(s -> s + "?q=123");
assertEquals("/foo;p=abc?q=123", this.exchange.transformUrl("/foo"));
}
}

4
spring-webflux/src/main/java/org/springframework/web/reactive/result/view/RedirectView.java

@ -289,9 +289,9 @@ public class RedirectView extends AbstractUrlBasedView { @@ -289,9 +289,9 @@ public class RedirectView extends AbstractUrlBasedView {
* @param exchange current exchange
*/
protected Mono<Void> sendRedirect(String targetUrl, ServerWebExchange exchange) {
String transformedUrl = (isRemoteHost(targetUrl) ? targetUrl : exchange.transformUrl(targetUrl));
ServerHttpResponse response = exchange.getResponse();
String encodedURL = (isRemoteHost(targetUrl) ? targetUrl : response.encodeUrl(targetUrl));
response.getHeaders().setLocation(URI.create(encodedURL));
response.getHeaders().setLocation(URI.create(transformedUrl));
response.setStatusCode(getStatusCode());
return Mono.empty();
}

4
spring-webflux/src/main/java/org/springframework/web/reactive/result/view/RequestContext.java

@ -203,7 +203,7 @@ public class RequestContext { @@ -203,7 +203,7 @@ public class RequestContext {
*/
public String getContextUrl(String relativeUrl) {
String url = StringUtils.applyRelativePath(getContextPath() + "/", relativeUrl);
return getExchange().getResponse().encodeUrl(url);
return getExchange().transformUrl(url);
}
/**
@ -220,7 +220,7 @@ public class RequestContext { @@ -220,7 +220,7 @@ public class RequestContext {
String url = StringUtils.applyRelativePath(getContextPath() + "/", relativeUrl);
UriTemplate template = new UriTemplate(url);
url = template.expand(params).toASCIIString();
return getExchange().getResponse().encodeUrl(url);
return getExchange().transformUrl(url);
}
/**

Loading…
Cancel
Save