packages feed

restman-0.7.4.0: src/HTTP/Client.hs

{-# language OverloadedStrings #-}
{-|
Module: HTTP.Client

Thin wrapper around wreq and http-client to provide a robust HTTP(S) connection manager
and re-export the subset of wreq and http-types symbols used throughout RESTman.

The key entry point is 'robustSettings', which configures an 'HC.ManagerSettings' with
a 30-second response timeout to prevent hangs on slow proxies or captive portals.

Note: The underlying http-client library has a hardcoded 8 KB limit per header line that
cannot be configured in this version. Some sites (e.g. slashdot.org with its extensive
@Content-Security-Policy@ header listing hundreds of domains) may exceed this limit and
will fail with an @OverlongHeaders@ exception. This is a known limitation of the
http-client library version in use.
-}
module HTTP.Client
    ( -- * HTTP.Client helpers
      UseDefaultHeaders(..)
    , knownMethods
    , Method
    , robustSettings
      -- * wreq re-exports
    , customMethodWith
    , customPayloadMethodWith
    , defaults
    , headers
    , responseBody
    , responseHeader
      -- * http-types re-exports
    , Header
    ) where

-- http-client
import qualified Network.HTTP.Client as HC
-- http-client-tls
import qualified Network.HTTP.Client.TLS as HCT
-- http-types
import Network.HTTP.Types.Header (Header)
-- wreq
import Network.Wreq
  ( customMethodWith
  , customPayloadMethodWith
  , defaults
  , headers
  , responseBody
  , responseHeader
  )

-- | Helper type for clarity of intention.
type Method = String

-- | Bool-ish (for now) with more descriptive names.
data UseDefaultHeaders
  = ReplaceDefaultHeaders          -- ^ Discard wreq's default headers; use only custom headers.
  | AppendCustomToDefaultHeaders   -- ^ Keep wreq's default headers and append custom headers.
  deriving (Eq, Ord, Enum, Bounded, Show, Read)

{-|
TLS-enabled 'HC.ManagerSettings' with a 30-second response timeout.

Use this when creating an 'HC.Manager' for RESTman so that requests do not
hang indefinitely on unresponsive proxies or captive portals.

> manager <- HC.newManager robustSettings
-}
robustSettings :: HC.ManagerSettings
robustSettings = HCT.tlsManagerSettings
        { HC.managerResponseTimeout = HC.responseTimeoutMicro 30000000  -- 30 seconds
        -- Note: managerRawConnection can be used to customize the connection,
        -- but header size limits are hardcoded in the http-client parser.
        -- The default limit is 8KB per header line. Sites like slashdot.org
        -- may exceed this with long cookie headers.
        }

{-|
Lifted from
https://en.wikipedia.org/w/index.php?title=Hypertext_Transfer_Protocol&oldid=954964381#Request_methods
-}
knownMethods :: [Method]
knownMethods =
  [ "GET"
  , "HEAD"
  , "POST"
  , "PUT"
  , "DELETE"
  , "TRACE"
  , "OPTIONS"
  , "CONNECT"
  , "PATCH"
  ]