Documentation

You are viewing the documentation for the 2.8.20 release in the 2.8.x series of releases. The latest stable release series is 3.0.x.

§Built-in HTTP filters

Play provides several standard filters that can modify the HTTP behavior of your application. You can also write your own filters in either Java or Scala.

§Default Filters

Play now comes with a default set of enabled filters, defined through configuration. If the property play.http.filters is null, then the default is now play.api.http.EnabledFilters, which loads up the filters defined by fully qualified class name in the play.filters.enabled configuration property.

In Play itself, play.filters.enabled is an empty list. However, the filters library is automatically loaded in sbt as an AutoPlugin called PlayFilters, and will append the following values to the play.filters.enabled property:

This means that on new projects, CSRF protection (ScalaCsrf / JavaCsrf), SecurityHeaders and AllowedHostsFilter are all defined automatically.

To append to the defaults list, use the +=:

play.filters.enabled+=MyFilter

If you have previously defined your own filters by extending play.api.http.DefaultHttpFilters, then you can also combine EnabledFilters with your own filters in code:

Java
import java.util.ArrayList;
import java.util.List;
import javax.inject.Inject;
import play.api.http.EnabledFilters;
import play.filters.cors.CORSFilter;
import play.http.DefaultHttpFilters;
import play.mvc.EssentialFilter;

public class Filters extends DefaultHttpFilters {

  @Inject
  public Filters(EnabledFilters enabledFilters, CORSFilter corsFilter) {
    super(combine(enabledFilters.asJava().getFilters(), corsFilter.asJava()));
  }

  private static List<EssentialFilter> combine(
      List<EssentialFilter> filters, EssentialFilter toAppend) {
    List<EssentialFilter> combinedFilters = new ArrayList<>(filters);
    combinedFilters.add(toAppend);
    return combinedFilters;
  }
}
Scala
import javax.inject.Inject

import play.filters.cors.CORSFilter
import play.api.http.DefaultHttpFilters
import play.api.http.EnabledFilters

class Filters @Inject() (enabledFilters: EnabledFilters, corsFilter: CORSFilter)
    extends DefaultHttpFilters(enabledFilters.filters :+ corsFilter: _*)

Otherwise, if you have a Filters class in the root or have play.http.filters defined explicitly, it will take precedence over the EnabledFilters functionality described below.

§Testing Default Filters

Because there are several filters enabled, functional tests may need to change slightly to ensure that all the tests pass and requests are valid. For example, a request that does not have a Host HTTP header set to localhost will not pass the AllowedHostsFilter and will return a 400 Forbidden response instead.

§Testing with AllowedHostsFilter

Because the AllowedHostsFilter filter is added automatically, functional tests need to have the Host HTTP header added.

If you are using FakeRequest or Helpers.fakeRequest, then the Host HTTP header is added for you automatically. If you are using play.mvc.Http.RequestBuilder, then you may need to add your own line to add the header manually:

Http.RequestBuilder request =
    new Http.RequestBuilder()
        .method(GET)
        .header(Http.HeaderNames.HOST, "localhost")
        .uri("/xx/Kiwi");

§Testing with CSRFFilter

Because the CSRFFilter filter is added automatically, tests that render a Twirl template that includes CSRF.formField, i.e.

@(userForm: Form[UserData])(implicit request: RequestHeader, m: Messages)

<h1>user form</h1>

@request.flash.get("success").getOrElse("")

@helper.form(action = routes.UserController.userPost()) {
  @helper.CSRF.formField
  @helper.inputText(userForm("name"))
  @helper.inputText(userForm("age"))
  <input type="submit" value="submit"/>
}

must contain a CSRF token in the request. In the Scala API, this is done by importing play.api.test.CSRFTokenHelper._, which enriches play.api.test.FakeRequest with the withCSRFToken method:

import org.specs2.mutable.Specification
import play.api.inject.guice.GuiceApplicationBuilder
import play.api.test.CSRFTokenHelper._
import play.api.test.Helpers._
import play.api.test.FakeRequest
import play.api.test.WithApplication

class UserControllerSpec extends Specification {
  "UserController GET" should {
    "render the index page from the application" in new WithApplication() {
      val controller = app.injector.instanceOf[UserController]
      val request    = FakeRequest().withCSRFToken
      val result     = controller.userGet().apply(request)

      status(result) must beEqualTo(OK)
      contentType(result) must beSome("text/html")
    }
  }
}

In the Java API, this is done by calling CSRFTokenHelper.addCSRFToken on a play.mvc.Http.RequestBuilder instance:

Http.RequestBuilder request = new Http.RequestBuilder().method(POST).uri("/xx/Kiwi");

request = CSRFTokenHelper.addCSRFToken(request);

§Disabling Default Filters

The simplest way to disable a filter is to add it to the play.filters.disabled list in application.conf:

play.filters.disabled+=play.filters.hosts.AllowedHostsFilter

This may be useful if you have functional tests that you do not want to go through the default filters.

To remove the default filters, you can set the entire list manually:

play.filters.enabled=[]

If you want to remove all filter classes, you can disable it through the disablePlugins mechanism:

lazy val root = project.in(file(".")).enablePlugins(PlayScala).disablePlugins(PlayFilters)

If you are writing functional tests involving GuiceApplicationBuilder, then you can disable all filters in a test by calling configure:

class UserControllerWithoutFiltersSpec extends Specification {
  "UserControllerWithoutFiltersSpec GET" should {
    "render the index page from the application" in new WithApplication(
      GuiceApplicationBuilder().configure("play.http.filters" -> "play.api.http.NoHttpFilters").build()
    ) {
      val controller = app.injector.instanceOf[UserController]
      val request    = FakeRequest().withCSRFToken
      val result     = controller.userGet().apply(request)

      status(result) must beEqualTo(OK)
      contentType(result) must beSome("text/html")
    }
  }
}

§Compile Time Default Filters

If you are using compile time dependency injection, then the default filters are resolved at compile time, rather than through runtime.

This means that the play.api.BuiltInComponents trait (for Scala) and play.BuiltInComponents interface (for Java) now contains an httpFilters method which is left abstract. The default list of filters is defined in play.filters.HttpFiltersComponents for Scala and play.filters.components.HttpFiltersComponents for Java. So, for most cases you will want to mixin HttpFiltersComponents and append your own filters:

Java
import play.ApplicationLoader;
import play.BuiltInComponentsFromContext;
import play.filters.components.HttpFiltersComponents;
import play.mvc.EssentialFilter;
import play.routing.Router;

import java.util.ArrayList;
import java.util.List;

public class MyAppComponents extends BuiltInComponentsFromContext implements HttpFiltersComponents {

  public MyAppComponents(ApplicationLoader.Context context) {
    super(context);
  }

  @Override
  public List<EssentialFilter> httpFilters() {
    List<EssentialFilter> combinedFilters =
        new ArrayList<>(HttpFiltersComponents.super.httpFilters());
    combinedFilters.add(new LoggingFilter(materializer()));
    return combinedFilters;
  }

  @Override
  public Router router() {
    return Router.empty(); // implement the router as needed
  }
}
Scala
import akka.util.ByteString
import play.api.ApplicationLoader
import play.api.BuiltInComponentsFromContext
import play.api.NoHttpFiltersComponents
import play.api.libs.streams.Accumulator
import play.api.mvc.EssentialAction
import play.api.mvc.EssentialFilter
import play.api.mvc.RequestHeader
import play.api.mvc.Result
import play.api.routing.Router
import play.filters.csrf.CSRFFilter

class MyAppComponents(context: ApplicationLoader.Context)
    extends BuiltInComponentsFromContext(context)
    with play.filters.HttpFiltersComponents {
  lazy val loggingFilter = new LoggingFilter()

  override def httpFilters: Seq[EssentialFilter] = {
    super.httpFilters :+ loggingFilter
  }

  override def router: Router = Router.empty // implement the router as needed
}

If you want to filter elements out of the list, you can do the following:

Java
public class MyAppComponents extends BuiltInComponentsFromContext implements HttpFiltersComponents {

  public MyAppComponents(ApplicationLoader.Context context) {
    super(context);
  }

  @Override
  public List<EssentialFilter> httpFilters() {
    return HttpFiltersComponents.super.httpFilters().stream()
        .filter(filter -> !filter.getClass().equals(CSRFFilter.class))
        .collect(Collectors.toList());
  }

  @Override
  public Router router() {
    return Router.empty(); // implement the router as needed
  }
}
Scala
class MyAppComponents(context: ApplicationLoader.Context)
    extends BuiltInComponentsFromContext(context)
    with play.filters.HttpFiltersComponents {
  override def httpFilters: Seq[EssentialFilter] = {
    super.httpFilters.filterNot(_.getClass == classOf[CSRFFilter])
  }

  override def router: Router = Router.empty // implement the router as needed
}

§Disabling Compile Time Default Filters

To disable the default filters, mix in play.api.NoHttpFiltersComponents for Scala and play.filters.components.NoHttpFiltersComponents for Java:

Java
public class MyAppComponents extends BuiltInComponentsFromContext
    implements NoHttpFiltersComponents {

  public MyAppComponents(ApplicationLoader.Context context) {
    super(context);
  }

  // no need to override httpFilters method

  @Override
  public Router router() {
    return Router.empty(); // implement the router as needed
  }
}
Scala
class MyAppComponents(context: ApplicationLoader.Context)
    extends BuiltInComponentsFromContext(context)
    with NoHttpFiltersComponents {
  override def router: Router = Router.empty // implement the router as needed
}

Both Scala play.api.NoHttpFiltersComponents and play.filters.components.NoHttpFiltersComponents have httpFilters method which returns an empty list of filters.

Next: Configuring gzip encoding