Skip to content

Commit

Permalink
Handle redirects
Browse files Browse the repository at this point in the history
Fixes micronaut-projects#360
Instead of passing a missing body to the view do an early exit if a redirect is encountered.
  • Loading branch information
Brutus5000 committed Mar 4, 2022
1 parent fd47ae9 commit d9f3267
Show file tree
Hide file tree
Showing 3 changed files with 149 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -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<Fruit> index() {
return HttpResponse.ok(new Fruit("apple", "red"));
}

@View("fruits")
@Get("/redirect")
public HttpResponse<Fruit> 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;
}
}
}
76 changes: 76 additions & 0 deletions test-suite/src/test/java/views/RedirectModelAndViewTest.java
Original file line number Diff line number Diff line change
@@ -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<String> 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();
}

}
5 changes: 5 additions & 0 deletions views-core/src/main/java/io/micronaut/views/ViewsFilter.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import io.micronaut.core.annotation.AnnotationMetadata;
import io.micronaut.core.annotation.NonNull;
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;
Expand Down Expand Up @@ -78,6 +79,10 @@ public final Publisher<MutableHttpResponse<?>> 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);
}
Optional<String> optionalView = viewsResolver.resolveView(request, response);
if (!optionalView.isPresent()) {
LOG.debug("no view found");
Expand Down

0 comments on commit d9f3267

Please sign in to comment.