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

zio.http.HandlerPlatformSpecific.scala Maven / Gradle / Ivy

package zio.http

import java.io.{File, FileNotFoundException}
import java.nio.charset.Charset
import java.util.zip.ZipFile

import zio.{Trace, ZIO}

import zio.stream.ZStream

trait HandlerPlatformSpecific {
  self: Handler.type =>

  /**
   * Creates a handler from a resource path
   */
  def fromResource(path: String, charset: Charset = Charsets.Utf8)(implicit
    trace: Trace,
  ): Handler[Any, Throwable, Any, Response] =
    Handler.fromZIO {
      ZIO
        .attemptBlocking(getClass.getClassLoader.getResource(path))
        .map { resource =>
          if (resource == null) Handler.fail(new FileNotFoundException(s"Resource $path not found"))
          else fromResourceWithURL(resource, charset)
        }
    }.flatten

  private[zio] def fromResourceWithURL(
    url: java.net.URL,
    charset: Charset,
  )(implicit trace: Trace): Handler[Any, Throwable, Any, Response] = {
    url.getProtocol match {
      case "file" => Handler.fromFile(new File(url.getPath), charset)
      case "jar"  =>
        val path         = new java.net.URI(url.getPath).getPath // remove "file:" prefix and normalize whitespace
        val bangIndex    = path.indexOf('!')
        val filePath     = path.substring(0, bangIndex)
        val resourcePath = path.substring(bangIndex + 2)
        val mediaType    = determineMediaType(resourcePath)
        val openZip      = ZIO.attemptBlockingIO(new ZipFile(filePath))
        val closeZip     = (jar: ZipFile) => ZIO.attemptBlocking(jar.close()).ignoreLogged

        def fileNotFound = new FileNotFoundException(s"Resource $resourcePath not found")

        def isDirectory = new IllegalArgumentException(s"Resource $resourcePath is a directory")

        Handler.fromZIO {
          ZIO
            .acquireReleaseWith(openZip)(closeZip) { jar =>
              for {
                entry <- ZIO
                  .attemptBlocking(Option(jar.getEntry(resourcePath)))
                  .collect(fileNotFound) { case Some(e) => e }
                _     <- ZIO.when(entry.isDirectory)(ZIO.fail(isDirectory))
                contentLength = entry.getSize
                inZStream     = ZStream
                  .acquireReleaseWith(openZip)(closeZip)
                  .mapZIO(jar => ZIO.attemptBlocking(jar.getEntry(resourcePath) -> jar))
                  .flatMap { case (entry, jar) => ZStream.fromInputStream(jar.getInputStream(entry)) }
                response      = Response(body = Body.fromStream(inZStream, contentLength))
              } yield mediaType.fold(response) { t =>
                val charset0 = if (t.mainType == "text" || !t.binary) Some(charset) else None
                response
                  .addHeader(Header.ContentType(t, charset = charset0))
              }
            }
        }

      case proto =>
        Handler.fail(new IllegalArgumentException(s"Unsupported protocol: $proto"))
    }
  }

  /**
   * Attempts to retrieve files from the classpath.
   */
  def getResource(path: String)(implicit trace: Trace): Handler[Any, Throwable, Any, java.net.URL] =
    Handler
      .fromZIO(ZIO.attemptBlocking(getClass.getClassLoader.getResource(path)))
      .flatMap { resource =>
        if (resource == null) Handler.fail(new IllegalArgumentException(s"Resource $path not found"))
        else Handler.succeed(resource)
      }

  /**
   * Attempts to retrieve files from the classpath.
   */
  def getResourceAsFile(path: String)(implicit trace: Trace): Handler[Any, Throwable, Any, File] =
    getResource(path).map(url => new File(url.getPath))

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy