From 963424d014cfbb223e09a389c3cf06124b748da8 Mon Sep 17 00:00:00 2001 From: Marcin Juraszek Date: Wed, 28 Jun 2023 16:35:28 +0200 Subject: [PATCH] Add configuration `cookie.oldName` config option (close #312) --- .../CollectorRoute.scala | 107 +++++++++--------- .../CollectorService.scala | 2 + .../model.scala | 2 + .../CollectorRouteSpec.scala | 1 + .../CollectorServiceSpec.scala | 42 +++++-- .../TestUtils.scala | 1 + .../config/ConfigSpec.scala | 1 + 7 files changed, 97 insertions(+), 59 deletions(-) diff --git a/core/src/main/scala/com.snowplowanalytics.snowplow.collectors.scalastream/CollectorRoute.scala b/core/src/main/scala/com.snowplowanalytics.snowplow.collectors.scalastream/CollectorRoute.scala index b86f4b07d..922411e1b 100644 --- a/core/src/main/scala/com.snowplowanalytics.snowplow.collectors.scalastream/CollectorRoute.scala +++ b/core/src/main/scala/com.snowplowanalytics.snowplow.collectors.scalastream/CollectorRoute.scala @@ -51,19 +51,40 @@ trait CollectorRoute { def routes: Route = doNotTrack(collectorService.doNotTrackCookie) { dnt => cookieIfWanted(collectorService.cookieName) { reqCookie => - val cookie = reqCookie.map(_.toCookie) - headers { (userAgent, refererURI, rawRequestURI, spAnonymous) => - val qs = queryString(rawRequestURI) - extractors(spAnonymous) { (host, ip, request) => - // get the adapter vendor and version from the path - path(Segment / Segment) { (vendor, version) => - val path = collectorService.determinePath(vendor, version) - post { - extractContentType { ct => - entity(as[String]) { body => + cookieIfWanted(collectorService.oldCookieName) { oldReqCookie => + val cookie = reqCookie.map(_.toCookie).orElse(oldReqCookie.map((_.toCookie))) + headers { (userAgent, refererURI, rawRequestURI, spAnonymous) => + val qs = queryString(rawRequestURI) + extractors(spAnonymous) { (host, ip, request) => + // get the adapter vendor and version from the path + path(Segment / Segment) { (vendor, version) => + val path = collectorService.determinePath(vendor, version) + post { + extractContentType { ct => + entity(as[String]) { body => + val r = collectorService.cookie( + qs, + Some(body), + path, + cookie, + userAgent, + refererURI, + host, + ip, + request, + pixelExpected = false, + doNotTrack = dnt, + Some(ct), + spAnonymous + ) + complete(r) + } + } + } ~ + (get | head) { val r = collectorService.cookie( qs, - Some(body), + None, path, cookie, userAgent, @@ -71,55 +92,37 @@ trait CollectorRoute { host, ip, request, - pixelExpected = false, + pixelExpected = true, doNotTrack = dnt, - Some(ct), + None, spAnonymous ) complete(r) } - } } ~ - (get | head) { - val r = collectorService.cookie( - qs, - None, - path, - cookie, - userAgent, - refererURI, - host, - ip, - request, - pixelExpected = true, - doNotTrack = dnt, - None, - spAnonymous - ) - complete(r) - } - } ~ - path("""ice\.png""".r | "i".r) { path => - (get | head) { - val r = collectorService.cookie( - qs, - None, - "/" + path, - cookie, - userAgent, - refererURI, - host, - ip, - request, - pixelExpected = true, - doNotTrack = dnt, - None, - spAnonymous - ) - complete(r) + path("""ice\.png""".r | "i".r) { path => + (get | head) { + val r = collectorService.cookie( + qs, + None, + "/" + path, + cookie, + userAgent, + refererURI, + host, + ip, + request, + pixelExpected = true, + doNotTrack = dnt, + None, + spAnonymous + ) + complete(r) + } } - } + } } + } } } ~ corsRoute ~ healthRoute ~ sinkHealthRoute ~ crossDomainRoute ~ rootRoute ~ robotsRoute ~ { diff --git a/core/src/main/scala/com.snowplowanalytics.snowplow.collectors.scalastream/CollectorService.scala b/core/src/main/scala/com.snowplowanalytics.snowplow.collectors.scalastream/CollectorService.scala index 968f9b9e2..5eee4be11 100644 --- a/core/src/main/scala/com.snowplowanalytics.snowplow.collectors.scalastream/CollectorService.scala +++ b/core/src/main/scala/com.snowplowanalytics.snowplow.collectors.scalastream/CollectorService.scala @@ -58,6 +58,7 @@ trait Service { spAnonymous: Option[String] = None ): HttpResponse def cookieName: Option[String] + def oldCookieName: Option[String] def doNotTrackCookie: Option[DntCookieMatcher] def determinePath(vendor: String, version: String): String def enableDefaultRedirect: Boolean @@ -83,6 +84,7 @@ class CollectorService( config.streams.sink.getClass.getSimpleName.toLowerCase override val cookieName = config.cookieName + override val oldCookieName = config.oldCookieName override val doNotTrackCookie = config.doNotTrackHttpCookie override val enableDefaultRedirect = config.enableDefaultRedirect override def sinksHealthy = sinks.good.isHealthy && sinks.bad.isHealthy diff --git a/core/src/main/scala/com.snowplowanalytics.snowplow.collectors.scalastream/model.scala b/core/src/main/scala/com.snowplowanalytics.snowplow.collectors.scalastream/model.scala index aa4052acd..f64f5a3e5 100644 --- a/core/src/main/scala/com.snowplowanalytics.snowplow.collectors.scalastream/model.scala +++ b/core/src/main/scala/com.snowplowanalytics.snowplow.collectors.scalastream/model.scala @@ -57,6 +57,7 @@ package model { final case class CookieConfig( enabled: Boolean, name: String, + oldName: Option[String], expiration: FiniteDuration, domains: Option[List[String]], fallbackDomain: Option[String], @@ -245,6 +246,7 @@ package model { None def cookieName = cookieConfig.map(_.name) + def oldCookieName = cookieConfig.flatMap(_.oldName) def cookieDomain = cookieConfig.flatMap(_.domains) def fallbackDomain = cookieConfig.flatMap(_.fallbackDomain) def cookieExpiration = cookieConfig.map(_.expiration) diff --git a/core/src/test/scala/com.snowplowanalytics.snowplow.collectors.scalastream/CollectorRouteSpec.scala b/core/src/test/scala/com.snowplowanalytics.snowplow.collectors.scalastream/CollectorRouteSpec.scala index a35b7512a..228b5113a 100644 --- a/core/src/test/scala/com.snowplowanalytics.snowplow.collectors.scalastream/CollectorRouteSpec.scala +++ b/core/src/test/scala/com.snowplowanalytics.snowplow.collectors.scalastream/CollectorRouteSpec.scala @@ -49,6 +49,7 @@ class CollectorRouteSpec extends Specification with Specs2RouteTest { spAnonymous: Option[String] = spAnonymous ): HttpResponse = HttpResponse(200, entity = s"cookie") def cookieName: Option[String] = Some("name") + def oldCookieName: Option[String] = None def doNotTrackCookie: Option[DntCookieMatcher] = None def determinePath(vendor: String, version: String): String = "/p1/p2" def enableDefaultRedirect: Boolean = withRedirects diff --git a/core/src/test/scala/com.snowplowanalytics.snowplow.collectors.scalastream/CollectorServiceSpec.scala b/core/src/test/scala/com.snowplowanalytics.snowplow.collectors.scalastream/CollectorServiceSpec.scala index cc1036ac8..03cec3bb0 100644 --- a/core/src/test/scala/com.snowplowanalytics.snowplow.collectors.scalastream/CollectorServiceSpec.scala +++ b/core/src/test/scala/com.snowplowanalytics.snowplow.collectors.scalastream/CollectorServiceSpec.scala @@ -601,6 +601,7 @@ class CollectorServiceSpec extends Specification { val conf = CookieConfig( true, "name", + None, 5.seconds, Some(List("domain")), None, @@ -627,6 +628,7 @@ class CollectorServiceSpec extends Specification { val conf = CookieConfig( true, "name", + None, 5.seconds, Some(List("domain")), None, @@ -640,6 +642,7 @@ class CollectorServiceSpec extends Specification { val conf = CookieConfig( true, "name", + None, 5.seconds, Some(List("domain")), None, @@ -654,6 +657,7 @@ class CollectorServiceSpec extends Specification { val conf = CookieConfig( true, "name", + None, 5.seconds, Some(List("domain")), None, @@ -820,26 +824,38 @@ class CollectorServiceSpec extends Specification { "not return a domain" in { "if a list of domains is not supplied in the config and there is no fallback domain" in { val request = HttpRequest() - val cookieConfig = CookieConfig(true, "name", 5.seconds, None, None, false, false, None) + val cookieConfig = CookieConfig(true, "name", None, 5.seconds, None, None, false, false, None) service.cookieDomain(request.headers, cookieConfig.domains, cookieConfig.fallbackDomain) shouldEqual None } "if a list of domains is supplied in the config but the Origin request header is empty and there is no fallback domain" in { - val request = HttpRequest() - val cookieConfig = CookieConfig(true, "name", 5.seconds, Some(List("domain.com")), None, false, false, None) + val request = HttpRequest() + val cookieConfig = + CookieConfig(true, "name", None, 5.seconds, Some(List("domain.com")), None, false, false, None) service.cookieDomain(request.headers, cookieConfig.domains, cookieConfig.fallbackDomain) shouldEqual None } "if none of the domains in the request's Origin header has a match in the list of domains supplied with the config and there is no fallback domain" in { val origins = Seq(HttpOrigin("http", Host("origin.com")), HttpOrigin("http", Host("otherorigin.com", 8080))) val request = HttpRequest().withHeaders(`Origin`(origins)) val cookieConfig = - CookieConfig(true, "name", 5.seconds, Some(List("domain.com", "otherdomain.com")), None, false, false, None) + CookieConfig( + true, + "name", + None, + 5.seconds, + Some(List("domain.com", "otherdomain.com")), + None, + false, + false, + None + ) service.cookieDomain(request.headers, cookieConfig.domains, cookieConfig.fallbackDomain) shouldEqual None } } "return the fallback domain" in { "if a list of domains is not supplied in the config but a fallback domain is configured" in { - val request = HttpRequest() - val cookieConfig = CookieConfig(true, "name", 5.seconds, None, Some("fallbackDomain"), false, false, None) + val request = HttpRequest() + val cookieConfig = + CookieConfig(true, "name", None, 5.seconds, None, Some("fallbackDomain"), false, false, None) service.cookieDomain(request.headers, cookieConfig.domains, cookieConfig.fallbackDomain) shouldEqual Some( "fallbackDomain" ) @@ -847,7 +863,17 @@ class CollectorServiceSpec extends Specification { "if the Origin header is empty and a fallback domain is configured" in { val request = HttpRequest() val cookieConfig = - CookieConfig(true, "name", 5.seconds, Some(List("domain.com")), Some("fallbackDomain"), false, false, None) + CookieConfig( + true, + "name", + None, + 5.seconds, + Some(List("domain.com")), + Some("fallbackDomain"), + false, + false, + None + ) service.cookieDomain(request.headers, cookieConfig.domains, cookieConfig.fallbackDomain) shouldEqual Some( "fallbackDomain" ) @@ -858,6 +884,7 @@ class CollectorServiceSpec extends Specification { val cookieConfig = CookieConfig( true, "name", + None, 5.seconds, Some(List("domain.com", "otherdomain.com")), Some("fallbackDomain"), @@ -877,6 +904,7 @@ class CollectorServiceSpec extends Specification { val cookieConfig = CookieConfig( true, "name", + None, 5.seconds, Some(List("domain.com", "otherdomain.com")), Some("fallbackDomain"), diff --git a/core/src/test/scala/com.snowplowanalytics.snowplow.collectors.scalastream/TestUtils.scala b/core/src/test/scala/com.snowplowanalytics.snowplow.collectors.scalastream/TestUtils.scala index 129585f44..5b7b7c189 100644 --- a/core/src/test/scala/com.snowplowanalytics.snowplow.collectors.scalastream/TestUtils.scala +++ b/core/src/test/scala/com.snowplowanalytics.snowplow.collectors.scalastream/TestUtils.scala @@ -31,6 +31,7 @@ object TestUtils { cookie = CookieConfig( true, "sp", + None, 365.days, None, None, diff --git a/core/src/test/scala/com.snowplowanalytics.snowplow.collectors.scalastream/config/ConfigSpec.scala b/core/src/test/scala/com.snowplowanalytics.snowplow.collectors.scalastream/config/ConfigSpec.scala index b04576656..730ad38e6 100644 --- a/core/src/test/scala/com.snowplowanalytics.snowplow.collectors.scalastream/config/ConfigSpec.scala +++ b/core/src/test/scala/com.snowplowanalytics.snowplow.collectors.scalastream/config/ConfigSpec.scala @@ -45,6 +45,7 @@ abstract class ConfigSpec extends Specification { enabled = true, expiration = 365.days, name = "sp", + oldName = None, domains = None, fallbackDomain = None, secure = true,