From ee6a019801c6d61975cc0832dd7f30744f263e7e Mon Sep 17 00:00:00 2001 From: Piotr Limanowski Date: Mon, 19 Feb 2024 12:46:20 +0100 Subject: [PATCH] Upcase cookie header name Since migrating to http4s we observed a flaw in cookie processing. Previously, with akka the headers were uppercased. Http4s follows RFC[1] related to header names more closely ignoring the case. This had a result in missing cookie extractions in enrich that only supports upper case Cookie header. We are making enrich case-insensitive. Meanwhile, until the change is migrated this is a workaround that will upcase cookie header. 1 - https://www.rfc-editor.org/rfc/rfc7230#section-3.2 --- .../Service.scala | 5 +++- .../ServiceSpec.scala | 26 +++++++++++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/core/src/main/scala/com.snowplowanalytics.snowplow.collector.core/Service.scala b/core/src/main/scala/com.snowplowanalytics.snowplow.collector.core/Service.scala index 1e01cfcb3..ad38446a6 100644 --- a/core/src/main/scala/com.snowplowanalytics.snowplow.collector.core/Service.scala +++ b/core/src/main/scala/com.snowplowanalytics.snowplow.collector.core/Service.scala @@ -304,7 +304,10 @@ class Service[F[_]: Sync]( request.headers.headers.flatMap { h => h.name match { case ci"X-Forwarded-For" | ci"X-Real-Ip" | ci"Cookie" if spAnonymous.isDefined => None - case _ => Some(h.toString()) + // FIXME: This is a temporary backport of old akka behaviour we will remove by + // adapting enrich to support a CIString header names as per RFC7230#Section-3.2 + case ci"Cookie" => Some(s"Cookie: ${h.value}") + case _ => Some(h.toString()) } } diff --git a/core/src/test/scala/com.snowplowanalytics.snowplow.collector.core/ServiceSpec.scala b/core/src/test/scala/com.snowplowanalytics.snowplow.collector.core/ServiceSpec.scala index e746e1308..0b932b6cc 100644 --- a/core/src/test/scala/com.snowplowanalytics.snowplow.collector.core/ServiceSpec.scala +++ b/core/src/test/scala/com.snowplowanalytics.snowplow.collector.core/ServiceSpec.scala @@ -288,6 +288,32 @@ class ServiceSpec extends Specification { ).asJava } + "sink event with Cookie header upcased" in { + val ProbeService(service, good, bad) = probeService() + + val req = Request[IO]( + method = Method.POST, + headers = Headers(Header.Raw(CIString("cookie"), "name=value")) + ) + val r = service + .cookie( + body = IO.pure(Some("b")), + path = "p", + request = req, + pixelExpected = false, + contentType = Some("image/gif") + ) + .unsafeRunSync() + + r.status mustEqual Status.Ok + good.storedRawEvents must have size 1 + bad.storedRawEvents must have size 0 + + val e = emptyCollectorPayload + deserializer.deserialize(e, good.storedRawEvents.head) + e.headers.asScala must contain("Cookie: name=value") + } + "return necessary cache control headers and respond with pixel when pixelExpected is true" in { val r = service .cookie(