org.http4k.server.ApacheServer.kt Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of http4k-server-apache Show documentation
Show all versions of http4k-server-apache Show documentation
Http4k HTTP Server built on top of Apache httpcore
package org.http4k.server
import org.apache.http.Header
import org.apache.http.HttpEntityEnclosingRequest
import org.apache.http.config.SocketConfig
import org.apache.http.entity.InputStreamEntity
import org.apache.http.impl.bootstrap.ServerBootstrap
import org.apache.http.impl.io.EmptyInputStream
import org.apache.http.protocol.HttpContext
import org.apache.http.protocol.HttpRequestHandler
import org.http4k.core.Headers
import org.http4k.core.HttpHandler
import org.http4k.core.Method
import org.http4k.core.Request
import org.http4k.core.Response
import org.http4k.core.safeLong
import org.http4k.core.then
import org.http4k.filter.ServerFilters
import java.util.concurrent.TimeUnit
import org.apache.http.HttpRequest as ApacheRequest
import org.apache.http.HttpResponse as ApacheResponse
/**
* Exposed to allow for insertion into a customised Apache WebServer instance
*/
class Http4kRequestHandler(handler: HttpHandler) : HttpRequestHandler {
private val safeHandler = ServerFilters.CatchAll().then(handler)
override fun handle(request: ApacheRequest, response: ApacheResponse, context: HttpContext) {
safeHandler(request.asHttp4kRequest()).into(response)
}
private fun ApacheRequest.asHttp4kRequest(): Request =
Request(Method.valueOf(requestLine.method), requestLine.uri)
.headers(allHeaders.toHttp4kHeaders()).let {
when (this) {
is HttpEntityEnclosingRequest -> it.body(entity.content, getFirstHeader("Content-Length")?.value.safeLong())
else -> it.body(EmptyInputStream.INSTANCE, 0)
}
}
private val headersThatApacheInterceptorSets = setOf("Transfer-Encoding", "Content-Length")
private fun Response.into(response: ApacheResponse) {
with(response) {
setStatusCode(status.code)
setReasonPhrase(status.description)
headers.filter { !headersThatApacheInterceptorSets.contains(it.first) }.forEach { (key, value) -> addHeader(key, value) }
entity = InputStreamEntity(body.stream)
}
}
private fun Array.toHttp4kHeaders(): Headers = listOf(*this.map { it.name to it.value }.toTypedArray())
}
data class ApacheServer(val port: Int = 8000) : ServerConfig {
override fun toServer(httpHandler: HttpHandler): Http4kServer = object : Http4kServer {
private val server = ServerBootstrap.bootstrap()
.setListenerPort(port)
.setSocketConfig(SocketConfig.custom()
.setTcpNoDelay(true)
.setSoKeepAlive(true)
.setSoReuseAddress(true)
.setBacklogSize(128)
.build())
.registerHandler("*", Http4kRequestHandler(httpHandler))
.create()
override fun start(): Http4kServer = apply {
server.start()
}
override fun stop() {
server.shutdown(15, TimeUnit.SECONDS)
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy