packages feed

http2-tls 0.2.7 → 0.2.8

raw patch · 5 files changed

+351/−16 lines, 5 filesdep +asyncdep +cryptondep +http-typesdep ~bytestringdep ~http2dep ~network-controlnew-component:exe:h2-clientnew-component:exe:h2-serverPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

Dependencies added: async, crypton, http-types, http2-tls, tls-session-manager

Dependency ranges changed: bytestring, http2, network-control, tls

API changes (from Hackage documentation)

- Network.HTTP2.TLS.Client: type Client a = forall b. () => Request -> Response -> IO b -> IO b -> Aux -> IO a
+ Network.HTTP2.TLS.Client: type Client a = SendRequest -> Aux -> IO a

Files

http2-tls.cabal view
@@ -1,6 +1,6 @@ cabal-version: >=1.10 name:          http2-tls-version:       0.2.7+version:       0.2.8 license:       BSD3 license-file:  LICENSE maintainer:    Kazu Yamamoto <kazu@iij.ad.jp>@@ -18,6 +18,10 @@ flag crypton     description: Use the crypton-x509-* package family instead of x509-* +flag devel+    description: Development commands+    default:     False+ library     exposed-modules:         Network.HTTP2.TLS.Client@@ -36,27 +40,68 @@     ghc-options:        -Wall     build-depends:         base >=4.9 && <5,-        bytestring >= 0.10,-        http2 >=5.1 && < 5.2,-        data-default-class >= 0.1 && < 0.2,-        network >= 3.1.4,-        time-manager >= 0.0.1 && < 0.1,-        unliftio >= 0.2 && < 0.3,-        network-run >= 0.2.6 && < 0.3,-        network-control >= 0.0.2 && < 0.1,-        recv >= 0.1.0 && < 0.2,-        utf8-string >= 1.0 && < 1.1+        bytestring >=0.10,+        http2 >=5.1 && <5.2,+        data-default-class >=0.1 && <0.2,+        network >=3.1.4,+        time-manager >=0.0.1 && <0.1,+        unliftio >=0.2 && <0.3,+        network-run >=0.2.6 && <0.3,+        network-control >=0.1 && <0.2,+        recv >=0.1.0 && <0.2,+        utf8-string >=1.0 && <1.1      if flag(crypton)         build-depends:-            -- If we raise the lower bound on @tls@, then the @crypton@ flag-            -- becomes useless and we should remove it.-            tls >=1.7 && < 2.1,-            crypton-x509-store >= 1.6 && < 1.7,-            crypton-x509-validation >= 1.6 && < 1.7+            tls >=1.7 && <2.1,+            crypton-x509-store >=1.6 && <1.7,+            crypton-x509-validation >=1.6 && <1.7      else         build-depends:             tls <1.7,             x509-store,             x509-validation++executable h2-client+    main-is:            h2-client.hs+    hs-source-dirs:     util+    other-modules:      Client+    default-language:   Haskell2010+    default-extensions: Strict StrictData+    ghc-options:        -Wall -threaded -rtsopts+    build-depends:+        base >=4.9 && <5,+        async,+        bytestring,+        http-types,+        http2,+        http2-tls,+        tls++    if flag(devel)++    else+        buildable: False++executable h2-server+    main-is:            h2-server.hs+    hs-source-dirs:     util+    other-modules:      Server+    default-language:   Haskell2010+    default-extensions: Strict StrictData+    ghc-options:        -Wall -threaded+    build-depends:+        base >=4.9 && <5,+        bytestring,+        crypton,+        http-types,+        http2,+        http2-tls,+        tls,+        tls-session-manager++    if flag(devel)++    else+        buildable: False
+ util/Client.hs view
@@ -0,0 +1,29 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RankNTypes #-}++module Client where++import Control.Concurrent.Async+import qualified Control.Exception as E+import qualified Data.ByteString.Char8 as C8+import Network.HTTP.Types++import Network.HTTP2.Client++client :: Int -> [Path] -> Client ()+client n0 paths sendRequest _aux = do+    ex <- E.try $ foldr1 concurrently_ $ map (client' n0 sendRequest) paths+    case ex of+        Right () -> return ()+        Left e -> print (e :: HTTP2Error)++client' :: Int -> SendRequest -> Path -> IO ()+client' n0 sendRequest path = loop n0+  where+    req = requestNoBody methodGet path []+    loop 0 = return ()+    loop n = do+        sendRequest req $ \rsp -> do+            print $ responseStatus rsp+            getResponseBodyChunk rsp >>= C8.putStrLn+        loop (n - 1)
+ util/Server.hs view
@@ -0,0 +1,55 @@+{-# LANGUAGE OverloadedStrings #-}++module Server where++import Control.Monad+import Crypto.Hash (Context, SHA1) -- crypton+import qualified Crypto.Hash as CH+import Data.ByteString (ByteString)+import qualified Data.ByteString as B+import Data.ByteString.Builder (byteString)+import qualified Data.ByteString.Char8 as C8+import Network.HTTP.Types+import Network.HTTP2.Server++server :: Server+server req _aux sendResponse = case requestMethod req of+    Just "GET"+        | requestPath req == Just "/" -> sendResponse responseHello []+    Just "POST" -> sendResponse (responseEcho req) []+    _ -> sendResponse response404 []++responseHello :: Response+responseHello = responseBuilder ok200 header body+  where+    header = [("Content-Type", "text/plain")]+    body = byteString "Hello, world!\n"++response404 :: Response+response404 = responseBuilder notFound404 header body+  where+    header = [("Content-Type", "text/plain")]+    body = byteString "Not found\n"++responseEcho :: Request -> Response+responseEcho req = setResponseTrailersMaker h2rsp maker+  where+    h2rsp = responseStreaming ok200 header streamingBody+    header = [("Content-Type", "text/plain")]+    streamingBody write _flush = loop+      where+        loop = do+            bs <- getRequestBodyChunk req+            unless (B.null bs) $ do+                void $ write $ byteString bs+                loop+    maker = trailersMaker (CH.hashInit :: Context SHA1)++-- Strictness is important for Context.+trailersMaker :: Context SHA1 -> Maybe ByteString -> IO NextTrailersMaker+trailersMaker ctx Nothing = return $ Trailers [("X-SHA1", sha1)]+  where+    sha1 = C8.pack $ show $ CH.hashFinalize ctx+trailersMaker ctx (Just bs) = return $ NextTrailersMaker $ trailersMaker ctx'+  where+    ctx' = CH.hashUpdate ctx bs
+ util/h2-client.hs view
@@ -0,0 +1,122 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards #-}++module Main where++import Control.Monad+import qualified Data.ByteString.Char8 as C8+import Data.IORef+import Network.HTTP2.TLS.Client+import Network.TLS+import System.Console.GetOpt+import System.Environment+import System.Exit++import Client++data Options = Options+    { optKeyLogFile :: Maybe FilePath+    , optValidate :: Bool+    , optResumption :: Bool+    , opt0RTT :: Bool+    , optNumOfReqs :: Int+    }+    deriving (Show)++defaultOptions :: Options+defaultOptions =+    Options+        { optKeyLogFile = Nothing+        , optValidate = False+        , optResumption = False+        , opt0RTT = False+        , optNumOfReqs = 1+        }++usage :: String+usage = "Usage: h2-client [OPTION] addr port [path]"++options :: [OptDescr (Options -> Options)]+options =+    [ Option+        ['l']+        ["key-log-file"]+        (ReqArg (\file o -> o{optKeyLogFile = Just file}) "<file>")+        "a file to store negotiated secrets"+    , Option+        ['e']+        ["validate"]+        (NoArg (\o -> o{optValidate = True}))+        "validate server's certificate"+    , Option+        ['R']+        ["resumption"]+        (NoArg (\o -> o{optResumption = True}))+        "try session resumption"+    , Option+        ['Z']+        ["0rtt"]+        (NoArg (\o -> o{opt0RTT = True}))+        "try sending early data"+    , Option+        ['n']+        ["number-of-requests"]+        (ReqArg (\n o -> o{optNumOfReqs = read n}) "<n>")+        "specify the number of requests"+    ]++showUsageAndExit :: String -> IO a+showUsageAndExit msg = do+    putStrLn msg+    putStrLn $ usageInfo usage options+    exitFailure++clientOpts :: [String] -> IO (Options, [String])+clientOpts argv =+    case getOpt Permute options argv of+        (o, n, []) -> return (foldl (flip id) defaultOptions o, n)+        (_, _, errs) -> showUsageAndExit $ concat errs++main :: IO ()+main = do+    args <- getArgs+    (Options{..}, ips) <- clientOpts args+    (host, port, paths) <- case ips of+        [] -> showUsageAndExit usage+        _ : [] -> showUsageAndExit usage+        h : p : [] -> return (h, read p, ["/"])+        h : p : ps -> return (h, read p, C8.pack <$> ps)+    ref <- newIORef Nothing+    let keylog msg = case optKeyLogFile of+            Nothing -> return ()+            Just file -> appendFile file (msg ++ "\n")+        settings =+            defaultSettings+                { settingsValidateCert = optValidate+                , settingsKeyLogger = keylog+                , settingsSessionManager = sessionRef ref+                }+    run settings host port $ client optNumOfReqs paths+    when (optResumption || opt0RTT) $ do+        mr <- readIORef ref+        case mr of+            Nothing -> do+                putStrLn "No session data"+                exitFailure+            _ -> do+                let settings2 =+                        defaultSettings+                            { settingsValidateCert = optValidate+                            , settingsKeyLogger = keylog+                            , settingsWantSessionResume = mr+                            , settingsUseEarlyData = opt0RTT+                            }+                run settings2 host port $ client optNumOfReqs paths++sessionRef :: IORef (Maybe (SessionID, SessionData)) -> SessionManager+sessionRef ref =+    noSessionManager+        { sessionEstablish = \sid sdata -> do+            writeIORef ref $ Just (sid, sdata)+            return Nothing+        }
+ util/h2-server.hs view
@@ -0,0 +1,84 @@+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards #-}++module Main (main) where++import Network.HTTP2.TLS.Server+import Network.TLS (Credentials (..), credentialLoadX509)+import Network.TLS.SessionTicket+import System.Console.GetOpt+import System.Environment+import System.Exit++import Server++options :: [OptDescr (Options -> Options)]+options =+    [ Option+        ['l']+        ["key-log-file"]+        (ReqArg (\file o -> o{optKeyLogFile = Just file}) "<file>")+        "a file to store negotiated secrets"+    , Option+        ['c']+        ["cert"]+        (ReqArg (\fl o -> o{optCertFile = fl}) "<file>")+        "certificate file"+    , Option+        ['k']+        ["key"]+        (ReqArg (\fl o -> o{optKeyFile = fl}) "<file>")+        "key file"+    ]++showUsageAndExit :: String -> IO a+showUsageAndExit msg = do+    putStrLn msg+    putStrLn $ usageInfo usage options+    exitFailure++serverOpts :: [String] -> IO (Options, [String])+serverOpts argv =+    case getOpt Permute options argv of+        (o, n, []) -> return (foldl (flip id) defaultOptions o, n)+        (_, _, errs) -> showUsageAndExit $ concat errs++data Options = Options+    { optKeyLogFile :: Maybe FilePath+    , optCertFile :: FilePath+    , optKeyFile :: FilePath+    }+    deriving (Show)++defaultOptions :: Options+defaultOptions =+    Options+        { optKeyLogFile = Nothing+        , optCertFile = "servercert.pem"+        , optKeyFile = "serverkey.pem"+        }++usage :: String+usage = "Usage: h2-server [OPTION] <addr> <port>"++main :: IO ()+main = do+    args <- getArgs+    (Options{..}, ips) <- serverOpts args+    (host, port) <- case ips of+        [h, p] -> return (h, p)+        _ -> showUsageAndExit usage+    Right cred@(!_cc, !_priv) <- credentialLoadX509 optCertFile optKeyFile+    sm <- newSessionTicketManager defaultConfig+    let keylog msg = case optKeyLogFile of+            Nothing -> return ()+            Just file -> appendFile file (msg ++ "\n")+        settings =+            defaultSettings+                { settingsKeyLogger = keylog+                , settingsSessionManager = sm+                , settingsEarlyDataSize = 4096+                }+        creds = Credentials [cred]+    run settings creds host (read port) server