Skip to content

Commit

Permalink
Add gunzip middleware to support gzipped payloads
Browse files Browse the repository at this point in the history
An experiment in adding a simple middleware that will handle gzipped
requests in the collector and process them as usual next.
  • Loading branch information
peel committed Dec 5, 2023
1 parent 3106307 commit 583e63b
Show file tree
Hide file tree
Showing 2 changed files with 42 additions and 1 deletion.
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/**
* Copyright (c) 2013-present Snowplow Analytics Ltd.
* All rights reserved.
*
* This program is licensed to you under the Snowplow Community License Version 1.0,
* and you may not use this file except in compliance with the Snowplow Community License Version 1.0.
* You may obtain a copy of the Snowplow Community License Version 1.0 at https://docs.snowplow.io/community-license-1.0
*/
package com.snowplowanalytics.snowplow.collector.core

import fs2.compression.Compression
import cats.data.Kleisli
import cats.effect._
import org.http4s._
import org.http4s.headers.`Content-Encoding`

object GUnzipMiddleware {
def apply[F[_]: Sync](service: HttpRoutes[F], bufferSize: Int = 100 * 1024): HttpRoutes[F] =
Kleisli { (req: Request[F]) =>
val req2 = req.headers.get[`Content-Encoding`] match {
case Some(header) if satisfiedByGzip(header) =>
val decoded = req.body.through(Compression.forSync[F].gunzip(bufferSize)).flatMap(_.content).handleErrorWith {
e =>
throw MalformedMessageBodyFailure(
"Failed to decode gzippped request body",
Some(e)
)
}
req
.removeHeader[`Content-Encoding`]
.withEntity(decoded)(
EntityEncoder.entityBodyEncoder
) // resolving implicit conflict
case _ => req
}
service(req2)
}

private def satisfiedByGzip(header: `Content-Encoding`) =
header.contentCoding.matches(ContentCoding.gzip) || header.contentCoding.matches(ContentCoding.`x-gzip`)
}
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ class Routes[F[_]: Sync](

val value: HttpApp[F] = {
val routes = healthRoutes <+> corsRoute <+> cookieRoutes <+> rootRoute <+> crossdomainRoute
val res = if (enableDefaultRedirect) routes else rejectRedirect <+> routes
val res = if (enableDefaultRedirect) GUnzipMiddleware(routes) else rejectRedirect <+> routes
res.orNotFound
}
}

0 comments on commit 583e63b

Please sign in to comment.