4 module Network.HTTP.Lucu.Preprocess
9 import Control.Concurrent.STM
11 import qualified Data.ByteString as Strict (ByteString)
12 import qualified Data.ByteString.Char8 as C8 hiding (ByteString)
15 import Network.HTTP.Lucu.Config
16 import Network.HTTP.Lucu.Headers
17 import Network.HTTP.Lucu.HttpVersion
18 import Network.HTTP.Lucu.Interaction
19 import Network.HTTP.Lucu.Request
20 import Network.HTTP.Lucu.Response
26 [1] HTTP/1.0 ならば Config を使って補完
27 [2] HTTP/1.1 ならば Host ヘッダで補完。Host が無ければ 400。
29 * Expect: に問題があった場合は 417 Expectation Failed に設定。
30 100-continue 以外のものは全部 417 に。
32 * Transfer-Encoding: に問題があったら 501 Not Implemented にする。具
33 体的には、identity でも chunked でもなければ 501 Not Implemented に
36 * メソッドが GET, HEAD, POST, PUT, DELETE の何れでもない場合は 501
39 * HTTP/1.0 でも HTTP/1.1 でもないリクエストに對しては 505 HTTP
40 Version Not Supported を返す。
42 * POST または PUT に Content-Length も Transfer-Encoding も無い時は、
43 411 Length Required にする。
45 * Content-Length の値が數値でなかったり負だったりしたら 400 Bad
48 * willDiscardBody その他の變數を設定する。
52 preprocess :: Interaction -> STM ()
54 = do req <- readItr itr itrRequest fromJust
56 let reqVer = reqVersion req
58 if reqVer /= HttpVersion 1 0 &&
59 reqVer /= HttpVersion 1 1 then
61 do setStatus HttpVersionNotSupported
62 writeItr itr itrWillClose True
65 -- HTTP/1.0 では Keep-Alive できない
66 do when (reqVer == HttpVersion 1 0)
67 $ writeItr itr itrWillClose True
74 HEAD -> writeItr itr itrWillDiscardBody True
75 POST -> writeItr itr itrRequestHasBody True
76 PUT -> writeItr itr itrRequestHasBody True
78 _ -> setStatus NotImplemented
82 setStatus :: StatusCode -> STM ()
84 = updateItr itr itrResponse
89 completeAuthority :: Request -> STM ()
90 completeAuthority !req
91 = when (uriAuthority (reqURI req) == Nothing)
92 $ if reqVersion req == HttpVersion 1 0 then
93 -- HTTP/1.0 なので Config から補完
94 do let conf = itrConfig itr
95 host = cnfServerHost conf
96 port = itrLocalPort itr
101 updateAuthority host (C8.pack portStr)
103 case getHeader (C8.pack "Host") req of
104 Just str -> let (host, portStr) = parseHost str
105 in updateAuthority host portStr
106 Nothing -> setStatus BadRequest
109 parseHost :: Strict.ByteString -> (Strict.ByteString, Strict.ByteString)
110 parseHost = C8.break (== ':')
113 updateAuthority :: Strict.ByteString -> Strict.ByteString -> STM ()
114 updateAuthority !host !portStr
115 = updateItr itr itrRequest
116 $! \ (Just req) -> Just req {
117 reqURI = let uri = reqURI req
119 uriAuthority = Just URIAuth {
121 , uriRegName = C8.unpack host
122 , uriPort = C8.unpack portStr
128 preprocessHeader :: Request -> STM ()
129 preprocessHeader !req
130 = do case getHeader (C8.pack "Expect") req of
132 Just value -> if value `noCaseEq` C8.pack "100-continue" then
133 writeItr itr itrExpectedContinue True
135 setStatus ExpectationFailed
137 case getHeader (C8.pack "Transfer-Encoding") req of
139 Just value -> unless (value `noCaseEq` C8.pack "identity")
140 $ if value `noCaseEq` C8.pack "chunked" then
141 writeItr itr itrRequestIsChunked True
143 setStatus NotImplemented
145 case getHeader (C8.pack "Content-Length") req of
147 Just value -> if C8.all isDigit value then
148 do let Just (len, _) = C8.readInt value
149 writeItr itr itrReqChunkLength $ Just len
150 writeItr itr itrReqChunkRemaining $ Just len
154 case getHeader (C8.pack "Connection") req of
156 Just value -> when (value `noCaseEq` C8.pack "close")
157 $ writeItr itr itrWillClose True