hunk.code_window: The Hasura GraphQL Engine supports HTTP compression.
   The server looks for the ``Accept-Encoding`` header in request.
   If the header contains ``br`` then the server uses `Brotli <https://en.wikipedia.org/wiki/Brotli>`__ compression else if the header contains
   ``gzip`` then the server uses `Gzip <https://en.wikipedia.org/wiki/Gzip>`__ compression.
   If both values are present then the server prefers ``Brotli`` over ``Gzip``.
   Also, the server sets the ``Content-Encoding`` response header value to ``br`` for ``Brotli`` compression or ``gzip`` for ``Gzip`` compression.
   **Only responses from "/v1/query" and "/v1/graphql" endpoints are compressed.**
hunk.labels: keep keep keep replace replace replace replace keep keep
hunk.after_edit: If the header contains ``gzip`` then the server uses `Gzip <https://en.wikipedia.org/wiki/Gzip>`__ compression.
   Also, the server sets the ``Content-Encoding`` response header value to ``gzip``.
  
hunk.file_path: docs/graphql/manual/deployment/compression.rst
hunk.type: replace
file: module Hasura.Server.Compression
    ( compressResponse
    , CompressionType(..)
    , compressionTypeToTxt
    )
  where
  
  import           Hasura.Prelude
  
  import           Hasura.Server.Utils       (brHeader, gzipHeader)
  
  import qualified Codec.Compression.Brotli  as BR
  import qualified Codec.Compression.GZip    as GZ
  import qualified Data.ByteString.Lazy      as BL
  import qualified Data.Text                 as T
  import qualified Network.HTTP.Types.Header as NH
  
  data CompressionType
    = CTGZip
    | CTBrotli
    deriving (Show, Eq)
  
  compressionTypeToTxt :: CompressionType -> T.Text
  compressionTypeToTxt CTGZip   = "gzip"
  compressionTypeToTxt CTBrotli = "brotli"
  
  compressResponse
    :: NH.RequestHeaders
    -> BL.ByteString
    -> (BL.ByteString, Maybe (Text, Text), Maybe CompressionType)
  compressResponse reqHeaders unCompressedResp =
    let compressionTypeM = getRequestedCompression reqHeaders
        appendCompressionType (res, headerM) = (res, headerM, compressionTypeM)
    in appendCompressionType $ case compressionTypeM of
         Just CTBrotli -> (BR.compress unCompressedResp, Just brHeader)
         Just CTGZip   -> (GZ.compress unCompressedResp, Just gzipHeader)
         Nothing       -> (unCompressedResp, Nothing)
  
  getRequestedCompression :: NH.RequestHeaders -> Maybe CompressionType
  getRequestedCompression reqHeaders
    | "br" `elem` acceptEncodingVals   = Just CTBrotli
    | "gzip" `elem` acceptEncodingVals = Just CTGZip
    | otherwise                        = Nothing
    where
      acceptEncodingVals = concatMap (splitHeaderVal . snd) $
                           filter (\h -> fst h == NH.hAcceptEncoding) reqHeaders
      splitHeaderVal bs = map T.strip $ T.splitOn "," $ bsToTxt bs
  