Skip to content

Commit 3306b5c

Browse files
committed
DATAREST-815 - Tweaked HalBrowser controller implementation to consider proxied requests.
We now use the APIs in place in Spring MVC to make sure we create proper redirects for requests that carry proxy headers so that the redirect target is still going through the proxy.
1 parent 127f1a8 commit 3306b5c

File tree

2 files changed

+50
-35
lines changed

2 files changed

+50
-35
lines changed

spring-data-rest-hal-browser/src/main/java/org/springframework/data/rest/webmvc/halbrowser/HalBrowser.java

Lines changed: 27 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -17,15 +17,14 @@
1717

1818
import javax.servlet.http.HttpServletRequest;
1919

20-
import org.springframework.beans.factory.annotation.Autowired;
21-
import org.springframework.data.rest.core.config.RepositoryRestConfiguration;
2220
import org.springframework.data.rest.webmvc.BasePathAwareController;
2321
import org.springframework.http.MediaType;
24-
import org.springframework.util.Assert;
2522
import org.springframework.web.bind.annotation.RequestMapping;
2623
import org.springframework.web.bind.annotation.RequestMethod;
2724
import org.springframework.web.servlet.View;
25+
import org.springframework.web.servlet.support.ServletUriComponentsBuilder;
2826
import org.springframework.web.servlet.view.RedirectView;
27+
import org.springframework.web.util.UriComponents;
2928

3029
/**
3130
* Controller with a few convenience redirects to expose the HAL browser shipped as static content.
@@ -37,22 +36,7 @@
3736
public class HalBrowser {
3837

3938
private static String BROWSER = "/browser";
40-
public static String BROWSER_INDEX = BROWSER.concat("/index.html");
41-
42-
private final RepositoryRestConfiguration configuration;
43-
44-
/**
45-
* Creates a new {@link HalBrowser} for the given {@link RepositoryRestConfiguration}.
46-
*
47-
* @param configuration must not be {@literal null}.
48-
*/
49-
@Autowired
50-
public HalBrowser(RepositoryRestConfiguration configuration) {
51-
52-
Assert.notNull(configuration, "RepositoryRestConfiguration must not be null!");
53-
54-
this.configuration = configuration;
55-
}
39+
private static String INDEX = "/index.html";
5640

5741
/**
5842
* Redirects requests to the API root asking for HTML to the HAL browser.
@@ -61,7 +45,7 @@ public HalBrowser(RepositoryRestConfiguration configuration) {
6145
*/
6246
@RequestMapping(value = { "/", "" }, method = RequestMethod.GET, produces = MediaType.TEXT_HTML_VALUE)
6347
public View index(HttpServletRequest request) {
64-
return browser(request);
48+
return getRedirectView(request, false);
6549
}
6650

6751
/**
@@ -71,10 +55,30 @@ public View index(HttpServletRequest request) {
7155
*/
7256
@RequestMapping(value = "/browser", method = RequestMethod.GET)
7357
public View browser(HttpServletRequest request) {
58+
return getRedirectView(request, request.getRequestURI().endsWith("/browser"));
59+
}
60+
61+
/**
62+
* Returns the View to redirect to to access the HAL browser.
63+
*
64+
* @param request must not be {@literal null}.
65+
* @param browserRelative
66+
* @return
67+
*/
68+
private View getRedirectView(HttpServletRequest request, boolean browserRelative) {
69+
70+
ServletUriComponentsBuilder builder = ServletUriComponentsBuilder.fromRequest(request);
71+
72+
UriComponents components = builder.build();
73+
String path = components.getPath() == null ? "" : components.getPath();
74+
75+
if (!browserRelative) {
76+
builder.path(BROWSER);
77+
}
7478

75-
String contextPath = request.getContextPath();
76-
String basePath = configuration.getBasePath().toString();
79+
builder.path(INDEX);
80+
builder.fragment(browserRelative ? path.substring(0, path.lastIndexOf("/browser")) : path);
7781

78-
return new RedirectView(basePath.concat(BROWSER_INDEX).concat("#").concat(contextPath.concat(basePath)), true);
82+
return new RedirectView(builder.build().toUriString());
7983
}
8084
}

spring-data-rest-hal-browser/src/test/java/org/springframework/data/rest/webmvc/halbrowser/HalBrowserUnitTests.java

Lines changed: 23 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -15,18 +15,12 @@
1515
*/
1616
package org.springframework.data.rest.webmvc.halbrowser;
1717

18-
import static org.hamcrest.CoreMatchers.*;
18+
import static org.hamcrest.Matchers.*;
1919
import static org.junit.Assert.*;
20-
import static org.mockito.Mockito.*;
2120

2221
import java.util.Collections;
2322

24-
import org.hamcrest.Matchers;
2523
import org.junit.Test;
26-
import org.springframework.data.rest.core.config.EnumTranslationConfiguration;
27-
import org.springframework.data.rest.core.config.MetadataConfiguration;
28-
import org.springframework.data.rest.core.config.ProjectionDefinitionConfiguration;
29-
import org.springframework.data.rest.core.config.RepositoryRestConfiguration;
3024
import org.springframework.http.HttpHeaders;
3125
import org.springframework.mock.web.MockHttpServletRequest;
3226
import org.springframework.mock.web.MockHttpServletResponse;
@@ -51,22 +45,39 @@ public class HalBrowserUnitTests {
5145
@Test
5246
public void createsContextRelativeRedirectForBrowser() throws Exception {
5347

54-
RepositoryRestConfiguration configuration = new RepositoryRestConfiguration(new ProjectionDefinitionConfiguration(),
55-
new MetadataConfiguration(), mock(EnumTranslationConfiguration.class));
56-
5748
MockHttpServletResponse response = new MockHttpServletResponse();
5849
MockHttpServletRequest request = new MockHttpServletRequest();
50+
request.setRequestURI("/context");
5951
request.setContextPath("/context");
6052

61-
View view = new HalBrowser(configuration).browser(request);
53+
View view = new HalBrowser().browser(request);
6254

6355
assertThat(view, is(instanceOf(RedirectView.class)));
6456

6557
((AbstractView) view).render(Collections.<String, Object> emptyMap(), request, response);
6658

6759
UriComponents components = UriComponentsBuilder.fromUriString(response.getHeader(HttpHeaders.LOCATION)).build();
6860

69-
assertThat(components.getPath(), Matchers.startsWith("/context"));
61+
assertThat(components.getPath(), startsWith("/context"));
7062
assertThat(components.getFragment(), is("/context"));
7163
}
64+
65+
@Test
66+
public void producesProxyRelativeRedirectIfNecessary() {
67+
68+
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/browser");
69+
request.addHeader("X-Forwarded-Host", "somehost");
70+
request.addHeader("X-Forwarded-Port", "4711");
71+
request.addHeader("X-Forwarded-Proto", "https");
72+
request.addHeader("X-Forwarded-Prefix", "/prefix");
73+
74+
View view = new HalBrowser().browser(request);
75+
76+
assertThat(view, is(instanceOf(RedirectView.class)));
77+
78+
String url = ((RedirectView) view).getUrl();
79+
80+
assertThat(url, startsWith("https://somehost:4711/prefix"));
81+
assertThat(url, endsWith("/prefix"));
82+
}
7283
}

0 commit comments

Comments
 (0)