packages feed

scotty 0.7.3 → 0.8.0

raw patch · 10 files changed

+120/−65 lines, 10 filesdep +hspecdep +scottydep −conduit-extradep ~basedep ~bytestringdep ~http-types

Dependencies added: hspec, scotty

Dependencies removed: conduit-extra

Dependency ranges changed: base, bytestring, http-types, wai, wai-extra, warp

Files

README.md view
@@ -1,4 +1,4 @@-# Scotty+# Scotty [![Build Status](https://travis-ci.org/scotty-web/scotty.svg)](https://travis-ci.org/scotty-web/scotty)[![Coverage Status](https://coveralls.io/repos/scotty-web/scotty/badge.png?branch=master)](https://coveralls.io/r/scotty-web/scotty?branch=master)  A Haskell web framework inspired by Ruby's Sinatra, using WAI and Warp. 
Web/Scotty.hs view
@@ -17,14 +17,14 @@       -- ** Route Patterns     , capture, regex, function, literal       -- ** Accessing the Request, Captures, and Query Parameters-    , request, header, reqHeader, headers, body, param, params, jsonData, files+    , request, header, headers, body, param, params, jsonData, files       -- ** Modifying the Response and Redirecting     , status, addHeader, setHeader, redirect       -- ** Setting Response Body       --       -- | Note: only one of these should be present in any given route       -- definition, as they completely replace the current 'Response' body.-    , text, html, file, json, source, raw+    , text, html, file, json, stream, source, raw       -- ** Exceptions     , raise, rescue, next, defaultHandler       -- * Parsing Parameters@@ -35,22 +35,23 @@  -- With the exception of this, everything else better just import types. import qualified Web.Scotty.Trans as Trans+import qualified Web.Scotty.Action as Action -- for 'source', to avoid deprecation warning on Trans.source  import Blaze.ByteString.Builder (Builder)  import Data.Aeson (FromJSON, ToJSON) import Data.ByteString.Lazy.Char8 (ByteString)-import Data.Conduit (Flush, Source) import Data.Text.Lazy (Text)+import Data.Conduit (Flush, Source)  import Network.HTTP.Types (Status, StdMethod)-import Network.Wai (Application, Middleware, Request)+import Network.Wai (Application, Middleware, Request, StreamingBody) import Network.Wai.Handler.Warp (Port)  import Web.Scotty.Types (ScottyT, ActionT, Param, RoutePattern, Options, File)  type ScottyM = ScottyT Text IO-type ActionM = ActionT Text IO +type ActionM = ActionT Text IO  -- | Run a scotty application using the warp server. scotty :: Port -> ScottyM () -> IO ()@@ -65,14 +66,14 @@ scottyApp :: ScottyM () -> IO Application scottyApp = Trans.scottyAppT id id --- | Global handler for uncaught exceptions. +-- | Global handler for uncaught exceptions. ----- Uncaught exceptions normally become 500 responses. +-- Uncaught exceptions normally become 500 responses. -- You can use this to selectively override that behavior. -- -- Note: IO exceptions are lifted into Scotty exceptions by default. -- This has security implications, so you probably want to provide your--- own defaultHandler in production which does not send out the error +-- own defaultHandler in production which does not send out the error -- strings as 500 responses. defaultHandler :: (Text -> ActionM ()) -> ScottyM () defaultHandler = Trans.defaultHandler@@ -134,11 +135,6 @@ header :: Text -> ActionM (Maybe Text) header = Trans.header --- | Get a request header. Header name is case-insensitive. (Deprecated in favor of `header`.)-reqHeader :: Text -> ActionM (Maybe Text)-reqHeader = Trans.header-{-# DEPRECATED reqHeader "Use header instead. reqHeader will be removed in the next release." #-}- -- | Get all the request headers. Header names are case-insensitive. headers :: ActionM [(Text, Text)] headers = Trans.headers@@ -198,11 +194,18 @@ json :: ToJSON a => a -> ActionM () json = Trans.json +-- | Set the body of the response to a StreamingBody. Doesn't set the+-- \"Content-Type\" header, so you probably want to do that on your+-- own with 'setHeader'.+stream :: StreamingBody -> ActionM ()+stream = Trans.stream+ -- | Set the body of the response to a Source. Doesn't set the -- \"Content-Type\" header, so you probably want to do that on your -- own with 'setHeader'. source :: Source IO (Flush Builder) -> ActionM ()-source = Trans.source+source = Action.source+{-# DEPRECATED source "Use 'stream' instead. This will be removed in the next release." #-}  -- | Set the body of the response to the given 'BL.ByteString' value. Doesn't set the -- \"Content-Type\" header, so you probably want to do that on your own with 'setHeader'.
Web/Scotty/Action.hs view
@@ -16,12 +16,12 @@     , raw     , readEither     , redirect-    , reqHeader -- Deprecated     , request     , rescue     , setHeader-    , source     , status+    , stream+    , source    -- Deprecated     , text     , Param     , Parsable(..)@@ -39,12 +39,13 @@ import qualified Data.ByteString.Char8 as B import qualified Data.ByteString.Lazy.Char8 as BL import qualified Data.CaseInsensitive as CI-import Data.Conduit (Flush, Source)-import Data.Default (def)-import Data.Monoid (mconcat)+import           Data.Conduit+import qualified Data.Conduit.List as CL+import           Data.Default (def)+import           Data.Monoid (mconcat) import qualified Data.Text as ST import qualified Data.Text.Lazy as T-import Data.Text.Lazy.Encoding (encodeUtf8)+import           Data.Text.Lazy.Encoding (encodeUtf8)  import Network.HTTP.Types import Network.Wai@@ -123,11 +124,6 @@ files :: (ScottyError e, Monad m) => ActionT e m [File] files = ActionT $ liftM getFiles ask --- | Get a request header. Header name is case-insensitive. (Deprecated in favor of `header`.)-reqHeader :: (ScottyError e, Monad m) => T.Text -> ActionT e m (Maybe T.Text)-reqHeader = header-{-# DEPRECATED reqHeader "Use header instead. This will be removed in the next release." #-}- -- | Get a request header. Header name is case-insensitive. header :: (ScottyError e, Monad m) => T.Text -> ActionT e m (Maybe T.Text) header k = do@@ -139,7 +135,7 @@ headers = do     hs <- liftM requestHeaders request     return [ ( strictByteStringToLazyText (CI.original k)-             , strictByteStringToLazyText v)  +             , strictByteStringToLazyText v)            | (k,v) <- hs ]  -- | Get the request body.@@ -198,7 +194,7 @@  instance (Parsable a) => Parsable [a] where parseParam = parseParamList -instance Parsable Bool where +instance Parsable Bool where     parseParam t = if t' == T.toCaseFold "true"                    then Right True                    else if t' == T.toCaseFold "false"@@ -262,8 +258,18 @@ -- | Set the body of the response to a Source. Doesn't set the -- \"Content-Type\" header, so you probably want to do that on your -- own with 'setHeader'.+stream :: (ScottyError e, Monad m) => StreamingBody -> ActionT e m ()+stream = ActionT . MS.modify . setContent . ContentStream++-- | Set the body of the response to a Source. Doesn't set the+-- \"Content-Type\" header, so you probably want to do that on your+-- own with 'setHeader'. source :: (ScottyError e, Monad m) => Source IO (Flush Builder) -> ActionT e m ()-source = ActionT . MS.modify . setContent . ContentSource+source src = stream $ \send flush -> src $$ CL.mapM_ (\mbuilder ->+    case mbuilder of+      Chunk b -> send b+      Flush -> flush)+-- Deprecated, but pragma is in Web.Scotty and Web.Scotty.Trans  -- | Set the body of the response to the given 'BL.ByteString' value. Doesn't set the -- \"Content-Type\" header, so you probably want to do that on your
Web/Scotty/Route.hs view
@@ -1,20 +1,17 @@-{-# LANGUAGE OverloadedStrings, FlexibleContexts, FlexibleInstances, RankNTypes #-}+{-# LANGUAGE FlexibleContexts, FlexibleInstances, LambdaCase,+             OverloadedStrings, RankNTypes, ScopedTypeVariables #-} module Web.Scotty.Route     ( get, post, put, delete, patch, addroute, matchAny, notFound,       capture, regex, function, literal     ) where  import Control.Arrow ((***))+import Control.Concurrent.MVar import Control.Monad.Error import qualified Control.Monad.State as MS  import qualified Data.ByteString.Char8 as B import qualified Data.ByteString.Lazy.Char8 as BL-import Data.Conduit (($$), (=$))-import Data.Conduit.Binary (sourceLbs)-import Data.Conduit.Lazy (lazyConsume)-import Data.Conduit.List (consume)-import Data.Either (partitionEithers) import Data.Maybe (fromMaybe) import Data.Monoid (mconcat) import Data.String (fromString)@@ -108,26 +105,39 @@ path :: Request -> T.Text path = T.fromStrict . TS.cons '/' . TS.intercalate "/" . pathInfo --- Stolen from wai-extra, modified to accept body as lazy ByteString+-- Stolen from wai-extra's Network.Wai.Parse, modified to accept body as list of Bytestrings.+-- Reason: WAI's requestBody is an IO action that returns the body as chunks. Once read,+-- they can't be read again. We read them into a lazy Bytestring, so Scotty user can get+-- the raw body, even if they also want to call wai-extra's parsing routines. parseRequestBody :: MonadIO m-                 => BL.ByteString+                 => [B.ByteString]                  -> Parse.BackEnd y                  -> Request                  -> m ([Parse.Param], [Parse.File y])-parseRequestBody b s r =+parseRequestBody bl s r =     case Parse.getRequestBodyType r of         Nothing -> return ([], [])-        Just rbt -> liftIO $ liftM partitionEithers $ sourceLbs b $$ Parse.conduitRequestBody s rbt =$ consume+        Just rbt -> do+            mvar <- liftIO $ newMVar bl -- MVar is a bit of a hack so we don't have to inline+                                        -- large portions of Network.Wai.Parse+            let provider = takeMVar mvar >>= \case+                                                []     -> putMVar mvar [] >> return B.empty+                                                (b:bs) -> putMVar mvar bs >> return b+            liftIO $ Parse.sinkRequestBody s rbt provider -mkEnv :: MonadIO m => Request -> [Param] -> m ActionEnv+mkEnv :: forall m. MonadIO m => Request -> [Param] -> m ActionEnv mkEnv req captures = do-    b <- liftIO $ liftM BL.fromChunks $ lazyConsume (requestBody req)+    let rbody = requestBody req+        takeAll :: ([B.ByteString] -> m [B.ByteString]) -> m [B.ByteString]+        takeAll prefix = liftIO rbody >>= \ b -> if B.null b then prefix [] else takeAll (prefix . (b:))+    bs <- takeAll return -    (formparams, fs) <- liftIO $ parseRequestBody b Parse.lbsBackEnd req+    (formparams, fs) <- liftIO $ parseRequestBody bs Parse.lbsBackEnd req      let convert (k, v) = (strictByteStringToLazyText k, strictByteStringToLazyText v)         parameters = captures ++ map convert formparams ++ queryparams         queryparams = parseEncodedParams $ rawQueryString req+        b = BL.fromChunks bs      return $ Env req parameters b [ (strictByteStringToLazyText k, fi) | (k,fi) <- fs ] 
Web/Scotty/Trans.hs view
@@ -21,14 +21,14 @@       -- ** Route Patterns     , capture, regex, function, literal       -- ** Accessing the Request, Captures, and Query Parameters-    , request, header, reqHeader, headers, body, param, params, jsonData, files+    , request, header, headers, body, param, params, jsonData, files       -- ** Modifying the Response and Redirecting     , status, addHeader, setHeader, redirect       -- ** Setting Response Body       --       -- | Note: only one of these should be present in any given route       -- definition, as they completely replace the current 'Response' body.-    , text, html, file, json, source, raw+    , text, html, file, json, stream, source, raw       -- ** Exceptions     , raise, rescue, next, defaultHandler, ScottyError(..)       -- * Parsing Parameters@@ -39,23 +39,32 @@     , ScottyT, ActionT     ) where -import Blaze.ByteString.Builder (fromByteString)+import Blaze.ByteString.Builder (Builder, fromByteString)  import Control.Monad (when) import Control.Monad.State (execStateT, modify) import Control.Monad.IO.Class +import Data.Conduit (Flush, Source) import Data.Default (def)  import Network.HTTP.Types (status404) import Network.Wai import Network.Wai.Handler.Warp (Port, runSettings, setPort, getPort) -import Web.Scotty.Action+import Web.Scotty.Action hiding (source)+import qualified Web.Scotty.Action as Action import Web.Scotty.Route import Web.Scotty.Types hiding (Application, Middleware) import qualified Web.Scotty.Types as Scotty +-- | Set the body of the response to a Source. Doesn't set the+-- \"Content-Type\" header, so you probably want to do that on your+-- own with 'setHeader'.+source :: (ScottyError e, Monad m) => Source IO (Flush Builder) -> ActionT e m ()+source = Action.source+{-# DEPRECATED source "Use 'stream' instead. This will be removed in the next release." #-}+ -- | Run a scotty application using the warp server. -- NB: scotty p === scottyT p id id scottyT :: (Monad m, MonadIO n)@@ -89,21 +98,21 @@            -> n Application scottyAppT runM runActionToIO defs = do     s <- runM $ execStateT (runS defs) def-    let rapp = runActionToIO . foldl (flip ($)) notFoundApp (routes s)+    let rapp = \ req callback -> runActionToIO (foldl (flip ($)) notFoundApp (routes s) req) >>= callback     return $ foldl (flip ($)) rapp (middlewares s)  notFoundApp :: Monad m => Scotty.Application m notFoundApp _ = return $ responseBuilder status404 [("Content-Type","text/html")]                        $ fromByteString "<h1>404: File Not Found!</h1>" --- | Global handler for uncaught exceptions. +-- | Global handler for uncaught exceptions. ----- Uncaught exceptions normally become 500 responses. +-- Uncaught exceptions normally become 500 responses. -- You can use this to selectively override that behavior. -- -- Note: IO exceptions are lifted into 'ScottyError's by 'stringError'. -- This has security implications, so you probably want to provide your--- own defaultHandler in production which does not send out the error +-- own defaultHandler in production which does not send out the error -- strings as 500 responses. defaultHandler :: Monad m => (e -> ActionT e m ()) -> ScottyT e m () defaultHandler f = ScottyT $ modify $ addHandler $ Just f
Web/Scotty/Types.hs view
@@ -10,7 +10,6 @@ import           Control.Monad.State  import           Data.ByteString.Lazy.Char8 (ByteString)-import qualified Data.Conduit as C import           Data.Default (Default, def) import           Data.Monoid (mempty) import           Data.String (IsString(..))@@ -42,7 +41,7 @@ type Application m = Request -> m Response  --------------- Scotty Applications ------------------data ScottyState e m = +data ScottyState e m =     ScottyState { middlewares :: [Wai.Middleware]                 , routes :: [Middleware m]                 , handler :: ErrorHandler e m@@ -72,7 +71,7 @@                    | ActionError e  -- | In order to use a custom exception type (aside from 'Text'), you must--- define an instance of 'ScottyError' for that type. +-- define an instance of 'ScottyError' for that type. class ScottyError e where     stringError :: String -> e     showError :: e -> Text@@ -87,7 +86,7 @@     showError Next            = pack "Next"     showError (ActionError e) = showError e -instance ScottyError e => Error (ActionError e) where +instance ScottyError e => Error (ActionError e) where     strMsg = stringError  type ErrorHandler e m = Maybe (e -> ActionT e m ())@@ -100,12 +99,12 @@ data ActionEnv = Env { getReq    :: Request                      , getParams :: [Param]                      , getBody   :: ByteString-                     , getFiles  :: [File] +                     , getFiles  :: [File]                      }  data Content = ContentBuilder Builder              | ContentFile    FilePath-             | ContentSource  (C.Source IO (C.Flush Builder))+             | ContentStream  StreamingBody  data ScottyResponse = SR { srStatus  :: Status                          , srHeaders :: ResponseHeaders@@ -136,5 +135,5 @@                   | Literal   Text                   | Function  (Request -> Maybe [Param]) -instance IsString RoutePattern where +instance IsString RoutePattern where     fromString = Capture . pack
Web/Scotty/Util.hs view
@@ -34,11 +34,14 @@ setStatus :: Status -> ScottyResponse -> ScottyResponse setStatus s sr = sr { srStatus = s } +-- Note: we currently don't support responseRaw, which may be useful+-- for websockets. However, we always read the request body, which+-- is incompatible with responseRaw responses. mkResponse :: ScottyResponse -> Response mkResponse sr = case srContent sr of                     ContentBuilder b  -> responseBuilder s h b                     ContentFile f     -> responseFile s h f Nothing-                    ContentSource src -> responseSource s h src+                    ContentStream str -> responseStream s h str     where s = srStatus sr           h = srHeaders sr 
changelog.md view
@@ -1,6 +1,17 @@+## 0.8.0++* Upgrade to wai/wai-extra/warp 3.0++* No longer depend on conduit-extra.++* The `source` response method has been deprecated in favor+  of a new `stream` response, matching changes in WAI 3.0.++* Removed the deprecated `reqHeader` function.+ ## 0.7.3 -* Bump upper bound for `case-insensitive`, `mtl` and `transformers`.+* Bump upper bound for case-insensitive, mtl and transformers.  ## 0.7.2 @@ -65,7 +76,7 @@ * Removed lambda action syntax. This will return when we have a better   story for typesafe routes. -* `reqHeader :: Text -> ActionM Text` ==> +* `reqHeader :: Text -> ActionM Text` ==>   `reqHeader :: Text -> ActionM (Maybe Text)`  * New `raw` method to set body to a raw `ByteString`
scotty.cabal view
@@ -1,5 +1,5 @@ Name:                scotty-Version:             0.7.3+Version:             0.8.0 Synopsis:            Haskell web framework inspired by Ruby's Sinatra, using WAI and Warp Homepage:            https://github.com/scotty-web/scotty Bug-reports:         https://github.com/scotty-web/scotty/issues@@ -74,18 +74,31 @@                        bytestring       >= 0.10.0.2 && < 0.11,                        case-insensitive >= 1.0.0.1  && < 1.3,                        conduit          >= 1.1      && < 1.2,-                       conduit-extra    >= 1.1      && < 1.2,                        data-default     >= 0.5.3    && < 0.6,                        http-types       >= 0.8.2    && < 0.9,                        mtl              >= 2.1.2    && < 2.3,                        regex-compat     >= 0.95.1   && < 0.96,                        text             >= 0.11.3.1 && < 1.2,                        transformers     >= 0.3.0.0  && < 0.5,-                       wai              >= 2.0.0    && < 2.2,-                       wai-extra        >= 2.0.1    && < 2.2,-                       warp             >= 2.1.1    && < 2.2+                       wai              >= 3.0.0    && < 3.1,+                       wai-extra        >= 3.0.0    && < 3.1,+                       warp             >= 3.0.0    && < 3.1    GHC-options: -Wall -fno-warn-orphans++test-suite spec+  main-is:             Spec.hs+  type:                exitcode-stdio-1.0+  default-language:    Haskell2010+  hs-source-dirs:      test+  build-depends:       base,+                       bytestring,+                       http-types,+                       wai,+                       hspec            >= 1.9.2,+                       wai-extra        >= 3.0.0,+                       scotty+  GHC-options:         -Wall -fno-warn-orphans  source-repository head   type:     git
+ test/Spec.hs view
@@ -0,0 +1,1 @@+{-# OPTIONS_GHC -F -pgmF hspec-discover #-}