packages feed

waiz-0.0.1.0: src/Network/Wai/Optics/Request.hs

{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE NoImplicitPrelude #-}
{-# OPTIONS_GHC -Wall #-}

-- | Classy optics and field lenses for 'Request'.
module Network.Wai.Optics.Request (
  -- * Classy optics
  GetRequest (..),
  HasRequest (..),
  ReviewRequest (..),
  AsRequest (..),
) where

import Control.Category (id)
import Control.Lens (Getter, Lens', Prism', Review, lens, prism', review, set, to, unto, view)
import Data.Bool (Bool)
import Data.ByteString (ByteString)
import Data.Maybe (Maybe (..))
import Data.Text (Text)
import Data.Vault.Lazy (Vault)
import Network.HTTP.Types (HttpVersion, Method, Query, RequestHeaders)
import Network.Socket (SockAddr)
import Network.Wai (Request)
import qualified Network.Wai as Wai
import Network.Wai.Internal (RequestBodyLength)
import Network.Wai.Optics.Internal (
  httpVersionL,
  isSecureL,
  pathInfoL,
  queryStringL,
  rawPathInfoL,
  rawQueryStringL,
  remoteHostL,
  requestBodyL,
  requestBodyLengthL,
  requestHeaderHostL,
  requestHeaderRangeL,
  requestHeaderRefererL,
  requestHeaderUserAgentL,
  requestHeadersL,
  requestMethodL,
  vaultL,
 )
import Prelude (IO, const, flip, (.))

-- | Type class for values that can be viewed as a 'Request'.
class GetRequest s where
  -- | A 'Getter' to obtain a 'Request'.
  getRequest :: Getter s Request

  -- | A 'Getter' on the HTTP request method.
  getRequestMethod :: Getter s Method
  getRequestMethod = getRequest . to Wai.requestMethod
  {-# INLINE getRequestMethod #-}

  -- | A 'Getter' on the HTTP version.
  getHttpVersion :: Getter s HttpVersion
  getHttpVersion = getRequest . to Wai.httpVersion
  {-# INLINE getHttpVersion #-}

  -- | A 'Getter' on the raw path info.
  getRawPathInfo :: Getter s ByteString
  getRawPathInfo = getRequest . to Wai.rawPathInfo
  {-# INLINE getRawPathInfo #-}

  -- | A 'Getter' on the raw query string.
  getRawQueryString :: Getter s ByteString
  getRawQueryString = getRequest . to Wai.rawQueryString
  {-# INLINE getRawQueryString #-}

  -- | A 'Getter' on the request headers.
  getRequestHeaders :: Getter s RequestHeaders
  getRequestHeaders = getRequest . to Wai.requestHeaders
  {-# INLINE getRequestHeaders #-}

  -- | A 'Getter' on whether the request was made over a secure connection.
  getIsSecure :: Getter s Bool
  getIsSecure = getRequest . to Wai.isSecure
  {-# INLINE getIsSecure #-}

  -- | A 'Getter' on the remote host address.
  getRemoteHost :: Getter s SockAddr
  getRemoteHost = getRequest . to Wai.remoteHost
  {-# INLINE getRemoteHost #-}

  -- | A 'Getter' on the parsed path segments.
  getPathInfo :: Getter s [Text]
  getPathInfo = getRequest . to Wai.pathInfo
  {-# INLINE getPathInfo #-}

  -- | A 'Getter' on the parsed query string.
  getQueryString :: Getter s Query
  getQueryString = getRequest . to Wai.queryString
  {-# INLINE getQueryString #-}

  -- | A 'Getter' on the request body action.
  getRequestBody :: Getter s (IO ByteString)
  getRequestBody = getRequest . to Wai.getRequestBodyChunk
  {-# INLINE getRequestBody #-}

  -- | A 'Getter' on the 'Vault'.
  getVault :: Getter s Vault
  getVault = getRequest . to Wai.vault
  {-# INLINE getVault #-}

  -- | A 'Getter' on the 'RequestBodyLength'.
  getRequestBodyLengthField :: Getter s RequestBodyLength
  getRequestBodyLengthField = getRequest . to Wai.requestBodyLength
  {-# INLINE getRequestBodyLengthField #-}

  -- | A 'Getter' on the @Host@ header.
  getRequestHeaderHost :: Getter s (Maybe ByteString)
  getRequestHeaderHost = getRequest . to Wai.requestHeaderHost
  {-# INLINE getRequestHeaderHost #-}

  -- | A 'Getter' on the @Range@ header.
  getRequestHeaderRange :: Getter s (Maybe ByteString)
  getRequestHeaderRange = getRequest . to Wai.requestHeaderRange
  {-# INLINE getRequestHeaderRange #-}

  -- | A 'Getter' on the @Referer@ header.
  getRequestHeaderReferer :: Getter s (Maybe ByteString)
  getRequestHeaderReferer = getRequest . to Wai.requestHeaderReferer
  {-# INLINE getRequestHeaderReferer #-}

  -- | A 'Getter' on the @User-Agent@ header.
  getRequestHeaderUserAgent :: Getter s (Maybe ByteString)
  getRequestHeaderUserAgent = getRequest . to Wai.requestHeaderUserAgent
  {-# INLINE getRequestHeaderUserAgent #-}

instance GetRequest Request where
  getRequest = id
  {-# INLINE getRequest #-}
  getRequestMethod = to Wai.requestMethod
  {-# INLINE getRequestMethod #-}
  getHttpVersion = to Wai.httpVersion
  {-# INLINE getHttpVersion #-}
  getRawPathInfo = to Wai.rawPathInfo
  {-# INLINE getRawPathInfo #-}
  getRawQueryString = to Wai.rawQueryString
  {-# INLINE getRawQueryString #-}
  getRequestHeaders = to Wai.requestHeaders
  {-# INLINE getRequestHeaders #-}
  getIsSecure = to Wai.isSecure
  {-# INLINE getIsSecure #-}
  getRemoteHost = to Wai.remoteHost
  {-# INLINE getRemoteHost #-}
  getPathInfo = to Wai.pathInfo
  {-# INLINE getPathInfo #-}
  getQueryString = to Wai.queryString
  {-# INLINE getQueryString #-}
  getRequestBody = to Wai.getRequestBodyChunk
  {-# INLINE getRequestBody #-}
  getVault = to Wai.vault
  {-# INLINE getVault #-}
  getRequestBodyLengthField = to Wai.requestBodyLength
  {-# INLINE getRequestBodyLengthField #-}
  getRequestHeaderHost = to Wai.requestHeaderHost
  {-# INLINE getRequestHeaderHost #-}
  getRequestHeaderRange = to Wai.requestHeaderRange
  {-# INLINE getRequestHeaderRange #-}
  getRequestHeaderReferer = to Wai.requestHeaderReferer
  {-# INLINE getRequestHeaderReferer #-}
  getRequestHeaderUserAgent = to Wai.requestHeaderUserAgent
  {-# INLINE getRequestHeaderUserAgent #-}

-- | Type class for values with a lens into a 'Request'.
class (GetRequest s) => HasRequest s where
  {-# MINIMAL setRequest #-}

  -- | Replace the 'Request' component.
  setRequest :: Request -> s -> s

  -- | A 'Lens'' into the 'Request' component.
  request :: Lens' s Request
  request = lens (view getRequest) (flip setRequest)
  {-# INLINE request #-}

  -- | Replace the HTTP request method.
  setRequestMethod :: Method -> s -> s
  setRequestMethod = set requestMethod
  {-# INLINE setRequestMethod #-}

  -- | A 'Lens'' on the HTTP request method.
  requestMethod :: Lens' s Method
  requestMethod = request . requestMethodL
  {-# INLINE requestMethod #-}

  -- | Replace the HTTP version.
  setHttpVersion :: HttpVersion -> s -> s
  setHttpVersion = set httpVersion
  {-# INLINE setHttpVersion #-}

  -- | A 'Lens'' on the HTTP version.
  httpVersion :: Lens' s HttpVersion
  httpVersion = request . httpVersionL
  {-# INLINE httpVersion #-}

  -- | Replace the raw path info.
  setRawPathInfo :: ByteString -> s -> s
  setRawPathInfo = set rawPathInfo
  {-# INLINE setRawPathInfo #-}

  -- | A 'Lens'' on the raw path info.
  rawPathInfo :: Lens' s ByteString
  rawPathInfo = request . rawPathInfoL
  {-# INLINE rawPathInfo #-}

  -- | Replace the raw query string.
  setRawQueryString :: ByteString -> s -> s
  setRawQueryString = set rawQueryString
  {-# INLINE setRawQueryString #-}

  -- | A 'Lens'' on the raw query string.
  rawQueryString :: Lens' s ByteString
  rawQueryString = request . rawQueryStringL
  {-# INLINE rawQueryString #-}

  -- | Replace the request headers.
  setRequestHeaders :: RequestHeaders -> s -> s
  setRequestHeaders = set requestHeaders
  {-# INLINE setRequestHeaders #-}

  -- | A 'Lens'' on the request headers.
  requestHeaders :: Lens' s RequestHeaders
  requestHeaders = request . requestHeadersL
  {-# INLINE requestHeaders #-}

  -- | Replace whether the request was made over a secure connection.
  setIsSecure :: Bool -> s -> s
  setIsSecure = set isSecure
  {-# INLINE setIsSecure #-}

  -- | A 'Lens'' on whether the request was made over a secure connection.
  isSecure :: Lens' s Bool
  isSecure = request . isSecureL
  {-# INLINE isSecure #-}

  -- | Replace the remote host address.
  setRemoteHost :: SockAddr -> s -> s
  setRemoteHost = set remoteHost
  {-# INLINE setRemoteHost #-}

  -- | A 'Lens'' on the remote host address.
  remoteHost :: Lens' s SockAddr
  remoteHost = request . remoteHostL
  {-# INLINE remoteHost #-}

  -- | Replace the parsed path segments.
  setPathInfo :: [Text] -> s -> s
  setPathInfo = set pathInfo
  {-# INLINE setPathInfo #-}

  -- | A 'Lens'' on the parsed path segments.
  pathInfo :: Lens' s [Text]
  pathInfo = request . pathInfoL
  {-# INLINE pathInfo #-}

  -- | Replace the parsed query string.
  setQueryString :: Query -> s -> s
  setQueryString = set queryString
  {-# INLINE setQueryString #-}

  -- | A 'Lens'' on the parsed query string.
  queryString :: Lens' s Query
  queryString = request . queryStringL
  {-# INLINE queryString #-}

  -- | Replace the request body action.
  setRequestBody :: IO ByteString -> s -> s
  setRequestBody = set requestBody
  {-# INLINE setRequestBody #-}

  -- | A 'Lens'' on the request body action.
  requestBody :: Lens' s (IO ByteString)
  requestBody = request . requestBodyL
  {-# INLINE requestBody #-}

  -- | Replace the 'Vault'.
  setVault :: Vault -> s -> s
  setVault = set vault
  {-# INLINE setVault #-}

  -- | A 'Lens'' on the 'Vault'.
  vault :: Lens' s Vault
  vault = request . vaultL
  {-# INLINE vault #-}

  -- | Replace the 'RequestBodyLength'.
  setRequestBodyLengthField :: RequestBodyLength -> s -> s
  setRequestBodyLengthField = set requestBodyLengthField
  {-# INLINE setRequestBodyLengthField #-}

  -- | A 'Lens'' on the 'RequestBodyLength'.
  requestBodyLengthField :: Lens' s RequestBodyLength
  requestBodyLengthField = request . requestBodyLengthL
  {-# INLINE requestBodyLengthField #-}

  -- | Replace the @Host@ header.
  setRequestHeaderHost :: Maybe ByteString -> s -> s
  setRequestHeaderHost = set requestHeaderHost
  {-# INLINE setRequestHeaderHost #-}

  -- | A 'Lens'' on the @Host@ header.
  requestHeaderHost :: Lens' s (Maybe ByteString)
  requestHeaderHost = request . requestHeaderHostL
  {-# INLINE requestHeaderHost #-}

  -- | Replace the @Range@ header.
  setRequestHeaderRange :: Maybe ByteString -> s -> s
  setRequestHeaderRange = set requestHeaderRange
  {-# INLINE setRequestHeaderRange #-}

  -- | A 'Lens'' on the @Range@ header.
  requestHeaderRange :: Lens' s (Maybe ByteString)
  requestHeaderRange = request . requestHeaderRangeL
  {-# INLINE requestHeaderRange #-}

  -- | Replace the @Referer@ header.
  setRequestHeaderReferer :: Maybe ByteString -> s -> s
  setRequestHeaderReferer = set requestHeaderReferer
  {-# INLINE setRequestHeaderReferer #-}

  -- | A 'Lens'' on the @Referer@ header.
  requestHeaderReferer :: Lens' s (Maybe ByteString)
  requestHeaderReferer = request . requestHeaderRefererL
  {-# INLINE requestHeaderReferer #-}

  -- | Replace the @User-Agent@ header.
  setRequestHeaderUserAgent :: Maybe ByteString -> s -> s
  setRequestHeaderUserAgent = set requestHeaderUserAgent
  {-# INLINE setRequestHeaderUserAgent #-}

  -- | A 'Lens'' on the @User-Agent@ header.
  requestHeaderUserAgent :: Lens' s (Maybe ByteString)
  requestHeaderUserAgent = request . requestHeaderUserAgentL
  {-# INLINE requestHeaderUserAgent #-}

instance HasRequest Request where
  setRequest = const
  {-# INLINE setRequest #-}
  requestMethod = requestMethodL
  {-# INLINE requestMethod #-}
  httpVersion = httpVersionL
  {-# INLINE httpVersion #-}
  rawPathInfo = rawPathInfoL
  {-# INLINE rawPathInfo #-}
  rawQueryString = rawQueryStringL
  {-# INLINE rawQueryString #-}
  requestHeaders = requestHeadersL
  {-# INLINE requestHeaders #-}
  isSecure = isSecureL
  {-# INLINE isSecure #-}
  remoteHost = remoteHostL
  {-# INLINE remoteHost #-}
  pathInfo = pathInfoL
  {-# INLINE pathInfo #-}
  queryString = queryStringL
  {-# INLINE queryString #-}
  requestBody = requestBodyL
  {-# INLINE requestBody #-}
  vault = vaultL
  {-# INLINE vault #-}
  requestBodyLengthField = requestBodyLengthL
  {-# INLINE requestBodyLengthField #-}
  requestHeaderHost = requestHeaderHostL
  {-# INLINE requestHeaderHost #-}
  requestHeaderRange = requestHeaderRangeL
  {-# INLINE requestHeaderRange #-}
  requestHeaderReferer = requestHeaderRefererL
  {-# INLINE requestHeaderReferer #-}
  requestHeaderUserAgent = requestHeaderUserAgentL
  {-# INLINE requestHeaderUserAgent #-}

-- | Type class for values that can be constructed from a 'Request'.
class ReviewRequest t where
  -- | A 'Review' to construct a value from a 'Request'.
  reviewRequest :: Review t Request

instance ReviewRequest Request where
  reviewRequest = unto id
  {-# INLINE reviewRequest #-}

-- | Type class for values with a prism into a 'Request'.
class (ReviewRequest t) => AsRequest t where
  {-# MINIMAL matchRequest #-}

  -- | Attempt to extract a 'Request'.
  matchRequest :: t -> Maybe Request

  -- | A 'Prism'' into a 'Request'.
  _Request :: Prism' t Request
  _Request = prism' (review reviewRequest) matchRequest
  {-# INLINE _Request #-}

instance AsRequest Request where
  matchRequest = Just
  {-# INLINE matchRequest #-}