--- /dev/null
+{-# LANGUAGE
+ QuasiQuotes
+ , RecordWildCards
+ , UnicodeSyntax
+ #-}
+-- |An internal module for generating Haskell modules eith an
+-- arbitrary file implanted.
+module Network.HTTP.Lucu.Implant
+ ( Input(..)
+
+ , originalLen
+ , gzippedLen
+ , useGZip
+
+ , openInput
+ )
+ where
+import Codec.Compression.GZip
+import Control.Applicative
+import qualified Data.Ascii as A
+import qualified Data.ByteString.Lazy as L
+import Data.Digest.Pure.SHA
+import Data.Maybe
+import Data.Time
+import Data.Time.Clock.POSIX
+import Network.HTTP.Lucu.ETag
+import Network.HTTP.Lucu.MIMEType hiding (mimeType)
+import Network.HTTP.Lucu.MIMEType.DefaultExtensionMap
+import Network.HTTP.Lucu.MIMEType.Guess
+import Network.HTTP.Lucu.MIMEType.TH
+import Prelude.Unicode
+import System.Posix.Files
+
+data Input
+ = Input {
+ iPath ∷ !FilePath
+ , iLastMod ∷ !UTCTime
+ , iType ∷ !MIMEType
+ , iETag ∷ !ETag
+ , iRawData ∷ !L.ByteString
+ , iGZipped ∷ !L.ByteString
+ }
+
+originalLen ∷ Input → Integer
+originalLen (Input {..})
+ = fromIntegral $ L.length iRawData
+
+gzippedLen ∷ Input → Integer
+gzippedLen (Input {..})
+ = fromIntegral $ L.length iGZipped
+
+useGZip ∷ Input → Bool
+useGZip i
+ = originalLen i ≥ gzippedLen i
+
+openInput ∷ FilePath → Maybe MIMEType → Maybe ETag → IO Input
+openInput fpath ctype etag
+ = do lastMod ← lastModified fpath
+ input ← openInputFile fpath
+ return Input {
+ iPath = fpath
+ , iLastMod = lastMod
+ , iType = fromMaybe octetStream
+ $ ctype <|> guessType fpath
+ , iETag = fromMaybe (mkETagFromInput input) etag
+ , iRawData = input
+ , iGZipped = compressWith compParams input
+ }
+ where
+ octetStream ∷ MIMEType
+ octetStream = [mimeType| application/octet-stream |]
+
+ compParams ∷ CompressParams
+ compParams = defaultCompressParams {
+ compressLevel = bestCompression
+ }
+
+lastModified ∷ FilePath → IO UTCTime
+lastModified "-" = getCurrentTime
+lastModified fpath = ( posixSecondsToUTCTime
+ ∘ fromRational
+ ∘ toRational
+ ∘ modificationTime
+ )
+ <$>
+ getFileStatus fpath
+
+openInputFile ∷ FilePath → IO L.ByteString
+openInputFile "-" = L.getContents
+openInputFile fpath = L.readFile fpath
+
+guessType ∷ FilePath → Maybe MIMEType
+guessType = guessTypeByFileName defaultExtensionMap
+
+mkETagFromInput ∷ L.ByteString → ETag
+mkETagFromInput input
+ = strongETag $ A.unsafeFromString
+ $ "SHA-1:" ⧺ showDigest (sha1 input)