module Network.HTTP.Lucu.Utils
( Scheme
, Host
, PathSegment
, Path
, splitBy
, quoteStr
, parseWWWFormURLEncoded
, uriCIScheme
, uriHost
, uriPathSegments
, trim
, (⊲)
, (⊳)
, (⋈)
, mapM
, getLastModified
)
where
import Control.Applicative hiding (empty)
import Control.Monad hiding (mapM)
import Data.Ascii (Ascii, AsciiBuilder, CIAscii)
import qualified Data.Ascii as A
import Data.ByteString (ByteString)
import qualified Data.ByteString.Char8 as BS
import Data.CaseInsensitive (CI)
import qualified Data.CaseInsensitive as CI
import Data.Char
import Data.Collections
import Data.Collections.BaseInstances ()
import Data.Convertible.Base
import Data.Convertible.Instances.Ascii ()
import Data.Convertible.Instances.Text ()
import Data.Convertible.Instances.Time ()
import Data.Maybe
import Data.Monoid.Unicode
import Data.Text (Text)
import Data.Time
import Network.URI
import Prelude hiding (last, mapM, null, reverse)
import Prelude.Unicode
import System.Directory
type Scheme = CIAscii
type Host = CI Text
type PathSegment = ByteString
type Path = [PathSegment]
splitBy ∷ (a → Bool) → [a] → [[a]]
splitBy isSep src
= case break isSep src of
(last , [] ) → [last]
(first, _sep:rest) → first : splitBy isSep rest
quoteStr ∷ Ascii → AsciiBuilder
quoteStr str = cs ("\"" ∷ Ascii) ⊕
go (cs str) (∅) ⊕
cs ("\"" ∷ Ascii)
where
go ∷ ByteString → AsciiBuilder → AsciiBuilder
go bs ab
= case BS.break (≡ '"') bs of
(x, y)
| BS.null y
→ ab ⊕ b2ab x
| otherwise
→ go (BS.tail y)
(ab ⊕ b2ab x ⊕ cs ("\\\"" ∷ Ascii))
b2ab ∷ ByteString → AsciiBuilder
b2ab = cs ∘ A.unsafeFromByteString
parseWWWFormURLEncoded ∷ Ascii → [(ByteString, ByteString)]
parseWWWFormURLEncoded src
| src ≡ "" = []
| otherwise = do pairStr ← splitBy (\ c → c ≡ ';' ∨ c ≡ '&') (cs src)
let (key, value) = break (≡ '=') pairStr
return ( unescape key
, unescape $ case value of
('=':val) → val
val → val
)
where
unescape ∷ String → ByteString
unescape = BS.pack ∘ unEscapeString ∘ (plusToSpace <$>)
plusToSpace ∷ Char → Char
plusToSpace '+' = ' '
plusToSpace c = c
uriCIScheme ∷ URI → CIAscii
uriCIScheme = convertUnsafe ∘ fst ∘ fromJust ∘ back ∘ uriScheme
uriHost ∷ URI → Host
uriHost = CI.mk ∘ cs ∘ uriRegName ∘ fromJust ∘ uriAuthority
uriPathSegments ∷ URI → Path
uriPathSegments uri
= let reqPathStr = uriPath uri
reqPath = [ unEscapeString x
| x ← splitBy (≡ '/') reqPathStr, (¬) (null x) ]
in
BS.pack <$> reqPath
trim ∷ String → String
trim = reverse ∘ f ∘ reverse ∘ f
where
f = dropWhile isSpace
infixr 5 ⊲
(⊲) ∷ Sequence α a ⇒ a → α → α
(⊲) = (<|)
infixl 5 ⊳
(⊳) ∷ Sequence α a ⇒ α → a → α
(⊳) = (|>)
infixr 5 ⋈
(⋈) ∷ Sequence α a ⇒ α → α → α
(⋈) = (><)
mapM ∷ (Foldable α a, Unfoldable β b, Functor m, Monad m)
⇒ (a → m b) → α → m β
mapM = flip foldrM empty ∘ (flip ((<$>) ∘ flip insert) ∘)
getLastModified ∷ FilePath → IO UTCTime
getLastModified = (cs <$>) ∘ getModificationTime