Sahil0shrma
07/29/2024, 10:19 AMoverride fun install(
plugin: InterceptorPlugin,
scope: HttpClient,
) {
scope.requestPipeline.intercept(HttpRequestPipeline.Transform) { request ->
userInterceptors.forEach {
it.interceptor.encryptContent(this, request)
}
}
scope.responsePipeline.intercept(HttpResponsePipeline.Receive) { (_, _) ->
userResponseInterceptors.forEach {
it.decrypt(this, plugin)
}
}
}
For end to end encryption, I am using "HttpRequestPipeline.Transform" and ecrypting the request and for decryption i am using "HttpResponsePipeline.Receive"
it is working fine when api succeeds.
The problem I’m encountering is that for every API success, HttpResponsePipeline.Receive is called once, but for every failure, it gets called twice. when this pipeline is called second time then it has empty response and it caused exception because body is already consumed.
Has anyone experienced a similar issue or have any insights on why this might be happening?Aleksei Tirman [JB]
07/29/2024, 10:34 AMSahil0shrma
07/29/2024, 10:34 AMSahil0shrma
07/29/2024, 10:41 AMclass ResponseDecryptionInterceptor : ApiResponseInterceptor {
override suspend fun decrypt(
response: PipelineContext<HttpResponseContainer, HttpClientCall>,
plugin: InterceptorPlugin
) {
val (type, content) = response.subject
val method = response.context.request.method
val status = response.context.response.status.value
val contentLength = response.context.response.contentLength()
if (contentLength == 0L) return@intercept
if (contentLength == null && method == HttpMethod.Head) return@intercept
if (content !is ByteReadChannel) return@intercept
val decryptedResponse = decryptContent(response)
val newResponse = with(plugin) {
if (response.context.response.status.isSuccess()) {
HttpResponseContainer(type, decryptedResponse)
}else{
HttpResponseContainer(type, DbxpMultiPartUtils.convertByteArrayToInput(decryptedResponse.toByteArray()))
}
}
}
@OptIn(InternalAPI::class)
private suspend fun decryptContent(pipelineContext: PipelineContext<HttpResponseContainer, HttpClientCall>): String {
pipelineContext.context.request.url.toString().contains("<http://10.0.2.2:8082>").not()) {
val jsonResponseString = pipelineContext.context.response.content.readUTF8Line().orEmpty()
val encryptedResponse = jsonResponseString?.fromStringJsonToObject<EncryptedResponse>(ignoreKeysUnknown = true)
val result = encryptedResponse?.let {
EncryptionUtil.decode(it.encryptedResponse)?.let { decoded ->
EncryptionUtil.decrypt(decoded)
}
}
println("decrypted body : $result")
if (!result.isNullOrEmpty()) {
return result
} else {
throw NetworkExceptionHandler.ParseException()
}
}
}
so in 400 case, when first time decrypt method is called, it successfully decrypts the body. after that it is getting called again from responsepipeline and then it throws exception.Aleksei Tirman [JB]
07/29/2024, 11:05 AMexpectedSuccess = true
to make the 400 Bad Request a failure?Sahil0shrma
07/29/2024, 11:07 AMAleksei Tirman [JB]
07/29/2024, 11:13 AMval client = HttpClient(OkHttp) {
expectSuccess = true
}
client.responsePipeline.intercept(HttpResponsePipeline.Receive) { (type, body) ->
proceedWith(HttpResponseContainer(type, body))
println("interceptor") // Called once
}
val response = client.get("<https://httpbin.org/status/400>")
println(response.bodyAsText())