]> gitweb @ CieloNegro.org - Lucu.git/blobdiff - Network/HTTP/Lucu/Implant.hs
Better name-rewriting engine
[Lucu.git] / Network / HTTP / Lucu / Implant.hs
diff --git a/Network/HTTP/Lucu/Implant.hs b/Network/HTTP/Lucu/Implant.hs
new file mode 100644 (file)
index 0000000..f80ac99
--- /dev/null
@@ -0,0 +1,98 @@
+{-# 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)