Wrap requests?

27 views
Skip to first unread message

Scott Stewart

unread,
Jan 9, 2015, 12:33:09 AM1/9/15
to unfilter...@googlegroups.com
Hi, 
I was hoping to use unfiltered to define a servlet filter that adds a value to the request as a cookie or header which could then be used in front of a servlet to gain access to this value. I'd prefer not to use a session to pass the value. I was thinking something like HttpServletRequestWrapper but I don't see how I could do this with a unfiltered.filter.Plan. I searched on variants of 'unfiltered wrap http request' but didn't find a similar scenario. Does anyone know if something like this is possible? 
Thanks -Scott

Doug Tangren

unread,
Jan 9, 2015, 8:30:08 AM1/9/15
to unfilter...@googlegroups.com
On Fri, Jan 9, 2015 at 12:33 AM, Scott Stewart <scotts...@gmail.com> wrote:
Hi, 
I was hoping to use unfiltered to define a servlet filter that adds a value to the request as a cookie or header which could then be used in front of a servlet to gain access to this value. I'd prefer not to use a session to pass the value. I was thinking something like HttpServletRequestWrapper but I don't see how I could do this with a unfiltered.filter.Plan. I searched on variants of 'unfiltered wrap http request' but didn't find a similar scenario. Does anyone know if something like this is possible? 

With filter.Plans the main interfaces is a partial function whose input is an unfiltered request that wraps an underlying http servlet request. With the underlying http servlet request you could wrap it in a HttpServletRequestWrapper, extend what you need, then wrap another plan. Below is some pseudo code


def wrap(p: Plan): Plan = Planify {
   case req => 
      val newReq = new HttpServletRequestWrapper(req) {
          ...
      }
      p.intent.lift(newReq).getOrElse(Pass)
}

Http(...).plan(wrap(plan))

 
Thanks -Scott

--
You received this message because you are subscribed to the Google Groups "Unfiltered" group.
To unsubscribe from this group and stop receiving emails from it, send an email to unfiltered-sca...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Scott Stewart

unread,
Jan 12, 2015, 12:44:17 PM1/12/15
to unfilter...@googlegroups.com
Thanks for the reply but req is a unfiltered.request.HttpRequest and can't be wrapped by HttpServletRequestWrapper, right? I'm sure there's some way..

Doug Tangren

unread,
Jan 12, 2015, 1:32:00 PM1/12/15
to unfilter...@googlegroups.com
On Mon, Jan 12, 2015 at 12:44 PM, Scott Stewart <scotts...@gmail.com> wrote:
Thanks for the reply but req is a unfiltered.request.HttpRequest and can't be wrapped by HttpServletRequestWrapper, right? I'm sure there's some way..

Sorry, Try new HttpServletRequestWrapper(req.underlying).

Scott Stewart

unread,
Jan 12, 2015, 2:38:57 PM1/12/15
to unfilter...@googlegroups.com
That works, but Plan.Intent is a Cycle.Intent[HttpServletRequest,HttpServletResponse] which is a PartialFunction[HttpRequest[HttpServletRequest], ResponseFunction[HttpServletResponse]] so lift(..) rejects the newReq. Maybe something like 

p.intent.lift(new RequestBinding(newReq)).getOrElse(Pass), but I'm still trying to wrap my head around how this would work

Scott Stewart

unread,
Jan 14, 2015, 3:35:41 PM1/14/15
to unfilter...@googlegroups.com
Ended up writing my own Plan that takes use of a special ResponseFunction because I wanted to be able to swap out a request within an intent like this:

case class MyPrincipal(user: String) extends Principal { def getName = user; }

def getUser(cookie: String): Option[String] = Some("dummyUser")

val userAuthPlan = new PlanWithRequestSwap {
def intent = {
case req @ Cookies(cookies) => cookies(authCookieName) match {
case Some(Cookie(_,authToken,_,_,_,_,_,_)) => getUser(authToken) match {
case Some(user) =>
println("got user: "+ user)
RequestSwap(new RequestBinding(new HttpServletRequestWrapper(req.underlying) {
override def getUserPrincipal = new MyPrincipal(user)
}))
case _ => Unauthorized
}
case _ => Unauthorized
}
}
}
val userProtectedPlan = Planify {
case req => req.underlying.getUserPrincipal match {
case MyPrincipal(user) => req match {
case Path("/userProtected") => HtmlBody(s"get protected as $user")
}
case x => Unauthorized ~> HtmlBody(s"Unrecognized principal: $x")
}
}

so I ended up with this:

case class RequestSwap(req: RequestBinding) extends ResponseFunction[Any] { def apply[T](res: HttpResponse[T]) = res; }
 
trait PlanWithRequestSwap extends Plan {
override def doFilter(request: ServletRequest,
response: ServletResponse,
chain: FilterChain) {
(request, response) match {
case (hreq: HttpServletRequest, hres: HttpServletResponse) =>
val request = new RequestBinding(hreq)
val response = new ResponseBinding(hres)
 
intent.lift(request) match {
case Some(rf:RequestSwap) => chain.doFilter(rf.req.underlying, response.underlying)
case Some(Pass) | None => chain.doFilter(request.underlying, response.underlying)
case Some(rf) => rf(response).outputStream.close()
}
}
}
}

I can run a server like the following but it will ultimately be exported as a servlet filter in front of more traditional java web apps:

val publicPlan = Planify {
case Path(Seg("setc"::name::value::Nil)) => SetCookies(Cookie(name, value, path=Some("/"))) ~> HtmlBody(s"set $name=$value")
}
unfiltered.jetty.Server.local(9080).plan(publicPlan).plan(userAuthPlan).plan(userProtectedPlan).run()

The full file is https://gist.github.com/scottstewartt/5a0d47d11c8d21dd062b and thanks again for your help and please don't hesitate to point out problems
-Scott

Reply all
Reply to author
Forward
0 new messages