packages feed

xml-push 0.0.0.14 → 0.0.0.15

raw patch · 9 files changed

+448/−287 lines, 9 filesPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

API changes (from Hackage documentation)

- Network.XmlPush.HttpPull.Tls.Server: instance XmlPusher HttpPullTlsSv
- Network.XmlPush.HttpPush.Tls: instance XmlPusher HttpPushTls
+ Network.XmlPush.Http.Tls.Server: HttpPullSvArgs :: (XmlNode -> Bool) -> XmlNode -> (XmlNode -> Bool) -> HttpPullSvArgs h
+ Network.XmlPush.Http.Tls.Server: HttpPullTlsSvArgs :: (HttpPullSvArgs h) -> TlsArgs -> HttpPullTlsSvArgs h
+ Network.XmlPush.Http.Tls.Server: HttpPushArgs :: (XmlNode -> Maybe (HandleMonad h h, String, Int, FilePath)) -> Maybe (HandleMonad h h) -> Maybe (String, Int, FilePath) -> (XmlNode -> FilePath) -> (XmlNode -> Bool) -> HttpPushArgs h
+ Network.XmlPush.Http.Tls.Server: HttpPushTlsArgs :: (HttpPushArgs h) -> TlsArgs -> TlsArgs -> HttpPushTlsArgs h
+ Network.XmlPush.Http.Tls.Server: HttpTlsSvArgs :: (XmlNode -> Mechanism) -> (HttpPullSvArgs h) -> (HttpPushArgs h) -> TlsArgs -> TlsArgs -> HttpTlsSvArgs h
+ Network.XmlPush.Http.Tls.Server: Pull :: Mechanism
+ Network.XmlPush.Http.Tls.Server: Push :: Mechanism
+ Network.XmlPush.Http.Tls.Server: data HttpPullSvArgs h
+ Network.XmlPush.Http.Tls.Server: data HttpPullTlsSvArgs h
+ Network.XmlPush.Http.Tls.Server: data HttpPushArgs h
+ Network.XmlPush.Http.Tls.Server: data HttpPushTlsArgs h
+ Network.XmlPush.Http.Tls.Server: data HttpTlsSv h
+ Network.XmlPush.Http.Tls.Server: data HttpTlsSvArgs h
+ Network.XmlPush.Http.Tls.Server: data Mechanism
+ Network.XmlPush.Http.Tls.Server: instance Show Mechanism
+ Network.XmlPush.Http.Tls.Server: instance XmlPusher HttpTlsSv
+ Network.XmlPush.Http.Tls.Server: tlsArgsCl :: String -> Bool -> (XmlNode -> Maybe (SignedCertificate -> Bool)) -> [CipherSuite] -> CertificateStore -> [(CertSecretKey, CertificateChain)] -> TlsArgsCl
+ Network.XmlPush.Http.Tls.Server: tlsArgsSv :: (XmlNode -> Maybe String) -> (XmlNode -> Maybe (SignedCertificate -> Bool)) -> [CipherSuite] -> Maybe CertificateStore -> [(CertSecretKey, CertificateChain)] -> TlsArgsSv

Files

examples/httpPushTlsE.hs view
@@ -15,10 +15,10 @@ 	ca <- readCertificateStore ["certs/cacert.sample_pem"] 	k' <- readKey "certs/yoshikuni.sample_key" 	c' <- readCertificateChain ["certs/yoshikuni.sample_crt"]-	ch <- connectTo "localhost" $ PortNumber 80+	ch <- connectTo "localhost" $ PortNumber 443 	testPusher (undefined :: HttpPushTls Handle) (Two (Just ch) Nothing) (HttpPushTlsArgs 		(HttpPushArgs (const Nothing) getServerHandle-			(Just ("localhost", 80, "")) gtPth wntRspns)+			(Just ("localhost", 443, "")) gtPth wntRspns) 		(tlsArgsCl "localhost" True (const Nothing) 			["TLS_RSA_WITH_AES_128_CBC_SHA"] ca 			[(k', c')])
examples/httpPushTlsT.hs view
@@ -14,7 +14,7 @@  main :: IO () main = do-	soc <- listenOn $ PortNumber 80+	soc <- listenOn $ PortNumber 443 	ca <- readCertificateStore ["certs/cacert.sample_pem"] 	k' <- readKey "certs/localhost.sample_key" 	c' <- readCertificateChain ["certs/localhost.sample_crt"]
+ src/Network/XmlPush/Http/Tls/Server.hs view
@@ -0,0 +1,72 @@+{-# LANGUAGE OverloadedStrings, TypeFamilies, FlexibleContexts, PackageImports #-}++module Network.XmlPush.Http.Tls.Server (+	HttpTlsSv,+	HttpTlsSvArgs(..), Mechanism(..),+	HttpPullTlsSvArgs(..), HttpPullSvArgs(HttpPullSvArgs),+	HttpPushTlsArgs(..), HttpPushArgs(HttpPushArgs),+	tlsArgsCl, tlsArgsSv,+	) where++import Control.Applicative+import "monads-tf" Control.Monad.Error+import Control.Monad.Base+import Control.Monad.Trans.Control+import Data.Maybe+import Data.HandleLike+import Data.Pipe+import Data.Pipe.List+import Text.XML.Pipe+import Network.XmlPush+import Network.XmlPush.HttpPull.Tls.Server.Body+import Network.XmlPush.HttpPush.Tls.Body+import qualified Network.XmlPush.Tls.Client as Cl+import qualified Network.XmlPush.Tls.Server as Sv+import Network.TigHTTP.Server+import Network.Sasl+import Network.PeyoTLS.Server+import "crypto-random" Crypto.Random++newtype HttpTlsSv h = HttpTlsSv (Either (HttpPullTlsSv h) (HttpPushTls h))++data Mechanism = Pull | Push deriving Show++data HttpTlsSvArgs h = HttpTlsSvArgs+	(XmlNode -> Mechanism) (HttpPullSvArgs h) (HttpPushArgs h)+	Cl.TlsArgs Sv.TlsArgs++instance XmlPusher HttpTlsSv where+	type NumOfHandle HttpTlsSv = Two+	type PusherArgs HttpTlsSv = HttpTlsSvArgs+	generate (Two ch (Just sh)) (HttpTlsSvArgs s pla psa tlsC tlsS) =+		makeHttpTlsSv ch sh s pla psa tlsC tlsS+	generate _ _ = error "bad"+	readFrom (HttpTlsSv e) = either readFrom readFrom e+	writeTo (HttpTlsSv e) = either writeTo writeTo e++makeHttpTlsSv :: (+	ValidateHandle h, MonadBaseControl IO (HandleMonad h),+	MonadError (HandleMonad h), SaslError (ErrorType (HandleMonad h))+	) => Maybe h -> h -> (XmlNode -> Mechanism) ->+	HttpPullSvArgs h -> HttpPushArgs h ->+	Cl.TlsArgs -> Sv.TlsArgs ->+	HandleMonad h (HttpTlsSv h)+makeHttpTlsSv ch sh s pla' psa' tlsC tlsS@(TlsArgs gn cc cs mca kcs) = do+	g <- liftBase (cprgCreate <$> createEntropyPool :: IO SystemRNG)+	(`run` g) $ do+		t <- open sh cs kcs mca+		rq <- getRequest t+		Just [rn] <- runPipe $ requestBody rq+			=$= xmlEvent+			=$= convert fromJust+			=$= xmlNode []+			=$= toList+		HttpTlsSv `liftM` case s rn of+			Pull -> do+				HttpPullTlsSv r w <- makeHttpPull [rn] t pla' gn cc+				return . Left $ HttpPullTlsSv r w+			Push -> do+				hlDebug t "critical" "PUSH\n"+				ps <- makeHttpPush [rn] ch t $+					HttpPushTlsArgs psa' tlsC tlsS+				return $ Right ps
src/Network/XmlPush/HttpPull/Server/Body.hs view
@@ -30,9 +30,7 @@ makeHttpPull :: (HandleLike h, MonadBaseControl IO (HandleMonad h)) => 	[XmlNode] -> One h -> HttpPullSvArgs h -> HandleMonad h (HttpPullSv h) makeHttpPull pre (One h) (HttpPullSvArgs ip ep ynr) = do---	hlDebug h "critical" "begin makeHttpPull\n" 	(inc, otc) <- runXml pre h ip ep ynr (convert id)---	hlDebug h "critical" "runXml done\n" 	return $ HttpPullSv (fromTChan inc) (toTChan otc)  data HttpPullSvTest h = HttpPullSvTest
src/Network/XmlPush/HttpPull/Tls/Server.hs view
@@ -5,77 +5,4 @@ 	HttpPullTlsSv, HttpPullTlsSvArgs(..), HttpPullSvArgs(..), TlsArgs(..) 	) where -import Prelude hiding (filter)--import Control.Applicative-import Control.Monad-import "monads-tf" Control.Monad.Trans-import Control.Monad.Base-import Control.Monad.Trans.Control--- import Data.List--- import Data.Char-import Data.HandleLike-import Data.Pipe-import Data.Pipe.TChan-import Data.X509 hiding (getCertificate)--- import Data.X509.Validation-import Text.XML.Pipe--- import Numeric-import Network.PeyoTLS.Server-import "crypto-random" Crypto.Random---- import qualified Data.ByteString as BS--- import qualified Data.ByteString.Char8 as BSC--import Network.XmlPush-import Network.XmlPush.HttpPull.Server.Common-import Network.XmlPush.Tls.Server--data HttpPullTlsSv h = HttpPullTlsSv-	(Pipe () XmlNode (HandleMonad h) ())-	(Pipe XmlNode () (HandleMonad h) ())--data HttpPullTlsSvArgs h = HttpPullTlsSvArgs (HttpPullSvArgs h) TlsArgs--instance XmlPusher HttpPullTlsSv where-	type NumOfHandle HttpPullTlsSv = One-	type PusherArgs HttpPullTlsSv = HttpPullTlsSvArgs-	generate = makeHttpPull-	readFrom (HttpPullTlsSv r _) = r-	writeTo (HttpPullTlsSv _ w) = w--makeHttpPull :: (ValidateHandle h, MonadBaseControl IO (HandleMonad h)) =>-	One h -> HttpPullTlsSvArgs h -> HandleMonad h (HttpPullTlsSv h)-makeHttpPull (One h) (HttpPullTlsSvArgs-	(HttpPullSvArgs ip ep ynr) (TlsArgs gn cc cs mca kcs)) = do-	g <- liftBase (cprgCreate <$> createEntropyPool :: IO SystemRNG)-	(inc, otc) <- (`run` g) $ do-		t <- open h cs kcs mca-		{--		getCertificate t >>= hlDebug t "medium" . BSC.pack . show-			. toHexStr-			. flip getFingerprint HashSHA256-			-}-		runXml [] t ip ep ynr $ checkNameP t gn cc-	return $ HttpPullTlsSv (fromTChan inc) (toTChan otc)--{--toHexStr :: Fingerprint -> String-toHexStr (Fingerprint bs) = lastN 29 .-	intercalate ":" . map (map toUpper . flip showHex "") $ BS.unpack bs--lastN :: Int -> [a] -> [a]-lastN n xs = drop (length xs - n) xs--}--checkNameP :: HandleLike h => TlsHandle h g -> (XmlNode -> Maybe String) ->-	(XmlNode -> Maybe (SignedCertificate -> Bool)) ->-	Pipe XmlNode XmlNode (TlsM h g) ()-checkNameP t gn cc = (await >>=) . maybe (return ()) $ \n -> do-	ok <- maybe (return True) (lift . checkName t) $ gn n-	unless ok $ error "checkNameP: bad client name"-	let ck = maybe (const True) id $ cc n-	c <- lift $ getCertificate t-	unless (ck c) $ error "checkNameP: bad certificate"-	yield n-	checkNameP t gn cc+import Network.XmlPush.HttpPull.Tls.Server.Body
+ src/Network/XmlPush/HttpPull/Tls/Server/Body.hs view
@@ -0,0 +1,87 @@+{-# LANGUAGE OverloadedStrings, TypeFamilies, FlexibleContexts,+	PackageImports #-}++module Network.XmlPush.HttpPull.Tls.Server.Body (+	HttpPullTlsSv(..), HttpPullTlsSvArgs(..), HttpPullSvArgs(..), TlsArgs(..),+	HttpPullTlsSvTest(..), HttpPullTlsSvTestArgs(..),+	makeHttpPull,+	makeHttpPullTls,+	) where++import Prelude hiding (filter)++import Control.Applicative+import Control.Monad+import "monads-tf" Control.Monad.Trans+import Control.Monad.Base+import Control.Monad.Trans.Control+import Data.HandleLike+import Data.Pipe+import Data.Pipe.TChan+import Data.X509 hiding (getCertificate)+import Text.XML.Pipe+import Network.PeyoTLS.Server+import "crypto-random" Crypto.Random++import Network.XmlPush+import Network.XmlPush.HttpPull.Server.Common+import Network.XmlPush.Tls.Server++data HttpPullTlsSv h = HttpPullTlsSv+	(Pipe () XmlNode (HandleMonad h) ())+	(Pipe XmlNode () (HandleMonad h) ())++data HttpPullTlsSvArgs h = HttpPullTlsSvArgs (HttpPullSvArgs h) TlsArgs++instance XmlPusher HttpPullTlsSv where+	type NumOfHandle HttpPullTlsSv = One+	type PusherArgs HttpPullTlsSv = HttpPullTlsSvArgs+	generate = makeHttpPullTls []+	readFrom (HttpPullTlsSv r _) = r+	writeTo (HttpPullTlsSv _ w) = w++data HttpPullTlsSvTest h = HttpPullTlsSvTest+	(Pipe () XmlNode (HandleMonad h) ())+	(Pipe XmlNode () (HandleMonad h) ())++data HttpPullTlsSvTestArgs h = HttpPullTlsSvTestArgs (HttpPullTlsSvArgs h) [XmlNode]++instance XmlPusher HttpPullTlsSvTest where+	type NumOfHandle HttpPullTlsSvTest = One+	type PusherArgs HttpPullTlsSvTest = HttpPullTlsSvTestArgs+	generate h (HttpPullTlsSvTestArgs a pre) = do+		HttpPullTlsSv r w <- makeHttpPullTls pre h a+		return $ HttpPullTlsSvTest r w+	readFrom (HttpPullTlsSvTest r _) = r+	writeTo (HttpPullTlsSvTest _ w) = w++makeHttpPullTls :: (ValidateHandle h, MonadBaseControl IO (HandleMonad h)) =>+	[XmlNode] ->+	One h -> HttpPullTlsSvArgs h -> HandleMonad h (HttpPullTlsSv h)+makeHttpPullTls pre (One h) (HttpPullTlsSvArgs+	(HttpPullSvArgs ip ep ynr) (TlsArgs gn cc cs mca kcs)) = do+	g <- liftBase (cprgCreate <$> createEntropyPool :: IO SystemRNG)+	(`run` g) $ do+		t <- open h cs kcs mca+		makeHttpPull pre t (HttpPullSvArgs ip ep ynr) gn cc++makeHttpPull :: (ValidateHandle h, CPRG g, MonadBaseControl IO (HandleMonad h)) =>+	[XmlNode] -> TlsHandle h g -> HttpPullSvArgs h ->+	(XmlNode -> Maybe String) ->+	(XmlNode -> Maybe (SignedCertificate -> Bool)) ->+	TlsM h g (HttpPullTlsSv h)+makeHttpPull pre t (HttpPullSvArgs ip ep ynr) gn cc = do+		(inc, otc) <- runXml pre t ip ep ynr $ checkNameP t gn cc+		return $ HttpPullTlsSv (fromTChan inc) (toTChan otc)++checkNameP :: HandleLike h => TlsHandle h g -> (XmlNode -> Maybe String) ->+	(XmlNode -> Maybe (SignedCertificate -> Bool)) ->+	Pipe XmlNode XmlNode (TlsM h g) ()+checkNameP t gn cc = (await >>=) . maybe (return ()) $ \n -> do+	ok <- maybe (return True) (lift . checkName t) $ gn n+	unless ok $ error "checkNameP: bad client name"+	let ck = maybe (const True) id $ cc n+	c <- lift $ getCertificate t+	unless (ck c) $ error "checkNameP: bad certificate"+	yield n+	checkNameP t gn cc
src/Network/XmlPush/HttpPush/Tls.hs view
@@ -6,209 +6,4 @@ 	HttpPushTls, HttpPushTlsArgs(..), HttpPushArgs(..), 	TlsArgsCl, tlsArgsCl, TlsArgsSv, tlsArgsSv) where -import Prelude hiding (filter)--import Control.Applicative-import Control.Monad-import "monads-tf" Control.Monad.Trans-import Control.Monad.Base-import Control.Monad.Trans.Control-import Control.Concurrent hiding (yield)-import Control.Concurrent.STM-import Data.Maybe-import Data.HandleLike-import Data.Pipe-import Data.Pipe.Flow-import Data.Pipe.TChan-import Data.X509 hiding (getCertificate)-import Data.X509.CertificateStore-import Text.XML.Pipe-import Network.TigHTTP.Server-import Network.PeyoTLS.ReadFile-import Network.PeyoTLS.Server (getCertificate)-import Network.PeyoTLS.Client (ValidateHandle)-import "crypto-random" Crypto.Random--import qualified Data.ByteString.Lazy as LBS-import qualified Network.PeyoTLS.Client as Cl-import qualified Network.PeyoTLS.Server as Sv--import Network.XmlPush-import Network.XmlPush.HttpPush.Common-import Network.XmlPush.Tls.Client as TC-import Network.XmlPush.Tls.Server as TS--type TlsArgsCl = TC.TlsArgs--tlsArgsCl :: String -> Bool ->-	(XmlNode -> Maybe (SignedCertificate -> Bool)) ->-	[Cl.CipherSuite] -> CertificateStore ->-	[(CertSecretKey, CertificateChain)] -> TlsArgsCl-tlsArgsCl = TC.TlsArgs--type TlsArgsSv = TS.TlsArgs--tlsArgsSv :: (XmlNode -> Maybe String) ->-	(XmlNode -> Maybe (SignedCertificate -> Bool)) -> [Cl.CipherSuite] ->-	Maybe CertificateStore -> [(CertSecretKey, CertificateChain)] -> TlsArgsSv-tlsArgsSv = TS.TlsArgs--data HttpPushTls h = HttpPushTls {-	needReply :: TVar Bool,-	clientReadChan :: TChan (XmlNode, Bool),-	clientWriteChan :: TChan (Maybe XmlNode),-	serverReadChan :: TChan (XmlNode, Bool),-	serverWriteChan :: TChan (Maybe XmlNode) }--data HttpPushTlsArgs h = HttpPushTlsArgs (HttpPushArgs h) TC.TlsArgs TS.TlsArgs--instance XmlPusher HttpPushTls where-	type NumOfHandle HttpPushTls = Two-	type PusherArgs HttpPushTls = HttpPushTlsArgs-	generate (Two ch sh) = makeHttpPushTls ch sh-	readFrom hp = fromTChans [clientReadChan hp, serverReadChan hp] =$=-		setNeedReply (needReply hp)-	writeTo hp = (convert (((), ) . Just) =$=) . toTChansM $ do-		nr <- liftBase . atomically . readTVar $ needReply hp-		liftBase . atomically $ writeTVar (needReply hp) False-		return [-			(const nr, serverWriteChan hp),-			(const True, clientWriteChan hp) ]--makeHttpPushTls :: (ValidateHandle h, MonadBaseControl IO (HandleMonad h)) =>-	Maybe h -> Maybe h ->-	HttpPushTlsArgs h -> HandleMonad h (HttpPushTls h)-makeHttpPushTls mch msh (HttpPushTlsArgs (HttpPushArgs gc gs hi gp wr)-	(TC.TlsArgs dn cdn cc' cs ca kcs) (TS.TlsArgs gn cc cs' mca' kcs')) = do-	vch <- liftBase . atomically $ newTVar mch-	vsh <- liftBase . atomically $ newTVar msh-	case hi of-		Just (hn, _, _) -> when (dn /= hn) $-			error "makeHttpPushTls: conflicted domain name"-		_ -> return ()-	v <- liftBase . atomically $ newTVar False-	vhi <- liftBase . atomically $ newTVar hi-	(ci, co) <- clientC vch vhi cdn cc' gp cs ca kcs-	(si, so) <- talk wr vsh gn cc cs' mca' kcs' vch vhi gc gs-	return $ HttpPushTls v ci co si so--clientC :: (ValidateHandle h, MonadBaseControl IO (HandleMonad h)) =>-	TVar (Maybe h) -> TVar (Maybe (String, Int, FilePath)) -> Bool ->-	(XmlNode -> Maybe (SignedCertificate -> Bool)) ->-	(XmlNode -> FilePath) ->-	[Cl.CipherSuite] -> CertificateStore ->-	[(CertSecretKey, CertificateChain)] ->-	HandleMonad h (TChan (XmlNode, Bool), TChan (Maybe XmlNode))-clientC vh vhi cdn cc gp cs ca kcs = do-	inc <- liftBase $ atomically newTChan-	otc <- liftBase $ atomically newTChan-	(g :: SystemRNG) <- liftBase $ cprgCreate <$> createEntropyPool-	void . liftBaseDiscard forkIO $ do-		h <- liftBase . atomically $ do-			mh <- readTVar vh-			case mh of-				Just h -> return h-				_ -> retry-		(hn, pn, pt) <- liftBase . atomically $ do-			mhi <- readTVar vhi-			case mhi of-				Just hi -> return hi-				_ -> retry-		(`Cl.run` g) $ do-			t <- (if cdn then Cl.open' h hn else Cl.open h) cs kcs ca-			runPipe_ $ fromTChan otc-				=$= filter isJust-				=$= convert fromJust-				=$= clientLoop t hn pn pt gp (checkCertCl t cc)-				=$= convert (, False)-				=$= toTChan inc-	return (inc, otc)--talk :: (ValidateHandle h, MonadBaseControl IO (HandleMonad h)) =>-	(XmlNode -> Bool) -> (TVar (Maybe h)) -> (XmlNode -> Maybe String) ->-	(XmlNode -> Maybe (SignedCertificate -> Bool)) -> [Sv.CipherSuite] ->-	Maybe CertificateStore -> [(CertSecretKey, CertificateChain)] ->-	TVar (Maybe h) -> TVar (Maybe (String, Int, FilePath)) ->-	(XmlNode -> Maybe (HandleMonad h h, String, Int, FilePath)) ->-	Maybe (HandleMonad h h) ->-	HandleMonad h (TChan (XmlNode, Bool), TChan (Maybe XmlNode))-talk wr vh gn cc cs mca kcs vch vhi gc mgs = do-	inc <- liftBase $ atomically newTChan-	otc <- liftBase $ atomically newTChan-	g <- liftBase (cprgCreate <$> createEntropyPool :: IO SystemRNG)-	void . liftBaseDiscard forkIO $ do-		flip (maybe (return ())) mgs $ \gs -> do-			h <- gs-			liftBase . atomically $ writeTVar vh (Just h)-		h <- liftBase . atomically $ do-			mh <- readTVar vh-			case mh of-				Just h -> return h-				_ -> retry-		(`Sv.run` g) $ do-			t <- Sv.open h cs kcs mca-			runPipe_ . forever $ do-				req <- lift $ getRequest t-				requestBody req-					=$= xmlEvent-					=$= convert fromJust-					=$= xmlNode []-					=$= setClient vch vhi gc-					=$= checkCert t cc-					=$= checkName t gn-					=$= checkReply wr otc-					=$= toTChan inc-				fromTChan otc =$= await >>= maybe (return ()) (\mn ->-					lift . putResponse t . responseP $ case mn of-						Just n -> LBS.fromChunks [xmlString [n]]-						_ -> "")-	return (inc, otc)--checkCert :: HandleLike h => Sv.TlsHandle h g ->-	(XmlNode -> Maybe (SignedCertificate -> Bool)) ->-	Pipe XmlNode XmlNode (Sv.TlsM h g) ()-checkCert t cc = (await >>=) . maybe (return ()) $ \n -> do-	let ck = maybe (const True) id $ cc n-	c <- lift $ getCertificate t-	unless (ck c) $ error "checkCert: bad certificate"-	yield n-	checkCert t cc--checkCertCl :: (ValidateHandle h, CPRG g) => Cl.TlsHandle h g ->-	(XmlNode -> Maybe (SignedCertificate -> Bool)) ->-	Pipe XmlNode XmlNode (Cl.TlsM h g) ()-checkCertCl t cc = (await >>=) . maybe (return ()) $ \n -> do-	lift $ hlDebug t "medium" "begin checkCertCl"-	let ck = maybe (const True) id $ cc n-	c <- lift $ Cl.getCertificate t-	unless (ck c) $ error "checkCert: bad certificate"-	yield n-	checkCertCl t cc--checkName :: HandleLike h => Sv.TlsHandle h g -> (XmlNode -> Maybe String) ->-	Pipe XmlNode XmlNode (Sv.TlsM h g) ()-checkName t gn = (await >>=) . maybe (return ()) $ \n -> do-	ok <- maybe (return True) (lift . svCheckName t) $ gn n-	unless ok $ error "checkName: bad client name"-	yield n-	checkName t gn--svCheckName :: HandleLike h => Sv.TlsHandle h g -> String -> Sv.TlsM h g Bool-svCheckName t n = do-	ns <- Sv.getNames t-	return $ n `elem` ns--setClient :: (MonadBase IO (HandleMonad h)) =>-	TVar (Maybe h) -> TVar (Maybe (String, Int, FilePath)) ->-	(XmlNode -> Maybe (HandleMonad h h, String, Int, FilePath)) ->-	Pipe XmlNode XmlNode (Sv.TlsM h g) ()-setClient vch vhi gc = (await >>=) . maybe (return ()) $ \n -> do-	yield n-	case gc n of-		Just (gh, hn, pn, pt) -> do-			h <- lift . lift $ lift gh-			lift . liftBase . atomically . writeTVar vch $ Just h-			lift . liftBase . atomically . writeTVar vhi-				$ Just (hn, pn, pt)-		_ -> return ()-	setClient vch vhi gc+import Network.XmlPush.HttpPush.Tls.Body
+ src/Network/XmlPush/HttpPush/Tls/Body.hs view
@@ -0,0 +1,279 @@+{-# LANGUAGE OverloadedStrings, TupleSections, ScopedTypeVariables,+	TypeFamilies, FlexibleContexts,+	PackageImports #-}++module Network.XmlPush.HttpPush.Tls.Body (+	HttpPushTls, HttpPushTlsArgs(..), HttpPushArgs(..),+	TlsArgsCl, tlsArgsCl, TlsArgsSv, tlsArgsSv,+	makeHttpPush, makeHttpPushTls,+	HttpPushTlsTest(..), HttpPushTlsTestArgs(..),+	) where++import Prelude hiding (filter)++import Control.Applicative+import Control.Monad+import "monads-tf" Control.Monad.Trans+import Control.Monad.Base+import Control.Monad.Trans.Control+import Control.Concurrent hiding (yield)+import Control.Concurrent.STM+import Data.Maybe+import Data.HandleLike+import Data.Pipe+import Data.Pipe.Flow+import Data.Pipe.TChan+import Data.X509 hiding (getCertificate)+import Data.X509.CertificateStore+import Text.XML.Pipe+import Network.TigHTTP.Server+import Network.PeyoTLS.ReadFile+import Network.PeyoTLS.Server (getCertificate)+import Network.PeyoTLS.Client (ValidateHandle)+import "crypto-random" Crypto.Random++import qualified Data.ByteString.Lazy as LBS+import qualified Network.PeyoTLS.Client as Cl+import qualified Network.PeyoTLS.Server as Sv++import Network.XmlPush+import Network.XmlPush.HttpPush.Common+import Network.XmlPush.Tls.Client as TC+import Network.XmlPush.Tls.Server as TS++type TlsArgsCl = TC.TlsArgs++tlsArgsCl :: String -> Bool ->+	(XmlNode -> Maybe (SignedCertificate -> Bool)) ->+	[Cl.CipherSuite] -> CertificateStore ->+	[(CertSecretKey, CertificateChain)] -> TlsArgsCl+tlsArgsCl = TC.TlsArgs++type TlsArgsSv = TS.TlsArgs++tlsArgsSv :: (XmlNode -> Maybe String) ->+	(XmlNode -> Maybe (SignedCertificate -> Bool)) -> [Cl.CipherSuite] ->+	Maybe CertificateStore -> [(CertSecretKey, CertificateChain)] -> TlsArgsSv+tlsArgsSv = TS.TlsArgs++data HttpPushTls h = HttpPushTls {+	needReply :: TVar Bool,+	clientReadChan :: TChan (XmlNode, Bool),+	clientWriteChan :: TChan (Maybe XmlNode),+	serverReadChan :: TChan (XmlNode, Bool),+	serverWriteChan :: TChan (Maybe XmlNode) }++data HttpPushTlsArgs h = HttpPushTlsArgs (HttpPushArgs h) TC.TlsArgs TS.TlsArgs++instance XmlPusher HttpPushTls where+	type NumOfHandle HttpPushTls = Two+	type PusherArgs HttpPushTls = HttpPushTlsArgs+	generate (Two ch sh) = makeHttpPushTls [] ch sh+	readFrom hp = fromTChans [clientReadChan hp, serverReadChan hp] =$=+		setNeedReply (needReply hp)+	writeTo hp = (convert (((), ) . Just) =$=) . toTChansM $ do+		nr <- liftBase . atomically . readTVar $ needReply hp+		liftBase . atomically $ writeTVar (needReply hp) False+		return [+			(const nr, serverWriteChan hp),+			(const True, clientWriteChan hp) ]++data HttpPushTlsTest h = HttpPushTlsTest (HttpPushTls h)+data HttpPushTlsTestArgs h = HttpPushTlsTestArgs (HttpPushTlsArgs h) [XmlNode]++instance XmlPusher HttpPushTlsTest where+	type NumOfHandle HttpPushTlsTest = Two+	type PusherArgs HttpPushTlsTest = HttpPushTlsTestArgs+	generate (Two ch sh) (HttpPushTlsTestArgs a p) =+		HttpPushTlsTest <$> makeHttpPushTls p ch sh a+	readFrom (HttpPushTlsTest hp) = readFrom hp+	writeTo (HttpPushTlsTest hp) = writeTo hp++makeHttpPushTls :: (ValidateHandle h, MonadBaseControl IO (HandleMonad h)) =>+	[XmlNode] ->+	Maybe h -> Maybe h ->+	HttpPushTlsArgs h -> HandleMonad h (HttpPushTls h)+makeHttpPushTls pre mch msh (HttpPushTlsArgs (HttpPushArgs gc gs hi gp wr)+	(TC.TlsArgs dn cdn cc' cs ca kcs) (TS.TlsArgs gn cc cs' mca' kcs')) = do+	vch <- liftBase . atomically $ newTVar mch+	vsh <- liftBase . atomically $ newTVar msh+	case hi of+		Just (hn, _, _) -> when (dn /= hn) $+			error "makeHttpPushTls: conflicted domain name"+		_ -> return ()+	v <- liftBase . atomically $ newTVar False+	vhi <- liftBase . atomically $ newTVar hi+	(ci, co) <- clientC vch vhi cdn cc' gp cs ca kcs+	(si, so) <- talk pre wr vsh gn cc cs' mca' kcs' vch vhi gc gs+	return $ HttpPushTls v ci co si so++makeHttpPush :: (ValidateHandle h, MonadBaseControl IO (HandleMonad h), CPRG g) =>+	[XmlNode] -> Maybe h -> Sv.TlsHandle h g ->+	HttpPushTlsArgs h -> Sv.TlsM h g (HttpPushTls h)+makeHttpPush pre mch t (HttpPushTlsArgs (HttpPushArgs gc gs hi gp wr)+	(TC.TlsArgs dn cdn cc' cs ca kcs) (TS.TlsArgs gn cc cs' mca' kcs')) = do+	vch <- lift . lift . liftBase . atomically $ newTVar mch+	vsh <- lift . lift . liftBase . atomically $ newTVar undefined+	hlDebug t "critical" "in makeHttpPush\n"+	case hi of+		Just (hn, _, _) -> when (dn /= hn) $+			error "makeHttpPushTls: conflicted domain name"+		_ -> return ()+	v <- lift . lift . liftBase . atomically $ newTVar False+	vhi <- lift . lift . liftBase . atomically $ newTVar hi+	(ci, co) <- lift . lift $ clientC vch vhi cdn cc' gp cs ca kcs+	(si, so) <- do+		inc <- lift . lift . liftBase $ atomically newTChan+		otc <- lift . lift . liftBase $ atomically newTChan+		hlDebug t "critical" "before talkT\n"+		void . liftBaseDiscard forkIO $+			talkT t inc otc pre wr gn cc vch vhi gc+		hlDebug t "critical" "after talkT\n"+		return (inc, otc)+	return $ HttpPushTls v ci co si so++clientC :: (ValidateHandle h, MonadBaseControl IO (HandleMonad h)) =>+	TVar (Maybe h) -> TVar (Maybe (String, Int, FilePath)) -> Bool ->+	(XmlNode -> Maybe (SignedCertificate -> Bool)) ->+	(XmlNode -> FilePath) ->+	[Cl.CipherSuite] -> CertificateStore ->+	[(CertSecretKey, CertificateChain)] ->+	HandleMonad h (TChan (XmlNode, Bool), TChan (Maybe XmlNode))+clientC vh vhi cdn cc gp cs ca kcs = do+	inc <- liftBase $ atomically newTChan+	otc <- liftBase $ atomically newTChan+	(g :: SystemRNG) <- liftBase $ cprgCreate <$> createEntropyPool+	void . liftBaseDiscard forkIO $ do+		h <- liftBase . atomically $ do+			mh <- readTVar vh+			case mh of+				Just h -> return h+				_ -> retry+		(hn, pn, pt) <- liftBase . atomically $ do+			mhi <- readTVar vhi+			case mhi of+				Just hi -> return hi+				_ -> retry+		(`Cl.run` g) $ do+			t <- (if cdn then Cl.open' h hn else Cl.open h) cs kcs ca+			runPipe_ $ fromTChan otc+				=$= filter isJust+				=$= convert fromJust+				=$= clientLoop t hn pn pt gp (checkCertCl t cc)+				=$= convert (, False)+				=$= toTChan inc+	return (inc, otc)++talk :: (ValidateHandle h, MonadBaseControl IO (HandleMonad h)) =>+	[XmlNode] ->+	(XmlNode -> Bool) -> (TVar (Maybe h)) -> (XmlNode -> Maybe String) ->+	(XmlNode -> Maybe (SignedCertificate -> Bool)) -> [Sv.CipherSuite] ->+	Maybe CertificateStore -> [(CertSecretKey, CertificateChain)] ->+	TVar (Maybe h) -> TVar (Maybe (String, Int, FilePath)) ->+	(XmlNode -> Maybe (HandleMonad h h, String, Int, FilePath)) ->+	Maybe (HandleMonad h h) ->+	HandleMonad h (TChan (XmlNode, Bool), TChan (Maybe XmlNode))+talk pre wr vh gn cc cs mca kcs vch vhi gc mgs = do+	g <- liftBase (cprgCreate <$> createEntropyPool :: IO SystemRNG)+	inc <- liftBase $ atomically newTChan+	otc <- liftBase $ atomically newTChan+	void . liftBaseDiscard forkIO $ do+		flip (maybe (return ())) mgs $ \gs -> do+			h <- gs+			liftBase . atomically $ writeTVar vh (Just h)+		h <- liftBase . atomically $ do+			mh <- readTVar vh+			case mh of+				Just h -> return h+				_ -> retry+		(`Sv.run` g) $ do+			t <- Sv.open h cs kcs mca+			talkT t inc otc pre wr gn cc vch vhi gc+	return (inc, otc)++talkT :: (ValidateHandle h, MonadBase IO (HandleMonad h), CPRG g) =>+	Sv.TlsHandle h g -> TChan (XmlNode, Bool) -> TChan (Maybe XmlNode) ->+	[XmlNode] -> (XmlNode -> Bool) -> (XmlNode -> Maybe String) ->+	(XmlNode -> Maybe (SignedCertificate -> Bool)) -> TVar (Maybe h) ->+	TVar (Maybe (String, Int, FilePath)) ->+	(XmlNode -> Maybe (HandleMonad h h, String, Int, FilePath)) ->+	Sv.TlsM h g ()+talkT t inc otc pre wr gn cc vch vhi gc = do+			runPipe_ . writeToChan t inc otc pre $+				setClient vch vhi gc =$= checkReply wr otc+			runPipe_ . forever $ do+				req <- lift $ getRequest t+				requestBody req+					=$= xmlEvent+					=$= convert fromJust+					=$= xmlNode []+					=$= setClient vch vhi gc+					=$= checkCert t cc+					=$= checkName t gn+					=$= checkReply wr otc+					=$= toTChan inc+				fromTChan otc =$= await >>= maybe (return ()) (\mn ->+					lift . putResponse t . responseP $ case mn of+						Just n -> LBS.fromChunks [xmlString [n]]+						_ -> "")++writeToChan :: (HandleLike h, MonadBase IO (HandleMonad h)) =>+	h -> TChan a -> TChan (Maybe XmlNode) -> [XmlNode] ->+	Pipe XmlNode a (HandleMonad h) () ->+	Pipe () () (HandleMonad h) ()+writeToChan _ _ _ [] _ = return ()+writeToChan h inc otc pre pp = do+	mapM yield pre =$= pp =$= toTChan inc+	fromTChan otc =$= await >>= maybe (return ()) (\mn ->+		lift . putResponse h . responseP $ case mn of+			Just n -> LBS.fromChunks [xmlString [n]]+			_ -> "")++checkCert :: HandleLike h => Sv.TlsHandle h g ->+	(XmlNode -> Maybe (SignedCertificate -> Bool)) ->+	Pipe XmlNode XmlNode (Sv.TlsM h g) ()+checkCert t cc = (await >>=) . maybe (return ()) $ \n -> do+	let ck = maybe (const True) id $ cc n+	c <- lift $ getCertificate t+	unless (ck c) $ error "checkCert: bad certificate"+	yield n+	checkCert t cc++checkCertCl :: (ValidateHandle h, CPRG g) => Cl.TlsHandle h g ->+	(XmlNode -> Maybe (SignedCertificate -> Bool)) ->+	Pipe XmlNode XmlNode (Cl.TlsM h g) ()+checkCertCl t cc = (await >>=) . maybe (return ()) $ \n -> do+	lift $ hlDebug t "medium" "begin checkCertCl"+	let ck = maybe (const True) id $ cc n+	c <- lift $ Cl.getCertificate t+	unless (ck c) $ error "checkCert: bad certificate"+	yield n+	checkCertCl t cc++checkName :: HandleLike h => Sv.TlsHandle h g -> (XmlNode -> Maybe String) ->+	Pipe XmlNode XmlNode (Sv.TlsM h g) ()+checkName t gn = (await >>=) . maybe (return ()) $ \n -> do+	ok <- maybe (return True) (lift . svCheckName t) $ gn n+	unless ok $ error "checkName: bad client name"+	yield n+	checkName t gn++svCheckName :: HandleLike h => Sv.TlsHandle h g -> String -> Sv.TlsM h g Bool+svCheckName t n = do+	ns <- Sv.getNames t+	return $ n `elem` ns++setClient :: (MonadBase IO (HandleMonad h)) =>+	TVar (Maybe h) -> TVar (Maybe (String, Int, FilePath)) ->+	(XmlNode -> Maybe (HandleMonad h h, String, Int, FilePath)) ->+	Pipe XmlNode XmlNode (Sv.TlsM h g) ()+setClient vch vhi gc = (await >>=) . maybe (return ()) $ \n -> do+	yield n+	case gc n of+		Just (gh, hn, pn, pt) -> do+			h <- lift . lift $ lift gh+			lift . liftBase . atomically . writeTVar vch $ Just h+			lift . liftBase . atomically . writeTVar vhi+				$ Just (hn, pn, pt)+		_ -> return ()+	setClient vch vhi gc
xml-push.cabal view
@@ -2,7 +2,7 @@ cabal-version:	>= 1.8  name:		xml-push-version:	0.0.0.14+version:	0.0.0.15 stability:	Experimenmtal author:		Yoshikuni Jujo <PAF01143@nifty.ne.jp> maintainer:	Yoshikuni Jujo <PAF01143@nifty.ne.jp>@@ -100,7 +100,7 @@ source-repository	this     type:	git     location:	git://github.com/YoshikuniJujo/xml-push.git-    tag:	xml-push-0.0.0.14+    tag:	xml-push-0.0.0.15  library     hs-source-dirs:	src@@ -112,6 +112,7 @@         Network.XmlPush.HttpPull.Tls.Client, Network.XmlPush.HttpPull.Tls.Server         Network.XmlPush.HttpPush, Network.XmlPush.HttpPush.Tls         Network.XmlPush.Http.Server+        Network.XmlPush.Http.Tls.Server     other-modules:         Network.XmlPush.Tls.Client         Network.XmlPush.Tls.Server@@ -120,8 +121,10 @@         Network.XmlPush.HttpPull.Client.Common         Network.XmlPush.HttpPull.Server.Common         Network.XmlPush.HttpPull.Server.Body+        Network.XmlPush.HttpPull.Tls.Server.Body         Network.XmlPush.HttpPush.Common         Network.XmlPush.HttpPush.Body+        Network.XmlPush.HttpPush.Tls.Body     build-depends:         base == 4.*, peyotls == 0.1.*, simple-pipe == 0.0.*, xml-pipe == 0.0.*,         handle-like == 0.1.*, monad-control == 0.3.*, transformers-base == 0.4.*,