Skip to content

Commit

Permalink
Client: correctly reject request (#236)
Browse files Browse the repository at this point in the history
  • Loading branch information
domenkozar committed Dec 22, 2023
1 parent 15bb687 commit bf607ba
Show file tree
Hide file tree
Showing 3 changed files with 30 additions and 18 deletions.
2 changes: 1 addition & 1 deletion src/Network/WebSockets/Http.hs
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ data HandshakeException
| MalformedResponse ResponseHead String
-- | The request was well-formed, but the library user rejected it.
-- (e.g. "unknown path")
| RequestRejected Request String
| RequestRejected RequestHead ResponseHead
-- | for example "EOF came too early" (which is actually a parse error)
-- or for your own errors. (like "unknown path"?)
| OtherHandshakeException String
Expand Down
2 changes: 2 additions & 0 deletions src/Network/WebSockets/Hybi13.hs
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,8 @@ finishResponse request response = do
-- - Switching Protocols
--
-- But we don't check it for now
when (responseCode response == 400) $ Left $
RequestRejected request response
when (responseCode response /= 101) $ Left $
MalformedResponse response "Wrong response status or message."

Expand Down
44 changes: 27 additions & 17 deletions tests/haskell/Network/WebSockets/Server/Tests.hs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ module Network.WebSockets.Server.Tests
import Control.Applicative ((<$>), (<|>))
import Control.Concurrent (forkIO, killThread,
threadDelay)
import Control.Concurrent.Async (Async, async, cancel)
import Control.Exception (SomeException, catch, handle)
import Control.Monad (forever, replicateM, unless)
import Data.IORef (IORef, newIORef, readIORef,
Expand Down Expand Up @@ -39,6 +40,7 @@ tests = testGroup "Network.WebSockets.Server.Tests"
, testCase "bulk server/client" testBulkServerClient
, testCase "onPong" testOnPong
, testCase "ipv6 server" testIpv6Server
, testCase "reject request" testRejectRequest
]


Expand Down Expand Up @@ -69,7 +71,7 @@ testBulkServerClient = testServerClient "127.0.0.1" sendTextDatas
testServerClient :: String -> (Connection -> [BL.ByteString] -> IO ()) -> Assertion
testServerClient host sendMessages = withEchoServer host 42940 "Bye" $ do
texts <- map unArbitraryUtf8 <$> sample
texts' <- retry $ runClient host 42940 "/chat" $ client texts
texts' <- runClient host 42940 "/chat" $ client texts
texts @=? texts'
where
client :: [BL.ByteString] -> ClientApp [BL.ByteString]
Expand All @@ -80,7 +82,29 @@ testServerClient host sendMessages = withEchoServer host 42940 "Bye" $ do
expectCloseException conn "Bye"
return texts'

--------------------------------------------------------------------------------
testRejectRequest :: Assertion
testRejectRequest = withRejectingServer
where
client :: ClientApp ()
client _ = error "Client should not be able to connect"

server :: ServerApp
server pendingConnection = rejectRequest pendingConnection "Bye"

withRejectingServer :: IO ()
withRejectingServer = do
serverThread <- async $ runServer "127.0.0.1" 42940 server
waitSome
() <- runClient "127.0.0.1" 42940 "/chat" client `catch` handler
waitSome
cancel serverThread
return ()

handler :: HandshakeException -> IO ()
handler (RequestRejected _ response) = do
responseCode response @=? 400
handler exc = error $ "Unexpected exception " ++ show exc

--------------------------------------------------------------------------------
testOnPong :: Assertion
Expand Down Expand Up @@ -115,29 +139,15 @@ sample = do
waitSome :: IO ()
waitSome = threadDelay $ 200 * 1000


--------------------------------------------------------------------------------
-- HOLY SHIT WHAT SORT OF ATROCITY IS THIS?!?!?!
--
-- The problem is that sometimes, the server hasn't been brought down yet
-- before the next test, which will cause it not to be able to bind to the
-- same port again. In this case, we just retry.
--
-- The same is true for our client: possibly, the server is not up yet
-- before we run the client. We also want to retry in that case.
retry :: IO a -> IO a
retry action = (\(_ :: SomeException) -> waitSome >> action) `handle` action


--------------------------------------------------------------------------------
withEchoServer :: String -> Int -> BL.ByteString -> IO a -> IO a
withEchoServer host port expectedClose action = do
cRef <- newIORef False
serverThread <- forkIO $ retry $ runServer host port (\c -> server c `catch` handleClose cRef)
serverThread <- async $ runServer host port (\c -> server c `catch` handleClose cRef)
waitSome
result <- action
waitSome
killThread serverThread
cancel serverThread
closeCalled <- readIORef cRef
unless closeCalled $ error "Expecting the CloseRequest exception"
return result
Expand Down

0 comments on commit bf607ba

Please sign in to comment.