sendFilePart

This commit is contained in:
Michael Snoyman 2011-04-01 12:49:59 +03:00
parent b1abfd1a6a
commit 35e424f241
3 changed files with 21 additions and 10 deletions

View File

@ -61,10 +61,11 @@ import Data.Monoid (mempty)
import Text.Hamlet (Html) import Text.Hamlet (Html)
import Text.Blaze.Renderer.Utf8 (renderHtmlBuilder) import Text.Blaze.Renderer.Utf8 (renderHtmlBuilder)
import Data.String (IsString (fromString)) import Data.String (IsString (fromString))
import Network.Wai (FilePart)
data Content = ContentBuilder Builder (Maybe Int) -- ^ The content and optional content length. data Content = ContentBuilder Builder (Maybe Int) -- ^ The content and optional content length.
| ContentEnum (forall a. Enumerator Builder IO a) | ContentEnum (forall a. Enumerator Builder IO a)
| ContentFile FilePath | ContentFile FilePath (Maybe FilePart)
-- | Zero-length enumerator. -- | Zero-length enumerator.
emptyContent :: Content emptyContent :: Content

View File

@ -195,7 +195,7 @@ class RenderRoute (Route a) => Yesod a where
-- be the inverse of 'splitPath'. -- be the inverse of 'splitPath'.
joinPath :: a joinPath :: a
-> Builder -- ^ application root -> Builder -- ^ application root
-> [TS.Text] -- ^ path pieces FIXME Text -> [TS.Text] -- ^ path pieces
-> [(TS.Text, TS.Text)] -- ^ query string -> [(TS.Text, TS.Text)] -- ^ query string
-> Builder -> Builder
joinPath _ ar pieces qs' = ar `mappend` encodePath pieces qs joinPath _ ar pieces qs' = ar `mappend` encodePath pieces qs
@ -407,7 +407,6 @@ widgetToPageContent (GWidget w) = do
let title = maybe mempty unTitle mTitle let title = maybe mempty unTitle mTitle
let scripts = runUniqueList scripts' let scripts = runUniqueList scripts'
let stylesheets = runUniqueList stylesheets' let stylesheets = runUniqueList stylesheets'
-- FIXME check size of cassius/julius template
let cssToHtml = preEscapedLazyText . renderCss let cssToHtml = preEscapedLazyText . renderCss
celper :: Cassius url -> Hamlet url celper :: Cassius url -> Hamlet url
celper = fmap cssToHtml celper = fmap cssToHtml

View File

@ -50,6 +50,7 @@ module Yesod.Handler
, invalidArgs , invalidArgs
-- ** Short-circuit responses. -- ** Short-circuit responses.
, sendFile , sendFile
, sendFilePart
, sendResponse , sendResponse
, sendResponseStatus , sendResponseStatus
, sendResponseCreated , sendResponseCreated
@ -280,7 +281,7 @@ data YesodAppResult
data HandlerContents = data HandlerContents =
HCContent H.Status ChooseRep HCContent H.Status ChooseRep
| HCError ErrorResponse | HCError ErrorResponse
| HCSendFile ContentType FilePath -- FIXME replace FilePath with opaque type from system-filepath? | HCSendFile ContentType FilePath (Maybe W.FilePart) -- FIXME replace FilePath with opaque type from system-filepath?
| HCRedirect RedirectType Text | HCRedirect RedirectType Text
| HCCreated Text | HCCreated Text
| HCWai W.Response | HCWai W.Response
@ -383,8 +384,8 @@ runHandler handler mrender sroute tomr ma sa =
let hs' = headers hs let hs' = headers hs
in return $ YARPlain (getStatus e) hs' ct c sess in return $ YARPlain (getStatus e) hs' ct c sess
YARWai _ -> return yar YARWai _ -> return yar
let sendFile' ct fp = let sendFile' ct fp p =
return $ YARPlain H.status200 (headers []) ct (ContentFile fp) finalSession return $ YARPlain H.status200 (headers []) ct (ContentFile fp p) finalSession
case contents of case contents of
HCContent status a -> do HCContent status a -> do
(ct, c) <- liftIO $ chooseRep a cts (ct, c) <- liftIO $ chooseRep a cts
@ -395,8 +396,8 @@ runHandler handler mrender sroute tomr ma sa =
return $ YARPlain return $ YARPlain
(getRedirectStatus rt) hs typePlain emptyContent (getRedirectStatus rt) hs typePlain emptyContent
finalSession finalSession
HCSendFile ct fp -> catchIter HCSendFile ct fp p -> catchIter
(sendFile' ct fp) (sendFile' ct fp p)
(handleError . toErrorHandler) (handleError . toErrorHandler)
HCCreated loc -> do HCCreated loc -> do
let hs = Header "Location" (encodeUtf8 loc) : headers [] let hs = Header "Location" (encodeUtf8 loc) : headers []
@ -510,7 +511,17 @@ getMessage = do
-- For some backends, this is more efficient than reading in the file to -- For some backends, this is more efficient than reading in the file to
-- memory, since they can optimize file sending via a system call to sendfile. -- memory, since they can optimize file sending via a system call to sendfile.
sendFile :: Monad mo => ContentType -> FilePath -> GGHandler sub master mo a sendFile :: Monad mo => ContentType -> FilePath -> GGHandler sub master mo a
sendFile ct = GHandler . lift . throwError . HCSendFile ct sendFile ct fp = GHandler . lift . throwError $ HCSendFile ct fp Nothing
-- | Same as 'sendFile', but only sends part of a file.
sendFilePart :: Monad mo
=> ContentType
-> FilePath
-> Integer -- ^ offset
-> Integer -- ^ count
-> GGHandler sub master mo a
sendFilePart ct fp off count =
GHandler . lift . throwError $ HCSendFile ct fp $ Just $ W.FilePart off count
-- | Bypass remaining handler code and output the given content with a 200 -- | Bypass remaining handler code and output the given content with a 200
-- status code. -- status code.
@ -688,7 +699,7 @@ yarToResponse renderHeaders (YARPlain s hs ct c sessionFinal) =
ContentBuilder b mlen -> ContentBuilder b mlen ->
let hs' = maybe finalHeaders finalHeaders' mlen let hs' = maybe finalHeaders finalHeaders' mlen
in W.ResponseBuilder s hs' b in W.ResponseBuilder s hs' b
ContentFile fp -> W.ResponseFile s finalHeaders fp Nothing -- FIXME handle partial files ContentFile fp p -> W.ResponseFile s finalHeaders fp p
ContentEnum e -> ContentEnum e ->
W.ResponseEnumerator $ \iter -> run_ $ e $$ iter s finalHeaders W.ResponseEnumerator $ \iter -> run_ $ e $$ iter s finalHeaders
where where