http-link-header 1.0.0 → 1.0.1
raw patch · 6 files changed
+58/−44 lines, 6 filesdep +bytestringPVP ok
version bump matches the API change (PVP)
Dependencies added: bytestring
API changes (from Hackage documentation)
+ Network.HTTP.Link.Parser: parseLinkHeaderBS :: ByteString -> Maybe [Link]
+ Network.HTTP.Link.Parser: parseLinkHeaderBS' :: ByteString -> Either String [Link]
Files
- http-link-header.cabal +2/−1
- library/Network/HTTP/Link/Parser.hs +32/−19
- library/Network/HTTP/Link/Types.hs +5/−5
- library/Network/HTTP/Link/Writer.hs +5/−5
- test-suite/Network/HTTP/Link/ParserSpec.hs +12/−12
- test-suite/Network/HTTP/Link/WriterSpec.hs +2/−2
http-link-header.cabal view
@@ -1,5 +1,5 @@ name: http-link-header-version: 1.0.0+version: 1.0.1 synopsis: A parser and writer for the HTTP Link header as specified in RFC 5988 "Web Linking". description: https://github.com/myfreeweb/http-link-header category: Web@@ -24,6 +24,7 @@ build-depends: base >= 4.3.0.0 && < 5 , text+ , bytestring , errors , network-uri , attoparsec
library/Network/HTTP/Link/Parser.hs view
@@ -1,4 +1,4 @@-{-# LANGUAGE OverloadedStrings, Safe, CPP #-}+{-# LANGUAGE OverloadedStrings, UnicodeSyntax, Safe, CPP #-} {-# OPTIONS_GHC -fno-warn-unused-do-bind #-} -- | The parser for the HTTP Link header as defined in RFC 5988.@@ -9,12 +9,16 @@ linkHeader , parseLinkHeader' , parseLinkHeader+, parseLinkHeaderBS'+, parseLinkHeaderBS ) where import Prelude hiding (takeWhile, take) import Control.Applicative import Control.Error.Util (hush) import Data.Text hiding (takeWhile, map, take)+import Data.Text.Encoding (decodeUtf8)+import Data.ByteString (ByteString) import Data.Char (isSpace) #if __GLASGOW_HASKELL__ < 709 import Data.Monoid (mconcat)@@ -23,22 +27,22 @@ import Network.URI import Network.HTTP.Link.Types -allConditions :: [a -> Bool] -> a -> Bool+allConditions ∷ [a → Bool] → a → Bool allConditions cs x = and $ map ($ x) cs -charWS :: Char -> Parser ()+charWS ∷ Char → Parser () charWS x = skipSpace >> char x >> skipSpace -quotedString :: Parser Text+quotedString ∷ Parser Text quotedString = do char '"'- v <- many stringPart+ v ← many stringPart char '"' return $ pack $ unEscapeString $ unpack $ mconcat v where stringPart = takeWhile1 (allConditions [(/= '"'), (/= '\\')]) <|> escapedChar escapedChar = char '\\' >> take 1 -paramName :: Text -> LinkParam+paramName ∷ Text → LinkParam paramName "rel" = Rel paramName "anchor" = Anchor paramName "rev" = Rev@@ -49,44 +53,53 @@ paramName "type" = ContentType paramName x = Other x -relType :: Parser Text+relType ∷ Parser Text relType = takeWhile1 $ inClass "-0-9a-z." -paramValue :: LinkParam -> Parser Text+paramValue ∷ LinkParam → Parser Text paramValue Rel = quotedString <|> relType paramValue Rev = quotedString <|> relType paramValue Title' = takeWhile (allConditions [not . isSpace]) paramValue _ = quotedString -param :: Parser (LinkParam, Text)+param ∷ Parser (LinkParam, Text) param = do charWS ';'- n <- takeWhile (allConditions [(/= '='), not . isSpace])+ n ← takeWhile (allConditions [(/= '='), not . isSpace]) let n' = paramName n charWS '='- v <- paramValue n'+ v ← paramValue n' return (n', v) -link :: Parser Link+link ∷ Parser Link link = do charWS '<'- linkText <- takeWhile1 $ allConditions [(/= '>'), not . isSpace]+ linkText ← takeWhile1 $ allConditions [(/= '>'), not . isSpace] charWS '>'- params <- many' $ param+ params ← many' $ param skipSpace case parseURIReference $ unpack linkText of- Just u -> return $ Link u params- Nothing -> fail "Couldn't parse the URI"+ Just u → return $ Link u params+ Nothing → fail "Couldn't parse the URI" -- | The Attoparsec parser for the Link header.-linkHeader :: Parser [Link]+linkHeader ∷ Parser [Link] linkHeader = link `sepBy'` (char ',') -- | Parses a Link header, returns an Either, where Left is the Attoparsec -- error string (probably not a useful one).-parseLinkHeader' :: Text -> Either String [Link]+parseLinkHeader' ∷ Text → Either String [Link] parseLinkHeader' = parseOnly linkHeader -- | Parses a Link header, returns a Maybe.-parseLinkHeader :: Text -> Maybe [Link]+parseLinkHeader ∷ Text → Maybe [Link] parseLinkHeader = hush . parseLinkHeader'++-- | Parses a Link header, returns an Either, where Left is the Attoparsec+-- error string (probably not a useful one).+parseLinkHeaderBS' ∷ ByteString → Either String [Link]+parseLinkHeaderBS' = parseLinkHeader' . decodeUtf8++-- | Parses a Link header, returns a Maybe.+parseLinkHeaderBS ∷ ByteString → Maybe [Link]+parseLinkHeaderBS = parseLinkHeader . decodeUtf8
library/Network/HTTP/Link/Types.hs view
@@ -1,4 +1,4 @@-{-# LANGUAGE Safe #-}+{-# LANGUAGE UnicodeSyntax, Safe #-} -- | The data type definitions for the HTTP Link header. module Network.HTTP.Link.Types where@@ -15,12 +15,12 @@ deriving (Eq, Show) -- | Extracts the URI from the link.-href :: Link -> URI+href ∷ Link → URI href (Link h _) = h -- | Extracts the parameters from the link.-linkParams :: Link -> [(LinkParam, Text)]+linkParams ∷ Link → [(LinkParam, Text)] linkParams (Link _ ps) = ps -lnk :: String -> [(LinkParam, Text)] -> Maybe Link-lnk u r = parseURI u >>= return . \x -> Link x r+lnk ∷ String → [(LinkParam, Text)] → Maybe Link+lnk u r = parseURI u >>= return . \x → Link x r
library/Network/HTTP/Link/Writer.hs view
@@ -1,4 +1,4 @@-{-# LANGUAGE OverloadedStrings, Safe, CPP #-}+{-# LANGUAGE OverloadedStrings, UnicodeSyntax, Safe, CPP #-} module Network.HTTP.Link.Writer ( writeLink@@ -12,7 +12,7 @@ import Network.URI import Network.HTTP.Link.Types -writeParamKey :: LinkParam -> Text+writeParamKey ∷ LinkParam → Text writeParamKey Rel = "rel" writeParamKey Anchor = "anchor" writeParamKey Rev = "rev"@@ -23,13 +23,13 @@ writeParamKey ContentType = "type" writeParamKey (Other t) = t -writeParam :: (LinkParam, Text) -> Text+writeParam ∷ (LinkParam, Text) → Text writeParam (t, v) = mconcat ["; ", writeParamKey t, "=\"", escPar v, "\""] where escPar = pack . escapeURIString (/= '"') . unpack -- maybe URI escaping is not what we should do here? eh, whatever -writeLink :: Link -> Text+writeLink ∷ Link → Text writeLink l = mconcat $ ["<", pack . show $ href l, ">"] ++ map writeParam (linkParams l) -writeLinkHeader :: [Link] -> Text+writeLinkHeader ∷ [Link] → Text writeLinkHeader = intercalate ", " . map writeLink
test-suite/Network/HTTP/Link/ParserSpec.hs view
@@ -1,4 +1,4 @@-{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE OverloadedStrings, UnicodeSyntax #-} module Network.HTTP.Link.ParserSpec where @@ -9,48 +9,48 @@ import Network.HTTP.Link.Types import Network.HTTP.Link.Parser -spec :: Spec+spec ∷ Spec spec = do describe "linkHeader" $ do let l u r = fromJust $ lnk u r it "parses a single link" $ do- ("<http://example.com>; rel=\"example\"" :: Text) ~> linkHeader+ ("<http://example.com>; rel=\"example\"" ∷ Text) ~> linkHeader `shouldParse` [ l "http://example.com" [(Rel, "example")] ] it "parses empty attributes" $ do- ("<http://example.com>; title=\"\"" :: Text) ~> linkHeader+ ("<http://example.com>; title=\"\"" ∷ Text) ~> linkHeader `shouldParse` [ l "http://example.com" [(Title, "")] ] it "parses custom attributes" $ do- ("<http://example.com>; weirdThingy=\"something\"" :: Text) ~> linkHeader+ ("<http://example.com>; weirdThingy=\"something\"" ∷ Text) ~> linkHeader `shouldParse` [ l "http://example.com" [(Other "weirdThingy", "something")] ] it "parses backslash escaped attributes" $ do- ("<http://example.com>; title=\"some \\\" thing \\\"\"" :: Text) ~> linkHeader+ ("<http://example.com>; title=\"some \\\" thing \\\"\"" ∷ Text) ~> linkHeader `shouldParse` [ l "http://example.com" [(Title, "some \" thing \"")] ] it "parses escaped attributes" $ do- ("<http://example.com>; title=\"some %22 thing %22\"" :: Text) ~> linkHeader+ ("<http://example.com>; title=\"some %22 thing %22\"" ∷ Text) ~> linkHeader `shouldParse` [ l "http://example.com" [(Title, "some \" thing \"")] ] it "parses multiple attributes" $ do- ("<http://example.com>; rel=\"example\"; title=\"example dot com\"" :: Text) ~> linkHeader+ ("<http://example.com>; rel=\"example\"; title=\"example dot com\"" ∷ Text) ~> linkHeader `shouldParse` [ l "http://example.com" [(Rel, "example"), (Title, "example dot com")] ] it "parses custom attributes named similarly to standard ones" $ do -- this was caught by QuickCheck! <3- ("<http://example.com>; rel=hello; relAtion=\"something\"; rev=next" :: Text) ~> linkHeader+ ("<http://example.com>; rel=hello; relAtion=\"something\"; rev=next" ∷ Text) ~> linkHeader `shouldParse` [ l "http://example.com" [(Rel, "hello"), (Other "relAtion", "something"), (Rev, "next")] ] it "parses unquoted rel, rev attributes" $ do- ("<http://example.com>; rel=next; rev=prev" :: Text) ~> linkHeader+ ("<http://example.com>; rel=next; rev=prev" ∷ Text) ~> linkHeader `shouldParse` [ l "http://example.com" [(Rel, "next"), (Rev, "prev")] ] it "does not blow up on title*" $ do- ("<http://example.com>; title*=UTF-8'de'n%c3%a4chstes%20Kapitel" :: Text) ~> linkHeader+ ("<http://example.com>; title*=UTF-8'de'n%c3%a4chstes%20Kapitel" ∷ Text) ~> linkHeader `shouldParse` [ l "http://example.com" [(Title', "UTF-8'de'n%c3%a4chstes%20Kapitel")] ] it "parses weird whitespace all over the place" $ do- ("\n\t < http://example.com\t>;rel=\t\"example\"; \ttitle =\"example dot com\" \n " :: Text) ~> linkHeader+ ("\n\t < http://example.com\t>;rel=\t\"example\"; \ttitle =\"example dot com\" \n " ∷ Text) ~> linkHeader `shouldParse` [ l "http://example.com" [(Rel, "example"), (Title, "example dot com")] ]
test-suite/Network/HTTP/Link/WriterSpec.hs view
@@ -1,4 +1,4 @@-{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE OverloadedStrings, UnicodeSyntax #-} module Network.HTTP.Link.WriterSpec where @@ -7,7 +7,7 @@ import Network.HTTP.Link.Types import Network.HTTP.Link.Writer -spec :: Spec+spec ∷ Spec spec = do describe "writeLinkHeader" $ do let l u r = fromJust $ lnk u r