Merge pull request #1417 from psibi/header-yesod

Add replaceOrAddHeader function to Yesod.Core.Handler module
This commit is contained in:
Sibi 2017-07-28 18:35:23 +05:30 committed by GitHub
commit e027652494
5 changed files with 122 additions and 2 deletions

View File

@ -1,3 +1,7 @@
## 1.4.36
* Add `replaceOrAddHeader` function in Yesod.Core.Handler module. [1416](https://github.com/yesodweb/yesod/issues/1416)
## 1.4.35.1 ## 1.4.35.1
* TH fix for GHC 8.2 * TH fix for GHC 8.2

View File

@ -10,6 +10,7 @@
{-# LANGUAGE TypeFamilies #-} {-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE RankNTypes #-} {-# LANGUAGE RankNTypes #-}
{-# LANGUAGE DeriveDataTypeable #-} {-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE ScopedTypeVariables #-}
--------------------------------------------------------- ---------------------------------------------------------
-- --
-- Module : Yesod.Handler -- Module : Yesod.Handler
@ -114,6 +115,7 @@ module Yesod.Core.Handler
, deleteCookie , deleteCookie
, addHeader , addHeader
, setHeader , setHeader
, replaceOrAddHeader
, setLanguage , setLanguage
-- ** Content caching and expiration -- ** Content caching and expiration
, cacheSeconds , cacheSeconds
@ -206,7 +208,7 @@ import Control.Monad.Trans.Class (lift)
import Data.Aeson (ToJSON(..)) import Data.Aeson (ToJSON(..))
import qualified Data.Text as T import qualified Data.Text as T
import Data.Text.Encoding (decodeUtf8With, encodeUtf8) import Data.Text.Encoding (decodeUtf8With, encodeUtf8, decodeUtf8)
import Data.Text.Encoding.Error (lenientDecode) import Data.Text.Encoding.Error (lenientDecode)
import qualified Data.Text.Lazy as TL import qualified Data.Text.Lazy as TL
import Text.Blaze.Html.Renderer.Utf8 (renderHtml) import Text.Blaze.Html.Renderer.Utf8 (renderHtml)
@ -787,6 +789,40 @@ setHeader :: MonadHandler m => Text -> Text -> m ()
setHeader = addHeader setHeader = addHeader
{-# DEPRECATED setHeader "Please use addHeader instead" #-} {-# DEPRECATED setHeader "Please use addHeader instead" #-}
-- | Replace an existing header with a new value or add a new header
-- if not present.
--
-- Note that, while the data type used here is 'Text', you must provide only
-- ASCII value to be HTTP compliant.
--
-- @since 1.4.36
replaceOrAddHeader :: MonadHandler m => Text -> Text -> m ()
replaceOrAddHeader a b =
modify $ \g -> g {ghsHeaders = replaceHeader (ghsHeaders g)}
where
repHeader = Header (encodeUtf8 a) (encodeUtf8 b)
sameHeaderName :: Header -> Header -> Bool
sameHeaderName (Header n1 _) (Header n2 _) = T.toLower (decodeUtf8 n1) == T.toLower (decodeUtf8 n2)
sameHeaderName _ _ = False
replaceIndividualHeader :: [Header] -> [Header]
replaceIndividualHeader [] = [repHeader]
replaceIndividualHeader xs = aux xs []
where
aux [] acc = acc ++ [repHeader]
aux (x:xs') acc =
if sameHeaderName repHeader x
then acc ++
[repHeader] ++
(filter (\header -> not (sameHeaderName header repHeader)) xs')
else aux xs' (acc ++ [x])
replaceHeader :: Endo [Header] -> Endo [Header]
replaceHeader endo =
let allHeaders :: [Header] = appEndo endo []
in Endo (\rest -> replaceIndividualHeader allHeaders ++ rest)
-- | Set the Cache-Control header to indicate this response should be cached -- | Set the Cache-Control header to indicate this response should be cached
-- for the given number of seconds. -- for the given number of seconds.
cacheSeconds :: MonadHandler m => Int -> m () cacheSeconds :: MonadHandler m => Int -> m ()

View File

@ -6,6 +6,7 @@ import YesodCoreTest.Exceptions
import YesodCoreTest.Widget import YesodCoreTest.Widget
import YesodCoreTest.Media import YesodCoreTest.Media
import YesodCoreTest.Links import YesodCoreTest.Links
import YesodCoreTest.Header
import YesodCoreTest.NoOverloadedStrings import YesodCoreTest.NoOverloadedStrings
import YesodCoreTest.InternalRequest import YesodCoreTest.InternalRequest
import YesodCoreTest.ErrorHandling import YesodCoreTest.ErrorHandling
@ -27,6 +28,7 @@ import Test.Hspec
specs :: Spec specs :: Spec
specs = do specs = do
headerTest
cleanPathTest cleanPathTest
exceptionsTest exceptionsTest
widgetTest widgetTest

View File

@ -0,0 +1,77 @@
{-# LANGUAGE OverloadedStrings, TemplateHaskell, QuasiQuotes,
TypeFamilies, MultiParamTypeClasses, ViewPatterns #-}
module YesodCoreTest.Header
( headerTest
, Widget
, resourcesApp
) where
import Data.Text (Text)
import Network.HTTP.Types (decodePathSegments)
import Network.Wai
import Network.Wai.Test
import Test.Hspec
import Yesod.Core
data App =
App
mkYesod
"App"
[parseRoutes|
/header1 Header1R GET
/header2 Header2R GET
/header3 Header3R GET
|]
instance Yesod App
getHeader1R :: Handler RepPlain
getHeader1R = do
addHeader "hello" "world"
return $ RepPlain $ toContent ("header test" :: Text)
getHeader2R :: Handler RepPlain
getHeader2R = do
addHeader "hello" "world"
replaceOrAddHeader "hello" "sibi"
return $ RepPlain $ toContent ("header test" :: Text)
getHeader3R :: Handler RepPlain
getHeader3R = do
addHeader "hello" "world"
addHeader "michael" "snoyman"
addHeader "yesod" "framework"
replaceOrAddHeader "yesod" "book"
return $ RepPlain $ toContent ("header test" :: Text)
runner :: Session () -> IO ()
runner f = toWaiApp App >>= runSession f
addHeaderTest :: IO ()
addHeaderTest =
runner $ do
res <- request defaultRequest {pathInfo = decodePathSegments "/header1"}
assertHeader "hello" "world" res
multipleHeaderTest :: IO ()
multipleHeaderTest =
runner $ do
res <- request defaultRequest {pathInfo = decodePathSegments "/header2"}
assertHeader "hello" "sibi" res
header3Test :: IO ()
header3Test = do
runner $ do
res <- request defaultRequest {pathInfo = decodePathSegments "/header3"}
assertHeader "hello" "world" res
assertHeader "michael" "snoyman" res
assertHeader "yesod" "book" res
headerTest :: Spec
headerTest =
describe "Test.Header" $ do
it "addHeader" addHeaderTest
it "multiple header" multipleHeaderTest
it "persist headers" header3Test

View File

@ -1,5 +1,5 @@
name: yesod-core name: yesod-core
version: 1.4.35.1 version: 1.4.36
license: MIT license: MIT
license-file: LICENSE license-file: LICENSE
author: Michael Snoyman <michael@snoyman.com> author: Michael Snoyman <michael@snoyman.com>
@ -150,6 +150,7 @@ test-suite tests
YesodCoreTest.Auth YesodCoreTest.Auth
YesodCoreTest.Cache YesodCoreTest.Cache
YesodCoreTest.CleanPath YesodCoreTest.CleanPath
YesodCoreTest.Header
YesodCoreTest.Csrf YesodCoreTest.Csrf
YesodCoreTest.ErrorHandling YesodCoreTest.ErrorHandling
YesodCoreTest.Exceptions YesodCoreTest.Exceptions