{-# LANGUAGE CPP #-}
{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE OverloadedStrings #-}

-- | Type and constants for handling HTTP header fields.
--
-- At the bottom are also some functions to handle certain header field values.
module Network.HTTP.Types.Header (
    -- * HTTP Headers
    Header,
    HeaderName,
    RequestHeaders,
    ResponseHeaders,

    -- ** Common headers

    -- | The following header constants are provided for convenience,
    -- to prevent accidental spelling errors.
    hAccept,
    hAcceptCharset,
    hAcceptEncoding,
    hAcceptLanguage,
    hAcceptRanges,
    hAge,
    hAllow,
    hAuthorization,
    hCacheControl,
    hConnection,
    hContentDisposition,
    hContentEncoding,
    hContentLanguage,
    hContentLength,
    hContentLocation,
    hContentMD5,
    hContentRange,
    hContentType,
    hCookie,
    hDate,
    hETag,
    hExpect,
    hExpires,
    hFrom,
    hHost,
    hIfMatch,
    hIfModifiedSince,
    hIfNoneMatch,
    hIfRange,
    hIfUnmodifiedSince,
    hLastModified,
    hLocation,
    hMaxForwards,
    hMIMEVersion,
    hOrigin,
    hPragma,
    hPrefer,
    hPreferenceApplied,
    hProxyAuthenticate,
    hProxyAuthorization,
    hRange,
    hReferer,
    hRetryAfter,
    hServer,
    hSetCookie,
    hTE,
    hTrailer,
    hTransferEncoding,
    hUpgrade,
    hUserAgent,
    hVary,
    hVia,
    hWWWAuthenticate,
    hWarning,

    -- ** Byte ranges

    -- | Convenience functions and types to handle values from Range headers.
    --
    -- https://www.rfc-editor.org/rfc/rfc9110.html#name-byte-ranges
    ByteRange (..),
    renderByteRangeBuilder,
    renderByteRange,
    ByteRanges,
    renderByteRangesBuilder,
    renderByteRanges,
    parseByteRanges,
)
where

import qualified Data.ByteString as B
import qualified Data.ByteString.Builder as B
import qualified Data.ByteString.Char8 as B8
import qualified Data.ByteString.Lazy as BL
import qualified Data.CaseInsensitive as CI
import Data.Data (Data)
import Data.List (intersperse)
#if __GLASGOW_HASKELL__ < 710
import Data.Monoid
#endif
import Data.Typeable (Typeable)
import GHC.Generics (Generic)

-- | A full HTTP header field with the name and value separated.
--
-- E.g. @\"Content-Length: 28\"@ parsed into a 'Header' would turn into @("Content-Length", "28")@
type Header = (HeaderName, B.ByteString)

-- | A case-insensitive name of a header field.
--
-- This is the part of the header field before the colon: @HeaderName: some value@
type HeaderName = CI.CI B.ByteString

-- | A list of 'Header's.
--
-- Same type as 'ResponseHeaders', but useful to differentiate in type signatures.
type RequestHeaders = [Header]

-- | A list of 'Header's.
--
-- Same type as 'RequestHeaders', but useful to differentiate in type signatures.
type ResponseHeaders = [Header]

-- | [Accept](https://www.rfc-editor.org/rfc/rfc9110.html#name-accept)
--
-- @since 0.7.0
hAccept :: HeaderName
hAccept :: CI ByteString
hAccept = CI ByteString
"Accept"

-- | [Accept-Charset](https://www.rfc-editor.org/rfc/rfc9110.html#name-accept-charset)
--
-- @since 0.9
hAcceptCharset :: HeaderName
hAcceptCharset :: CI ByteString
hAcceptCharset = CI ByteString
"Accept-Charset"

-- | [Accept-Encoding](https://www.rfc-editor.org/rfc/rfc9110.html#name-accept-encoding)
--
-- @since 0.9
hAcceptEncoding :: HeaderName
hAcceptEncoding :: CI ByteString
hAcceptEncoding = CI ByteString
"Accept-Encoding"

-- | [Accept-Language](https://www.rfc-editor.org/rfc/rfc9110.html#name-accept-language)
--
-- @since 0.7.0
hAcceptLanguage :: HeaderName
hAcceptLanguage :: CI ByteString
hAcceptLanguage = CI ByteString
"Accept-Language"

-- | [Accept-Ranges](https://www.rfc-editor.org/rfc/rfc9110.html#name-accept-ranges)
--
-- @since 0.9
hAcceptRanges :: HeaderName
hAcceptRanges :: CI ByteString
hAcceptRanges = CI ByteString
"Accept-Ranges"

-- | [Age](https://www.rfc-editor.org/rfc/rfc9111.html#name-age)
--
-- @since 0.9
hAge :: HeaderName
hAge :: CI ByteString
hAge = CI ByteString
"Age"

-- | [Allow](https://www.rfc-editor.org/rfc/rfc9110.html#name-allow)
--
-- @since 0.9
hAllow :: HeaderName
hAllow :: CI ByteString
hAllow = CI ByteString
"Allow"

-- | [Authorization](https://www.rfc-editor.org/rfc/rfc9110.html#name-authorization)
--
-- @since 0.7.0
hAuthorization :: HeaderName
hAuthorization :: CI ByteString
hAuthorization = CI ByteString
"Authorization"

-- | [Cache-Control](https://www.rfc-editor.org/rfc/rfc9111.html#name-cache-control)
--
-- @since 0.7.0
hCacheControl :: HeaderName
hCacheControl :: CI ByteString
hCacheControl = CI ByteString
"Cache-Control"

-- | [Connection](https://www.rfc-editor.org/rfc/rfc9110.html#name-connection)
--
-- @since 0.7.0
hConnection :: HeaderName
hConnection :: CI ByteString
hConnection = CI ByteString
"Connection"

-- | [Content-Encoding](https://www.rfc-editor.org/rfc/rfc9110.html#name-content-encoding)
--
-- @since 0.7.0
hContentEncoding :: HeaderName
hContentEncoding :: CI ByteString
hContentEncoding = CI ByteString
"Content-Encoding"

-- | [Content-Language](https://www.rfc-editor.org/rfc/rfc9110.html#name-content-language)
--
-- @since 0.9
hContentLanguage :: HeaderName
hContentLanguage :: CI ByteString
hContentLanguage = CI ByteString
"Content-Language"

-- | [Content-Length](https://www.rfc-editor.org/rfc/rfc9110.html#name-content-length)
--
-- @since 0.7.0
hContentLength :: HeaderName
hContentLength :: CI ByteString
hContentLength = CI ByteString
"Content-Length"

-- | [Content-Location](https://www.rfc-editor.org/rfc/rfc9110.html#name-content-location)
--
-- @since 0.9
hContentLocation :: HeaderName
hContentLocation :: CI ByteString
hContentLocation = CI ByteString
"Content-Location"

-- | [Content-MD5](https://www.rfc-editor.org/rfc/rfc2616.html#section-14.15)
--
-- /This header has been obsoleted in RFC 9110./
--
-- @since 0.7.0
hContentMD5 :: HeaderName
hContentMD5 :: CI ByteString
hContentMD5 = CI ByteString
"Content-MD5"

-- | [Content-Range](https://www.rfc-editor.org/rfc/rfc9110.html#name-content-range)
--
-- @since 0.9
hContentRange :: HeaderName
hContentRange :: CI ByteString
hContentRange = CI ByteString
"Content-Range"

-- | [Content-Type](https://www.rfc-editor.org/rfc/rfc9110.html#name-content-type)
--
-- @since 0.7.0
hContentType :: HeaderName
hContentType :: CI ByteString
hContentType = CI ByteString
"Content-Type"

-- | [Date](https://www.rfc-editor.org/rfc/rfc9110.html#name-date)
--
-- @since 0.7.0
hDate :: HeaderName
hDate :: CI ByteString
hDate = CI ByteString
"Date"

-- | [ETag](https://www.rfc-editor.org/rfc/rfc9110.html#name-etag)
--
-- @since 0.9
hETag :: HeaderName
hETag :: CI ByteString
hETag = CI ByteString
"ETag"

-- | [Expect](https://www.rfc-editor.org/rfc/rfc9110.html#name-expect)
--
-- @since 0.9
hExpect :: HeaderName
hExpect :: CI ByteString
hExpect = CI ByteString
"Expect"

-- | [Expires](https://www.rfc-editor.org/rfc/rfc9111.html#name-expires)
--
-- @since 0.9
hExpires :: HeaderName
hExpires :: CI ByteString
hExpires = CI ByteString
"Expires"

-- | [From](https://www.rfc-editor.org/rfc/rfc9110.html#name-from)
--
-- @since 0.9
hFrom :: HeaderName
hFrom :: CI ByteString
hFrom = CI ByteString
"From"

-- | [Host](https://www.rfc-editor.org/rfc/rfc9110.html#name-host-and-authority)
--
-- @since 0.9
hHost :: HeaderName
hHost :: CI ByteString
hHost = CI ByteString
"Host"

-- | [If-Match](https://www.rfc-editor.org/rfc/rfc9110.html#name-if-match)
--
-- @since 0.9
hIfMatch :: HeaderName
hIfMatch :: CI ByteString
hIfMatch = CI ByteString
"If-Match"

-- | [If-Modified-Since](https://www.rfc-editor.org/rfc/rfc9110.html#name-if-modified-since)
--
-- @since 0.7.0
hIfModifiedSince :: HeaderName
hIfModifiedSince :: CI ByteString
hIfModifiedSince = CI ByteString
"If-Modified-Since"

-- | [If-None-Match](https://www.rfc-editor.org/rfc/rfc9110.html#name-if-none-match)
--
-- @since 0.9
hIfNoneMatch :: HeaderName
hIfNoneMatch :: CI ByteString
hIfNoneMatch = CI ByteString
"If-None-Match"

-- | [If-Range](https://www.rfc-editor.org/rfc/rfc9110.html#name-if-range)
--
-- @since 0.7.0
hIfRange :: HeaderName
hIfRange :: CI ByteString
hIfRange = CI ByteString
"If-Range"

-- | [If-Unmodified-Since](https://www.rfc-editor.org/rfc/rfc9110.html#name-if-unmodified-since)
--
-- @since 0.9
hIfUnmodifiedSince :: HeaderName
hIfUnmodifiedSince :: CI ByteString
hIfUnmodifiedSince = CI ByteString
"If-Unmodified-Since"

-- | [Last-Modified](https://www.rfc-editor.org/rfc/rfc9110.html#name-last-modified)
--
-- @since 0.7.0
hLastModified :: HeaderName
hLastModified :: CI ByteString
hLastModified = CI ByteString
"Last-Modified"

-- | [Location](https://www.rfc-editor.org/rfc/rfc9110.html#name-location)
--
-- @since 0.7.1
hLocation :: HeaderName
hLocation :: CI ByteString
hLocation = CI ByteString
"Location"

-- | [Max-Forwards](https://www.rfc-editor.org/rfc/rfc9110.html#name-max-forwards)
--
-- @since 0.9
hMaxForwards :: HeaderName
hMaxForwards :: CI ByteString
hMaxForwards = CI ByteString
"Max-Forwards"

-- | [Pragma](https://www.rfc-editor.org/rfc/rfc9111.html#name-pragma)
--
-- /This header has been deprecated in RFC 9111 in favor of "Cache-Control"./
--
-- @since 0.9
hPragma :: HeaderName
hPragma :: CI ByteString
hPragma = CI ByteString
"Pragma"

-- | [Proxy-Authenticate](https://www.rfc-editor.org/rfc/rfc9110.html#name-proxy-authenticate)
--
-- @since 0.9
hProxyAuthenticate :: HeaderName
hProxyAuthenticate :: CI ByteString
hProxyAuthenticate = CI ByteString
"Proxy-Authenticate"

-- | [Proxy-Authorization](https://www.rfc-editor.org/rfc/rfc9110.html#name-proxy-authorization)
--
-- @since 0.9
hProxyAuthorization :: HeaderName
hProxyAuthorization :: CI ByteString
hProxyAuthorization = CI ByteString
"Proxy-Authorization"

-- | [Range](https://www.rfc-editor.org/rfc/rfc9110.html#name-range)
--
-- @since 0.7.0
hRange :: HeaderName
hRange :: CI ByteString
hRange = CI ByteString
"Range"

-- | [Referer](https://www.rfc-editor.org/rfc/rfc9110.html#name-referer)
--
-- @since 0.7.0
hReferer :: HeaderName
hReferer :: CI ByteString
hReferer = CI ByteString
"Referer"

-- | [Retry-After](https://www.rfc-editor.org/rfc/rfc9110.html#name-retry-after)
--
-- @since 0.9
hRetryAfter :: HeaderName
hRetryAfter :: CI ByteString
hRetryAfter = CI ByteString
"Retry-After"

-- | [Server](https://www.rfc-editor.org/rfc/rfc9110.html#name-server)
--
-- @since 0.7.1
hServer :: HeaderName
hServer :: CI ByteString
hServer = CI ByteString
"Server"

-- | [TE](https://www.rfc-editor.org/rfc/rfc9110.html#name-te)
--
-- @since 0.9
hTE :: HeaderName
hTE :: CI ByteString
hTE = CI ByteString
"TE"

-- | [Trailer](https://www.rfc-editor.org/rfc/rfc9110.html#name-trailer)
--
-- @since 0.9
hTrailer :: HeaderName
hTrailer :: CI ByteString
hTrailer = CI ByteString
"Trailer"

-- | [Transfer-Encoding](https://www.rfc-editor.org/rfc/rfc9112#name-transfer-encoding)
--
-- @since 0.9
hTransferEncoding :: HeaderName
hTransferEncoding :: CI ByteString
hTransferEncoding = CI ByteString
"Transfer-Encoding"

-- | [Upgrade](https://www.rfc-editor.org/rfc/rfc9110.html#name-upgrade)
--
-- @since 0.9
hUpgrade :: HeaderName
hUpgrade :: CI ByteString
hUpgrade = CI ByteString
"Upgrade"

-- | [User-Agent](https://www.rfc-editor.org/rfc/rfc9110.html#name-user-agent)
--
-- @since 0.7.0
hUserAgent :: HeaderName
hUserAgent :: CI ByteString
hUserAgent = CI ByteString
"User-Agent"

-- | [Vary](https://www.rfc-editor.org/rfc/rfc9110.html#name-vary)
--
-- @since 0.9
hVary :: HeaderName
hVary :: CI ByteString
hVary = CI ByteString
"Vary"

-- | [Via](https://www.rfc-editor.org/rfc/rfc9110.html#name-via)
--
-- @since 0.9
hVia :: HeaderName
hVia :: CI ByteString
hVia = CI ByteString
"Via"

-- | [WWW-Authenticate](https://www.rfc-editor.org/rfc/rfc9110.html#name-www-authenticate)
--
-- @since 0.9
hWWWAuthenticate :: HeaderName
hWWWAuthenticate :: CI ByteString
hWWWAuthenticate = CI ByteString
"WWW-Authenticate"

-- | [Warning](https://www.rfc-editor.org/rfc/rfc9111.html#name-warning)
--
-- /This header has been obsoleted in RFC 9110./
--
-- @since 0.9
hWarning :: HeaderName
hWarning :: CI ByteString
hWarning = CI ByteString
"Warning"

-- | [Content-Disposition](https://www.rfc-editor.org/rfc/rfc6266.html)
--
-- @since 0.10
hContentDisposition :: HeaderName
hContentDisposition :: CI ByteString
hContentDisposition = CI ByteString
"Content-Disposition"

-- | [MIME-Version](https://www.rfc-editor.org/rfc/rfc2616.html#section-19.4.1)
--
-- @since 0.10
hMIMEVersion :: HeaderName
hMIMEVersion :: CI ByteString
hMIMEVersion = CI ByteString
"MIME-Version"

-- | [Cookie](https://www.rfc-editor.org/rfc/rfc6265.html#section-4.2)
--
-- @since 0.7.0
hCookie :: HeaderName
hCookie :: CI ByteString
hCookie = CI ByteString
"Cookie"

-- | [Set-Cookie](https://www.rfc-editor.org/rfc/rfc6265.html#section-4.1)
--
-- @since 0.10
hSetCookie :: HeaderName
hSetCookie :: CI ByteString
hSetCookie = CI ByteString
"Set-Cookie"

-- | [Origin](https://www.rfc-editor.org/rfc/rfc6454.html#section-7)
--
-- @since 0.10
hOrigin :: HeaderName
hOrigin :: CI ByteString
hOrigin = CI ByteString
"Origin"

-- | [Prefer](https://www.rfc-editor.org/rfc/rfc7240.html#section-2)
--
-- @since 0.12.2
hPrefer :: HeaderName
hPrefer :: CI ByteString
hPrefer = CI ByteString
"Prefer"

-- | [Preference-Applied](https://www.rfc-editor.org/rfc/rfc7240.html#section-3)
--
-- @since 0.12.2
hPreferenceApplied :: HeaderName
hPreferenceApplied :: CI ByteString
hPreferenceApplied = CI ByteString
"Preference-Applied"

-- | An individual byte range.
--
-- Negative indices are not allowed!
--
-- @since 0.6.11
data ByteRange
    = ByteRangeFrom !Integer
    | ByteRangeFromTo !Integer !Integer
    | ByteRangeSuffix !Integer
    deriving
        ( -- | @since 0.8.4
          Int -> ByteRange -> ShowS
[ByteRange] -> ShowS
ByteRange -> String
(Int -> ByteRange -> ShowS)
-> (ByteRange -> String)
-> ([ByteRange] -> ShowS)
-> Show ByteRange
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> ByteRange -> ShowS
showsPrec :: Int -> ByteRange -> ShowS
$cshow :: ByteRange -> String
show :: ByteRange -> String
$cshowList :: [ByteRange] -> ShowS
showList :: [ByteRange] -> ShowS
Show
        , -- | @since 0.8.4
          ByteRange -> ByteRange -> Bool
(ByteRange -> ByteRange -> Bool)
-> (ByteRange -> ByteRange -> Bool) -> Eq ByteRange
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: ByteRange -> ByteRange -> Bool
== :: ByteRange -> ByteRange -> Bool
$c/= :: ByteRange -> ByteRange -> Bool
/= :: ByteRange -> ByteRange -> Bool
Eq
        , -- | @since 0.8.4
          Eq ByteRange
Eq ByteRange =>
(ByteRange -> ByteRange -> Ordering)
-> (ByteRange -> ByteRange -> Bool)
-> (ByteRange -> ByteRange -> Bool)
-> (ByteRange -> ByteRange -> Bool)
-> (ByteRange -> ByteRange -> Bool)
-> (ByteRange -> ByteRange -> ByteRange)
-> (ByteRange -> ByteRange -> ByteRange)
-> Ord ByteRange
ByteRange -> ByteRange -> Bool
ByteRange -> ByteRange -> Ordering
ByteRange -> ByteRange -> ByteRange
forall a.
Eq a =>
(a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
$ccompare :: ByteRange -> ByteRange -> Ordering
compare :: ByteRange -> ByteRange -> Ordering
$c< :: ByteRange -> ByteRange -> Bool
< :: ByteRange -> ByteRange -> Bool
$c<= :: ByteRange -> ByteRange -> Bool
<= :: ByteRange -> ByteRange -> Bool
$c> :: ByteRange -> ByteRange -> Bool
> :: ByteRange -> ByteRange -> Bool
$c>= :: ByteRange -> ByteRange -> Bool
>= :: ByteRange -> ByteRange -> Bool
$cmax :: ByteRange -> ByteRange -> ByteRange
max :: ByteRange -> ByteRange -> ByteRange
$cmin :: ByteRange -> ByteRange -> ByteRange
min :: ByteRange -> ByteRange -> ByteRange
Ord
        , -- | @since 0.8.4
          Typeable
        , -- | @since 0.8.4
          Typeable ByteRange
Typeable ByteRange =>
(forall (c :: * -> *).
 (forall d b. Data d => c (d -> b) -> d -> c b)
 -> (forall g. g -> c g) -> ByteRange -> c ByteRange)
-> (forall (c :: * -> *).
    (forall b r. Data b => c (b -> r) -> c r)
    -> (forall r. r -> c r) -> Constr -> c ByteRange)
-> (ByteRange -> Constr)
-> (ByteRange -> DataType)
-> (forall (t :: * -> *) (c :: * -> *).
    Typeable t =>
    (forall d. Data d => c (t d)) -> Maybe (c ByteRange))
-> (forall (t :: * -> * -> *) (c :: * -> *).
    Typeable t =>
    (forall d e. (Data d, Data e) => c (t d e)) -> Maybe (c ByteRange))
-> ((forall b. Data b => b -> b) -> ByteRange -> ByteRange)
-> (forall r r'.
    (r -> r' -> r)
    -> r -> (forall d. Data d => d -> r') -> ByteRange -> r)
-> (forall r r'.
    (r' -> r -> r)
    -> r -> (forall d. Data d => d -> r') -> ByteRange -> r)
-> (forall u. (forall d. Data d => d -> u) -> ByteRange -> [u])
-> (forall u.
    Int -> (forall d. Data d => d -> u) -> ByteRange -> u)
-> (forall (m :: * -> *).
    Monad m =>
    (forall d. Data d => d -> m d) -> ByteRange -> m ByteRange)
-> (forall (m :: * -> *).
    MonadPlus m =>
    (forall d. Data d => d -> m d) -> ByteRange -> m ByteRange)
-> (forall (m :: * -> *).
    MonadPlus m =>
    (forall d. Data d => d -> m d) -> ByteRange -> m ByteRange)
-> Data ByteRange
ByteRange -> Constr
ByteRange -> DataType
(forall b. Data b => b -> b) -> ByteRange -> ByteRange
forall a.
Typeable a =>
(forall (c :: * -> *).
 (forall d b. Data d => c (d -> b) -> d -> c b)
 -> (forall g. g -> c g) -> a -> c a)
-> (forall (c :: * -> *).
    (forall b r. Data b => c (b -> r) -> c r)
    -> (forall r. r -> c r) -> Constr -> c a)
-> (a -> Constr)
-> (a -> DataType)
-> (forall (t :: * -> *) (c :: * -> *).
    Typeable t =>
    (forall d. Data d => c (t d)) -> Maybe (c a))
-> (forall (t :: * -> * -> *) (c :: * -> *).
    Typeable t =>
    (forall d e. (Data d, Data e) => c (t d e)) -> Maybe (c a))
-> ((forall b. Data b => b -> b) -> a -> a)
-> (forall r r'.
    (r -> r' -> r) -> r -> (forall d. Data d => d -> r') -> a -> r)
-> (forall r r'.
    (r' -> r -> r) -> r -> (forall d. Data d => d -> r') -> a -> r)
-> (forall u. (forall d. Data d => d -> u) -> a -> [u])
-> (forall u. Int -> (forall d. Data d => d -> u) -> a -> u)
-> (forall (m :: * -> *).
    Monad m =>
    (forall d. Data d => d -> m d) -> a -> m a)
-> (forall (m :: * -> *).
    MonadPlus m =>
    (forall d. Data d => d -> m d) -> a -> m a)
-> (forall (m :: * -> *).
    MonadPlus m =>
    (forall d. Data d => d -> m d) -> a -> m a)
-> Data a
forall u. Int -> (forall d. Data d => d -> u) -> ByteRange -> u
forall u. (forall d. Data d => d -> u) -> ByteRange -> [u]
forall r r'.
(r -> r' -> r)
-> r -> (forall d. Data d => d -> r') -> ByteRange -> r
forall r r'.
(r' -> r -> r)
-> r -> (forall d. Data d => d -> r') -> ByteRange -> r
forall (m :: * -> *).
Monad m =>
(forall d. Data d => d -> m d) -> ByteRange -> m ByteRange
forall (m :: * -> *).
MonadPlus m =>
(forall d. Data d => d -> m d) -> ByteRange -> m ByteRange
forall (c :: * -> *).
(forall b r. Data b => c (b -> r) -> c r)
-> (forall r. r -> c r) -> Constr -> c ByteRange
forall (c :: * -> *).
(forall d b. Data d => c (d -> b) -> d -> c b)
-> (forall g. g -> c g) -> ByteRange -> c ByteRange
forall (t :: * -> *) (c :: * -> *).
Typeable t =>
(forall d. Data d => c (t d)) -> Maybe (c ByteRange)
forall (t :: * -> * -> *) (c :: * -> *).
Typeable t =>
(forall d e. (Data d, Data e) => c (t d e)) -> Maybe (c ByteRange)
$cgfoldl :: forall (c :: * -> *).
(forall d b. Data d => c (d -> b) -> d -> c b)
-> (forall g. g -> c g) -> ByteRange -> c ByteRange
gfoldl :: forall (c :: * -> *).
(forall d b. Data d => c (d -> b) -> d -> c b)
-> (forall g. g -> c g) -> ByteRange -> c ByteRange
$cgunfold :: forall (c :: * -> *).
(forall b r. Data b => c (b -> r) -> c r)
-> (forall r. r -> c r) -> Constr -> c ByteRange
gunfold :: forall (c :: * -> *).
(forall b r. Data b => c (b -> r) -> c r)
-> (forall r. r -> c r) -> Constr -> c ByteRange
$ctoConstr :: ByteRange -> Constr
toConstr :: ByteRange -> Constr
$cdataTypeOf :: ByteRange -> DataType
dataTypeOf :: ByteRange -> DataType
$cdataCast1 :: forall (t :: * -> *) (c :: * -> *).
Typeable t =>
(forall d. Data d => c (t d)) -> Maybe (c ByteRange)
dataCast1 :: forall (t :: * -> *) (c :: * -> *).
Typeable t =>
(forall d. Data d => c (t d)) -> Maybe (c ByteRange)
$cdataCast2 :: forall (t :: * -> * -> *) (c :: * -> *).
Typeable t =>
(forall d e. (Data d, Data e) => c (t d e)) -> Maybe (c ByteRange)
dataCast2 :: forall (t :: * -> * -> *) (c :: * -> *).
Typeable t =>
(forall d e. (Data d, Data e) => c (t d e)) -> Maybe (c ByteRange)
$cgmapT :: (forall b. Data b => b -> b) -> ByteRange -> ByteRange
gmapT :: (forall b. Data b => b -> b) -> ByteRange -> ByteRange
$cgmapQl :: forall r r'.
(r -> r' -> r)
-> r -> (forall d. Data d => d -> r') -> ByteRange -> r
gmapQl :: forall r r'.
(r -> r' -> r)
-> r -> (forall d. Data d => d -> r') -> ByteRange -> r
$cgmapQr :: forall r r'.
(r' -> r -> r)
-> r -> (forall d. Data d => d -> r') -> ByteRange -> r
gmapQr :: forall r r'.
(r' -> r -> r)
-> r -> (forall d. Data d => d -> r') -> ByteRange -> r
$cgmapQ :: forall u. (forall d. Data d => d -> u) -> ByteRange -> [u]
gmapQ :: forall u. (forall d. Data d => d -> u) -> ByteRange -> [u]
$cgmapQi :: forall u. Int -> (forall d. Data d => d -> u) -> ByteRange -> u
gmapQi :: forall u. Int -> (forall d. Data d => d -> u) -> ByteRange -> u
$cgmapM :: forall (m :: * -> *).
Monad m =>
(forall d. Data d => d -> m d) -> ByteRange -> m ByteRange
gmapM :: forall (m :: * -> *).
Monad m =>
(forall d. Data d => d -> m d) -> ByteRange -> m ByteRange
$cgmapMp :: forall (m :: * -> *).
MonadPlus m =>
(forall d. Data d => d -> m d) -> ByteRange -> m ByteRange
gmapMp :: forall (m :: * -> *).
MonadPlus m =>
(forall d. Data d => d -> m d) -> ByteRange -> m ByteRange
$cgmapMo :: forall (m :: * -> *).
MonadPlus m =>
(forall d. Data d => d -> m d) -> ByteRange -> m ByteRange
gmapMo :: forall (m :: * -> *).
MonadPlus m =>
(forall d. Data d => d -> m d) -> ByteRange -> m ByteRange
Data
        , -- | @since 0.12.4
          (forall x. ByteRange -> Rep ByteRange x)
-> (forall x. Rep ByteRange x -> ByteRange) -> Generic ByteRange
forall x. Rep ByteRange x -> ByteRange
forall x. ByteRange -> Rep ByteRange x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cfrom :: forall x. ByteRange -> Rep ByteRange x
from :: forall x. ByteRange -> Rep ByteRange x
$cto :: forall x. Rep ByteRange x -> ByteRange
to :: forall x. Rep ByteRange x -> ByteRange
Generic
        )

-- | Turns a byte range into a byte string 'B.Builder'.
--
-- @since 0.6.11
renderByteRangeBuilder :: ByteRange -> B.Builder
renderByteRangeBuilder :: ByteRange -> Builder
renderByteRangeBuilder (ByteRangeFrom Integer
from) = Integer -> Builder
B.integerDec Integer
from Builder -> Builder -> Builder
forall a. Monoid a => a -> a -> a
`mappend` Char -> Builder
B.char7 Char
'-'
renderByteRangeBuilder (ByteRangeFromTo Integer
from Integer
to) = Integer -> Builder
B.integerDec Integer
from Builder -> Builder -> Builder
forall a. Monoid a => a -> a -> a
`mappend` Char -> Builder
B.char7 Char
'-' Builder -> Builder -> Builder
forall a. Monoid a => a -> a -> a
`mappend` Integer -> Builder
B.integerDec Integer
to
renderByteRangeBuilder (ByteRangeSuffix Integer
suffix) = Char -> Builder
B.char7 Char
'-' Builder -> Builder -> Builder
forall a. Monoid a => a -> a -> a
`mappend` Integer -> Builder
B.integerDec Integer
suffix

-- | Renders a byte range into a 'B.ByteString'.
--
-- >>> renderByteRange (ByteRangeFrom 2048)
-- "2048-"
--
-- @since 0.6.11
renderByteRange :: ByteRange -> B.ByteString
renderByteRange :: ByteRange -> ByteString
renderByteRange = LazyByteString -> ByteString
BL.toStrict (LazyByteString -> ByteString)
-> (ByteRange -> LazyByteString) -> ByteRange -> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Builder -> LazyByteString
B.toLazyByteString (Builder -> LazyByteString)
-> (ByteRange -> Builder) -> ByteRange -> LazyByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteRange -> Builder
renderByteRangeBuilder

-- | A list of byte ranges.
--
-- @since 0.6.11
type ByteRanges = [ByteRange]

-- | Turns a list of byte ranges into a byte string 'B.Builder'.
--
-- @since 0.6.11
renderByteRangesBuilder :: ByteRanges -> B.Builder
renderByteRangesBuilder :: [ByteRange] -> Builder
renderByteRangesBuilder [ByteRange]
xs =
    ByteString -> Builder
B.byteString ByteString
"bytes="
        Builder -> Builder -> Builder
forall a. Monoid a => a -> a -> a
`mappend` [Builder] -> Builder
forall a. Monoid a => [a] -> a
mconcat (Builder -> [Builder] -> [Builder]
forall a. a -> [a] -> [a]
intersperse (Char -> Builder
B.char7 Char
',') ([Builder] -> [Builder]) -> [Builder] -> [Builder]
forall a b. (a -> b) -> a -> b
$ (ByteRange -> Builder) -> [ByteRange] -> [Builder]
forall a b. (a -> b) -> [a] -> [b]
map ByteRange -> Builder
renderByteRangeBuilder [ByteRange]
xs)

-- | Renders a list of byte ranges into a 'B.ByteString'.
--
-- >>> renderByteRanges [ByteRangeFrom 2048, ByteRangeSuffix 20]
-- "bytes=2048-,-20"
--
-- @since 0.6.11
renderByteRanges :: ByteRanges -> B.ByteString
renderByteRanges :: [ByteRange] -> ByteString
renderByteRanges = LazyByteString -> ByteString
BL.toStrict (LazyByteString -> ByteString)
-> ([ByteRange] -> LazyByteString) -> [ByteRange] -> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Builder -> LazyByteString
B.toLazyByteString (Builder -> LazyByteString)
-> ([ByteRange] -> Builder) -> [ByteRange] -> LazyByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [ByteRange] -> Builder
renderByteRangesBuilder

-- | Parse the value of a Range header into a 'ByteRanges'.
--
-- >>> parseByteRanges "error"
-- Nothing
-- >>> parseByteRanges "bytes=0-499"
-- Just [ByteRangeFromTo 0 499]
-- >>> parseByteRanges "bytes=500-999"
-- Just [ByteRangeFromTo 500 999]
-- >>> parseByteRanges "bytes=-500"
-- Just [ByteRangeSuffix 500]
-- >>> parseByteRanges "bytes=9500-"
-- Just [ByteRangeFrom 9500]
-- >>> parseByteRanges "bytes=0-0,-1"
-- Just [ByteRangeFromTo 0 0,ByteRangeSuffix 1]
-- >>> parseByteRanges "bytes=500-600,601-999"
-- Just [ByteRangeFromTo 500 600,ByteRangeFromTo 601 999]
-- >>> parseByteRanges "bytes=500-700,601-999"
-- Just [ByteRangeFromTo 500 700,ByteRangeFromTo 601 999]
--
-- @since 0.9.1
parseByteRanges :: B.ByteString -> Maybe ByteRanges
parseByteRanges :: ByteString -> Maybe [ByteRange]
parseByteRanges ByteString
bs1 = do
    bs2 <- ByteString -> ByteString -> Maybe ByteString
stripPrefixB ByteString
"bytes=" ByteString
bs1
    (r, bs3) <- range bs2
    ranges (r :) bs3
  where
    range :: ByteString -> Maybe (ByteRange, ByteString)
range ByteString
bs2 = do
        (i, bs3) <- ByteString -> Maybe (Integer, ByteString)
B8.readInteger ByteString
bs2
        if i < 0 -- has prefix "-" ("-0" is not valid, but here treated as "0-")
            then Just (ByteRangeSuffix (negate i), bs3)
            else do
                bs4 <- stripPrefixB "-" bs3
                case B8.readInteger bs4 of
                    Just (Integer
j, ByteString
bs5) | Integer
j Integer -> Integer -> Bool
forall a. Ord a => a -> a -> Bool
>= Integer
i -> (ByteRange, ByteString) -> Maybe (ByteRange, ByteString)
forall a. a -> Maybe a
Just (Integer -> Integer -> ByteRange
ByteRangeFromTo Integer
i Integer
j, ByteString
bs5)
                    Maybe (Integer, ByteString)
_ -> (ByteRange, ByteString) -> Maybe (ByteRange, ByteString)
forall a. a -> Maybe a
Just (Integer -> ByteRange
ByteRangeFrom Integer
i, ByteString
bs4)
    ranges :: ([ByteRange] -> t) -> ByteString -> Maybe t
ranges [ByteRange] -> t
front ByteString
bs3
        | ByteString -> Bool
B.null ByteString
bs3 = t -> Maybe t
forall a. a -> Maybe a
Just ([ByteRange] -> t
front [])
        | Bool
otherwise = do
            bs4 <- ByteString -> ByteString -> Maybe ByteString
stripPrefixB ByteString
"," ByteString
bs3
            (r, bs5) <- range bs4
            ranges (front . (r :)) bs5

    -- FIXME: Use 'stripPrefix' from the 'bytestring' package.
    -- Might have to update the dependency constraints though.
    stripPrefixB :: ByteString -> ByteString -> Maybe ByteString
stripPrefixB ByteString
x ByteString
y
        | ByteString
x ByteString -> ByteString -> Bool
`B.isPrefixOf` ByteString
y = ByteString -> Maybe ByteString
forall a. a -> Maybe a
Just (Int -> ByteString -> ByteString
B.drop (ByteString -> Int
B.length ByteString
x) ByteString
y)
        | Bool
otherwise = Maybe ByteString
forall a. Maybe a
Nothing