UrlCallback.kt

  1. package com.hexagonkt.http.server.callbacks

  2. import com.hexagonkt.core.ResourceNotFoundException
  3. import com.hexagonkt.core.logging.Logger
  4. import com.hexagonkt.core.media.mediaTypeOfOrNull
  5. import com.hexagonkt.core.require
  6. import com.hexagonkt.core.urlOf
  7. import com.hexagonkt.http.model.ContentType
  8. import com.hexagonkt.http.handlers.HttpContext
  9. import java.net.URL

  10. class UrlCallback(private val url: URL) : (HttpContext) -> HttpContext {

  11.     constructor(url: String) : this(urlOf(url))

  12.     private companion object {
  13.         val logger: Logger = Logger(UrlCallback::class)
  14.     }

  15.     override fun invoke(context: HttpContext): HttpContext {
  16.         val requestPath = when (context.pathParameters.size) {
  17.             0 -> ""
  18.             1 -> context.pathParameters.require("0")
  19.             else -> error("URL loading require a single path parameter or none")
  20.         }

  21.         check(!requestPath.contains("..")) { "Requested path cannot contain '..': $requestPath" }
  22.         logger.debug { "Resolving resource: $requestPath" }

  23.         return try {
  24.             if (requestPath.endsWith("/"))
  25.                 throw ResourceNotFoundException("$requestPath not found (folder)")

  26.             val url = when {
  27.                 requestPath.isEmpty() -> url.toString()
  28.                 url.toString() == "classpath:/" -> "classpath:$requestPath"
  29.                 else -> "$url/$requestPath"
  30.             }

  31.             val resource = urlOf(url)
  32.             val bytes = resource.readBytes()
  33.             val mediaType = mediaTypeOfOrNull(resource)
  34.             context.ok(bytes, contentType = mediaType?.let { ContentType(it) })
  35.         }
  36.         catch (e: ResourceNotFoundException) {
  37.             context.notFound(e.message ?: "")
  38.         }
  39.     }
  40. }