4343import org .springframework .core .io .buffer .DataBufferFactory ;
4444import org .springframework .core .io .buffer .DataBufferUtils ;
4545import org .springframework .http .HttpHeaders ;
46+ import org .springframework .http .HttpStatus ;
4647import org .springframework .http .HttpStatusCode ;
4748import org .springframework .http .MediaType ;
4849import org .springframework .http .codec .ServerSentEvent ;
6162import org .springframework .web .reactive .accept .RequestedContentTypeResolver ;
6263import org .springframework .web .reactive .result .HandlerResultHandlerSupport ;
6364import org .springframework .web .server .NotAcceptableStatusException ;
65+ import org .springframework .web .server .ResponseStatusException ;
6466import org .springframework .web .server .ServerWebExchange ;
6567
6668/**
8991 * presence of annotations, for example, for {@code @ResponseBody}.
9092 *
9193 * @author Rossen Stoyanchev
94+ * @author Sebastien Deleuze
9295 * @since 5.0
9396 */
9497public class ViewResolutionResultHandler extends HandlerResultHandlerSupport implements HandlerResultHandler , Ordered {
@@ -256,65 +259,70 @@ public Mono<Void> handleResult(ServerWebExchange exchange, HandlerResult result)
256259 clazz = FragmentsRendering .class ;
257260 }
258261
259- if (returnValue == NO_VALUE || ClassUtils .isVoidType (clazz )) {
260- viewsMono = resolveViews (getDefaultViewName (exchange ), locale );
261- }
262- else if (CharSequence .class .isAssignableFrom (clazz ) && !hasModelAnnotation (parameter )) {
263- viewsMono = resolveViews (returnValue .toString (), locale );
264- }
265- else if (Rendering .class .isAssignableFrom (clazz )) {
266- Rendering render = (Rendering ) returnValue ;
267- HttpStatusCode status = render .status ();
268- if (status != null ) {
269- exchange .getResponse ().setStatusCode (status );
262+ try {
263+ if (returnValue == NO_VALUE || ClassUtils .isVoidType (clazz )) {
264+ viewsMono = resolveViews (getDefaultViewName (exchange ), locale );
270265 }
271- exchange .getResponse ().getHeaders ().putAll (render .headers ());
272- model .addAllAttributes (render .modelAttributes ());
273- Object view = render .view ();
274- if (view == null ) {
275- view = getDefaultViewName (exchange );
266+ else if (CharSequence .class .isAssignableFrom (clazz ) && !hasModelAnnotation (parameter )) {
267+ viewsMono = resolveViews (returnValue .toString (), locale );
276268 }
277- viewsMono = (view instanceof String viewName ? resolveViews (viewName , locale ) :
278- Mono .just (Collections .singletonList ((View ) view )));
279- }
280- else if (FragmentsRendering .class .isAssignableFrom (clazz )) {
281- ServerHttpResponse response = exchange .getResponse ();
282- FragmentsRendering render = (FragmentsRendering ) returnValue ;
283- HttpStatusCode status = render .status ();
284- if (status != null ) {
285- response .setStatusCode (status );
269+ else if (Rendering .class .isAssignableFrom (clazz )) {
270+ Rendering render = (Rendering ) returnValue ;
271+ HttpStatusCode status = render .status ();
272+ if (status != null ) {
273+ exchange .getResponse ().setStatusCode (status );
274+ }
275+ exchange .getResponse ().getHeaders ().putAll (render .headers ());
276+ model .addAllAttributes (render .modelAttributes ());
277+ Object view = render .view ();
278+ if (view == null ) {
279+ view = getDefaultViewName (exchange );
280+ }
281+ viewsMono = (view instanceof String viewName ? resolveViews (viewName , locale ) :
282+ Mono .just (Collections .singletonList ((View ) view )));
286283 }
287- response .getHeaders ().putAll (render .headers ());
288- bindingContext .updateModel (exchange );
289-
290- StreamHandler streamHandler =
291- (this .sseHandler .supports (exchange .getRequest ()) ? this .sseHandler : null );
292-
293- if (streamHandler != null ) {
294- streamHandler .updateResponse (exchange );
284+ else if (FragmentsRendering .class .isAssignableFrom (clazz )) {
285+ ServerHttpResponse response = exchange .getResponse ();
286+ FragmentsRendering render = (FragmentsRendering ) returnValue ;
287+ HttpStatusCode status = render .status ();
288+ if (status != null ) {
289+ response .setStatusCode (status );
290+ }
291+ response .getHeaders ().putAll (render .headers ());
292+ bindingContext .updateModel (exchange );
293+
294+ StreamHandler streamHandler =
295+ (this .sseHandler .supports (exchange .getRequest ()) ? this .sseHandler : null );
296+
297+ if (streamHandler != null ) {
298+ streamHandler .updateResponse (exchange );
299+ }
300+
301+ Flux <Flux <DataBuffer >> renderFlux = render .fragments ()
302+ .concatMap (fragment -> renderFragment (fragment , null , streamHandler , locale , bindingContext , exchange ))
303+ .doOnDiscard (DataBuffer .class , DataBufferUtils ::release );
304+
305+ return response .writeAndFlushWith (renderFlux );
306+ }
307+ else if (Model .class .isAssignableFrom (clazz )) {
308+ model .addAllAttributes (((Model ) returnValue ).asMap ());
309+ viewsMono = resolveViews (getDefaultViewName (exchange ), locale );
310+ }
311+ else if (Map .class .isAssignableFrom (clazz ) && !hasModelAnnotation (parameter )) {
312+ model .addAllAttributes ((Map <String , ?>) returnValue );
313+ viewsMono = resolveViews (getDefaultViewName (exchange ), locale );
314+ }
315+ else if (View .class .isAssignableFrom (clazz )) {
316+ viewsMono = Mono .just (Collections .singletonList ((View ) returnValue ));
317+ }
318+ else {
319+ String name = getNameForReturnValue (parameter );
320+ model .addAttribute (name , returnValue );
321+ viewsMono = resolveViews (getDefaultViewName (exchange ), locale );
295322 }
296-
297- Flux <Flux <DataBuffer >> renderFlux = render .fragments ()
298- .concatMap (fragment -> renderFragment (fragment , null , streamHandler , locale , bindingContext , exchange ))
299- .doOnDiscard (DataBuffer .class , DataBufferUtils ::release );
300-
301- return response .writeAndFlushWith (renderFlux );
302- }
303- else if (Model .class .isAssignableFrom (clazz )) {
304- model .addAllAttributes (((Model ) returnValue ).asMap ());
305- viewsMono = resolveViews (getDefaultViewName (exchange ), locale );
306- }
307- else if (Map .class .isAssignableFrom (clazz ) && !hasModelAnnotation (parameter )) {
308- model .addAllAttributes ((Map <String , ?>) returnValue );
309- viewsMono = resolveViews (getDefaultViewName (exchange ), locale );
310- }
311- else if (View .class .isAssignableFrom (clazz )) {
312- viewsMono = Mono .just (Collections .singletonList ((View ) returnValue ));
313323 }
314- else {
315- String name = getNameForReturnValue (parameter );
316- model .addAttribute (name , returnValue );
317- viewsMono = resolveViews (getDefaultViewName (exchange ), locale );
324+ catch (ResponseStatusException ex ) {
325+ return Mono .error (ex );
318326 }
319327 bindingContext .updateModel (exchange );
320328 return viewsMono .flatMap (views -> render (views , model .asMap (), null , bindingContext , exchange ));
@@ -324,12 +332,16 @@ else if (View.class.isAssignableFrom(clazz)) {
324332 /**
325333 * Select a default view name when a controller did not specify it.
326334 * Use the request path the leading and trailing slash stripped.
335+ * @throws ResponseStatusException with a 400 error code if the path contains a "redirect:" prefix
327336 */
328337 private String getDefaultViewName (ServerWebExchange exchange ) {
329338 String path = exchange .getRequest ().getPath ().pathWithinApplication ().value ();
330339 if (path .startsWith ("/" )) {
331340 path = path .substring (1 );
332341 }
342+ if (path .startsWith (UrlBasedViewResolver .REDIRECT_URL_PREFIX )) {
343+ throw new ResponseStatusException (HttpStatus .BAD_REQUEST , "Rejected path '" + path + "' with 'redirect:' prefix" );
344+ }
333345 if (path .endsWith ("/" )) {
334346 path = path .substring (0 , path .length () - 1 );
335347 }
0 commit comments