common/app/http/ResultWithPreconnectPreload.scala (51 lines of code) (raw):
package http
import common.{CssPreloadAsset, JsPreloadAsset, PreloadAsset, ThirdPartyJsPreload, UrlPreload}
import model.ApplicationContext
import play.api.mvc.{RequestHeader, Result}
trait ResultWithPreconnectPreload {
final implicit class RichResult(self: Result) {
val linkHeaderKey = "Link"
def withPreload(assets: Seq[PreloadAsset])(implicit context: ApplicationContext, request: RequestHeader): Result = {
if (assets.nonEmpty) {
val preloadFiles = assets
.map {
case jsFile: JsPreloadAsset =>
s"<${conf.Static(jsFile.asset)}>; rel=preload; as=script; nopush"
case cssFile: CssPreloadAsset =>
s"<${conf.Static(common.Assets.css.projectCss(Some(cssFile.asset.stripSuffix(".css"))))}>; rel=preload; as=style; nopush"
case thirdPartyJsFile: ThirdPartyJsPreload =>
s"<${thirdPartyJsFile.asset}>; rel=preload; as=script; nopush"
case url: UrlPreload =>
s"<${url.asset}>; rel=preload; nopush"
}
.mkString(",")
val linkHeaderValue = self.header.headers.get(linkHeaderKey).map(_ ++ s",$preloadFiles") getOrElse preloadFiles
self.withHeaders(linkHeaderKey -> linkHeaderValue)
} else self
}
def withPreconnect(urls: Seq[String]): Result = {
// Reference: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Link
// Reference: https://www.w3.org/TR/resource-hints/
/*
Note that the two above references disagree on the exact grammar. The first indicates
Link: <https://example.com>; rel="preconnect"
while the second indicates:
Link: <https://example.com>; rel=preconnect
The difference being the presence of quotes around "preconnect".
Let's adopt the second version to be consistent with the choice made in def withPreload
*/
if (urls.nonEmpty) {
val preconnections = urls
.map(url => s"<${url}>; rel=preconnect")
.mkString(",")
val linkHeaderValue =
self.header.headers.get(linkHeaderKey).map(_ ++ s",$preconnections") getOrElse preconnections
self.withHeaders(linkHeaderKey -> linkHeaderValue)
} else self
}
}
}
object HttpPreconnections {
val defaultUrls = Seq(
"https://assets.guim.co.uk/",
"https://i.guim.co.uk",
"https://j.ophan.co.uk",
"https://ophan.theguardian.com",
"https://api.nextgen.guardianapps.co.uk",
"https://hits-secure.theguardian.com",
"https://interactive.guim.co.uk",
"https://phar.gu-web.net",
"https://static.theguardian.com",
"https://support.theguardian.com",
)
}