Handlers.kt
- @file:Suppress("FunctionName") // Uppercase functions are used for providing named constructors
- package com.hexagontk.http.handlers
- import com.hexagontk.handlers.Context
- import com.hexagontk.http.model.*
- import com.hexagontk.http.model.HttpMethod.*
- import com.hexagontk.http.model.HttpProtocol.HTTP
- import java.math.BigInteger
- import java.security.cert.X509Certificate
- typealias HttpCallbackType = HttpContext.() -> HttpContext
- typealias HttpExceptionCallbackType<T> = HttpContext.(T) -> HttpContext
- private val BODY_TYPES_NAMES: String by lazy {
- val bodyTypes = setOf(String::class, ByteArray::class, Int::class, Long::class)
- bodyTypes.joinToString(", ") { it.simpleName.toString() }
- }
- internal fun toCallback(block: HttpCallbackType): (Context<HttpCall>) -> Context<HttpCall> =
- { context -> HttpContext(context).block() }
- internal fun <E : Exception> toCallback(
- block: HttpExceptionCallbackType<E>
- ): (Context<HttpCall>, E) -> Context<HttpCall> =
- { context, e -> HttpContext(context).block(e) }
- fun HttpCallbackType.process(
- request: HttpRequest,
- attributes: Map<*, *> = emptyMap<Any, Any>()
- ): HttpContext =
- this(HttpContext(request = request, attributes = attributes))
- fun HttpCallbackType.process(
- method: HttpMethod = GET,
- protocol: HttpProtocol = HTTP,
- host: String = "localhost",
- port: Int = 80,
- path: String = "",
- queryParameters: Parameters = Parameters(),
- headers: Headers = Headers(),
- body: Any = "",
- parts: List<HttpPart> = emptyList(),
- formParameters: Parameters = Parameters(),
- cookies: List<Cookie> = emptyList(),
- contentType: ContentType? = null,
- certificateChain: List<X509Certificate> = emptyList(),
- accept: List<ContentType> = emptyList(),
- contentLength: Long = -1L,
- attributes: Map<*, *> = emptyMap<Any, Any>(),
- authorization: Authorization? = null,
- ): HttpContext =
- this.process(
- HttpRequest(
- method,
- protocol,
- host,
- port,
- path,
- queryParameters,
- headers,
- body,
- parts,
- formParameters,
- cookies,
- contentType,
- certificateChain,
- accept,
- contentLength,
- authorization
- ),
- attributes,
- )
- // TODO rename to 'buildPath' to follow same pattern as Kotlin's 'buildList' or 'buildMap'???
- fun path(pattern: String = "", block: HandlerBuilder.() -> Unit): PathHandler {
- val builder = HandlerBuilder()
- builder.block()
- return path(pattern, builder.handlers)
- }
- fun path(contextPath: String = "", handlers: List<HttpHandler>): PathHandler =
- handlers
- .let {
- if (it.size == 1 && it[0] is PathHandler)
- (it[0] as PathHandler).addPrefix(contextPath) as PathHandler
- else
- PathHandler(contextPath, it)
- }
- fun Get(pattern: String = "", callback: HttpCallbackType): OnHandler =
- OnHandler(GET, pattern, callback)
- fun Ws(pattern: String = "", callback: HttpCallbackType): OnHandler =
- Get(pattern, callback)
- fun Head(pattern: String = "", callback: HttpCallbackType): OnHandler =
- OnHandler(HEAD, pattern, callback)
- fun Post(pattern: String = "", callback: HttpCallbackType): OnHandler =
- OnHandler(POST, pattern, callback)
- fun Put(pattern: String = "", callback: HttpCallbackType): OnHandler =
- OnHandler(PUT, pattern, callback)
- fun Delete(pattern: String = "", callback: HttpCallbackType): OnHandler =
- OnHandler(DELETE, pattern, callback)
- fun Trace(pattern: String = "", callback: HttpCallbackType): OnHandler =
- OnHandler(TRACE, pattern, callback)
- fun Options(pattern: String = "", callback: HttpCallbackType): OnHandler =
- OnHandler(OPTIONS, pattern, callback)
- fun Patch(pattern: String = "", callback: HttpCallbackType): OnHandler =
- OnHandler(PATCH, pattern, callback)
- /**
- * Convert an object to a byte array. If the body class is not supported, it throws a runtime
- * exception. IMPORTANT: Must be enclosed on a try/catch block to check runtime errors.
- *
- * @param body Object to convert to bytes.
- * @return The bytes of the supplied object.
- */
- fun bodyToBytes(body: Any): ByteArray =
- when (body) {
- is String -> body.toByteArray()
- is ByteArray -> body
- is Int -> BigInteger.valueOf(body.toLong()).toByteArray()
- is Long -> BigInteger.valueOf(body).toByteArray()
- else -> {
- val className = body.javaClass.simpleName
- val message = "Unsupported body type: $className. Must be: $BODY_TYPES_NAMES"
- throw IllegalStateException(message)
- }
- }