Skip to content

Instantly share code, notes, and snippets.

@brikis98
Last active December 17, 2015 08:48
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save brikis98/5582159 to your computer and use it in GitHub Desktop.
Save brikis98/5582159 to your computer and use it in GitHub Desktop.
object RedirectFilter extends Filter {
def apply(next: RequestHeader => Result)(request: RequestHeader): Result = {
getRedirectParams(request).flatMap { case (newRequest, body) =>
route(newRequest).map { iteratee =>
AsyncResult(Enumerator(body).run(iteratee))
}
} getOrElse {
next(request)
}
}
private def getRedirectParams(request: RequestHeader): Option[(RequestHeader, Array[Byte])] = {
if (someCondition) {
Some(toPostRequest(request), "Some new body data".getBytes("UTF-8"))
} else {
None
}
}
private def toPostRequest(originalRequest: RequestHeader): RequestHeader = {
originalRequest.copy(
uri = "/some/new/uri",
path = "/some/new/uri",
method = "POST"
)
}
private def route(request: RequestHeader): Option[Iteratee[Array[Byte], Result]] = {
Play.global.onRouteRequest(request).collect {
case action: EssentialAction => Play.global.doFilter(action)(request)
}
}
}
@guillaumebort
Copy link

@brikis98 Yes I see, you are right, there is 2 pieces of logic (concerning the Action invocation) applied in the Netty handler directly. For now I don't see how you could solve that. The only way id to do it yourself.

To be sure that the requestHeader is properly tagged, I think you need something like:

Play.global.onRouteRequest(request).collect {
  case action: EssentialAction => Play.global.doFilter(action)(request match {
    case r: RequestTaggingHandler => r.tagRequest(request)
    case _ => request
  })
}

It would probably be better if we could extract this "Action invocation steps" outside of the Netty handler to avoid the repetition and to make it available for plugins and tests. It seems easy, but perhaps there is additional problems I don't see here. You should bring this discussion to the play-framework-dev Google group.

@jroper
Copy link

jroper commented May 22, 2013

Ok, so you want to supply a new body? If you don't want to supply a new body, then the easiest way is to do it in onRouteRequest. But if you want to supply a new body, you could do this in onRouteRequest too, but as a filter, you should use EssentialFilter:

object RedirectFilter extends EssentialFilter {
  def apply(next: EssentialAction) = new EssentialAction {
    def apply(rh: RequestHeader) = {
      getRedirectParams(rh).flatMap { case (newRequest, body) =>
        route(newRequest).map { iteratee =>
          // Ignore the actual body - or you could consume it and transform it somehow.
          Iteratee.ignore[Array[Byte]].mapM { _ =>
            // Feed in the new body to the new action
            Enumerator(body) |>>> iteratee
          }
        }
      } getOrElse {
        next(request)
      }
    }
  }

  // Other methods go here, and like Guillaume pointed out, make sure you tag it
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment