resHead ∷ Exp
resHead
- = infixApp (var $ name "Just")
- (op $ name "$" )
- (doE [ foundEntityStmt
- , setContentTypeStmt
- ])
+ = function "Just" `app`
+ paren (doE [ foundEntityStmt
+ , setContentTypeStmt
+ ])
resGetGZipped ∷ Exp
resGetGZipped
- = infixApp (var $ name "Just")
- (op $ name "$" )
- (doE [ foundEntityStmt
- , setContentTypeStmt
- , bindGZipStmt
- , conditionalOutputStmt
- ])
+ = function "Just" `app`
+ paren (doE [ foundEntityStmt
+ , setContentTypeStmt
+ , bindGZipStmt
+ , conditionalOutputStmt
+ ])
where
condVarName ∷ Name
condVarName = name "gzipAllowed"
bindGZipStmt
= genStmt (⊥)
(pvar condVarName)
- (metaFunction "isEncodingAcceptable" [strE "gzip"])
+ (function "isEncodingAcceptable" `app` strE "gzip")
conditionalOutputStmt ∷ Stmt
conditionalOutputStmt
(doE [ setContentEncodingGZipStmt
, outputStmt (var dataVarName)
])
- (metaFunction "output"
- [paren (metaFunction "decompress" [var dataVarName])])
+ ( function "output"
+ `app`
+ paren (function "decompress" `app` var dataVarName)
+ )
resGetRaw ∷ Exp
resGetRaw
- = infixApp (var $ name "Just")
- (op $ name "$" )
- (doE [ foundEntityStmt
- , setContentTypeStmt
- , outputStmt (var $ name "rawData")
- ])
+ = function "Just" `app`
+ paren (doE [ foundEntityStmt
+ , setContentTypeStmt
+ , outputStmt (var $ name "rawData")
+ ])
setContentEncodingGZipStmt ∷ Stmt
setContentEncodingGZipStmt
- = qualStmt $
- metaFunction "setContentEncoding"
- [ listE [ strE "gzip" ] ]
+ = qualStmt
+ ( function "setContentEncoding"
+ `app`
+ listE [ strE "gzip" ]
+ )
foundEntityStmt ∷ Stmt
foundEntityStmt
setContentTypeStmt ∷ Stmt
setContentTypeStmt
- = qualStmt $
- metaFunction "setContentType"
- [var $ name "contentType"]
+ = qualStmt
+ ( function "setContentType"
+ `app`
+ var (name "contentType")
+ )
outputStmt ∷ Exp → Stmt
outputStmt e
- = qualStmt $
- metaFunction "output" [e]
+ = qualStmt $ function "output" `app` e
entityTagDecl ∷ ETag → [Decl]
entityTagDecl eTag
varName = name "entityTag"
valExp ∷ Exp
- valExp = metaFunction "parseETag" [strE $ eTagToString eTag]
+ valExp = function "parseETag" `app` strE (eTagToString eTag)
lastModifiedDecl ∷ UTCTime → [Decl]
lastModifiedDecl lastMod
varName = name "lastModified"
valExp ∷ Exp
- valExp = metaFunction "read" [strE $ show lastMod]
+ valExp = function "read" `app` strE (show lastMod)
contentTypeDecl ∷ MIMEType → [Decl]
contentTypeDecl mime
varName = name "contentType"
valExp ∷ Exp
- valExp = metaFunction "parseMIMEType" [strE $ mimeToString mime]
+ valExp = function "parseMIMEType" `app` strE (mimeToString mime)
mimeToString ∷ MIMEType → String
mimeToString = A.toString ∘ A.fromAsciiBuilder ∘ printMIMEType
" Compression: gzip\n"
else
" Compression: disabled\n"
- , " MIME Type: ", show mimeType, "\n"
+ , " MIME Type: ", mimeTypeToString mimeType, "\n"
, " ETag: ", eTagToString eTag, "\n"
, " Last Modified: ", show localLastMod, "\n"
, " -}"
eTagToString ∷ ETag → String
eTagToString = A.toString ∘ A.fromAsciiBuilder ∘ printETag
+mimeTypeToString ∷ MIMEType → String
+mimeTypeToString = A.toString ∘ A.fromAsciiBuilder ∘ printMIMEType
+
getModuleName ∷ [CmdOpt] → IO ModuleName
getModuleName opts
= case modNameOpts of
-- *** MIME Type
, MIMEType(..)
+ , mkMIMEType
, parseMIMEType
-- *** Authorization
-- |Convert an 'ETag' to 'AsciiBuilder'.
printETag ∷ ETag → AsciiBuilder
+{-# INLINEABLE printETag #-}
printETag et
= ( if etagIsWeak et then
A.toAsciiBuilder "W/"
-- |Parse 'Etag' from an 'Ascii'. This functions throws an exception
-- for parse error.
parseETag ∷ Ascii → ETag
+{-# INLINEABLE parseETag #-}
parseETag str
- = let p = do et ← eTagP
- endOfInput
- return et
- bs = A.toByteString str
- in
- case parseOnly p bs of
- Right et → et
- Left err → error ("unparsable ETag: " ⧺ A.toString str ⧺ ": " ⧺ err)
+ = case parseOnly p $ A.toByteString str of
+ Right et → et
+ Left err → error ("unparsable ETag: " ⧺ A.toString str ⧺ ": " ⧺ err)
+ where
+ p ∷ Parser ETag
+ {-# INLINE p #-}
+ p = do et ← eTagP
+ endOfInput
+ return et
-- |This is equivalent to @'ETag' 'Prelude.False'@. If you want to
-- generate an ETag from a file, try using
-- 'Network.HTTP.Lucu.StaticFile.generateETagFromFile'.
strongETag ∷ Ascii → ETag
+{-# INLINE strongETag #-}
strongETag = ETag False
-- |This is equivalent to @'ETag' 'Prelude.True'@.
weakETag ∷ Ascii → ETag
+{-# INLINE weakETag #-}
weakETag = ETag True
eTagP ∷ Parser ETag
+{-# INLINEABLE eTagP #-}
eTagP = do isWeak ← option False (string "W/" *> return True)
str ← quotedStr
return $ ETag isWeak str
eTagListP ∷ Parser [ETag]
+{-# INLINEABLE eTagListP #-}
eTagListP = do xs ← listOf eTagP
when (null xs) $
fail "empty list of ETags"
-- |Manipulation of MIME Types.
module Network.HTTP.Lucu.MIMEType
( MIMEType(..)
+ , mkMIMEType
+
, parseMIMEType
, printMIMEType
, mtParams ∷ !(Map CIAscii Text)
} deriving (Eq, Show)
+-- |Construct a 'MIMEType' without any parameters.
+mkMIMEType ∷ CIAscii → CIAscii → MIMEType
+{-# INLINE mkMIMEType #-}
+mkMIMEType maj min
+ = MIMEType maj min (∅)
+
-- |Convert a 'MIMEType' to 'AsciiBuilder'.
printMIMEType ∷ MIMEType → AsciiBuilder
+{-# INLINEABLE printMIMEType #-}
printMIMEType (MIMEType maj min params)
= A.toAsciiBuilder (A.fromCIAscii maj) ⊕
A.toAsciiBuilder "/" ⊕
-- |Parse 'MIMEType' from an 'Ascii'. This function throws an
-- exception for parse error.
parseMIMEType ∷ Ascii → MIMEType
+{-# INLINEABLE parseMIMEType #-}
parseMIMEType str
- = let p = do t ← mimeTypeP
- endOfInput
- return t
- bs = A.toByteString str
- in
- case parseOnly p bs of
- Right t → t
- Left err → error ("unparsable MIME Type: " ⧺ A.toString str ⧺ ": " ⧺ err)
+ = case parseOnly p $ A.toByteString str of
+ Right t → t
+ Left err → error ("unparsable MIME Type: " ⧺ A.toString str ⧺ ": " ⧺ err)
+ where
+ p ∷ Parser MIMEType
+ {-# INLINE p #-}
+ p = do t ← mimeTypeP
+ endOfInput
+ return t
mimeTypeP ∷ Parser MIMEType
+{-# INLINEABLE mimeTypeP #-}
mimeTypeP = do maj ← A.toCIAscii <$> token
_ ← char '/'
min ← A.toCIAscii <$> token
return $ MIMEType maj min params
mimeTypeListP ∷ Parser [MIMEType]
+{-# INLINE mimeTypeListP #-}
mimeTypeListP = listOf mimeTypeP
-import qualified Data.ByteString.Lazy.Char8 as L8
+{-# LANGUAGE
+ OverloadedStrings
+ , UnicodeSyntax
+ #-}
+import qualified Data.ByteString.Lazy.Char8 as Lazy
+import Control.Applicative
+import Control.Monad.Unicode
import Data.Maybe
+import Data.Monoid.Unicode
import Network.HTTP.Lucu
-main :: IO ()
+main ∷ IO ()
main = let config = defaultConfig { cnfServerPort = "9999" }
resources = mkResTree [ ([], resMain) ]
in
runHttpd config resources []
-resMain :: ResourceDef
+resMain ∷ ResourceDef
resMain
- = ResourceDef {
- resUsesNativeThread = False
- , resIsGreedy = False
- , resGet
- = Just $ do setContentType $ read "text/html"
- output ("<title>Multipart Form Test</title>" ++
- "<form action=\"/\" method=\"post\" enctype=\"multipart/form-data\">" ++
- " Upload some file:" ++
- " <input type=\"text\" name=\"text\">" ++
- " <input type=\"file\" name=\"file\">" ++
- " <input type=\"submit\" value=\"Submit\">" ++
- "</form>")
- , resHead = Nothing
+ = emptyResource {
+ resGet
+ = Just $ do setContentType $ mkMIMEType "text" "html"
+ output ("<title>Multipart Form Test</title>\n" ⊕
+ "<form action=\"/\" method=\"post\" enctype=\"multipart/form-data\">\n" ⊕
+ " Upload some file:\n" ⊕
+ " <input type=\"text\" name=\"text\">\n" ⊕
+ " <input type=\"file\" name=\"file\">\n" ⊕
+ " <input type=\"submit\" value=\"Submit\">\n" ⊕
+ "</form>\n")
, resPost
- = Just $ do form <- inputForm defaultLimit
- let text = fromMaybe L8.empty $ fmap fdContent $ lookup "text" form
- file = fromMaybe L8.empty $ fmap fdContent $ lookup "file" form
- fileName = fdFileName =<< lookup "file" form
- setContentType $ read "text/plain"
- outputChunk ("You entered \"" ++ L8.unpack text ++ "\".\n")
- outputChunk ("You uploaded a " ++ show (L8.length file) ++ " bytes long file.\n")
- output ("The file name is " ++ show fileName ++ ".\n")
- , resPut = Nothing
- , resDelete = Nothing
- }
\ No newline at end of file
+ = Just $ do form ← inputForm defaultLimit
+ let text = fromMaybe (∅) $ fdContent <$> lookup "text" form
+ file = fromMaybe (∅) $ fdContent <$> lookup "file" form
+ fileName = fdFileName =≪ lookup "file" form
+ setContentType $ mkMIMEType "text" "plain"
+ outputChunk ("You entered \"" ⊕ text ⊕ "\".\n")
+ outputChunk ("You uploaded a " ⊕ Lazy.pack (show $ Lazy.length file) ⊕ " bytes long file.\n")
+ output ("The file name is " ⊕ Lazy.pack (show fileName) ⊕ ".\n")
+ }
-{-# LANGUAGE PackageImports #-}
-import Control.Monad
-import "mtl" Control.Monad.Trans
-import Data.Time.Clock
-import Network.HTTP.Lucu
-import OpenSSL
-import OpenSSL.EVP.PKey
-import OpenSSL.RSA
+{-# LANGUAGE
+ OverloadedStrings
+ , PackageImports
+ , UnicodeSyntax
+ #-}
+import Control.Applicative
+import "mtl" Control.Monad.Trans
+import Control.Monad.Unicode
+import qualified Data.ByteString.Lazy.Char8 as Lazy
+import Data.Time.Clock
+import Network.HTTP.Lucu
+import OpenSSL
+import OpenSSL.EVP.PKey
+import OpenSSL.RSA
import qualified OpenSSL.Session as SSL
-import OpenSSL.X509
+import OpenSSL.X509
-main :: IO ()
+main ∷ IO ()
main = withOpenSSL $
- do ctx <- SSL.context
+ do ctx ← SSL.context
- key <- generateRSAKey 1024 3 Nothing
- cert <- genCert key
+ key ← generateRSAKey 1024 3 Nothing
+ cert ← genCert key
SSL.contextSetPrivateKey ctx key
SSL.contextSetCertificate ctx cert
SSL.contextSetDefaultCiphers ctx
, sslContext = ctx
}
}
- resources = mkResTree [ ( []
- , helloWorld )
- ]
+ resources = mkResTree [ ([], helloWorld) ]
putStrLn "Access https://localhost:9001/ with your browser."
runHttpd config resources []
-
-helloWorld :: ResourceDef
+helloWorld ∷ ResourceDef
helloWorld
- = ResourceDef {
- resUsesNativeThread = False
- , resIsGreedy = False
- , resGet
- = Just $ do setContentType $ read "text/plain"
+ = emptyResource {
+ resGet
+ = Just $ do setContentType $ parseMIMEType "text/plain"
outputChunk "getRemoteCertificate = "
- cert <- do c <- getRemoteCertificate
- case c of
- Just c -> liftIO $ printX509 c
- Nothing -> return "Nothing"
+ cert ← do cert ← getRemoteCertificate
+ case cert of
+ Just c → liftIO $ Lazy.pack <$> printX509 c
+ Nothing → return "Nothing"
outputChunk cert
- , resHead = Nothing
- , resPost = Nothing
- , resPut = Nothing
- , resDelete = Nothing
}
-
-genCert :: KeyPair k => k -> IO X509
+genCert ∷ KeyPair k ⇒ k → IO X509
genCert pkey
- = do cert <- newX509
+ = do cert ← newX509
setVersion cert 2
setSerialNumber cert 1
setIssuerName cert [("CN", "localhost")]
setSubjectName cert [("CN", "localhost")]
- setNotBefore cert =<< liftM (addUTCTime (-1)) getCurrentTime
- setNotAfter cert =<< liftM (addUTCTime (365 * 24 * 60 * 60)) getCurrentTime
+ setNotBefore cert =≪ addUTCTime (-1) <$> getCurrentTime
+ setNotAfter cert =≪ addUTCTime (365 * 24 * 60 * 60) <$> getCurrentTime
setPublicKey cert pkey
signX509 cert pkey Nothing
return cert
\ No newline at end of file