yesod-core-1.4.15.1: Creation of type-safe, RESTful web applications.

Safe HaskellNone
LanguageHaskell98

Yesod.Core.Handler

Contents

Synopsis

Handler monad

data HandlerT site m a Source

A generic handler monad, which can have a different subsite and master site. We define a newtype for better error message.

Instances

MonadBaseControl b m => MonadBaseControl b (HandlerT site m) Source

Note: although we provide a MonadBaseControl instance, lifted-base's fork function is incompatible with the underlying ResourceT system. Instead, if you must fork a separate thread, you should use resourceForkIO.

Using fork usually leads to an exception that says "Control.Monad.Trans.Resource.register': The mutable state is being accessed after cleanup. Please contact the maintainers."

MonadBase b m => MonadBase b (HandlerT site m) Source 
Monad m => MonadReader site (HandlerT site m) Source 
MonadTrans (HandlerT site) Source 
Monad m => Monad (HandlerT site m) Source 
Monad m => Functor (HandlerT site m) Source 
Monad m => Applicative (HandlerT site m) Source 
MonadActive m => MonadActive (HandlerT site m) Source 
MonadThrow m => MonadThrow (HandlerT site m) Source 
MonadCatch m => MonadCatch (HandlerT site m) Source 
MonadMask m => MonadMask (HandlerT site m) Source 
MonadIO m => MonadLogger (HandlerT site m) Source 
MonadIO m => MonadLoggerIO (HandlerT site m) Source 
MonadIO m => MonadIO (HandlerT site m) Source 
(MonadIO m, MonadBase IO m, MonadThrow m) => MonadResource (HandlerT site m) Source 
MonadResourceBase m => MonadHandler (HandlerT site m) Source 
type MonadRoute (HandlerT site m) = Route site Source 
type HandlerSite (HandlerT site m) = site Source 
type StM (HandlerT site m) a = StM m a Source 

Read information from handler

getYesod :: MonadHandler m => m (HandlerSite m) Source

Get the master site application argument.

getsYesod :: MonadHandler m => (HandlerSite m -> a) -> m a Source

Get a specific component of the master site application argument. Analogous to the gets function for operating on StateT.

getUrlRender :: MonadHandler m => m (Route (HandlerSite m) -> Text) Source

Get the URL rendering function.

getUrlRenderParams :: MonadHandler m => m (Route (HandlerSite m) -> [(Text, Text)] -> Text) Source

The URL rendering function with query-string parameters.

getCurrentRoute :: MonadHandler m => m (Maybe (Route (HandlerSite m))) Source

Get the route requested by the user. If this is a 404 response- where the user requested an invalid route- this function will return Nothing.

waiRequest :: MonadHandler m => m Request Source

Get the request's Request value.

rawRequestBody :: MonadHandler m => Source m ByteString Source

Stream in the raw request body without any parsing.

Since 1.2.0

Request information

Request datatype

type RequestBodyContents = ([(Text, Text)], [(Text, FileInfo)]) Source

A tuple containing both the POST parameters and submitted files.

data YesodRequest Source

The parsed request information. This type augments the standard WAI Request with additional information.

Constructors

YesodRequest 

Fields

reqGetParams :: ![(Text, Text)]

Same as queryString, but decoded to Text.

reqCookies :: ![(Text, Text)]
 
reqWaiRequest :: !Request
 
reqLangs :: ![Text]

Languages which the client supports. This is an ordered list by preference.

reqToken :: !(Maybe Text)

A random, session-specific token used to prevent CSRF attacks.

reqSession :: !SessionMap

Initial session sent from the client.

Since 1.2.0

reqAccept :: ![ContentType]

An ordered list of the accepted content types.

Since 1.2.0

fileSource :: MonadResource m => FileInfo -> Source m ByteString Source

Stream the data from the file. Since Yesod 1.2, this has been generalized to work in any MonadResource.

Convenience functions

languages :: MonadHandler m => m [Text] Source

Get the list of supported languages supplied by the user.

Languages are determined based on the following three (in descending order of preference):

  • The _LANG get parameter.
  • The _LANG cookie.
  • The _LANG user session variable.
  • Accept-Language HTTP header.

Yesod will seek the first language from the returned list matched with languages supporting by your application. This language will be used to render i18n templates. If a matching language is not found the default language will be used.

This is handled by parseWaiRequest (not exposed).

Lookup parameters

lookupGetParam :: MonadHandler m => Text -> m (Maybe Text) Source

Lookup for GET parameters.

lookupCookie :: MonadHandler m => Text -> m (Maybe Text) Source

Lookup for cookie data.

lookupFile :: (MonadHandler m, MonadResource m) => Text -> m (Maybe FileInfo) Source

Lookup for POSTed files.

lookupHeader :: MonadHandler m => CI ByteString -> m (Maybe ByteString) Source

Lookup a request header.

Since 1.2.2

Lookup authentication data

lookupBasicAuth :: MonadHandler m => m (Maybe (Text, Text)) Source

Lookup basic authentication data from Authorization header of request. Returns user name and password

Since 1.4.9

lookupBearerAuth :: MonadHandler m => m (Maybe Text) Source

Lookup bearer authentication datafrom Authorization header of request. Returns bearer token value

Since 1.4.9

Multi-lookup

lookupGetParams :: MonadHandler m => Text -> m [Text] Source

Lookup for GET parameters.

lookupPostParams :: (MonadResource m, MonadHandler m) => Text -> m [Text] Source

Lookup for POST parameters.

lookupCookies :: MonadHandler m => Text -> m [Text] Source

Lookup for cookie data.

lookupFiles :: (MonadHandler m, MonadResource m) => Text -> m [FileInfo] Source

Lookup for POSTed files.

lookupHeaders :: MonadHandler m => CI ByteString -> m [ByteString] Source

Lookup a request header.

Since 1.2.2

Responses

Pure

respond :: (Monad m, ToContent a) => ContentType -> a -> m TypedContent Source

Provide a pure value for the response body.

respond ct = return . TypedContent ct . toContent

Since 1.2.0

Streaming

respondSource :: ContentType -> Source (HandlerT site IO) (Flush Builder) -> HandlerT site IO TypedContent Source

Use a Source for the response body.

Note that, for ease of use, the underlying monad is a HandlerT. This implies that you can run any HandlerT action. However, since a streaming response occurs after the response headers have already been sent, some actions make no sense here. For example: short-circuit responses, setting headers, changing status codes, etc.

Since 1.2.0

sendChunk :: Monad m => ToFlushBuilder a => a -> Producer m (Flush Builder) Source

In a streaming response, send a single chunk of data. This function works on most datatypes, such as ByteString and Html.

Since 1.2.0

sendFlush :: Monad m => Producer m (Flush Builder) Source

In a streaming response, send a flush command, causing all buffered data to be immediately sent to the client.

Since 1.2.0

sendChunkBS :: Monad m => ByteString -> Producer m (Flush Builder) Source

Type-specialized version of sendChunk for strict ByteStrings.

Since 1.2.0

sendChunkLBS :: Monad m => ByteString -> Producer m (Flush Builder) Source

Type-specialized version of sendChunk for lazy ByteStrings.

Since 1.2.0

sendChunkText :: Monad m => Text -> Producer m (Flush Builder) Source

Type-specialized version of sendChunk for strict Texts.

Since 1.2.0

sendChunkLazyText :: Monad m => Text -> Producer m (Flush Builder) Source

Type-specialized version of sendChunk for lazy Texts.

Since 1.2.0

sendChunkHtml :: Monad m => Html -> Producer m (Flush Builder) Source

Type-specialized version of sendChunk for Htmls.

Since 1.2.0

Redirecting

class RedirectUrl master a where Source

Some value which can be turned into a URL for redirects.

Methods

toTextUrl :: (MonadHandler m, HandlerSite m ~ master) => a -> m Text Source

Converts the value to the URL and a list of query-string parameters.

Instances

RedirectUrl master String Source 
RedirectUrl master Text Source 
RedirectUrl master (Route master) Source 
(RedirectUrl master a, PathPiece b) => RedirectUrl master (Fragment a b) Source 
((~) * key Text, (~) * val Text) => RedirectUrl master (Route master, Map key val) Source 
((~) * key Text, (~) * val Text) => RedirectUrl master (Route master, [(key, val)]) Source 

redirect :: (MonadHandler m, RedirectUrl (HandlerSite m) url) => url -> m a Source

Redirect to the given route. HTTP status code 303 for HTTP 1.1 clients and 302 for HTTP 1.0 This is the appropriate choice for a get-following-post technique, which should be the usual use case.

If you want direct control of the final status code, or need a different status code, please use redirectWith.

redirectWith :: (MonadHandler m, RedirectUrl (HandlerSite m) url) => Status -> url -> m a Source

Redirect to the given URL with the specified status code.

redirectToPost :: (MonadHandler m, RedirectUrl (HandlerSite m) url) => url -> m a Source

Redirect to a POST resource.

This is not technically a redirect; instead, it returns an HTML page with a POST form, and some Javascript to automatically submit the form. This can be useful when you need to post a plain link somewhere that needs to cause changes on the server.

data Fragment a b Source

Add a fragment identifier to a route to be used when redirecting. For example:

redirect (NewsfeedR :#: storyId)

Since 1.2.9.

Constructors

a :#: b 

Instances

(RedirectUrl master a, PathPiece b) => RedirectUrl master (Fragment a b) Source 
(Show a, Show b) => Show (Fragment a b) Source 

Errors

notFound :: MonadHandler m => m a Source

Return a 404 not found page. Also denotes no handler available.

badMethod :: MonadHandler m => m a Source

Return a 405 method not supported page.

notAuthenticated :: MonadHandler m => m a Source

Return a 401 status code

permissionDenied :: MonadHandler m => Text -> m a Source

Return a 403 permission denied page.

permissionDeniedI :: (RenderMessage (HandlerSite m) msg, MonadHandler m) => msg -> m a Source

Return a 403 permission denied page.

invalidArgs :: MonadHandler m => [Text] -> m a Source

Return a 400 invalid arguments page.

invalidArgsI :: (MonadHandler m, RenderMessage (HandlerSite m) msg) => [msg] -> m a Source

Return a 400 invalid arguments page.

Short-circuit responses.

sendFile :: MonadHandler m => ContentType -> FilePath -> m a Source

Bypass remaining handler code and output the given file.

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.

sendFilePart Source

Arguments

:: MonadHandler m 
=> ContentType 
-> FilePath 
-> Integer

offset

-> Integer

count

-> m a 

Same as sendFile, but only sends part of a file.

sendResponse :: (MonadHandler m, ToTypedContent c) => c -> m a Source

Bypass remaining handler code and output the given content with a 200 status code.

sendResponseStatus :: (MonadHandler m, ToTypedContent c) => Status -> c -> m a Source

Bypass remaining handler code and output the given content with the given status code.

sendResponseCreated :: MonadHandler m => Route (HandlerSite m) -> m a Source

Send a 201 Created response with the given route as the Location response header.

sendWaiResponse :: MonadHandler m => Response -> m b Source

Send a Response. Please note: this function is rarely necessary, and will disregard any changes to response headers and session that you have already specified. This function short-circuits. It should be considered only for very specific needs. If you are not sure if you need it, you don't.

sendWaiApplication :: MonadHandler m => Application -> m b Source

Switch over to handling the current request with a WAI Application.

Since 1.2.17

sendRawResponse :: (MonadHandler m, MonadBaseControl IO m) => (Source IO ByteString -> Sink ByteString IO () -> m ()) -> m a Source

Send a raw response. This is used for cases such as WebSockets. Requires WAI 2.1 or later, and a web server which supports raw responses (e.g., Warp).

Since 1.2.7

sendRawResponseNoConduit :: (MonadHandler m, MonadBaseControl IO m) => (IO ByteString -> (ByteString -> IO ()) -> m ()) -> m a Source

Send a raw response without conduit. This is used for cases such as WebSockets. Requires WAI 3.0 or later, and a web server which supports raw responses (e.g., Warp).

Since 1.2.16

notModified :: MonadHandler m => m a Source

Send a 304 not modified response immediately. This is a short-circuiting action.

Since 1.4.4

Different representations

HTTP allows content negotation to determine what representation of data you would like to use. The most common example of this is providing both a user-facing HTML page and an API facing JSON response from the same URL. The means of achieving this is the Accept HTTP header, which provides a list of content types the client will accept, sorted by preference.

By using selectRep and provideRep, you can provide a number of different representations, e.g.:

selectRep $ do
  provideRep produceHtmlOutput
  provideRep produceJsonOutput

The first provided representation will be used if no matches are found.

selectRep :: MonadHandler m => Writer (Endo [ProvidedRep m]) () -> m TypedContent Source

Select a representation to send to the client based on the representations provided inside this do-block. Should be used together with provideRep.

Since 1.2.0

provideRep :: (Monad m, HasContentType a) => m a -> Writer (Endo [ProvidedRep m]) () Source

Provide a single representation to be used, based on the request of the client. Should be used together with selectRep.

Since 1.2.0

provideRepType :: (Monad m, ToContent a) => ContentType -> m a -> Writer (Endo [ProvidedRep m]) () Source

Same as provideRep, but instead of determining the content type from the type of the value itself, you provide the content type separately. This can be a convenience instead of creating newtype wrappers for uncommonly used content types.

provideRepType "application/x-special-format" "This is the content"

Since 1.2.0

data ProvidedRep m Source

Internal representation of a single provided representation.

Since 1.2.0

Setting headers

setCookie :: MonadHandler m => SetCookie -> m () Source

Set the cookie on the client.

getExpires Source

Arguments

:: MonadIO m 
=> Int

minutes

-> m UTCTime 

Helper function for setCookieExpires value

deleteCookie Source

Arguments

:: MonadHandler m 
=> Text

key

-> Text

path

-> m () 

Unset the cookie on the client.

Note: although the value used for key and path is Text, you should only use ASCII values to be HTTP compliant.

addHeader :: MonadHandler m => Text -> Text -> m () Source

Set an arbitrary response header.

Note that, while the data type used here is Text, you must provide only ASCII value to be HTTP compliant.

Since 1.2.0

setHeader :: MonadHandler m => Text -> Text -> m () Source

Deprecated: Please use addHeader instead

Deprecated synonym for addHeader.

setLanguage :: MonadHandler m => Text -> m () Source

Set the language in the user session. Will show up in languages on the next request.

Content caching and expiration

cacheSeconds :: MonadHandler m => Int -> m () Source

Set the Cache-Control header to indicate this response should be cached for the given number of seconds.

neverExpires :: MonadHandler m => m () Source

Set the Expires header to some date in 2037. In other words, this content is never (realistically) expired.

alreadyExpired :: MonadHandler m => m () Source

Set an Expires header in the past, meaning this content should not be cached.

expiresAt :: MonadHandler m => UTCTime -> m () Source

Set an Expires header to the given date.

setEtag :: MonadHandler m => Text -> m () Source

Check the if-none-match header and, if it matches the given value, return a 304 not modified response. Otherwise, set the etag header to the given value.

Note that it is the responsibility of the caller to ensure that the provided value is a value etag value, no sanity checking is performed by this function.

Since 1.4.4

Session

lookupSession :: MonadHandler m => Text -> m (Maybe Text) Source

Lookup for session data.

lookupSessionBS :: MonadHandler m => Text -> m (Maybe ByteString) Source

Lookup for session data in binary format.

getSession :: MonadHandler m => m SessionMap Source

Get all session variables.

setSession Source

Arguments

:: MonadHandler m 
=> Text

key

-> Text

value

-> m () 

Set a variable in the user's session.

The session is handled by the clientsession package: it sets an encrypted and hashed cookie on the client. This ensures that all data is secure and not tampered with.

setSessionBS :: MonadHandler m => Text -> ByteString -> m () Source

Same as setSession, but uses binary data for the value.

deleteSession :: MonadHandler m => Text -> m () Source

Unsets a session variable. See setSession.

clearSession :: MonadHandler m => m () Source

Clear all session variables.

Since: 1.0.1

Ultimate destination

setUltDest :: (MonadHandler m, RedirectUrl (HandlerSite m) url) => url -> m () Source

Sets the ultimate destination variable to the given route.

An ultimate destination is stored in the user session and can be loaded later by redirectUltDest.

setUltDestCurrent :: MonadHandler m => m () Source

Same as setUltDest, but uses the current page.

If this is a 404 handler, there is no current page, and then this call does nothing.

setUltDestReferer :: MonadHandler m => m () Source

Sets the ultimate destination to the referer request header, if present.

This function will not overwrite an existing ultdest.

redirectUltDest Source

Arguments

:: (RedirectUrl (HandlerSite m) url, MonadHandler m) 
=> url

default destination if nothing in session

-> m a 

Redirect to the ultimate destination in the user's session. Clear the value from the session.

The ultimate destination is set with setUltDest.

This function uses redirect, and thus will perform a temporary redirect to a GET request.

clearUltDest :: MonadHandler m => m () Source

Remove a previously set ultimate destination. See setUltDest.

Messages

setMessage :: MonadHandler m => Html -> m () Source

Sets a message in the user's session.

See getMessage.

setMessageI :: (MonadHandler m, RenderMessage (HandlerSite m) msg) => msg -> m () Source

Sets a message in the user's session.

See getMessage.

getMessage :: MonadHandler m => m (Maybe Html) Source

Gets the message in the user's session, if available, and then clears the variable.

See setMessage.

Helpers for specific content

Hamlet

hamletToRepHtml :: MonadHandler m => HtmlUrl (Route (HandlerSite m)) -> m Html Source

Deprecated: Use withUrlRenderer instead

Wraps the Content generated by hamletToContent in a RepHtml.

giveUrlRenderer :: MonadHandler m => ((Route (HandlerSite m) -> [(Text, Text)] -> Text) -> output) -> m output Source

Deprecated: Use withUrlRenderer instead

Deprecated synonym for withUrlRenderer.

Since 1.2.0

withUrlRenderer :: MonadHandler m => ((Route (HandlerSite m) -> [(Text, Text)] -> Text) -> output) -> m output Source

Provide a URL rendering function to the given function and return the result. Useful for processing Shakespearean templates.

Since 1.2.20

Misc

newIdent :: MonadHandler m => m Text Source

Get a unique identifier.

Lifting

handlerToIO :: (MonadIO m1, MonadIO m2) => HandlerT site m1 (HandlerT site IO a -> m2 a) Source

Returns a function that runs HandlerT actions inside IO.

Sometimes you want to run an inner HandlerT action outside the control flow of an HTTP request (on the outer HandlerT action). For example, you may want to spawn a new thread:

getFooR :: Handler RepHtml
getFooR = do
  runInnerHandler <- handlerToIO
  liftIO $ forkIO $ runInnerHandler $ do
    Code here runs inside GHandler but on a new thread.
    This is the inner GHandler.
    ...
  Code here runs inside the request's control flow.
  This is the outer GHandler.
  ...

Another use case for this function is creating a stream of server-sent events using GHandler actions (see yesod-eventsource).

Most of the environment from the outer GHandler is preserved on the inner GHandler, however:

  • The request body is cleared (otherwise it would be very difficult to prevent huge memory leaks).
  • The cache is cleared (see CacheKey).

Changes to the response made inside the inner GHandler are ignored (e.g., session variables, cookies, response headers). This allows the inner GHandler to outlive the outer GHandler (e.g., on the forkIO example above, a response may be sent to the client without killing the new thread).

forkHandler Source

Arguments

:: (SomeException -> HandlerT site IO ())

error handler

-> HandlerT site IO () 
-> HandlerT site IO () 

forkIO for a Handler (run an action in the background)

Uses handlerToIO, liftResourceT, and resourceForkIO for correctness and efficiency

Since 1.2.8

i18n

getMessageRender :: (MonadHandler m, RenderMessage (HandlerSite m) message) => m (message -> Text) Source

Per-request caching

cached :: (MonadHandler m, Typeable a) => m a -> m a Source

Use a per-request cache to avoid performing the same action multiple times. Values are stored by their type, the result of typeOf from Typeable. Therefore, you should use different newtype wrappers at each cache site.

For example, yesod-auth uses an un-exported newtype, CachedMaybeAuth and exports functions that utilize it such as maybeAuth. This means that another module can create its own newtype wrapper to cache the same type from a different action without any cache conflicts.

See the original announcement: http://www.yesodweb.com/blog/2013/03/yesod-1-2-cleaner-internals

Since 1.2.0

cachedBy :: (MonadHandler m, Typeable a) => ByteString -> m a -> m a Source

a per-request cache. just like cached. cached can only cache a single value per type. cachedBy stores multiple values per type by usage of a ByteString key

cached is ideal to cache an action that has only one value of a type, such as the session's current user cachedBy is required if the action has parameters and can return multiple values per type. You can turn those parameters into a ByteString cache key. For example, caching a lookup of a Link by a token where multiple token lookups might be performed.

Since 1.4.0

stripHandlerT :: HandlerT child (HandlerT parent m) a -> (parent -> child) -> (Route child -> Route parent) -> Maybe (Route child) -> HandlerT parent m a Source

Converts a child handler to a parent handler

Exported since 1.4.11

AJAX CSRF protection

When a user has authenticated with your site, all requests made from the browser to your server will include the session information that you use to verify that the user is logged in. Unfortunately, this allows attackers to make unwanted requests on behalf of the user by e.g. submitting an HTTP request to your site when the user visits theirs. This is known as a Cross Site Request Forgery (CSRF) attack.

To combat this attack, you need a way to verify that the request is valid. This is achieved by generating a random string ("token"), storing it in your encrypted session so that the server can look it up (see reqToken), and adding the token to HTTP requests made to your server. When a request comes in, the token in the request is compared to the one from the encrypted session. If they match, you can be sure the request is valid.

Yesod implements this behavior in two ways:

  1. The yesod-form package stores the CSRF token in a hidden field in the form, then validates it with functions like runFormPost.
  2. Yesod can store the CSRF token in a cookie which is accessible by Javascript. Requests made by Javascript can lookup this cookie and add it as a header to requests. The server then checks the token in the header against the one in the encrypted session.

The form-based approach has the advantage of working for users with Javascript disabled, while adding the token to the headers with Javascript allows things like submitting JSON or binary data in AJAX requests. Yesod supports checking for a CSRF token in either the POST parameters of the form (checkCsrfHeaderNamed), the headers (checkCsrfHeaderNamed), or both options (checkCsrfHeaderOrParam).

The easiest way to check both sources is to add the defaultCsrfMiddleware to your Yesod Middleware.

Setting CSRF Cookies

setCsrfCookie :: MonadHandler m => m () Source

Sets a cookie with a CSRF token, using defaultCsrfCookieName for the cookie name.

Since 1.4.14

setCsrfCookieWithCookie :: MonadHandler m => SetCookie -> m () Source

Takes a SetCookie and overrides its value with a CSRF token, then sets the cookie.

Since 1.4.14

defaultCsrfCookieName :: ByteString Source

The default cookie name for the CSRF token (XSRF-TOKEN).

Since 1.4.14

Looking up CSRF Headers

checkCsrfHeaderNamed :: MonadHandler m => CI ByteString -> m () Source

Takes a header name to lookup a CSRF token. If the value doesn't match the token stored in the session, this function throws a PermissionDenied error.

Since 1.4.14

hasValidCsrfHeaderNamed :: MonadHandler m => CI ByteString -> m Bool Source

Takes a header name to lookup a CSRF token, and returns whether the value matches the token stored in the session.

Since 1.4.14

defaultCsrfHeaderName :: CI ByteString Source

The default header name for the CSRF token (X-XSRF-TOKEN).

Since 1.4.14

Looking up CSRF POST Parameters

hasValidCsrfParamNamed :: MonadHandler m => Text -> m Bool Source

Takes a POST parameter name to lookup a CSRF token, and returns whether the value matches the token stored in the session.

Since 1.4.14

checkCsrfParamNamed :: MonadHandler m => Text -> m () Source

Takes a POST parameter name to lookup a CSRF token. If the value doesn't match the token stored in the session, this function throws a PermissionDenied error.

Since 1.4.14

defaultCsrfParamName :: Text Source

The default parameter name for the CSRF token ("_token")

Since 1.4.14

Checking CSRF Headers or POST Parameters

checkCsrfHeaderOrParam Source

Arguments

:: MonadHandler m 
=> CI ByteString

The header name to lookup the CSRF token

-> Text

The POST parameter name to lookup the CSRF token

-> m () 

Checks that a valid CSRF token is present in either the request headers or POST parameters. If the value doesn't match the token stored in the session, this function throws a PermissionDenied error.

Since 1.4.14