Skip to content

Commit

Permalink
RenderingResponse must set status code on RedirectView
Browse files Browse the repository at this point in the history
This commit makes sure that WebFlux's RenderingResponse sets the HTTP
status code when rendering a RedirectView.

Closes: gh-28839
  • Loading branch information
poutsma committed Aug 30, 2022
1 parent 4c0ece9 commit f919439
Show file tree
Hide file tree
Showing 2 changed files with 52 additions and 0 deletions.
Expand Up @@ -39,6 +39,8 @@
import org.springframework.util.Assert;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.reactive.result.view.RedirectView;
import org.springframework.web.reactive.result.view.View;
import org.springframework.web.reactive.result.view.ViewResolver;
import org.springframework.web.server.ServerWebExchange;

Expand Down Expand Up @@ -195,13 +197,24 @@ protected Mono<Void> writeToInternal(ServerWebExchange exchange, Context context
.switchIfEmpty(Mono.error(() ->
new IllegalArgumentException("Could not resolve view with name '" + name() + "'")))
.flatMap(view -> {
setStatus(view);
List<MediaType> mediaTypes = view.getSupportedMediaTypes();
return view.render(model(),
contentType == null && !mediaTypes.isEmpty() ? mediaTypes.get(0) : contentType,
exchange);
});
}

private void setStatus(View view) {
if (view instanceof RedirectView) {
HttpStatus httpStatus = HttpStatus.resolve(rawStatusCode());
if (httpStatus != null && httpStatus.is3xxRedirection()) {
RedirectView redirectView = (RedirectView) view;
redirectView.setStatusCode(httpStatus);
}
}
}

}

}
Expand Up @@ -16,6 +16,7 @@

package org.springframework.web.reactive.function.server;

import java.time.Duration;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
Expand All @@ -37,6 +38,7 @@
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.reactive.result.view.AbstractView;
import org.springframework.web.reactive.result.view.RedirectView;
import org.springframework.web.reactive.result.view.View;
import org.springframework.web.reactive.result.view.ViewResolver;
import org.springframework.web.reactive.result.view.ViewResolverSupport;
Expand All @@ -47,8 +49,10 @@

import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;

/**
* @author Arjen Poutsma
Expand Down Expand Up @@ -155,6 +159,41 @@ public void render() {
.verify();
}

@Test
public void writeTo() {
Map<String, Object> model = Collections.singletonMap("foo", "bar");
RenderingResponse renderingResponse = RenderingResponse.create("view")
.status(HttpStatus.FOUND)
.modelAttributes(model)
.build().block(Duration.of(5, ChronoUnit.MILLIS));
assertThat(renderingResponse).isNotNull();

MockServerWebExchange exchange = MockServerWebExchange.from(MockServerHttpRequest.get("http://localhost"));
MediaType contentType = MediaType.APPLICATION_PDF;
exchange.getResponse().getHeaders().setContentType(contentType);

ViewResolver viewResolver = mock(ViewResolver.class);
RedirectView view = mock(RedirectView.class);
given(viewResolver.resolveViewName(eq("view"), any())).willReturn(Mono.just(view));
given(view.render(model, contentType, exchange)).willReturn(Mono.empty());

List<ViewResolver> viewResolvers = new ArrayList<>();
viewResolvers.add(viewResolver);

HandlerStrategies mockConfig = mock(HandlerStrategies.class);
given(mockConfig.viewResolvers()).willReturn(viewResolvers);

ServerResponse.Context context = mock(ServerResponse.Context.class);
given(context.viewResolvers()).willReturn(viewResolvers);

Mono<Void> result = renderingResponse.writeTo(exchange, context);
StepVerifier.create(result)
.expectComplete()
.verify();

verify(view).setStatusCode(HttpStatus.FOUND);
}

@Test
public void defaultContentType() {
Mono<RenderingResponse> result = RenderingResponse.create("view").build();
Expand Down

0 comments on commit f919439

Please sign in to comment.