web-cookiejar 0.1.0.0 → 0.1.1.0
raw patch · 4 files changed
+94/−6 lines, 4 filesdep +directorydep ~QuickCheck
Dependencies added: directory
Dependency ranges changed: QuickCheck
Files
- ChangeLog.md +6/−0
- src/Web/Cookie/Jar.hs +82/−3
- test/Cookie/JarSpec.hs +3/−1
- web-cookiejar.cabal +3/−2
ChangeLog.md view
@@ -2,6 +2,12 @@ `web-cookiejar` uses [PVP Versioning][1]. +## 0.1.1.0 -- 2025-06-23++* Relax the upper bound of the QuickCheck test dependency+* Add combinators that simplify common usage with http-client++ ## 0.1.0.0 -- 2025-04-07 * Initial version.
src/Web/Cookie/Jar.hs view
@@ -11,12 +11,19 @@ in the Netscape/Mozilla cookie jar; see `cookieBuilder`. -} module Web.Cookie.Jar- ( -- * read/write Cookie Jar files+ ( -- * read and write files writeJar , writeJar' , writeNetscapeJar , readJar+ , readJarX+ , BadJarFile + -- * update HTTP messages+ , addCookiesFromFile+ , saveCookies+ , usingCookiesFromFile+ -- * Cookie jar format -- ** parsing@@ -36,6 +43,7 @@ where import Control.Applicative ((<|>))+import Control.Exception (Exception, throwIO) import Control.Monad (void) import Data.Attoparsec.ByteString.Char8 ( Parser@@ -51,7 +59,7 @@ , try ) import Data.ByteString (ByteString)-import qualified Data.ByteString as B+import qualified Data.ByteString as BS import Data.ByteString.Builder ( Builder , byteString@@ -61,6 +69,7 @@ ) import qualified Data.ByteString.Lazy as L import Data.Char (ord)+import Data.Time (getCurrentTime) import Data.Time.Clock.POSIX ( posixSecondsToUTCTime , utcTimeToPOSIXSeconds@@ -68,11 +77,74 @@ import Network.HTTP.Client ( Cookie (..) , CookieJar+ , Request+ , Response , createCookieJar , destroyCookieJar+ , insertCookiesIntoRequest+ , updateCookieJar )+import System.Directory (doesFileExist) +-- | Perform a HTTP request first loading then saving any matching cookies from a cookie file+usingCookiesFromFile :: FilePath -> Request -> (Request -> IO (Response b)) -> IO (Response b)+usingCookiesFromFile jarPath req doReq = do+ req' <- addCookiesFromFile jarPath req+ resp <- doReq req'+ saveCookies jarPath resp req'+++{- | Add any appropriate Cookies from a cookie file to a @Request@++ - if the file is absent, no update occurs+ - throws @BadJarFile@ if the file can't be parsed+-}+addCookiesFromFile+ :: FilePath+ -- ^ path to the cookie file+ -> Request+ -> IO Request+addCookiesFromFile dataPath req = do+ pathExists <- doesFileExist dataPath+ if not pathExists+ then pure req+ else do+ now <- getCurrentTime+ readJarX dataPath >>= \jar -> do+ let (req', _jar') = insertCookiesIntoRequest req jar now+ pure req'+++{- | Update the cookie file with any cookies in the response++When the file does not exist, it's created as long as the parent directory+exists and permits the file to be written++The output is saved to the cookie file using 'writeJar'++throws an exception if:+ - cannot write due to permissions or parent directory not existing+ - the file exists, but cannot be parsed into Cookies+-}+saveCookies :: FilePath -> Response a -> Request -> IO (Response a)+saveCookies dataPath resp req = do+ pathExists <- doesFileExist dataPath+ old <- if pathExists then readJarX dataPath else pure (createCookieJar [])+ now <- getCurrentTime+ let (updated, resp_) = updateCookieJar resp req now old+ writeJar dataPath updated+ pure resp_+++-- | Reasons a jar file could not be loaded+data BadJarFile = InvalidJar+ deriving (Eq, Show)+++instance Exception BadJarFile++ -- | Parse a @ByteString@ containing a cookie jar in the Netscape/Mozilla format parseCookieJar :: ByteString -> Either String CookieJar parseCookieJar = parseOnly cookieJarParser@@ -185,7 +257,14 @@ -- | Read a Cookie Jar from a file. readJar :: FilePath -> IO (Either String CookieJar)-readJar = fmap parseCookieJar . B.readFile+readJar = fmap parseCookieJar . BS.readFile+++-- | Like 'readJar', but throws @BadJarFile@ in @IO@ if the read fails+readJarX :: FilePath -> IO CookieJar+readJarX p =+ let handleErr = either (const $ throwIO InvalidJar) pure+ in readJar p >>= handleErr {- | Builder for one cookie; generates a single line in the Cookie Jar file format
test/Cookie/JarSpec.hs view
@@ -91,7 +91,9 @@ cookieJarWithX- :: (CookieJar -> Builder) -> CookieJar -> (CookieJar, ByteString, Either String CookieJar)+ :: (CookieJar -> Builder)+ -> CookieJar+ -> (CookieJar, ByteString, Either String CookieJar) cookieJarWithX toBuilder j = let txt = asByteString $ toBuilder j in (j, txt, parseCookieJar txt)
web-cookiejar.cabal view
@@ -1,6 +1,6 @@ cabal-version: 3.0 name: web-cookiejar-version: 0.1.0.0+version: 0.1.1.0 synopsis: Parsing/printing of persistent web cookies description: A library that provides parsing and printing functions that read and write web@@ -34,6 +34,7 @@ , attoparsec >=0.14.4 && <0.15 , base >=4.10 && <5 , bytestring >=0.10.8 && <0.11 || >=0.11.3 && <0.13+ , directory >=1.3 && <1.4 , http-client >=0.5 && <0.8 , time >=1.8 && <1.15 @@ -52,7 +53,7 @@ , bytestring , hspec >=2.7.0 && <2.12.0 , http-client- , QuickCheck >= 2.13 && < 2.16+ , QuickCheck >= 2.13 && < 2.18 , temporary >= 1.2 && < 1.4 , time , web-cookiejar