app/com/gu/viewer/proxy/ProxyClient.scala (56 lines of code) (raw):
package com.gu.viewer.proxy
import com.gu.viewer.config.AppConfig
import play.api.libs.ws.WSClient
import play.api.mvc.{Cookie, Cookies, DefaultCookieHeaderEncoding}
import play.api.http.HeaderNames.{CONTENT_LENGTH, COOKIE, USER_AGENT}
import scala.concurrent.{ExecutionContext, Future}
import scala.concurrent.duration._
import play.api.http.CookiesConfiguration
import play.api.http.HttpConfiguration
class ProxyClient(ws: WSClient, config: AppConfig)(implicit ec: ExecutionContext) extends DefaultCookieHeaderEncoding {
private val TIMEOUT = 10000.millis
private def proxy(
method: String,
destination: String,
headers: Seq[(String, String)] = Seq.empty,
cookies: Seq[Cookie] = Seq.empty,
queryString: Seq[(String, String)] = Seq.empty,
body: Map[String, Seq[String]] = Map.empty,
followRedirects: Boolean = false
)(handler: PartialFunction[ProxyResponse, Future[ProxyResult]] = PartialFunction.empty): Future[ProxyResult] = {
val cookieHeader = if (cookies.nonEmpty) Some(COOKIE -> encodeCookieHeader(cookies)) else None
val contentLengthHeader = if (body.nonEmpty) Some(CONTENT_LENGTH -> body.size.toString) else None
val userAgentHeader = Some(USER_AGENT -> s"gu-viewer ${config.stage}")
def handleResponse: PartialFunction[ProxyResponse, Future[ProxyResult]] = {
case response =>
Future.successful(ProxyResultWithBody(response))
}
ws.url(destination)
.withFollowRedirects(follow = followRedirects)
.withHttpHeaders(headers ++ contentLengthHeader ++ userAgentHeader ++ cookieHeader: _*)
.withQueryStringParameters(queryString: _*)
.withRequestTimeout(TIMEOUT)
.withBody(body)
.withMethod(method)
.stream()
.map(new ProxyResponse(_))
.flatMap(handler orElse handleResponse)
}
def get(
destination: String,
headers: Seq[(String, String)] = Seq.empty,
cookies: Seq[Cookie] = Seq.empty,
queryString: Seq[(String, String)] = Seq.empty,
followRedirects: Boolean = false
)(handler: PartialFunction[ProxyResponse, Future[ProxyResult]] = PartialFunction.empty) =
proxy("GET", destination, headers, cookies, queryString, followRedirects = followRedirects)(handler)
def post(
destination: String,
headers: Seq[(String, String)] = Seq.empty,
cookies: Seq[Cookie] = Seq.empty,
queryString: Seq[(String, String)] = Seq.empty,
body: Map[String, Seq[String]] = Map.empty,
followRedirects: Boolean = false
)(handler: PartialFunction[ProxyResponse, Future[ProxyResult]] = PartialFunction.empty) =
proxy("POST", destination, headers, cookies, queryString, body, followRedirects)(handler)
}