diff --git a/test-suite/src/test/java/io/micronaut/views/model/RedirectFruitsController.java b/test-suite/src/test/java/io/micronaut/views/model/RedirectFruitsController.java new file mode 100644 index 000000000..d2cc25b16 --- /dev/null +++ b/test-suite/src/test/java/io/micronaut/views/model/RedirectFruitsController.java @@ -0,0 +1,68 @@ +/* + * Copyright 2017-2021 original 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 io.micronaut.views.model; + +import io.micronaut.context.annotation.Requires; +import io.micronaut.core.annotation.Introspected; +import io.micronaut.core.util.CollectionUtils; +import io.micronaut.http.HttpResponse; +import io.micronaut.http.annotation.Controller; +import io.micronaut.http.annotation.Get; +import io.micronaut.security.annotation.Secured; +import io.micronaut.security.rules.SecurityRule; +import io.micronaut.views.View; + +import java.net.URI; +import java.util.Collections; +import java.util.Map; + +@Secured(SecurityRule.IS_AUTHENTICATED) +@Requires(property = "spec.name", value = "RedirectModelAndViewSpec") +@Controller +public class RedirectFruitsController { + + @View("fruits") + @Get + public HttpResponse index() { + return HttpResponse.ok(new Fruit("apple", "red")); + } + + @View("fruits") + @Get("/redirect") + public HttpResponse redirect() { + return HttpResponse.redirect(URI.create("/")); + } + + @Introspected + public static class Fruit { + private final String name; + private final String color; + + public Fruit(String name, String color) { + this.name = name; + this.color = color; + } + + public String getName() { + return name; + } + + public String getColor() { + return color; + } + } +} diff --git a/test-suite/src/test/java/views/RedirectModelAndViewTest.java b/test-suite/src/test/java/views/RedirectModelAndViewTest.java new file mode 100644 index 000000000..7a6b9e4c6 --- /dev/null +++ b/test-suite/src/test/java/views/RedirectModelAndViewTest.java @@ -0,0 +1,76 @@ +/* + * Copyright 2017-2021 original 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 views; + +import io.micronaut.context.ApplicationContext; +import io.micronaut.core.util.CollectionUtils; +import io.micronaut.core.util.StringUtils; +import io.micronaut.http.HttpRequest; +import io.micronaut.http.HttpResponse; +import io.micronaut.http.HttpStatus; +import io.micronaut.http.client.BlockingHttpClient; +import io.micronaut.http.client.DefaultHttpClientConfiguration; +import io.micronaut.http.client.HttpClient; +import io.micronaut.http.client.HttpClientConfiguration; +import io.micronaut.runtime.server.EmbeddedServer; +import io.micronaut.views.model.RedirectFruitsController; +import io.micronaut.views.model.UnmodifiableFruitsController; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +// Issue: https://github.com/micronaut-projects/micronaut-views/issues/360 +class RedirectModelAndViewTest { + + @Test + void aRedirectingResponseIsPassedThrough() { + EmbeddedServer embeddedServer = ApplicationContext.run(EmbeddedServer.class, CollectionUtils.mapOf( + "spec.name", "RedirectModelAndViewSpec", + "micronaut.views.soy.enabled", StringUtils.FALSE)); + + DefaultHttpClientConfiguration configuration = new DefaultHttpClientConfiguration(); + configuration.setFollowRedirects(false); + HttpClient httpClient = HttpClient.create(embeddedServer.getURL(), configuration); + + //given: + BlockingHttpClient client = httpClient.toBlocking(); + //expect: + assertTrue(embeddedServer.getApplicationContext().containsBean(RedirectFruitsController.class)); + + //when: + HttpRequest request = HttpRequest.GET("/redirect").basicAuth("john", "secret"); + HttpResponse response = client.exchange(request, String.class); + + //then: + assertEquals(HttpStatus.MOVED_PERMANENTLY, response.status()); + + //when: + String html = response.body(); + + //then: + assertNull(html); + + //cleanup: + httpClient.close(); + + //and: + embeddedServer.close(); + } + +} diff --git a/views-core/src/main/java/io/micronaut/views/ViewsFilter.java b/views-core/src/main/java/io/micronaut/views/ViewsFilter.java index db5590fd1..0e46d5e7f 100644 --- a/views-core/src/main/java/io/micronaut/views/ViewsFilter.java +++ b/views-core/src/main/java/io/micronaut/views/ViewsFilter.java @@ -20,11 +20,12 @@ import io.micronaut.core.annotation.NonNull; import io.micronaut.core.annotation.Nullable; import io.micronaut.core.io.Writable; +import io.micronaut.http.HttpStatus; +import io.micronaut.http.MediaType; +import io.micronaut.http.MutableHttpResponse; import io.micronaut.http.HttpAttributes; import io.micronaut.http.HttpRequest; import io.micronaut.http.HttpResponse; -import io.micronaut.http.MediaType; -import io.micronaut.http.MutableHttpResponse; import io.micronaut.http.annotation.Filter; import io.micronaut.http.annotation.Produces; import io.micronaut.http.filter.HttpServerFilter; @@ -146,6 +147,10 @@ public final Publisher> doFilter(HttpRequest request, ServerFilterChain chain) { return Flux.from(chain.proceed(request)) .switchMap(response -> { + if(response.getStatus() == HttpStatus.MOVED_PERMANENTLY) { + LOG.debug("redirect, passing through"); + return Flux.just(response); + } Object body = response.body(); Optional writableOptional = parseTurboStreamWritable(request, response, body); if (writableOptional.isPresent()) {