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

utils.request.scala Maven / Gradle / Ivy

package otoroshi.utils.http

import akka.http.scaladsl.model.Uri
import com.github.blemale.scaffeine.Scaffeine
import otoroshi.env.Env
import play.api.mvc.RequestHeader

import java.util.concurrent.ConcurrentHashMap
import scala.util.Try

object RequestImplicits {

  private val uriCache = Scaffeine().maximumSize(9999).build[String, String]()

  implicit class EnhancedRequestHeader(val requestHeader: RequestHeader) extends AnyVal {
    def contentLengthStr: Option[String]     = requestHeader.headers.get("Content-Length")
    def theUri: Uri                          = Uri(requestHeader.uri)
    def thePath: String                      = theUri.path.toString()
    def relativeUri: String = {
      val uri = requestHeader.uri
      uriCache.get(
        uri,
        _ => {
          // println(s"computing uri for $uri")
          Try(Uri(uri).toRelative.toString()).getOrElse(uri)
        }
      )
    }
    @inline
    def theDomain(implicit env: Env): String = theHost.split(':').head
    @inline
    def theSecured(implicit env: Env): Boolean = {
      if (env.datastores.globalConfigDataStore.latestSafe.exists(_.trustXForwarded)) {
        requestHeader.headers
          .get("X-Forwarded-Proto")
          .orElse(requestHeader.headers.get("X-Forwarded-Protocol"))
          .map(_ == "https")
          .getOrElse(requestHeader.secure)
      } else {
        requestHeader.secure
      }
    }
    @inline
    def theSecuredTrusted: Boolean = {
      requestHeader.headers
        .get("X-Forwarded-Proto")
        .orElse(requestHeader.headers.get("X-Forwarded-Protocol"))
        .map(_ == "https")
        .getOrElse(requestHeader.secure)
    }
    @inline
    def theUrl(implicit env: Env): String = {
      s"${theProtocol}://${theHost}${relativeUri}"
    }
    @inline
    def theProtocol(implicit env: Env): String = {
      if (env.datastores.globalConfigDataStore.latestSafe.exists(_.trustXForwarded)) {
        requestHeader.headers
          .get("X-Forwarded-Proto")
          .orElse(requestHeader.headers.get("X-Forwarded-Protocol"))
          .map(_ == "https")
          .orElse(Some(requestHeader.secure))
          .map {
            case true  => "https"
            case false => "http"
          }
          .getOrElse("http")
      } else {
        if (requestHeader.secure) "https" else "http"
      }
    }
    @inline
    def theWsProtocol(implicit env: Env): String = {
      if (env.datastores.globalConfigDataStore.latestSafe.exists(_.trustXForwarded)) {
        requestHeader.headers
          .get("X-Forwarded-Proto")
          .orElse(requestHeader.headers.get("X-Forwarded-Protocol"))
          .map(_ == "https")
          .orElse(Some(requestHeader.secure))
          .map {
            case true  => "wss"
            case false => "ws"
          }
          .getOrElse("ws")
      } else {
        if (requestHeader.secure) "wss" else "ws"
      }
    }
    @inline
    def theHost(implicit env: Env): String = {
      if (env.datastores.globalConfigDataStore.latestSafe.exists(_.trustXForwarded)) {
        requestHeader.headers.get("X-Forwarded-Host").getOrElse(requestHeader.host)
      } else {
        requestHeader.host
      }
    }
    @inline
    def theIpAddress(implicit env: Env): String = {
      if (env.datastores.globalConfigDataStore.latestSafe.exists(_.trustXForwarded)) {
        requestHeader.headers
          .get("X-Forwarded-For")
          .map { rawHeader =>
            if (rawHeader.nonEmpty && rawHeader.contains(",")) {
              rawHeader.split(",").map(_.trim).headOption.getOrElse(rawHeader)
            } else {
              rawHeader
            }
          }
          .getOrElse(requestHeader.remoteAddress)
      } else {
        requestHeader.remoteAddress
      }
    }
    @inline
    def theUserAgent: String = {
      requestHeader.headers.get("User-Agent").getOrElse("none")
    }
    @inline
    def clientCertChainPem: Seq[String] = {
      import otoroshi.ssl.SSLImplicits._
      requestHeader.clientCertificateChain
        .map(chain =>
          chain.map { cert =>
            cert.asPem
          // s"${PemHeaders.BeginCertificate}\n${Base64.getEncoder.encodeToString(cert.getEncoded)}\n${PemHeaders.EndCertificate}"
          }
        )
        .getOrElse(Seq.empty[String])
    }
    @inline
    def clientCertChainPemString: String     = clientCertChainPem.mkString("\n")

    @inline
    def theHasBody: Boolean = {
      otoroshi.utils.body.BodyUtils.hasBody(requestHeader)
      // (requestHeader.method, requestHeader.headers.get("Content-Length")) match {
      //   case ("GET", Some(_))    => true
      //   case ("GET", None) if ctype.isDefined => true
      //   case ("GET", None)       => false
      //   case ("HEAD", Some(_))   => true
      //   case ("HEAD", None) if ctype.isDefined => true
      //   case ("HEAD", None)      => false
      //   case ("PATCH", _)        => true
      //   case ("POST", _)         => true
      //   case ("PUT", _)          => true
      //   case ("QUERY", _)        => true
      //   case ("DELETE", Some(_)) => true
      //   case ("DELETE", None) if ctype.isDefined => true
      //   case ("DELETE", None)    => false
      //   case _                   => true
      // }
    }

    @inline
    def theHasBodyWithoutLength: (Boolean, Boolean) = otoroshi.utils.body.BodyUtils.hasBodyWithoutLength(requestHeader)
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy