withSizeLimit

Signature

def withSizeLimit(maxBytes: Long): Directive0 

Description

Fails the stream with EntityStreamSizeException if its request entity size exceeds given limit. Limit given as parameter overrides limit configured with pekko.http.parsing.max-content-length.

The whole mechanism of entity size checking is intended to prevent certain Denial-of-Service attacks. So suggested setup is to have pekko.http.parsing.max-content-length relatively low and use withSizeLimit directive for endpoints which expects bigger entities.

See also withoutSizeLimit for skipping request entity size check.

Examples

Scala
sourceval route = withSizeLimit(500) {
  entity(as[String]) { _ =>
    complete(HttpResponse())
  }
}

// tests:
def entityOfSize(size: Int) =
  HttpEntity(ContentTypes.`text/plain(UTF-8)`, List.fill(size)('0').mkString)

Post("/abc", entityOfSize(500)) ~> route ~> check {
  status shouldEqual StatusCodes.OK
}

Post("/abc", entityOfSize(501)) ~> Route.seal(route) ~> check {
  status shouldEqual StatusCodes.ContentTooLarge
}
Java
sourceimport static org.apache.pekko.http.javadsl.server.Directives.complete;
import static org.apache.pekko.http.javadsl.server.Directives.entity;
import static org.apache.pekko.http.javadsl.server.Directives.withSizeLimit;

final Route route =
    withSizeLimit(500, () -> entity(Unmarshaller.entityToString(), (entity) -> complete("ok")));

Function<Integer, HttpRequest> withEntityOfSize =
    (sizeLimit) -> {
      char[] charArray = new char[sizeLimit];
      Arrays.fill(charArray, '0');
      return HttpRequest.POST("/").withEntity(new String(charArray));
    };

// tests:
testRoute(route).run(withEntityOfSize.apply(500)).assertStatusCode(StatusCodes.OK);

testRoute(route)
    .run(withEntityOfSize.apply(501))
    .assertStatusCode(StatusCodes.CONTENT_TOO_LARGE);

Beware that request entity size check is executed when entity is consumed. Therefore in the following example even request with entity greater than argument to withSizeLimit will succeed (because this route does not consume entity):

sourceval route = withSizeLimit(500) {
  complete(HttpResponse())
}

// tests:
def entityOfSize(size: Int) =
  HttpEntity(ContentTypes.`text/plain(UTF-8)`, List.fill(size)('0').mkString)

Post("/abc", entityOfSize(500)) ~> route ~> check {
  status shouldEqual StatusCodes.OK
}

Post("/abc", entityOfSize(501)) ~> route ~> check {
  status shouldEqual StatusCodes.OK
}

Directive withSizeLimit is implemented in terms of HttpEntity.withSizeLimit which means that in case of nested withSizeLimit directives the innermost is applied:

Scala
sourceval route =
  withSizeLimit(500) {
    withSizeLimit(800) {
      entity(as[String]) { _ =>
        complete(HttpResponse())
      }
    }
  }

// tests:
def entityOfSize(size: Int) =
  HttpEntity(ContentTypes.`text/plain(UTF-8)`, List.fill(size)('0').mkString)
Post("/abc", entityOfSize(800)) ~> route ~> check {
  status shouldEqual StatusCodes.OK
}

Post("/abc", entityOfSize(801)) ~> Route.seal(route) ~> check {
  status shouldEqual StatusCodes.ContentTooLarge
}
Java
sourceimport static org.apache.pekko.http.javadsl.server.Directives.complete;
import static org.apache.pekko.http.javadsl.server.Directives.entity;
import static org.apache.pekko.http.javadsl.server.Directives.withSizeLimit;

final Route route =
    withSizeLimit(
        500,
        () ->
            withSizeLimit(
                800, () -> entity(Unmarshaller.entityToString(), (entity) -> complete("ok"))));

Function<Integer, HttpRequest> withEntityOfSize =
    (sizeLimit) -> {
      char[] charArray = new char[sizeLimit];
      Arrays.fill(charArray, '0');
      return HttpRequest.POST("/").withEntity(new String(charArray));
    };

// tests:
testRoute(route).run(withEntityOfSize.apply(800)).assertStatusCode(StatusCodes.OK);

testRoute(route)
    .run(withEntityOfSize.apply(801))
    .assertStatusCode(StatusCodes.CONTENT_TOO_LARGE);