Unify HTTP client redirect behavior and provide configuration option

Update `ClientHttpRequestFactoryBuilder` implementations to ensure
that all libraries have consistent redirect follow behavior. Following
of redirects is enabled by default.

The `ClientHttpRequestFactorySettings` may be used to change if
redirects should be followed. The `spring.http.client.redirects`
property may also be used to update the default behavior.

Closes gh-42879
This commit is contained in:
Phillip Webb
2024-10-25 00:46:01 -07:00
parent a92001130f
commit 36a22fcd59
20 changed files with 307 additions and 74 deletions

View File

@@ -36,8 +36,7 @@ import static org.assertj.core.api.Assertions.assertThat;
*
* @author Dave Syer
*/
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT,
properties = { "management.server.port:0", "spring.http.client.factory=simple" })
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT, properties = { "management.server.port:0" })
class SampleActuatorUiApplicationPortTests {
@LocalServerPort

View File

@@ -39,8 +39,7 @@ import static org.assertj.core.api.Assertions.assertThat;
*
* @author Dave Syer
*/
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT,
properties = { "server.error.include-message=always", "spring.http.client.factory=simple" })
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT, properties = { "server.error.include-message=always" })
class SampleActuatorUiApplicationTests {
@Autowired
@@ -51,7 +50,7 @@ class SampleActuatorUiApplicationTests {
HttpHeaders headers = new HttpHeaders();
headers.setAccept(Arrays.asList(MediaType.TEXT_HTML));
ResponseEntity<String> entity = this.restTemplate.withBasicAuth("user", getPassword())
.exchange("/", HttpMethod.GET, new HttpEntity<>(headers), String.class);
.exchange("/", HttpMethod.GET, new HttpEntity<Void>(headers), String.class);
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);
assertThat(entity.getBody()).contains("<title>Hello");
}
@@ -75,7 +74,7 @@ class SampleActuatorUiApplicationTests {
HttpHeaders headers = new HttpHeaders();
headers.setAccept(Arrays.asList(MediaType.TEXT_HTML));
ResponseEntity<String> entity = this.restTemplate.withBasicAuth("user", getPassword())
.exchange("/error", HttpMethod.GET, new HttpEntity<>(headers), String.class);
.exchange("/error", HttpMethod.GET, new HttpEntity<Void>(headers), String.class);
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.INTERNAL_SERVER_ERROR);
assertThat(entity.getBody()).contains("<html>")
.contains("<body>")

View File

@@ -25,8 +25,12 @@ import java.util.Map;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.http.client.ClientHttpRequestFactorySettings;
import org.springframework.boot.http.client.ClientHttpRequestFactorySettings.Redirects;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.boot.test.web.server.LocalServerPort;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
@@ -37,6 +41,7 @@ import org.springframework.http.RequestEntity;
import org.springframework.http.ResponseEntity;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;
import static org.assertj.core.api.Assertions.assertThat;
@@ -48,12 +53,22 @@ import static org.assertj.core.api.Assertions.assertThat;
* @author Madhura Bhave
*/
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
properties = { "server.servlet.session.timeout:2", "spring.http.client.factory=simple" })
properties = { "server.servlet.session.timeout:2" })
class SampleSessionJdbcApplicationTests {
private static final ClientHttpRequestFactorySettings DONT_FOLLOW_REDIRECTS = ClientHttpRequestFactorySettings
.defaults()
.withRedirects(Redirects.DONT_FOLLOW);
@Autowired
private RestTemplateBuilder restTemplateBuilder;
@Autowired
private TestRestTemplate restTemplate;
@LocalServerPort
private String port;
private static final URI ROOT_URI = URI.create("/");
@Test
@@ -68,14 +83,15 @@ class SampleSessionJdbcApplicationTests {
}
private String performLogin() {
RestTemplate restTemplate = this.restTemplateBuilder.requestFactorySettings(DONT_FOLLOW_REDIRECTS).build();
HttpHeaders headers = new HttpHeaders();
headers.setAccept(Collections.singletonList(MediaType.TEXT_HTML));
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
MultiValueMap<String, String> form = new LinkedMultiValueMap<>();
form.set("username", "user");
form.set("password", "password");
ResponseEntity<String> entity = this.restTemplate.exchange("/login", HttpMethod.POST,
new HttpEntity<>(form, headers), String.class);
ResponseEntity<String> entity = restTemplate.exchange("http://localhost:" + this.port + "/login",
HttpMethod.POST, new HttpEntity<>(form, headers), String.class);
return entity.getHeaders().getFirst("Set-Cookie");
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2022 the original author or authors.
* Copyright 2012-2024 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.
@@ -37,7 +37,7 @@ import static org.assertj.core.api.Assertions.assertThat;
*
* @author Dave Syer
*/
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT, properties = "spring.http.client.redirects=dont-follow")
class SampleGroovyTemplateApplicationTests {
@LocalServerPort

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2022 the original author or authors.
* Copyright 2012-2024 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.
@@ -37,7 +37,7 @@ import static org.assertj.core.api.Assertions.assertThat;
*
* @author Dave Syer
*/
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT, properties = "spring.http.client.redirects=dont-follow")
class SampleWebUiApplicationTests {
@Autowired