Skip to content

Commit

Permalink
Add plugin to override host in Location headers
Browse files Browse the repository at this point in the history
  • Loading branch information
mathieuancelin committed Jul 8, 2024
1 parent ee6898b commit 8120a43
Showing 1 changed file with 59 additions and 1 deletion.
60 changes: 59 additions & 1 deletion otoroshi/app/next/plugins/headers.scala
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package otoroshi.next.plugins

import akka.http.scaladsl.model.Uri
import akka.stream.Materializer
import otoroshi.el.{HeadersExpressionLanguage, TargetExpressionLanguage}
import otoroshi.env.Env
Expand Down Expand Up @@ -62,7 +63,7 @@ class OverrideHost extends NgRequestTransformer {
override def categories: Seq[NgPluginCategory] = Seq(NgPluginCategory.Headers, NgPluginCategory.Classic)
override def visibility: NgPluginVisibility = NgPluginVisibility.NgUserLand

override def multiInstance: Boolean = false
override def multiInstance: Boolean = true
override def core: Boolean = true
override def usesCallbacks: Boolean = false
override def transformsRequest: Boolean = true
Expand Down Expand Up @@ -99,6 +100,63 @@ class OverrideHost extends NgRequestTransformer {
}
}

class OverrideLocationHeader extends NgRequestTransformer {

override def steps: Seq[NgStep] = Seq(NgStep.TransformRequest)
override def categories: Seq[NgPluginCategory] = Seq(NgPluginCategory.Headers)
override def visibility: NgPluginVisibility = NgPluginVisibility.NgUserLand

override def multiInstance: Boolean = true
override def core: Boolean = true
override def usesCallbacks: Boolean = false
override def transformsRequest: Boolean = false
override def transformsResponse: Boolean = false
override def transformsError: Boolean = false
override def isTransformRequestAsync: Boolean = false
override def isTransformResponseAsync: Boolean = true
override def name: String = "Override Location header"
override def description: Option[String] =
"This plugin override the current Location header with the Host of the backend target".some
override def defaultConfigObject: Option[NgPluginConfig] = None
override def noJsForm: Boolean = true

override def transformResponseSync(
ctx: NgTransformerResponseContext
)(implicit env: Env, ec: ExecutionContext, mat: Materializer): Either[Result, NgPluginHttpResponse] = {
ctx.attrs.get(Keys.BackendKey) match {
case None => ctx.otoroshiResponse.right
case Some(backend) => {
val status = ctx.otoroshiResponse.status
if ((status > 299 && status < 400) || status == 201) {
ctx.otoroshiResponse.header("Location") match {
case None => ctx.otoroshiResponse.right
case Some(location) if location.startsWith("http://") || location.startsWith("https://") => ctx.otoroshiResponse.right
case Some(location) => {
val host = TargetExpressionLanguage(
backend.hostname,
Some(ctx.request),
ctx.route.serviceDescriptor.some,
ctx.route.some,
ctx.attrs.get(otoroshi.plugins.Keys.ApiKeyKey),
ctx.attrs.get(otoroshi.plugins.Keys.UserKey),
ctx.attrs.get(otoroshi.plugins.Keys.ElCtxKey).get,
ctx.attrs,
env
)
val oldLocation = Uri(location)
val newLocation = oldLocation.copy(authority = oldLocation.authority.copy(host = Uri.Host(host))).toString()
val headers = ctx.otoroshiResponse.headers.-("Location").-("location").+("Location" -> newLocation)
ctx.otoroshiResponse.copy(headers = headers).right
}
}
} else {
ctx.otoroshiResponse.right
}
}
}
}
}

class HeadersValidation extends NgAccessValidator {

private val configReads: Reads[NgHeaderValuesConfig] = NgHeaderValuesConfig.format
Expand Down

0 comments on commit 8120a43

Please sign in to comment.