Parse binary response as json, and then check it

Hello,

I have a page that returns a pretty big response body as binary, but when decoded as plain text the response is in JSON format.
I want to transform the response so that it can be traversed as JSON and checked.

For example:

import org.asynchttpclient.util.Base64
import io.gatling.http.response._
import java.nio.charset.StandardCharsets.UTF_8

// ....


val read = exec(http("Get some results")
  .get("/foo?bar=baz") // response is in binary, needs to be transformed to text, which should be parsed as JSON
  .transformResponse { case response if response.isReceived =>
    new ResponseWrapper(response) {
      override val body = new ByteArrayResponseBody(Base64.decode(response.body.string), UTF_8)
    }
  }
  .check(
    jsonPath("$.alpha.beta").exists.saveAs("gamma")
  )
)

But this throws an error:

12:54:39.387 [DEBUG] i.g.h.a.AsyncHandler - Request ‘Get some results’ failed for user 1
java.lang.StringIndexOutOfBoundsException: String index out of range: 102327
at java.lang.String.charAt(String.java:658)
at org.asynchttpclient.util.Base64.decode(Base64.java:125)
at Foo$$anonfun$1$$anon$1.(Foo.scala:41)
at Foo$$anonfun$1.applyOrElse(Foo.scala:40)
at Foo$$anonfun$1.applyOrElse(Foo.scala:39)
at io.gatling.http.response.ResponseBuilder.build(ResponseBuilder.scala:205)
at io.gatling.http.ahc.AsyncHandler.withResponse(AsyncHandler.scala:126)
at io.gatling.http.ahc.AsyncHandler.onCompleted(AsyncHandler.scala:134)
at io.gatling.http.ahc.AsyncHandler.onCompleted(AsyncHandler.scala:47)
at org.asynchttpclient.netty.NettyResponseFuture.getContent(NettyResponseFuture.java:189)
at org.asynchttpclient.netty.NettyResponseFuture.done(NettyResponseFuture.java:223)
at org.asynchttpclient.netty.handler.HttpHandler.finishUpdate(HttpHandler.java:58)
at org.asynchttpclient.netty.handler.HttpHandler.handleChunk(HttpHandler.java:159)
at org.asynchttpclient.netty.handler.HttpHandler.handleRead(HttpHandler.java:187)
at org.asynchttpclient.netty.handler.AsyncHttpClientHandler.channelRead(AsyncHttpClientHandler.java:76)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:357)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:343)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:336)
at io.netty.channel.ChannelInboundHandlerAdapter.channelRead(ChannelInboundHandlerAdapter.java:86)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:357)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:343)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:336)
at io.netty.handler.codec.MessageToMessageDecoder.channelRead(MessageToMessageDecoder.java:102)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:357)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:343)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:336)
at io.netty.channel.CombinedChannelDuplexHandler$DelegatingChannelHandlerContext.fireChannelRead(CombinedChannelDuplexHandler.java:435)
at io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:293)
at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:267)
at io.netty.channel.CombinedChannelDuplexHandler.channelRead(CombinedChannelDuplexHandler.java:250)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:357)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:343)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:336)
at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1294)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:357)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:343)
at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:911)
at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:131)
at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:643)
at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:566)
at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:480)
at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:442)
at io.netty.util.concurrent.SingleThreadEventExecutor$2.run(SingleThreadEventExecutor.java:131)
at io.netty.util.concurrent.DefaultThreadFactory$DefaultRunnableDecorator.run(DefaultThreadFactory.java:144)
at java.lang.Thread.run(Thread.java:748)
12:54:39.389 [WARN ] i.g.h.a.ResponseProcessor - Request ‘Get some results’ failed: j.l.StringIndexOutOfBoundsException: String index out of range: 102327
12:54:39.399 [TRACE] i.g.h.a.ResponseProcessor -

Is this an intended purpose for transformResponse? Am I doing this incorrectly?

Thanks kindly!

  • Jay

Is there something I can provide that will encourage you to help me?

I’d like to provide an actionable reproducer but that’s just not really possible here.

A “that’s not what this is intended for” or something else would be fine.

Thanks!

Providing a sample of the String you’re trying to decode and the Base64 variant (yes, there isn’t one single Base64, there are variants, the one from AHC might not match the one you’ve used to encode) you’ve used to encode would sure help.