Skip to content

Instantly share code, notes, and snippets.

@ryandavidhartman
Created October 6, 2016 01:17
Show Gist options
  • Save ryandavidhartman/e625e31f80bda4ea08851cbdb0a404f3 to your computer and use it in GitHub Desktop.
Save ryandavidhartman/e625e31f80bda4ea08851cbdb0a404f3 to your computer and use it in GitHub Desktop.
package com.angieslist.common.play.controller
import com.angieslist.common.http.DispatchHttpClientComponent
import com.angieslist.common.{Logger, LoggerComponent}
import com.ning.http.client.FluentCaseInsensitiveStringsMap
import com.typesafe.config.{Config, ConfigFactory}
import dispatch.{url, _}
import play.api.mvc._
import scala.collection.JavaConversions._
import scala.concurrent.ExecutionContext
import scala.concurrent.ExecutionContext.Implicits.global
trait ProxyConfig {
val config: Config = ConfigFactory.load()
val routes = config.getConfigList("proxiedRoutes").map(config => config.getString("path") -> config.getString("proxy"))
def proxiedRoutes: Map[String,String] = routes.toMap
}
trait ProxyController extends Controller{
def proxyWildCard(wildcard: String)(implicit executionContext: ExecutionContext): Action[AnyContent]
def proxyTo(request: RequestHeader)(implicit executionContext: ExecutionContext): Future[Result]
def proxyTo(request: RequestHeader, wildcard: String)(implicit executionContext: ExecutionContext): Future[Result]
}
class DispatchProxyController(dispatchClient: Http, proxiedRoutes: Map[String,String], logger: Logger) extends ProxyController {
//val http = Http.configure(_ setFollowRedirects true setCompressionEnabled true)
val stripResponseHeaders = Seq("transfer-encoding", "Connection", "Content-Length")
def proxy = proxyWildCard("")
def proxyWildCard(wildcard: String)(implicit executionContext: ExecutionContext): Action[AnyContent] = Action.async { request =>
proxyTo(request, wildcard)
}
def proxyTo(request: RequestHeader)(implicit executionContext: ExecutionContext): Future[Result] = proxyTo(request, "")
def proxyTo(request: RequestHeader, wildcard: String)(implicit executionContext: ExecutionContext): Future[Result] = {
val target = proxiedRoutes.get(request.path)
target map { t =>
logger.debug(s"Proxying to target [${target}] for path [${request.path}] and wildcard.")
proxyRequest(request, t + wildcard)
} getOrElse {
val notFound = proxiedRoutes.get("/notfound")
notFound map { nf =>
proxyRequest(request, nf + request.path)
} getOrElse {Future.successful(NotFound("Not Found"))}
}
}
private def proxyRequest(request: RequestHeader, urlToProxy: String) = {
val site = url(urlToProxy).setHeaders(request.headers.toMap)
dispatchClient(site).map { r =>
val body = r.getResponseBody
Ok(body).withHeaders(
fixHeaders(r.getHeaders, body.length).toSeq: _*
)
}
}
private def fixHeaders(headers: FluentCaseInsensitiveStringsMap, bodyLength: Int) = {
headers
.filterKeys(k => {
!stripResponseHeaders.contains(k)
})
.mapValues(_.head)
}
}
trait ProxyControllerComponent {
def proxyController: ProxyController
}
trait DispatchProxyControllerComponent extends ProxyController {
this: LoggerComponent
with ProxyConfig
with DispatchHttpClientComponent=>
lazy val proxyController: ProxyController = new DispatchProxyController(dispatchClient, proxiedRoutes, logger)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment