snap-server 0.4.0.2 → 0.4.1
raw patch · 7 files changed
+75/−59 lines, 7 filesdep ~enumeratordep ~snap-core
Dependency ranges changed: enumerator, snap-core
Files
- snap-server.cabal +3/−3
- src/Snap/Internal/Http/Server.hs +1/−1
- src/Snap/Internal/Http/Server/Backend.hs +1/−2
- src/Snap/Internal/Http/Server/GnuTLS.hs +21/−23
- src/Snap/Internal/Http/Server/HttpPort.hs +18/−16
- test/snap-server-testsuite.cabal +8/−8
- test/suite/Test/Blackbox.hs +23/−6
snap-server.cabal view
@@ -1,5 +1,5 @@ name: snap-server-version: 0.4.0.2+version: 0.4.1 synopsis: A fast, iteratee-based, epoll-enabled web server for the Snap Framework description: This is the first developer prerelease of the Snap framework. Snap is a@@ -111,14 +111,14 @@ bytestring-nums, containers, directory-tree,- enumerator == 0.4.*,+ enumerator >= 0.4.7 && <0.5, filepath, MonadCatchIO-transformers >= 0.2.1 && < 0.3, mtl == 2.0.*, murmur-hash >= 0.1 && < 0.2, network >= 2.3 && <2.4, old-locale,- snap-core >= 0.4.0.2 && <0.5,+ snap-core >= 0.4.1 && <0.5, template-haskell, time, transformers,
src/Snap/Internal/Http/Server.hs view
@@ -784,7 +784,7 @@ where f h = if null cookies then h- else Map.insert "Set-Cookie" cookies h+ else Map.insertWith (flip (++)) "Set-Cookie" cookies h cookies = fmap cookieToBS . Map.elems $ rspCookies r
src/Snap/Internal/Http/Server/Backend.hs view
@@ -92,6 +92,5 @@ data NetworkSession = NetworkSession { _socket :: CInt , _session :: Ptr Word- , _recvBuffer :: Ptr CChar- , _recvLen :: CSize+ , _recvLen :: Int }
src/Snap/Internal/Http/Server/GnuTLS.hs view
@@ -24,13 +24,14 @@ import Data.Dynamic import Foreign.C +import Snap.Internal.Debug import Snap.Internal.Http.Server.Backend #ifdef GNUTLS-import Control.Monad (liftM) import qualified Data.ByteString as B-import Data.ByteString.Unsafe (unsafeUseAsCStringLen) import Data.ByteString.Internal (w2c)+import qualified Data.ByteString.Internal as BI+import qualified Data.ByteString.Unsafe as BI import Foreign import qualified Network.Socket as Socket #endif@@ -148,8 +149,7 @@ gnutls_certificate_send_x509_rdn_sequence session 1 gnutls_session_enable_compatibility_mode session - buffer <- mallocBytes $ fromIntegral recvSize- let s = NetworkSession socket (castPtr session) buffer $+ let s = NetworkSession socket (castPtr session) $ fromIntegral recvSize gnutls_transport_set_ptr session $ intPtrToPtr $ fromIntegral $ socket@@ -162,10 +162,9 @@ ------------------------------------------------------------------------------ endSession :: NetworkSession -> IO ()-endSession (NetworkSession _ session buffer _) = do+endSession (NetworkSession _ session _) = do throwErrorIf "TLS bye" $ gnutls_bye (castPtr session) 1 `finally` do gnutls_deinit $ castPtr session- free buffer ------------------------------------------------------------------------------@@ -182,7 +181,7 @@ ------------------------------------------------------------------------------ send :: IO () -> IO () -> NetworkSession -> ByteString -> IO () send tickleTimeout onBlock (NetworkSession { _session = session}) bs =- unsafeUseAsCStringLen bs $ uncurry loop+ BI.unsafeUseAsCStringLen bs $ uncurry loop where loop ptr len = do sent <- gnutls_record_send (castPtr session) ptr $ fromIntegral len@@ -198,30 +197,29 @@ --------------------------------------------------------------------------------- | I originally wrote recv to use mallocBytes and unsafePackCStringFinalizer--- to achieve zero-copy. The downside to that method is we might waste memory--- if a malicious adversary only sends us a few bytes, since the entire buffer--- won't be freed until the ByteString is collected. Thus I use--- packCStringLen which makes a copy. Perhaps in the future the recv function--- could be changed to use unsafePackCStringFinalizer if the buffer is at--- least 3/4 full and packCStringLen otherwise or something like that recv :: IO b -> NetworkSession -> IO (Maybe ByteString)-recv onBlock (NetworkSession _ session recvBuf recvLen) = loop+recv onBlock (NetworkSession _ session recvLen) = do+ fp <- BI.mallocByteString recvLen+ sz <- withForeignPtr fp loop+ if (sz :: Int) <= 0+ then return Nothing+ else return $ Just $ BI.fromForeignPtr fp 0 $ fromEnum sz+ where- loop = do- size <- gnutls_record_recv (castPtr session) recvBuf recvLen+ loop recvBuf = do+ debug $ "TLS: calling record_recv with recvLen=" ++ show recvLen+ size <- gnutls_record_recv (castPtr session) recvBuf $ toEnum recvLen+ debug $ "TLS: record_recv returned with size=" ++ show size let size' = fromIntegral size case size' of- x | x == 0 -> return Nothing- | x > 0 -> liftM Just $ B.packCStringLen (recvBuf, x)- | isIntrCode x -> loop- | isAgainCode x -> onBlock >> loop+ x | x >= 0 -> return x+ | isIntrCode x -> loop recvBuf+ | isAgainCode x -> onBlock >> loop recvBuf | otherwise -> (throwError "TLS recv" $ fromIntegral size')- >> return Nothing -------------------------------------------------------------------------------throwError :: String -> ReturnCode -> IO ()+throwError :: String -> ReturnCode -> IO a throwError prefix rc = gnutls_strerror rc >>= peekCString >>= throwIO . GnuTLSException . (prefix'++)
src/Snap/Internal/Http/Server/HttpPort.hs view
@@ -22,8 +22,8 @@ #ifdef PORTABLE import qualified Network.Socket.ByteString as SB #else-import Control.Monad (liftM)-import Data.ByteString.Unsafe (unsafeUseAsCStringLen)+import qualified Data.ByteString.Internal as BI+import qualified Data.ByteString.Unsafe as BI #endif import Snap.Internal.Debug@@ -56,14 +56,13 @@ ------------------------------------------------------------------------------ createSession :: Int -> CInt -> IO () -> IO NetworkSession-createSession buffSize s _ = do- buffer <- mallocBytes $ fromIntegral buffSize- return $ NetworkSession s nullPtr buffer $ fromIntegral buffSize+createSession buffSize s _ =+ return $ NetworkSession s nullPtr $ fromIntegral buffSize ------------------------------------------------------------------------------ endSession :: NetworkSession -> IO ()-endSession (NetworkSession {_recvBuffer = buff}) = free buff+endSession _ = return () #ifdef PORTABLE @@ -84,24 +83,27 @@ ------------------------------------------------------------------------------ recv :: IO () -> NetworkSession -> IO (Maybe ByteString)-recv onBlock (NetworkSession s _ buff buffSize) = do- sz <- throwErrnoIfMinus1RetryMayBlock- "recv"- (c_read s buff buffSize)- onBlock+recv onBlock (NetworkSession s _ buffSize) = do+ fp <- BI.mallocByteString $ fromEnum buffSize+ sz <- withForeignPtr fp $ \p ->+ throwErrnoIfMinus1RetryMayBlock+ "recv"+ (c_read s p $ toEnum buffSize)+ onBlock+ if sz == 0- then return Nothing- else liftM Just $ B.packCStringLen (buff, fromIntegral sz)+ then return Nothing+ else return $ Just $ BI.fromForeignPtr fp 0 $ fromEnum sz ------------------------------------------------------------------------------ send :: IO () -> IO () -> NetworkSession -> ByteString -> IO ()-send tickleTimeout onBlock (NetworkSession s _ _ _) bs =- unsafeUseAsCStringLen bs $ uncurry loop+send tickleTimeout onBlock (NetworkSession s _ _) bs =+ BI.unsafeUseAsCStringLen bs $ uncurry loop where loop ptr len = do sent <- throwErrnoIfMinus1RetryMayBlock "send"- (c_write s ptr $ fromIntegral len)+ (c_write s ptr $ toEnum len) onBlock let sent' = fromIntegral sent
test/snap-server-testsuite.cabal view
@@ -35,10 +35,10 @@ containers, directory, directory-tree,- enumerator == 0.4.*,+ enumerator >= 0.4.7 && <0.5, filepath, haskell98,- http-enumerator >= 0.2.1.5 && <0.3,+ http-enumerator >= 0.3.1 && <0.4, HUnit >= 1.2 && < 2, monads-fd >= 0.1.0.4 && <0.2, murmur-hash >= 0.1 && < 0.2,@@ -46,7 +46,7 @@ old-locale, parallel > 2, process,- snap-core >= 0.4 && <0.5,+ snap-core >= 0.4.1 && <0.5, template-haskell, test-framework >= 0.3.1 && <0.4, test-framework-hunit >= 0.2.5 && < 0.3,@@ -96,7 +96,7 @@ cereal >= 0.3 && < 0.4, containers, directory-tree,- enumerator == 0.4.*,+ enumerator >= 0.4.7 && <0.5, filepath, haskell98, HUnit >= 1.2 && < 2,@@ -106,7 +106,7 @@ MonadCatchIO-transformers >= 0.2.1 && < 0.3, murmur-hash >= 0.1 && < 0.2, network == 2.3.*,- snap-core >= 0.4 && <0.5,+ snap-core >= 0.4.1 && <0.5, template-haskell, time, transformers,@@ -173,7 +173,7 @@ bytestring-nums >= 0.3.1 && < 0.4, containers, directory-tree,- enumerator == 0.4.*,+ enumerator >= 0.4.7 && <0.5, filepath, haskell98, HUnit >= 1.2 && < 2,@@ -183,7 +183,7 @@ network == 2.3.*, old-locale, parallel > 2,- snap-core >= 0.4 && <0.5,+ snap-core >= 0.4.1 && <0.5, template-haskell, test-framework >= 0.3.1 && <0.4, test-framework-hunit >= 0.2.5 && < 0.3,@@ -221,5 +221,5 @@ build-depends: base >= 4 && < 5, network == 2.3.*,- http-enumerator >= 0.2.1.3 && <0.3,+ http-enumerator >= 0.3.1 && <0.4, criterion >= 0.5 && <0.6
test/suite/Test/Blackbox.hs view
@@ -9,7 +9,7 @@ -------------------------------------------------------------------------------- import Control.Concurrent-import Control.Exception (SomeException, catch)+import Control.Exception (SomeException, catch, throwIO) import Control.Monad import qualified Data.ByteString.Base16 as B16 import qualified Data.ByteString.Char8 as S@@ -17,18 +17,22 @@ import qualified Data.ByteString.Lazy.Char8 as L import Data.Int import Data.List+import Data.Monoid import qualified Network.HTTP.Enumerator as HTTP import qualified Network.Socket.ByteString as N import Prelude hiding (catch, take) import System.Timeout import Test.Framework+import Test.Framework.Options import Test.Framework.Providers.HUnit import Test.Framework.Providers.QuickCheck2 import Test.HUnit hiding (Test, path) import Test.QuickCheck+import qualified Test.QuickCheck.Property as QC import qualified Test.QuickCheck.Monadic as QC import Test.QuickCheck.Monadic hiding (run, assert) ------------------------------------------------------------------------------+import Snap.Internal.Debug import Snap.Http.Server import Snap.Test.Common import Test.Common.Rot13@@ -93,10 +97,15 @@ ------------------------------------------------------------------------------ doPong :: Bool -> Int -> IO ByteString doPong ssl port = do- let uri = (if ssl then "https" else "http")- ++ "://127.0.0.1:" ++ show port ++ "/pong"+ debug "getting URI"+ let !uri = (if ssl then "https" else "http")+ ++ "://127.0.0.1:" ++ show port ++ "/pong"+ debug $ "URI is: '" ++ uri ++ "', calling simpleHttp" - rsp <- HTTP.simpleHttp uri+ rsp <- HTTP.simpleHttp uri `catch` (\(e::SomeException) -> do+ debug $ "simpleHttp threw exception: " ++ show e+ throwIO e)+ debug $ "response was " ++ show rsp return $ S.concat $ L.toChunks rsp @@ -149,9 +158,17 @@ ------------------------------------------------------------------------------ testFileUpload :: Bool -> Int -> String -> Test-testFileUpload ssl port name = testProperty (name ++ "/blackbox/upload") $- monadicIO $ forAllM arbitrary prop+testFileUpload ssl port name = + plusTestOptions testOptions $+ testProperty (name ++ "/blackbox/upload") $+ QC.mapSize (if ssl then min 100 else id) $+ monadicIO $+ forAllM arbitrary prop where+ testOptions = if ssl+ then mempty { topt_maximum_generated_tests = Just 100 }+ else mempty+ boundary = "boundary-jdsklfjdsalkfjadlskfjldskjfldskjfdsfjdsklfldksajfl" prefix = [ "--"