packages feed

wrecker-0.1.2.0: src/Network/Wreq/Wrecker.hs

{-| This is a copy of the wrecker 'Session' API,
    'Network.Wreq.Session' which utilizes 'wrecker''s
    'record' function.
-}
{-# LANGUAGE CPP, RecordWildCards #-}
module Network.Wreq.Wrecker where
import Wrecker
import qualified Network.Wreq.Session as Session
import Network.Connection (ConnectionContext)
import qualified Network.HTTP.Client.Internal as HTTP
import qualified Network.HTTP.Client_0_5_3_2_SHIM as HTTP_SHIM
import qualified Network.HTTP.Client_0_5_3_2_SHIM.Internal as HTTP_SHIM
import qualified Network.HTTP.Client.TLS_0_3_3_SHIM as TLS
import qualified Data.ByteString.Lazy as L
import qualified Network.Wreq.Types as Wreq
import Data.Default (def)
import Data.ByteString (ByteString)
import Network.Socket

data Session = Session
  { sSession  :: Session.Session
  , sRecorder :: Recorder
  }

toHTTPConnection :: HTTP_SHIM.Connection
                 -> HTTP.Connection
toHTTPConnection HTTP_SHIM.Connection {..} = HTTP.Connection {..}

toSHIMConnection :: HTTP.Connection
                 -> HTTP_SHIM.Connection
toSHIMConnection HTTP.Connection {..} = HTTP_SHIM.Connection {..}

convertTlsConnection :: IO (  Maybe HostAddress
                           -> String
                           -> Int
                           -> IO HTTP_SHIM.Connection
                           )
                     -> IO (  Maybe HostAddress
                           -> String
                           -> Int
                           -> IO HTTP.Connection
                           )
convertTlsConnection
  = fmap (\f -> \a s i -> fmap toHTTPConnection $ f a s i)

convertTlsProxyConnection :: IO (  ByteString
                                -> (HTTP_SHIM.Connection -> IO ())
                                -> String
                                -> Maybe HostAddress
                                -> String
                                -> Int
                                -> IO HTTP_SHIM.Connection
                                )
                          -> IO (  ByteString
                                -> (HTTP.Connection -> IO ())
                                -> String
                                -> Maybe HostAddress
                                -> String
                                -> Int
                                -> IO HTTP.Connection
                                )
convertTlsProxyConnection
  = fmap (\f
         -> \b g s m s' i
            -> fmap toHTTPConnection
             $ f b (g . toHTTPConnection) s m s' i
         )

convert :: HTTP_SHIM.ManagerSettings -> HTTP.ManagerSettings
convert HTTP_SHIM.ManagerSettings {..} =
  let d = HTTP.defaultManagerSettings
  in HTTP.ManagerSettings
      { HTTP.managerConnCount           = HTTP.managerConnCount d
      , HTTP.managerRawConnection       = HTTP.managerRawConnection d
      , HTTP.managerTlsConnection       = convertTlsConnection
                                        $ managerTlsConnection
      , HTTP.managerTlsProxyConnection  = convertTlsProxyConnection
                                        $ managerTlsProxyConnection
      , HTTP.managerResponseTimeout     = HTTP.managerResponseTimeout d
      , HTTP.managerRetryableException  = HTTP.managerRetryableException d
      , HTTP.managerWrapIOException     = HTTP.managerWrapIOException d
      , HTTP.managerIdleConnectionCount = HTTP.managerIdleConnectionCount d
      , HTTP.managerModifyRequest       = HTTP.managerModifyRequest d
      , HTTP.managerProxyInsecure       = HTTP.managerProxyInsecure d
      , HTTP.managerProxySecure         = HTTP.managerProxySecure d
      }

-- |
-- Module      : Network.Wreq.Internal.Types
-- Copyright   : (c) 2014 Bryan O'Sullivan
--
-- License     : BSD-style
-- Maintainer  : bos@serpentine.com
-- Stability   : experimental
-- Portability : GHC
--
-- HTTP client types.

-- All of this code below was copied from bos's `Network.Wreq.Session`
-- and modified to include the wrecker recorder

defaultManagerSettings :: ConnectionContext -> HTTP.ManagerSettings
defaultManagerSettings context
  = convert
  $ (TLS.mkManagerSettingsContext (Just context) def Nothing)
          { HTTP_SHIM.managerResponseTimeout = HTTP_SHIM.responseTimeoutNone }
-- | Create a 'Session' using the 'wrecker' 'Environment', passing it to the given function.  The
-- 'Session' will no longer be valid after that function returns.
--
-- This session manages cookies and uses default session manager
-- configuration.
withWreq :: Environment -> (Session -> IO a) -> IO a
withWreq env
  = withSessionControl (recorder env)
                       (Just (HTTP.createCookieJar []))
                       (defaultManagerSettings (context env))

-- | Create a session.
--
-- This uses the default session manager settings, but does not manage
-- cookies.  It is intended for use with REST-like HTTP-based APIs,
-- which typically do not use cookies.
withAPISession :: ConnectionContext -> Recorder -> (Session -> IO a) -> IO a
withAPISession context recorder
  = withSessionControl recorder
                       Nothing
                       (defaultManagerSettings context)

-- | Create a session, using the given cookie jar and manager settings.
withSessionControl :: Recorder
                   -> Maybe HTTP.CookieJar
                   -- ^ If 'Nothing' is specified, no cookie management
                   -- will be performed.
                   -> HTTP.ManagerSettings
                   -> (Session -> IO a) -> IO a
withSessionControl recorder cookie settings f
  = Session.withSessionControl cookie settings
  $ \session -> f (Session session recorder)

-- this records things. It's not ideal, but an more acurate
-- implementation is harder. Pull requests welcome.
withSess :: (Session.Session -> String -> IO a) -> Session -> String -> IO a
withSess f sess key = record (sRecorder sess) key $  f (sSession sess) key

withSess1 :: (Session.Session -> String -> a -> IO b) -> Session -> String -> a -> IO b
withSess1 f sess key b = record (sRecorder sess) key $  f (sSession sess) key b

-- | 'Session'-specific version of 'Network.Wreq.get'.
get :: Session -> String -> IO (HTTP.Response L.ByteString)
get = withSess Session.get

-- | 'Session'-specific version of 'Network.Wreq.post'.
post :: Wreq.Postable a
     => Session
     -> String
     -> a
     -> IO (HTTP.Response L.ByteString)
post = withSess1 Session.post

-- | 'Session'-specific version of 'Network.Wreq.head_'.
head_ :: Session -> String -> IO (HTTP.Response ())
head_ = withSess Session.head_

-- | 'Session'-specific version of 'Network.Wreq.options'.
options :: Session -> String -> IO (HTTP.Response ())
options = withSess Session.options

-- | 'Session'-specific version of 'Network.Wreq.put'.
put :: Wreq.Putable a => Session -> String -> a -> IO (HTTP.Response L.ByteString)
put = withSess1 Session.put

-- | 'Session'-specific version of 'Network.Wreq.delete'.
delete :: Session -> String -> IO (HTTP.Response L.ByteString)
delete = withSess Session.delete

-- | 'Session'-specific version of 'Network.Wreq.getWith'.
getWith :: Wreq.Options -> Session -> String -> IO (HTTP.Response L.ByteString)
getWith opts = withSess (Session.getWith opts)

-- | 'Session'-specific version of 'Network.Wreq.postWith'.
postWith :: Wreq.Postable a => Wreq.Options -> Session -> String -> a
         -> IO (HTTP.Response L.ByteString)
postWith opts = withSess1 (Session.postWith opts)

-- | 'Session'-specific version of 'Network.Wreq.headWith'.
headWith :: Wreq.Options -> Session -> String -> IO (HTTP.Response ())
headWith opts = withSess (Session.headWith opts)

-- | 'Session'-specific version of 'Network.Wreq.optionsWith'.
optionsWith :: Wreq.Options -> Session -> String -> IO (HTTP.Response ())
optionsWith opts = withSess (Session.optionsWith opts)

-- | 'Session'-specific version of 'Network.Wreq.putWith'.
putWith :: Wreq.Putable a => Wreq.Options -> Session -> String -> a
        -> IO (HTTP.Response L.ByteString)
putWith opts = withSess1 (Session.putWith opts)

-- | 'Session'-specific version of 'Network.Wreq.deleteWith'.
deleteWith :: Wreq.Options -> Session -> String -> IO (HTTP.Response L.ByteString)
deleteWith opts = withSess (Session.deleteWith opts)