requestReader :: Config -> ResTree -> Handle -> HostName -> InteractionQueue -> IO ()
requestReader cnf tree h host tQueue
- = do catch (acceptRequest B.empty) $ \ exc ->
+ = do catch (do input <- B.hGetContents h
+ acceptRequest input) $ \ exc ->
case exc of
IOException _ -> return ()
AsyncException ThreadKilled -> return ()
_ -> print exc
where
acceptRequest :: ByteString -> IO ()
- acceptRequest soFar
+ acceptRequest input
-- キューに最大パイプライン深度以上のリクエストが溜まってゐる
-- 時は、それが限度以下になるまで待つ。
= do atomically $ do queue <- readTVar tQueue
-- リクエストを讀む。パースできない場合は直ちに 400 Bad
-- Request 應答を設定し、それを出力してから切斷するやう
-- に ResponseWriter に通知する。
- hWaitForInput h (-1)
- chunk <- B.hGetNonBlocking h 1024
-
- let input = B.append soFar chunk
case parse requestP input of
(Success req , input') -> acceptParsableRequest req input'
(IllegalInput, _ ) -> acceptNonparsableRequest BadRequest
- (ReachedEOF , _ ) -> if B.length input >= 1024 * 1024 then
- -- ヘッダ長過ぎ
- acceptNonparsableRequest RequestEntityTooLarge
- else
- acceptRequest input
+ (ReachedEOF , _ ) -> acceptNonparsableRequest BadRequest
acceptNonparsableRequest :: StatusCode -> IO ()
acceptNonparsableRequest status
resVersion = HttpVersion 1 1
, resStatus = status
, resHeaders = []
+
}
atomically $ do writeItr itr itrResponse $ Just res
writeItr itr itrWillClose True
enqueue itr
acceptParsableRequest :: Request -> ByteString -> IO ()
- acceptParsableRequest req soFar
+ acceptParsableRequest req input
= do itr <- newInteraction cnf host (Just req)
action
<- atomically $
do preprocess itr
isErr <- readItrF itr itrResponse (isError . resStatus)
if isErr == Just True then
- acceptSemanticallyInvalidRequest itr soFar
+ acceptSemanticallyInvalidRequest itr input
else
case findResource tree $ (reqURI . fromJust . itrRequest) itr of
Nothing -- Resource が無かった
- -> acceptRequestForNonexistentResource itr soFar
+ -> acceptRequestForNonexistentResource itr input
Just rsrcDef -- あった
- -> acceptRequestForExistentResource itr soFar rsrcDef
+ -> acceptRequestForExistentResource itr input rsrcDef
action
acceptSemanticallyInvalidRequest :: Interaction -> ByteString -> STM (IO ())
- acceptSemanticallyInvalidRequest itr soFar
+ acceptSemanticallyInvalidRequest itr input
= do writeItr itr itrState Done
writeDefaultPage itr
postprocess itr
enqueue itr
- return $ acceptRequest soFar
+ return $ acceptRequest input
acceptRequestForNonexistentResource :: Interaction -> ByteString -> STM (IO ())
- acceptRequestForNonexistentResource itr soFar
+ acceptRequestForNonexistentResource itr input
= do let res = Response {
resVersion = HttpVersion 1 1
, resStatus = NotFound
writeDefaultPage itr
postprocess itr
enqueue itr
- return $ acceptRequest soFar
+ return $ acceptRequest input
acceptRequestForExistentResource :: Interaction -> ByteString -> ResourceDef -> STM (IO ())
- acceptRequestForExistentResource itr soFar rsrcDef
+ acceptRequestForExistentResource itr input rsrcDef
= do requestHasBody <- readItr itr itrRequestHasBody id
writeItr itr itrState (if requestHasBody
then ExaminingHeader
enqueue itr
return $ do runResource rsrcDef itr
if requestHasBody then
- observeRequest itr soFar
+ observeRequest itr input
else
- acceptRequest soFar
+ acceptRequest input
observeRequest :: Interaction -> ByteString -> IO ()
- observeRequest itr soFar
+ observeRequest itr input
= do isChunked <- atomically $ readItr itr itrRequestIsChunked id
if isChunked then
- observeChunkedRequest itr soFar
+ observeChunkedRequest itr input
else
- observeNonChunkedRequest itr soFar
+ observeNonChunkedRequest itr input
observeChunkedRequest :: Interaction -> ByteString -> IO ()
- observeChunkedRequest itr soFar
+ observeChunkedRequest itr input
= fail "FIXME: not implemented"
observeNonChunkedRequest :: Interaction -> ByteString -> IO ()
- observeNonChunkedRequest itr soFar
- = fail "FIXME: not implemented"
-{-
+ observeNonChunkedRequest itr input
= do action
<- atomically $
do wantedM <- readItr itr itrReqBodyWanted id
if wantedM == Nothing then
do wasteAll <- readItr itr itrReqBodyWasteAll id
if wasteAll then
- return $ wasteAllReqBody itr soFar
+ -- 破棄要求が來た
+ do remainingM <- readItr itr itrReqChunkRemaining id
+
+ let (_, input') = if remainingM == Nothing then
+ (B.takeWhile (\ _ -> True) input, B.empty)
+ else
+ B.splitAt (fromIntegral $ fromJust remainingM) input
+
+ writeItr itr itrReqChunkRemaining $ Just 0
+ writeItr itr itrReqChunkIsOver True
+ writeItr itr itrReqBodyWanted Nothing
+ writeItr itr itrReceivedBody B.empty
+
+ return $ acceptRequest input'
else
+ -- 要求がまだ来ない
retry
else
- -- 受信要求が來た。
- if B.empty soFar then
- return $ receiveNonChunkedReqBody itr
- else
- do remaining <- readItr itr itrReqChunkRemaining fromJust
-
- let wanted = fromJust wanted
- (chunk, input') = B.splitAt (min wanted remaining) soFar
- newRemaining = remaining - B.length chunk
- isOver = newRemaining == 0
-
- writeItr itr itrReqChunkRemaining newRemaining
- writeItr itr itrReqChunkIsOver isOver
- writeItr itr itrReqBodyWanted (if isOver then
- Nothing
- else
- Just wanted)
- writeItr itr itrReceivedBody chunk
-
- if isOver then
- return $ acceptRequest input'
- else
- return $ observeNonChunkedRequest itr input'
+ -- 受信要求が來た
+ do remainingM <- readItr itr itrReqChunkRemaining id
+
+ let wanted = fromJust wantedM
+ expectedChunkLen = fromIntegral $ maybe wanted (min wanted) remainingM
+ (chunk, input') = B.splitAt expectedChunkLen input
+ newRemaining = fmap
+ (\ x -> x - (fromIntegral $ B.length chunk))
+ remainingM
+ isOver = B.length chunk < expectedChunkLen
+
+ writeItr itr itrReqChunkRemaining newRemaining
+ writeItr itr itrReqChunkIsOver isOver
+ writeItr itr itrReqBodyWanted Nothing
+ writeItr itr itrReceivedBody chunk
+
+ if isOver then
+ return $ acceptRequest input'
+ else
+ return $ observeNonChunkedRequest itr input'
action
- receiveNonChunkedReqBody :: Interaction -> IO ()
- receiveNonChunkedReqBody itr
- = do wanted <- atomically $ readItr itr itrReqBodyWanted fromJust
- remaining <- atomically $ readItr itr itrReqChunkRemaining fromJust
-
- hWaitForInput h (-1)
- chunk <- B.hGetNonBlocking h (min wanted remaining)
-
- let newRemaining = remaining - B.length chunk
- isOver = newRemaining == 0
-
- atomically $ do writeItr itr itrReqChunkRemaining newRemaining
- writeItr itr itrReqChunkIsOver isOver
- writeItr itr itrReqBodyWanted (if isOver then
- Nothing
- else
- Just wanted)
- writeItr itr itrReceivedBody chunk
-
- if isOver then
- return $ acceptRequest B.empty
- else
- return $ observeNonChunkedRequest itr B.empty
-
-
- wasteAllReqBody :: Interaction -> ByteString -> IO ()
- wasteAllReqBody itr soFar
- =
-
--}
-
enqueue :: Interaction -> STM ()
enqueue itr = do queue <- readTVar tQueue
writeTVar tQueue (itr <| queue)
\ No newline at end of file