HelidonRequestAdapter.kt

package com.hexagonkt.http.server.helidon

import com.hexagonkt.core.media.MediaType
import com.hexagonkt.core.media.MediaTypeGroup
import com.hexagonkt.http.model.*
import com.hexagonkt.http.model.Headers
import io.helidon.http.HeaderNames
import io.helidon.http.Method
import io.helidon.http.media.multipart.MultiPart
import io.helidon.webserver.http.ServerRequest
import java.security.cert.X509Certificate
import kotlin.jvm.optionals.getOrNull

class HelidonRequestAdapter(
    methodName: Method,
    req: ServerRequest,
) : HttpRequestPort {

    override val certificateChain: List<X509Certificate> by lazy {
        req.remotePeer().tlsCertificates().getOrNull()
            ?.toList()
            ?.map { it as X509Certificate }
            ?: emptyList()
    }

    override val accept: List<ContentType> by lazy {
        req.headers().acceptedTypes().map {
            val mt = it.mediaType()
            val t = mt.type().uppercase()
            val st = mt.subtype()
            ContentType(MediaType(MediaTypeGroup.valueOf(t), st))
        }
    }

    override val contentLength: Long by lazy {
        req.headers().get(HeaderNames.CONTENT_LENGTH).get().toLong()
    }

    override val queryParameters: QueryParameters by lazy {
        QueryParameters(
            req.query().names().map {
                QueryParameter(it, req.query().all(it))
            }
        )
    }

    override val parts: List<HttpPart> by lazy {
        try {
            val multiPart = req.content().`as`(MultiPart::class.java)
            var parts = emptyList<HttpPart>()
            // TODO Fails when parsing multiple parts !?
            multiPart.forEach { p ->
                val name = p.name()
                val bytes = p.inputStream().readAllBytes()
                val fileName = p.fileName().getOrNull()
                    ?.let { HttpPart(name, bytes, it) }
                    ?: HttpPart(name, String(bytes))

                parts = parts + fileName
            }
            parts
        }
        catch (e: Exception) {
            emptyList()
        }
    }

    override val formParameters: FormParameters by lazy {
        val fields = parts
            .filter { it.submittedFileName == null }
            .map { FormParameter(it.name, it.bodyString()) }

        FormParameters(fields)
    }

    override val method: HttpMethod by lazy {
        HttpMethod.valueOf(methodName.text())
    }

    override val protocol: HttpProtocol by lazy {
        HttpProtocol.valueOf(req.prologue().protocol())
    }

    override val host: String by lazy {
        req.remotePeer().host()
    }

    override val port: Int by lazy {
        req.remotePeer().port()
    }

    override val path: String by lazy {
        req.path().path()
    }

    override val cookies: List<Cookie> by lazy {
        req.headers().cookies().toMap().map { (k, v) -> Cookie(k, v.first()) }
    }

    override val body: Any by lazy {
        req.content().inputStream().readAllBytes()
    }

    override val headers: Headers by lazy {
        Headers(req.headers().map { Header(it.name(), it.allValues()) })
    }

    override val contentType: ContentType? by lazy {
        req.headers().contentType().map {
            val mt = it.mediaType()
            val t = mt.type().uppercase()
            val st = mt.subtype()
            ContentType(MediaType(MediaTypeGroup.valueOf(t), st))
        }
        .orElse(null)
    }

    override val authorization: Authorization? by lazy { authorization() }

    override fun with(
        body: Any,
        headers: Headers,
        contentType: ContentType?,
        method: HttpMethod,
        protocol: HttpProtocol,
        host: String,
        port: Int,
        path: String,
        queryParameters: QueryParameters,
        parts: List<HttpPart>,
        formParameters: FormParameters,
        cookies: List<Cookie>,
        accept: List<ContentType>,
        authorization: Authorization?,
        certificateChain: List<X509Certificate>
    ): HttpRequestPort =
        throw UnsupportedOperationException()
}