X-Git-Url: http://git.cielonegro.org/gitweb.cgi?p=Lucu.git;a=blobdiff_plain;f=Network%2FHTTP%2FLucu%2FResource.hs;h=b478503c8bc53d6af8b74e6b9cf196350b1772c2;hp=19a2a0a73a4779e882b02114fcf28805a782eab8;hb=0678be8;hpb=1ead053df6a792edafa9d714c4c038a8a9c3ad16 diff --git a/Network/HTTP/Lucu/Resource.hs b/Network/HTTP/Lucu/Resource.hs index 19a2a0a..b478503 100644 --- a/Network/HTTP/Lucu/Resource.hs +++ b/Network/HTTP/Lucu/Resource.hs @@ -71,7 +71,6 @@ module Network.HTTP.Lucu.Resource ( -- * Types Resource(..) - , emptyResource , Rsrc , FormData(..) @@ -150,19 +149,23 @@ import Control.Monad.IO.Class import Control.Monad.Unicode import Data.Ascii (Ascii, CIAscii) import qualified Data.Ascii as A +import Data.Attempt import qualified Data.Attoparsec.Char8 as P import Data.ByteString (ByteString) import qualified Data.ByteString as Strict import qualified Data.ByteString.Lazy as Lazy import Data.Collections +import Data.Convertible.Base import Data.List (intersperse, sort) import Data.Maybe import Data.Monoid import Data.Monoid.Unicode +import Data.Proxy +import Data.Tagged import Data.Text (Text) import qualified Data.Text as T import Data.Time -import qualified Data.Time.HTTP as HTTP +import Data.Time.Format.HTTP import Network.HTTP.Lucu.Abortion import Network.HTTP.Lucu.Authentication import Network.HTTP.Lucu.Config @@ -213,14 +216,13 @@ getRequestVersion ∷ Rsrc HttpVersion getRequestVersion = reqVersion <$> getRequest -- |This is an analogy of CGI PATH_INFO. 'getPathInfo' always returns --- @[]@ if the corresponding --- 'Network.HTTP.Lucu.Resource.Tree.Resource' is not greedy. See: --- 'getResourcePath' +-- @[]@ if the corresponding 'Resource' is not greedy. See +-- 'getResourcePath'. -- -- Note that the returned path components are URI-decoded. getPathInfo ∷ Rsrc [Strict.ByteString] getPathInfo = do rsrcPath ← getResourcePath - reqPath ← splitPathInfo <$> getRequestURI + reqPath ← uriPathSegments <$> getRequestURI return $ drop (length rsrcPath) reqPath -- |Assume the query part of request URI as @@ -353,7 +355,9 @@ foundEntity tag timeStamp method ← getMethod when (method ≡ GET ∨ method ≡ HEAD) - $ setHeader "Last-Modified" (HTTP.toAscii timeStamp) + $ setHeader "Last-Modified" + $ flip proxy http + $ cs timeStamp when (method ≡ POST) $ abort $ mkAbortion' InternalServerError @@ -376,7 +380,7 @@ foundETag tag when (method ≡ GET ∨ method ≡ HEAD) $ setHeader "ETag" $ A.fromAsciiBuilder - $ printETag tag + $ cs tag when (method ≡ POST) $ abort $ mkAbortion' InternalServerError @@ -447,7 +451,9 @@ foundTimeStamp timeStamp method ← getMethod when (method ≡ GET ∨ method ≡ HEAD) - $ setHeader "Last-Modified" (HTTP.toAscii timeStamp) + $ setHeader "Last-Modified" + $ flip proxy http + $ cs timeStamp when (method ≡ POST) $ abort $ mkAbortion' InternalServerError @@ -461,28 +467,28 @@ foundTimeStamp timeStamp ifModSince ← getHeader "If-Modified-Since" case ifModSince of - Just str → case HTTP.fromAscii str of - Right lastTime + Just str → case fromAttempt $ ca (Tagged str ∷ Tagged HTTP Ascii) of + Just lastTime → when (timeStamp ≤ lastTime) $ abort $ mkAbortion' statusForIfModSince $ "The entity has not been modified since " ⊕ A.toText str - Left e + Nothing → abort $ mkAbortion' BadRequest - $ "Malformed If-Modified-Since: " ⊕ T.pack e + $ "Malformed If-Modified-Since: " ⊕ A.toText str Nothing → return () ifUnmodSince ← getHeader "If-Unmodified-Since" case ifUnmodSince of - Just str → case HTTP.fromAscii str of - Right lastTime + Just str → case fromAttempt $ ca (Tagged str ∷ Tagged HTTP Ascii) of + Just lastTime → when (timeStamp > lastTime) $ abort $ mkAbortion' PreconditionFailed $ "The entity has not been modified since " ⊕ A.toText str - Left e + Nothing → abort $ mkAbortion' BadRequest - $ "Malformed If-Unmodified-Since: " ⊕ T.pack e + $ "Malformed If-Unmodified-Since: " ⊕ A.toText str Nothing → return () driftTo ReceivingBody @@ -581,10 +587,9 @@ getForm limit → readMultipartFormData params Just cType → abort $ mkAbortion' UnsupportedMediaType - $ A.toText - $ A.fromAsciiBuilder - $ A.toAsciiBuilder "Unsupported media type: " - ⊕ MT.printMIMEType cType + $ cs + $ ("Unsupported media type: " ∷ Ascii) + ⊕ cs cType where readWWWFormURLEncoded = (map toPairWithFormData ∘ parseWWWFormURLEncoded) @@ -629,8 +634,7 @@ redirect sc uri -- \"Content-Type\" as @mType@. Declaring \"Content-Type\" is -- mandatory for sending a response body. setContentType ∷ MIMEType → Rsrc () -setContentType - = setHeader "Content-Type" ∘ A.fromAsciiBuilder ∘ MT.printMIMEType +setContentType = setHeader "Content-Type" ∘ cs -- |@'setLocation' uri@ declares the response header \"Location\" as -- @uri@. You usually don't need to call this function directly. @@ -664,11 +668,11 @@ setContentEncoding codings -- |@'setWWWAuthenticate' challenge@ declares the response header -- \"WWW-Authenticate\" as @challenge@. setWWWAuthenticate ∷ AuthChallenge → Rsrc () -setWWWAuthenticate = setHeader "WWW-Authenticate" ∘ printAuthChallenge +setWWWAuthenticate = setHeader "WWW-Authenticate" ∘ cs -- |Write a chunk in 'Strict.ByteString' to the response body. You -- must first declare the response header \"Content-Type\" before --- applying this function. See: 'setContentType' +-- applying this function. See 'setContentType'. putChunk ∷ Strict.ByteString → Rsrc () putChunk = putBuilder ∘ BB.fromByteString @@ -676,7 +680,7 @@ putChunk = putBuilder ∘ BB.fromByteString -- can be safely applied to an infinitely long 'Lazy.ByteString'. -- -- Note that you must first declare the response header --- \"Content-Type\" before applying this function. See: --- 'setContentType' +-- \"Content-Type\" before applying this function. See +-- 'setContentType'. putChunks ∷ Lazy.ByteString → Rsrc () putChunks = putBuilder ∘ BB.fromLazyByteString