1 module Network.HTTP.Lucu.RequestReader
2 ( requestReader -- Config -> ResTree -> Handle -> HostName -> InteractionQueue -> IO ()
6 import Control.Concurrent.STM
7 import Control.Exception
9 import qualified Data.ByteString.Lazy.Char8 as B
10 import Data.ByteString.Lazy.Char8 (ByteString)
14 import qualified Data.Sequence as S
15 import Data.Sequence (Seq, (<|), ViewR(..))
17 import Network.HTTP.Lucu.Config
18 import Network.HTTP.Lucu.DefaultPage
19 import Network.HTTP.Lucu.HttpVersion
20 import Network.HTTP.Lucu.Interaction
21 import Network.HTTP.Lucu.Parser
22 import Network.HTTP.Lucu.Postprocess
23 import Network.HTTP.Lucu.Preprocess
24 import Network.HTTP.Lucu.Request
25 import Network.HTTP.Lucu.Response
26 import Network.HTTP.Lucu.Resource
27 import Prelude hiding (catch)
30 import GHC.Conc (unsafeIOToSTM)
32 requestReader :: Config -> ResTree -> Handle -> HostName -> InteractionQueue -> IO ()
33 requestReader cnf tree h host tQueue
34 = do catch (acceptRequest B.empty) $ \ exc ->
36 IOException _ -> return ()
37 AsyncException ThreadKilled -> return ()
38 BlockedIndefinitely -> putStrLn "requestReader: blocked indefinitely"
41 acceptRequest :: ByteString -> IO ()
43 -- キューに最大パイプライン深度以上のリクエストが溜まってゐる
45 = do atomically $ do queue <- readTVar tQueue
46 when (S.length queue >= cnfMaxPipelineDepth cnf)
49 -- リクエストを讀む。パースできない場合は直ちに 400 Bad
50 -- Request 應答を設定し、それを出力してから切斷するやう
51 -- に ResponseWriter に通知する。
53 chunk <- B.hGetNonBlocking h 1024
55 let input = B.append soFar chunk
56 case parse requestP input of
57 (Success req , input') -> acceptParsableRequest req input'
58 (IllegalInput, _ ) -> acceptNonparsableRequest
59 (ReachedEOF , _ ) -> if B.length input >= 1024 * 1024 then
61 acceptNonparsableRequest
66 acceptNonparsableRequest :: IO ()
67 acceptNonparsableRequest
68 = do itr <- newInteraction host Nothing
70 resVersion = HttpVersion 1 1
71 , resStatus = BadRequest
74 atomically $ do writeItr itr itrResponse $ Just res
75 writeItr itr itrWillClose True
76 writeItr itr itrState Done
81 acceptParsableRequest :: Request -> ByteString -> IO ()
82 acceptParsableRequest req soFar
83 = do itr <- newInteraction host (Just req)
87 isErr <- readItrF itr itrResponse (isError . resStatus)
88 if isErr == Just True then
89 acceptSemanticallyInvalidRequest itr soFar
91 case findResource tree $ (reqURI . fromJust . itrRequest) itr of
92 Nothing -- Resource が無かった
93 -> acceptRequestForNonexistentResource itr soFar
96 -> acceptRequestForExistentResource itr soFar rsrcDef
99 acceptSemanticallyInvalidRequest :: Interaction -> ByteString -> STM (IO ())
100 acceptSemanticallyInvalidRequest itr soFar
101 = do writeItr itr itrState Done
105 return $ acceptRequest soFar
107 acceptRequestForNonexistentResource :: Interaction -> ByteString -> STM (IO ())
108 acceptRequestForNonexistentResource itr soFar
109 = do let res = Response {
110 resVersion = HttpVersion 1 1
111 , resStatus = NotFound
114 writeItr itr itrResponse $ Just res
115 writeItr itr itrState Done
119 return $ acceptRequest soFar
121 acceptRequestForExistentResource :: Interaction -> ByteString -> ResourceDef -> STM (IO ())
122 acceptRequestForExistentResource itr soFar rsrcDef
123 = do requestHasBody <- readItr itr itrRequestHasBody id
124 writeItr itr itrState (if requestHasBody
128 return $ do runResource rsrcDef itr
129 if requestHasBody then
130 observeRequest itr soFar
134 observeRequest :: Interaction -> ByteString -> IO ()
135 observeRequest itr soFar = fail "FIXME: Not Implemented"
137 enqueue :: Interaction -> STM ()
138 enqueue itr = do queue <- readTVar tQueue
139 writeTVar tQueue (itr <| queue)