All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.http4k.client.Apache4AsyncClient.kt Maven / Gradle / Ivy

There is a newer version: 5.41.0.0
Show newest version
package org.http4k.client

import org.apache.http.Header
import org.apache.http.HttpResponse
import org.apache.http.StatusLine
import org.apache.http.client.config.CookieSpecs.IGNORE_COOKIES
import org.apache.http.client.config.RequestConfig
import org.apache.http.client.methods.HttpEntityEnclosingRequestBase
import org.apache.http.client.methods.HttpRequestBase
import org.apache.http.concurrent.FutureCallback
import org.apache.http.conn.ConnectTimeoutException
import org.apache.http.entity.ByteArrayEntity
import org.apache.http.entity.InputStreamEntity
import org.apache.http.impl.nio.client.CloseableHttpAsyncClient
import org.apache.http.impl.nio.client.HttpAsyncClients
import org.http4k.core.BodyMode
import org.http4k.core.BodyMode.Memory
import org.http4k.core.BodyMode.Stream
import org.http4k.core.Headers
import org.http4k.core.Request
import org.http4k.core.Response
import org.http4k.core.Status
import org.http4k.core.Status.Companion.CLIENT_TIMEOUT
import org.http4k.core.Status.Companion.SERVICE_UNAVAILABLE
import java.net.SocketTimeoutException
import java.net.URI

object Apache4AsyncClient {
    @JvmStatic
    @JvmOverloads
    @JvmName("create")
    operator fun invoke(
        client: CloseableHttpAsyncClient = defaultApacheAsyncHttpClient(),
        responseBodyMode: BodyMode = Memory,
        requestBodyMode: BodyMode = Memory
    ): AsyncHttpHandler {
        if (!client.isRunning) client.start()

        return object : AsyncHttpHandler {
            override fun close() = client.close()

            override fun invoke(request: Request, fn: (Response) -> Unit) {
                client.execute(request.toApacheRequest(), object : FutureCallback {
                    override fun cancelled() {}

                    override fun completed(result: HttpResponse) = fn(result.toHttp4kResponse())

                    override fun failed(e: Exception) = fn(Response(when (e) {
                        is ConnectTimeoutException -> CLIENT_TIMEOUT
                        is SocketTimeoutException -> CLIENT_TIMEOUT
                        else -> SERVICE_UNAVAILABLE
                    }.toClientStatus(e)))
                })
            }

            private fun HttpResponse.toHttp4kResponse(): Response =
                Response(statusLine.toTarget()).headers(allHeaders.toTarget()).run {
                    entity?.let { body(responseBodyMode(it.content)) } ?: this
                }

            private fun Request.toApacheRequest(): HttpRequestBase = object : HttpEntityEnclosingRequestBase() {
                init {
                    val request = this@toApacheRequest
                    uri = URI(request.uri.toString())
                    entity = when (requestBodyMode) {
                        Stream -> InputStreamEntity(request.body.stream, request.header("content-length")?.toLong()
                            ?: -1)
                        Memory -> ByteArrayEntity(request.body.payload.array())
                    }
                    request.headers.filter { !it.first.equals("content-length", true) }.map { addHeader(it.first, it.second) }
                }

                override fun getMethod(): String = [email protected]
            }

            private fun StatusLine.toTarget() = Status(statusCode, reasonPhrase)

            private fun Array
.toTarget(): Headers = map { it.name to it.value } } } private fun defaultApacheAsyncHttpClient() = HttpAsyncClients.custom() .setDefaultRequestConfig(RequestConfig.custom() .setRedirectsEnabled(false) .setCookieSpec(IGNORE_COOKIES) .build()).build().apply { start() } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy