parsing - Custom multipartFormData parser in play2 scala to handle multiple encodings on dataparts -
i'm trying implement custom multipartformdata data parser handle callback sendgrid api. callback multipart request dataparts encoded in different encodings: eg utf-8
or iso-8859-1
.
sendgrid provides charsets field json object explains encoding each field have:
{"to":"utf-8","html":"iso-8859-1","subject":"utf-8","from":"utf-8","text":"iso-8859-1"}
i extract charsets dataparts this:
val charsets = extract(request.body.dataparts, "charsets", _.as[charsets]).getorelse(charsets(some(""), some(""), some(""), some(""), some(""))) def extract[t](env: map[string, seq[string]], key: string, conv: jsvalue => t): option[t] = { env.get(key).flatmap(_.headoption).map(json.parse).map(conv) } case class charsets(to: option[string], html: option[string], subject: option[string], from: option[string], text: option[string]) object charsets { implicit val charsetreads = json.format[charsets] }
but wont work since might have wrong encoding set parser.
the original handledatapart
hardcoded use utf-8
def handledatapart: parthandler[part] = { case headers @ multipart.partinfomatcher(partname) if !multipart.fileinfomatcher.unapply(headers).isdefined => traversable.takeupto[array[byte]](default_max_text_length) .transform(iteratee.consume[array[byte]]().map(bytes => datapart(partname, new string(bytes, "utf-8")))) .flatmap { data => cont({ case input.el(_) => done(maxdatapartsizeexceeded(partname), input.empty) case in => done(data, in) }) } }
so begin extract charsets object , use when creating dataparts or instead of creating string each field, create array[byte] , in controller handle creation of strings. maybe there other way? how solve this? feel stuck , need guidance.
got answer buddy tor! works charm!
class parser @inject()(mailrequestservice: mailrequestservice, surveyservice: surveyservice) extends controller { val utf8 = "utf-8" def parsemail = action.async(rawformdata) { request => val charsets = extract(request.body.dataparts, "charsets", _.as[charsets]).getorelse(charsets(some(""), some(""), some(""), some(""), some(""))) val envelope = extract(request.body.dataparts, "envelope", _.as[envelope]).getorelse(envelope(nil, "")) val sendgrid = sendgridmail( extractstring(request.body.dataparts, "text", charsets), extractstring(request.body.dataparts, "html", charsets), extractstring(request.body.dataparts, "from", charsets), extractstring(request.body.dataparts, "to", charsets), charsets, envelope ) val simple = mailrequestservice.createnewmail(sendgrid).map { result => result.fold( exception => throw new unexpectedserviceexception("could not save sendgrid mail: "+sendgrid, exception), mail => ok("success") ) } simple } def extractstring(data: map[string, seq[array[byte]]], key: string, charsets: charsets): option[string] = { play.logger.info("data = " + data) data.get(key).flatmap(_.headoption).map { firstvalue => (charsets, key) match { case (charset, "text") if charset.text.isdefined => val cset = java.nio.charset.charset.forname(charset.text.get) some(new string(firstvalue, cset)) case (charset, "html") if charset.html.isdefined => val cset = java.nio.charset.charset.forname(charset.html.get) some(new string(firstvalue, cset)) case (charset, "from") if charset.from.isdefined => val cset = java.nio.charset.charset.forname(charset.from.get) some(new string(firstvalue, cset)) case (charset, "to") if charset.to.isdefined => val cset = java.nio.charset.charset.forname(charset.to.get) some(new string(firstvalue, cset)) case _ => some("") } }.getorelse(some("")) } /** * 1. retrieve value key eg. envelope * 2. use flatmap flatten structure not option[option[_] ] * 3. call map , use jsonparse on string jsvalue * 4. call map , use provided method eg _.as[envelope] results in t, in case envelope * 5. return! */ def extract[t](env: map[string, seq[array[byte]]], key: string, conv: jsvalue => t): option[t] = { env.get(key).flatmap(_.headoption.map(a => new string(a, "utf-8"))).map(json.parse).map(conv) } def findsurveybyemail(email: string): future[option[survey]] = { surveyservice.findsurveybyemail(email) } def handler: parse.multipart.parthandler[part] = { case headers @ partinfomatcher(partname) if !fileinfomatcher.unapply(headers).isdefined => traversable.takeupto[array[byte]](1024 * 100) .transform(iteratee.consume[array[byte]]().map(bytes => filepart(partname, "", none, bytes))) .flatmap { data => cont({ case input.el(_) => done(data, input.empty) case in => done(data, in) }) } case headers => done(badpart(headers), input.empty) } def rawformdata[a]: bodyparser[rawdataformdata] = bodyparser("multipartformdata") { request => multipart.multipartparser(handler)(request).map { errororparts => errororparts.right.map { parts => val data = parts.collect { case filepart(key, _, _, value: array[byte]) => (key, value) }.groupby(_._1).mapvalues(_.map(_._2)) rawdataformdata(data) } } } } case class rawdataformdata(dataparts: map[string, seq[array[byte]]])
thank tor!
Comments
Post a Comment