scala - EssentialAction: How to Get the Body of a Request without Parsing It -
given following essentialaction...
object mycontroller extends controller { ... def hastoken(action: token => essentialaction) = essentialaction { request => ... // doesn't compile val body = request.body match { case json: jsvalue => json.tostring case _ => "" } // calculate hash body content here ... } // here authenticated action def getuser(userid: strign) = hastoken { token => action(parse.json) { request => request.body.validate[user] match { ... } } } } ... how body of request without parsing it?
i don't want , don't need parse request body in hastoken since body going parsed in action getuser. need raw content of body calculate hash.
the code in hastoken doesn't compile because request of type requestheader whereas need request, defines body.
will work ?
object mycontroller extends controller { // hastoken action def authenticate(action: token => essentialaction) = essentialaction { requestheader => // ... execute logic verify authenticity using requestheader } // action validate tampering of request body , validity of json def validate[a](action: token => request[a]) = action(parse.json) { request => val body = request.body body match { case json: jsvalue => json.tostring case _ => "" } // calculate hash body content here body.validate[user] match { // ... } } def getuser(userid: strign) = authenticate { token => validate { user => //.... continue } } } - authentication uses requestheader
- validation uses request body. (bonus: body parsed once)
edit:
question #1: don't want validate body in validate... since need generic validation mechanism used everywhere regardless of content type (e.g. user, message, etc.).
how adding type param (so made generic):
def validate[a, b](action: token => request[a])(implicit reads: reads[b]) = action(parse.json) { request => // ... } question #2: furthermore, if token validation fails, body don't have processed (that's important in case of file upload, has performed if , if validation succeeded). that's way, in opinion, best option read raw content of body in validate.
this can achieved:
def validate[a, b](action: token => request[a])(implicit reads: reads[b]) = action(parse.json) { request => val body = request.body body match { case json: jsvalue => json.tostring case _ => "" } // calculate hash body content here , figure out if body tampered if (bodyisnottampered) { body.validate[b] match { // ... } } else { // log , return future.successful(badrequest) } } edit 3: full solution:
import play.api.libs.json.{json, jsvalue, format} object compilationutils { class token case class user(name: string) implicit val userformat = json.format[user] def authenticate = new token // authentication logic def istampered(body: jsvalue) = { val bodyasstr: string = json.stringify(body) // calculate hash body content here false } } object mycontroller extends controller { import compilationutils._ // hastoken action def authenticate(action: token => essentialaction) = essentialaction { requestheader => action(authenticate)(requestheader) // execute logic verify authenticity using requestheader } // action validate tampering of request body , validity of json def validate[a, b](request: request[a])(implicit formata: format[a], formatb: format[b]): either[result, b] = { val body = request.body val bodyasjsvalue = json.tojson(body) if (!istampered(bodyasjsvalue)) { bodyasjsvalue.validate[b].fold( valid = res => right(res), invalid = err => left(badrequest(err.tostring)) ) } else { left(badrequest) // request tampered } } def getuser(userid: string) = authenticate { token => action(parse.json) { request => validate(request).fold( badreq => badreq, user => // continue... ok("") ) } } }
Comments
Post a Comment