@@ -3,7 +3,7 @@
33
44module Main where
55
6−import Control.Exception (throwIO)
6+import Control.Exception (throwIO, throw)
77import Control.Monad
88import qualified Data.ByteString as S
99--import Data.ByteString.Char8 (ByteString)
@@ -31,12 +31,14 @@ main = do
3131 let requestLine2 = "GET http://www.example.com/cgi-path/search.cgi?key=parser HTTP/1.0"
3232 defaultMain [
3333 bgroup "requestLine1" [
34− bench "parseRequestLine2" $ parseRequestLine1 requestLine1
34+ bench "parseRequestLine3" $ whnf parseRequestLine3 requestLine1
35+ , bench "parseRequestLine2" $ parseRequestLine2 requestLine1
3536 , bench "parseRequestLine1" $ parseRequestLine1 requestLine1
3637 , bench "parseRequestLine0" $ parseRequestLine0 requestLine1
3738 ]
3839 , bgroup "requestLine2" [
39− bench "parseRequestLine2" $ parseRequestLine1 requestLine2
40+ bench "parseRequestLine3" $ whnf parseRequestLine3 requestLine2
41+ , bench "parseRequestLine2" $ parseRequestLine2 requestLine2
4042 , bench "parseRequestLine1" $ parseRequestLine1 requestLine2
4143 , bench "parseRequestLine0" $ parseRequestLine0 requestLine2
4244 ]
@@ -44,6 +46,40 @@ main = do
4446
4547----------------------------------------------------------------
4648
49+-- |
50+--
51+-- >>> parseRequestLine3 "GET / HTTP/1.1"
52+-- ("GET","/","",HTTP/1.1)
53+-- >>> parseRequestLine3 "POST /cgi/search.cgi?key=foo HTTP/1.0"
54+-- ("POST","/cgi/search.cgi","?key=foo",HTTP/1.0)
55+-- >>> parseRequestLine3 "GET "
56+-- *** Exception: BadFirstLine "GET "
57+-- >>> parseRequestLine3 "GET /NotHTTP UNKNOWN/1.1"
58+-- *** Exception: NonHttp
59+parseRequestLine3 :: ByteString
60+ -> (H.Method
61+ ,ByteString -- Path
62+ ,ByteString -- Query
63+ ,H.HttpVersion)
64+parseRequestLine3 requestLine = ret
65+ where
66+ (!method,!rest) = S.breakByte 32 requestLine -- ' '
67+ (!pathQuery,!httpVer')
68+ | rest == "" = throw badmsg
69+ | otherwise = S.breakByte 32 (S.drop 1 rest) -- ' '
70+ (!path,!query) = S.breakByte 63 pathQuery -- '?'
71+ !httpVer = S.drop 1 httpVer'
72+ (!http,!ver)
73+ | httpVer == "" = throw badmsg
74+ | otherwise = S.breakByte 47 httpVer -- '/'
75+ !hv | http /= "HTTP" = throw NonHttp
76+ | ver == "/1.1" = H.http11
77+ | otherwise = H.http10
78+ !ret = (method,path,query,hv)
79+ badmsg = BadFirstLine $ B.unpack requestLine
80+
81+----------------------------------------------------------------
82+
4783-- |
4884--
4985-- >>> parseRequestLine2 "GET / HTTP/1.1"