happstack-server-7.1.7.1: Web related tools and services.

Safe Haskell | None

Happstack.Server.RqData

Contents

- Looking up keys
  - Form Values and Query Parameters
  - Cookies
  - low-level
- Filters
- Validation and Parsing
- Handling POST/PUT Requests
  - Body Policy
- RqData Monad & Error Reporting
  - Using RqData with ServerMonad
- HasRqData class

Description

Functions for extracting values from the query string, form data, cookies, etc.

For in-depth documentation see the following section of the Happstack Crash Course:

http://happstack.com/docs/crashcourse/RqData.html

Synopsis

- look :: (Functor m, Monad m, HasRqData m) => String -> m String
- looks :: (Functor m, Monad m, HasRqData m) => String -> m [String]
- lookText :: (Functor m, Monad m, HasRqData m) => String -> m Text
- lookText' :: (Functor m, Monad m, HasRqData m) => String -> m Text
- lookTexts :: (Functor m, Monad m, HasRqData m) => String -> m [Text]
- lookTexts' :: (Functor m, Monad m, HasRqData m) => String -> m [Text]
- lookBS :: (Functor m, Monad m, HasRqData m) => String -> m ByteString
- lookBSs :: (Functor m, Monad m, HasRqData m) => String -> m [ByteString]
- lookRead :: (Functor m, Monad m, HasRqData m, FromReqURI a) => String -> m a
- lookReads :: (Functor m, Monad m, HasRqData m, FromReqURI a) => String -> m [a]
- lookFile :: (Monad m, HasRqData m) => String -> m (FilePath, FilePath, ContentType)
- lookPairs :: (Monad m, HasRqData m) => m [(String, Either FilePath String)]
- lookPairsBS :: (Monad m, HasRqData m) => m [(String, Either FilePath ByteString)]
- lookCookie :: (Monad m, HasRqData m) => String -> m Cookie
- lookCookieValue :: (Functor m, Monad m, HasRqData m) => String -> m String
- readCookieValue :: (Functor m, Monad m, HasRqData m, FromReqURI a) => String -> m a
- lookInput :: (Monad m, HasRqData m) => String -> m Input
- lookInputs :: (Monad m, HasRqData m) => String -> m [Input]
- body :: HasRqData m => m a -> m a
- queryString :: HasRqData m => m a -> m a
- bytestring :: HasRqData m => m a -> m a
- checkRq :: (Monad m, HasRqData m) => m a -> (a -> Either String b) -> m b
- checkRqM :: (Monad m, HasRqData m) => m a -> (a -> m (Either String b)) -> m b
- readRq :: FromReqURI a => String -> String -> Either String a
- unsafeReadRq :: Read a => String -> String -> Either String a
- decodeBody :: (ServerMonad m, MonadPlus m, MonadIO m, FilterMonad Response m, WebMonad Response m) => BodyPolicy -> m ()
- data BodyPolicy = BodyPolicy {
  - inputWorker :: Int64 -> Int64 -> Int64 -> InputWorker
  - maxDisk :: Int64
  - maxRAM :: Int64
  - maxHeader :: Int64
  }
- defaultBodyPolicy :: FilePath -> Int64 -> Int64 -> Int64 -> BodyPolicy
- data RqData a
- mapRqData :: (Either (Errors String) a -> Either (Errors String) b) -> RqData a -> RqData b
- newtype Errors a = Errors {
  - unErrors :: [a]
  }
- getDataFn :: (HasRqData m, ServerMonad m) => RqData a -> m (Either [String] a)
- withDataFn :: (HasRqData m, MonadPlus m, ServerMonad m) => RqData a -> (a -> m r) -> m r
- class FromData a where
  - fromData :: RqData a
- getData :: (HasRqData m, ServerMonad m, FromData a) => m (Either [String] a)
- withData :: (HasRqData m, FromData a, MonadPlus m, ServerMonad m) => (a -> m r) -> m r
- type RqEnv = ([(String, Input)], Maybe [(String, Input)], [(String, Cookie)])
- class HasRqData m where
  - askRqEnv :: m RqEnv
  - localRqEnv :: (RqEnv -> RqEnv) -> m a -> m a
  - rqDataError :: Errors String -> m a

# Looking up keys

## Form Values and Query Parameters

look :: (Functor m, Monad m, HasRqData m) => String -> m String

Gets the first matching named input parameter as a `String`

Searches the QUERY_STRING followed by the Request body.

This function assumes the underlying octets are UTF-8 encoded.

Example:

     handler :: ServerPart Response
     handler =
          do foo <- look "foo"
             ok $ toResponse $ "foo = " ++ foo

see also: `looks`, `lookBS`, and `lookBSs`

looks :: (Functor m, Monad m, HasRqData m) => String -> m [String]

Gets all matches for the named input parameter as `String`s

Searches the QUERY_STRING followed by the Request body.

This function assumes the underlying octets are UTF-8 encoded.

see also: `look` and `lookBSs`

lookText :: (Functor m, Monad m, HasRqData m) => String -> m Text

Gets the first matching named input parameter as a lazy `Text`

Searches the QUERY_STRING followed by the Request body.

This function assumes the underlying octets are UTF-8 encoded.

see also: `lookTexts`, `look`, `looks`, `lookBS`, and `lookBSs`

lookText' :: (Functor m, Monad m, HasRqData m) => String -> m Text

Gets the first matching named input parameter as a strict `Text`

Searches the QUERY_STRING followed by the Request body.

This function assumes the underlying octets are UTF-8 encoded.

see also: `lookTexts`, `look`, `looks`, `lookBS`, and `lookBSs`

lookTexts :: (Functor m, Monad m, HasRqData m) => String -> m [Text]

Gets all matches for the named input parameter as lazy `Text`s

Searches the QUERY_STRING followed by the Request body.

This function assumes the underlying octets are UTF-8 encoded.

see also: `lookText`, `looks` and `lookBSs`

lookTexts' :: (Functor m, Monad m, HasRqData m) => String -> m [Text]

Gets all matches for the named input parameter as strict `Text`s

Searches the QUERY_STRING followed by the Request body.

This function assumes the underlying octets are UTF-8 encoded.

see also: `lookText'`, `looks` and `lookBSs`

lookBS :: (Functor m, Monad m, HasRqData m) => String -> m ByteString

Gets the first matching named input parameter as a lazy `ByteString`

Searches the QUERY_STRING followed by the Request body.

see also: `lookBSs`

lookBSs :: (Functor m, Monad m, HasRqData m) => String -> m [ByteString]

Gets all matches for the named input parameter as lazy `ByteString`s

Searches the QUERY_STRING followed by the Request body.

see also: `lookBS`

lookRead :: (Functor m, Monad m, HasRqData m, FromReqURI a) => String -> m a

Gets the first matching named input parameter and decodes it using `Read`

Searches the QUERY_STRING followed by the Request body.

This function assumes the underlying octets are UTF-8 encoded.

see also: `lookReads`

lookReads :: (Functor m, Monad m, HasRqData m, FromReqURI a) => String -> m [a]

Gets all matches for the named input parameter and decodes them using `Read`

Searches the QUERY_STRING followed by the Request body.

This function assumes the underlying octets are UTF-8 encoded.

see also: `lookReads`

lookFile

Arguments

:: (Monad m, HasRqData m) |
=> String | name of input field to search for
-> m (FilePath, FilePath, ContentType) | (temporary file location, uploaded file name, content-type)

Gets the first matching named file

Files can only appear in the request body. Additionally, the form must set enctype="multipart/form-data".

This function returns a tuple consisting of:

1. The temporary location of the uploaded file
2. The local filename supplied by the browser
3. The content-type supplied by the browser

If the user does not supply a file in the html form input field, the behaviour will depend upon the browser. Most browsers will send a 0-length file with an empty file name, so checking that (2) is not empty is usually sufficient to ensure the field has been filled.

NOTE: You must move the file from the temporary location before the `Response` is sent. The temporary files are automatically removed after the `Response` is sent.

lookPairs :: (Monad m, HasRqData m) => m [(String, Either FilePath String)]

gets all the input parameters, and converts them to a `String`

The results will contain the QUERY_STRING followed by the Request body.

This function assumes the underlying octets are UTF-8 encoded.

see also: `lookPairsBS`

lookPairsBS :: (Monad m, HasRqData m) => m [(String, Either FilePath ByteString)]

gets all the input parameters

The results will contain the QUERY_STRING followed by the Request body.

see also: `lookPairs`

## Cookies

lookCookie :: (Monad m, HasRqData m) => String -> m Cookie

Gets the named cookie the cookie name is case insensitive

lookCookieValue :: (Functor m, Monad m, HasRqData m) => String -> m String

gets the named cookie as a string

readCookieValue :: (Functor m, Monad m, HasRqData m, FromReqURI a) => String -> m a

gets the named cookie as the requested Read type

## low-level

lookInput :: (Monad m, HasRqData m) => String -> m Input

Gets the first matching named input parameter

Searches the QUERY_STRING followed by the Request body.

see also: `lookInputs`

lookInputs :: (Monad m, HasRqData m) => String -> m [Input]

Gets all matches for the named input parameter

Searches the QUERY_STRING followed by the Request body.

see also: `lookInput`

# Filters

body :: HasRqData m => m a -> m a

limit the scope to the Request body

     handler :: ServerPart Response
     handler =
         do foo <- body $ look "foo"
            ok $ toResponse $ "foo = " ++ foo

queryString :: HasRqData m => m a -> m a

limit the scope to the QUERY_STRING

     handler :: ServerPart Response
     handler =
         do foo <- queryString $ look "foo"
            ok $ toResponse $ "foo = " ++ foo

bytestring :: HasRqData m => m a -> m a

limit the scope to `Input`s which produce a `ByteString` (aka, not a file)

# Validation and Parsing

checkRq :: (Monad m, HasRqData m) => m a -> (a -> Either String b) -> m b

convert or validate a value

This is similar to `fmap` except that the function can fail by returning Left and an error message. The error will be propagated by calling `rqDataError`.

This function is useful for a number of things including:

1. Parsing a `String` into another type
2. Checking that a value meets some requirements (for example, that is an Int between 1 and 10).

Example usage at:

http://happstack.com/docs/crashcourse/RqData.html#rqdatacheckrq

checkRqM :: (Monad m, HasRqData m) => m a -> (a -> m (Either String b)) -> m b

like `checkRq` but the check function can be monadic

readRq

Arguments

:: FromReqURI a |
=> String | name of key (only used for error reporting)
-> String | `String` to `read`
-> Either String a | `Left` on error, `Right` on success

use `fromReqURI` to convert a `String` to a value of type `a`

     look "key" `checkRq` (readRq "key")

use with `checkRq`

unsafeReadRq

Arguments

:: Read a |
=> String | name of key (only used for error reporting)
-> String | `String` to `read`
-> Either String a | `Left` on error, `Right` on success

use `read` to convert a `String` to a value of type `a`

     look "key" `checkRq` (unsafeReadRq "key")

use with `checkRq`

NOTE: This function is marked unsafe because some Read instances are vulnerable to attacks that attempt to create an out of memory condition. For example:

     read "1e10000000000000" :: Integer

see also: `readRq`

# Handling POST/PUT Requests

decodeBody :: (ServerMonad m, MonadPlus m, MonadIO m, FilterMonad Response m, WebMonad Response m) => BodyPolicy -> m ()

The POST/PUT body of a Request is not received or decoded unless this function is invoked.

It is an error to try to use the look functions for a POST/PUT request with out first calling this function.

It is ok to call `decodeBody` at the beginning of every request:

     main = simpleHTTP nullConf $
               do decodeBody (defaultBodyPolicy "/tmp/" 4096 4096 4096)
                  handlers

You can achieve finer granularity quotas by calling `decodeBody` with different values in different handlers.

Only the first call to `decodeBody` will have any effect. Calling it a second time, even with different quota values, will do nothing.

## Body Policy

data BodyPolicy

see `defaultBodyPolicy`

Constructors

BodyPolicy |
Fields inputWorker :: Int64 -> Int64 -> Int64 -> InputWorker maxDisk :: Int64 maximum bytes for files uploaded in this `Request` maxRAM :: Int64 maximum bytes for all non-file values in the `Request` body maxHeader :: Int64 maximum bytes of overhead for headers in `multipart/form-data`

defaultBodyPolicy

Arguments

:: FilePath | temporary directory for file uploads
-> Int64 | maximum bytes for files uploaded in this `Request`
-> Int64 | maximum bytes for all non-file values in the `Request` body
-> Int64 | maximum bytes of overhead for headers in `multipart/form-data`
-> BodyPolicy |

create a `BodyPolicy` for use with decodeBody

# RqData Monad & Error Reporting

data RqData a

An applicative functor and monad for looking up key/value pairs in the QUERY_STRING, Request body, and cookies.

Instances

Monad RqData |
Functor RqData |
MonadPlus RqData |
Applicative RqData |
Alternative RqData |
HasRqData RqData |
MonadReader RqEnv RqData |

mapRqData :: (Either (Errors String) a -> Either (Errors String) b) -> RqData a -> RqData b

transform the result of 'RqData a'.

This is similar to `fmap` except it also allows you to modify the `Errors` not just `a`.

newtype Errors a

a list of errors

Constructors

Errors |
Fields unErrors :: [a]

Instances

Typeable1 Errors |
Eq a => Eq (Errors a) |
Data a => Data (Errors a) |
Ord a => Ord (Errors a) |
Read a => Read (Errors a) |
Show a => Show (Errors a) |
Monoid (Errors a) |
Error (Errors String) |

## Using RqData with ServerMonad

getDataFn

Arguments

:: (HasRqData m, ServerMonad m) |
=> RqData a | `RqData` monad to evaluate
-> m (Either [String] a) | return `Left` errors or `Right` a

run `RqData` in a `ServerMonad`.

Example: a simple `GET` or `POST` variable based authentication guard. It handles the request with `errorHandler` if authentication fails.

      data AuthCredentials = AuthCredentials { username :: String,  password :: String }

      isValid :: AuthCredentials -> Bool
      isValid = const True

      myRqData :: RqData AuthCredentials
      myRqData = do
         username <- look "username"
         password <- look "password"
         return (AuthCredentials username password)

      checkAuth :: (String -> ServerPart Response) -> ServerPart Response
      checkAuth errorHandler = do
         d <- getDataFn myRqData
         case d of
             (Left e) -> errorHandler (unlines e)
             (Right a) | isValid a -> mzero
             (Right a) | otherwise -> errorHandler "invalid"

NOTE: you must call `decodeBody` prior to calling this function if the request method is POST or PUT.

withDataFn :: (HasRqData m, MonadPlus m, ServerMonad m) => RqData a -> (a -> m r) -> m r

similar to `getDataFn`, except it calls a sub-handler on success or `mzero` on failure.

NOTE: you must call `decodeBody` prior to calling this function if the request method is POST or PUT.

class FromData a where

Used by `withData` and `getData`. Make your preferred data type an instance of `FromData` to use those functions.

Methods

fromData :: RqData a

Instances

FromData a => FromData (Maybe a) |
(FromData a, FromData b) => FromData (a, b) |
(FromData a, FromData b, FromData c) => FromData (a, b, c) |
(FromData a, FromData b, FromData c, FromData d) => FromData (a, b, c, d) |

getData :: (HasRqData m, ServerMonad m, FromData a) => m (Either [String] a)

A variant of `getDataFn` that uses `FromData` to chose your `RqData` for you. The example from `getData` becomes:

      data AuthCredentials = AuthCredentials { username :: String,  password :: String }

      isValid :: AuthCredentials -> Bool
      isValid = const True

      myRqData :: RqData AuthCredentials
      myRqData = do
         username <- look "username"
         password <- look "password"
         return (AuthCredentials username password)

      instance FromData AuthCredentials where
         fromData = myRqData

      checkAuth :: (String -> ServerPart Response) -> ServerPart Response
      checkAuth errorHandler = do
         d <- getData
         case d of
             (Left e) -> errorHandler (unlines e)
             (Right a) | isValid a -> mzero
             (Right a) | otherwise -> errorHandler "invalid"

NOTE: you must call `decodeBody` prior to calling this function if the request method is POST or PUT.

withData :: (HasRqData m, FromData a, MonadPlus m, ServerMonad m) => (a -> m r) -> m r

similar to `getData` except it calls a subhandler on success or `mzero` on failure.

NOTE: you must call `decodeBody` prior to calling this function if the request method is POST or PUT.

# HasRqData class

type RqEnv = ([(String, Input)], Maybe [(String, Input)], [(String, Cookie)])

the environment used to lookup query parameters. It consists of the triple: (query string inputs, body inputs, cookie inputs)

class HasRqData m where

A class for monads which contain a `RqEnv`

Methods

askRqEnv :: m RqEnv

localRqEnv :: (RqEnv -> RqEnv) -> m a -> m a

rqDataError :: Errors String -> m a

lift some `Errors` into `RqData`

Instances

HasRqData RqData |
MonadIO m => HasRqData (ServerPartT m) |
(Monad m, HasRqData m) => HasRqData (ReaderT s m) |
(Monad m, HasRqData m) => HasRqData (StateT s m) |
(Monad m, HasRqData m, Monoid w) => HasRqData (WriterT w m) |
(Monad m, HasRqData m, Monoid w) => HasRqData (RWST r w s m) |