How to convert request.body to a byte array in order to calculate MD5? - scala

I'm creating a scala function in a Play! application that authenticates requests to my web-service. The authentication is basically an HMAC authentication. The method receives the type of bodyParser to be used. Since I don't know the type of the -bodyParser, how can I convert request.body to a generic Array[Byte] on which I can run my MD5 processing?
def Authenticated[T](authType : AuthenticationType, bodyParser : BodyParser[T])(f : (Request[T]) => Result) = {
Action(bodyParser) { request =>
// Authentication logic starts here
// TODO: Something like: var bodyData : Array[Byte] = request.body.toByteArray()
// The rest is easy...
var contentMD5 = calculateMD5(bodyDat)
f(request)
}
}

Any request body received by Play can be parsed to a Http.RawBuffer which can give a pure a raw byte array representation of your request body.
The line of code you're looking for is
var bodyData : Array[Byte] = request.body.asRaw.asBytes()

Related

Lagom - Add header to response in service call composition

i want to write code which will refresh cookie (via set-cookie http header) in Lagom.
For clarification Cookie is an encoded string (for example AES).
Lets take lagom service call composition for authentication from Implementing services and edit it
def authenticated[Request, Response](
serviceCall: User => ServerServiceCall[Request, Response]
) = ServerServiceCall.composeAsync { requestHeader =>
//Get cookie from header and decode it
val cookie = decodeCookie(requestHeader)
//Get user based on cookie decode function
val userLookup = getUser(cookie)
userLookup.map {
case Some(user) =>
serviceCall(user)
case None => throw Forbidden("User must be authenticated")
}
}
It is possible to manipulate serviceCall(user) response headers?
I tried something like this:
serviceCall( employee ).handleResponseHeader { case (responseHeader, response) =>
responseHeader.withHeader("Set-Cookie",encodeCookie("NewCookieStringExample")) // Add header
response
}
But function handleResponseHeader requires only response[T] as result and header would not be changed because is immutable.
I know that i can pass cookie to serviceCall(user) and in every service call implementation return tuple with ResponseHeader and Response but this will impact all endpoints and will add much more code.
Use of HeaderFilter is possible too but this would decode and encode cookie twice in one request (in header filter and in authenticated service call composition )
Any tips?
You can return the modified Header and the Response as a Tuple:
serviceCall( employee ).handleResponseHeader((responseHeader, response) => {
val modifiedHeader = responseHeader.withHeader("Set-Cookie",encodeCookie("NewCookieStringExample")) // Add header
(modifiedHeader, response)
})
By the way, The provided example does not compile for me. composeAsync wants a Future[ServerServiceCall[...]].

Gatling request body as bytearray

val scn = scenario("gatling test").
feed(circularfeeder.circular)
.exec(http("request")
.post(endpoint)
.header("Content-Type", "application/json")
.header("Accept-Encoding", "charset=UTF-8")
.body(StringBody("""${request}"""))
.check(status.is(200))
The above code is used to send every circularfeeder data as a string to the body of the request. Suppose if i want to send as byte array instead of string in the body how do I modify the line .body(StringBody("""${request}"""))
The code .body(ByteArrayBody(getBytesData("""${request}"""))) does not work. Any advise?
Option 1
Call getBytes method on request string and pass that to ByteArrayBody
.body(ByteArrayBody { session =>
session("request")
.validate[String]
.map(s => s.getBytes(StandardCharsets.UTF_8))
})
Option 2
Convert the raw data you got from your feeder.
val circularfeeder = csv("myFile.csv").convert {
case ("request", string) => string.getBytes(StandardCharsets.UTF_8)
}
...
.body(ByteArrayBody("${request}"))

How to send a POST request with Content-Type "application/x-www-form-urlencoded"

I am trying to send a POST request from my TornadoFX application to my nodejs server.
That's how i send my request to the server:
val api: Rest by inject()
api.baseURI = "http://localhost:5000/"
api.post("api/register", userModel) {
it.addHeader("Content-Type", "application/x-www-form-urlencoded")
}
My UserModel looks like this:
class UserModel : JsonModel {
val nameProperty = SimpleStringProperty("")
var name by nameProperty
val emailProperty = SimpleStringProperty("")
var email by emailProperty
override fun toJSON(json: JsonBuilder) {
with(json) {
add("name", name)
add("email", email)
}
}
}
Printing the request body on my node server i get following:
[Object: null prototype] {
'{"name":"Test","email":"test#test.org"}': ''
}
When i send a request via Postman i get the following body:
[Object: null prototype] {
name: 'Test',
email: 'test#test.org'
}
And that's what i'm trying to produce with TornadoFX without success.
I am grateful for any help!
You are correctly setting the Content-Type header, but you're pushing a JsonModel as your data, and consequently the framework will convert it to a JSON structure by calling toJSON() on it. The application/x-www-form-urlencoded content type expects an URL encoded piece of data, so you need to convert your data into an url encoded string. I suggest adding a function to your domain model like this:
fun toURLEncoded() =
"name=${name.urlEncoded}&email=${email.urlEncoded}".byteInputStream(StandardCharsets.UTF_8)
This example uses an extension function called urlEncoded to avoid clutter. You can define that extension function like this for example:
fun Any.urlEncoded(): String = URLEncoder.encode(toString(), "UTF-8")
Now you just have to call api.post("api/register", userModel.toURLEncoded()) and you should be good to go.

How to read query parameters in akka-http?

I know akka-http libraries marshal and unmarshal to class type while processing request.But now, I need to read request-parameters of GET request. I tried parameter() method and It is returning ParamDefAux type but i need those values as strings types
I check for answer at below questions.
How can I parse out get request parameters in spray-routing?
Query parameters for GET requests using Akka HTTP (formally known as Spray)
but can't do what i need.
Please tell me how can i extract query parameters from request. OR How can I extract required value from ParamDefAux
Request URL
http://host:port/path?key=authType&value=Basic345
Get method definition
val propName = parameter("key")
val propValue = parameter("value")
complete(persistanceMgr.deleteSetting(propName,propValue))
My method declarations
def deleteSetting(name:String,value:String): Future[String] = Future{
code...
}
For a request like http://host:port/path?key=authType&value=Basic345 try
path("path") {
get {
parameters('key.as[String], 'value.as[String]) { (key, value) =>
complete {
someFunction(key,value)
}
}
}
}
Even though being less explicit in the code, you can also extract all the query parameters at once from the context. You can use as follows:
// Previous part of the Akka HTTP routes ...
extract(_.request.uri.query()) { params =>
complete {
someFunction(key,value)
}
}
If you wish extract query parameters as one piece
extract(ctx => ctx.request.uri.queryString(charset = Charset.defaultCharset)) { queryParams =>
//useyourMethod()
}

Gatling2: Get response body as byte array

I want to send a request and will receive a byte[] body response. Based on this byte[] response I want to extract a value (using protobuf) and the reuse this value in another resquest.
After some hours search, I cannot find a possibility to extract the http response body as a byte array:
val httpConfig = http
.baseURL("http://www.whatever.com")
val request = exec(http("FirstRequest")
.post("/message")
.body(new ByteArrayBody((session: Session) => getFirstRequest(session)))
.check(status.is(200), ???getByteResponse???))
val response = exec(http("SecondRequest")
.post("/message")
.body(new ByteArrayBody((session: Session) => getSecondRequest(session)))
.check(status.is(200), ???getByteResponse???))
val scn = scenario("Request").exec(request,response)
setUp(scn.inject(atOnce(1 user)))
.protocols(httpConfig)
Alternatively it would also be fine if I could set a value in getFirstRequest, that I can reuse in getSecondRequest:
private def getFirstRequest(session: Session): Array[Byte] = {
... setting a session attribute ... (long)
... some protobuf stuff returning a byte array ...
}
private def getSecondRequest(session: Session): Array[Byte] = {
var value= session("value").as[Long]
... some protobuf stuff using value from session and then returning byte array...
}
I think you can try something like this :
.check(status.is(200), bodyBytes.saveAs("responseBody"))
This will save the body of the response in the virtual user's session.