packages feed

req 3.12.0 → 3.13.4

raw patch · 6 files changed

Files

CHANGELOG.md view
@@ -1,3 +1,34 @@+## Req 3.13.4++* Fixed empty ciphersuite list when compiling against `tls < 2.0.6`+  (see [PR 175](https://github.com/mrkkrp/req/pull/175)). As a side effect, now+  compatible with older versions of `crypton-connection` (>= 0.3).++## Req 3.13.3++* Works with `crypton-connection-0.4` and newer.++## Req 3.13.2++* Disable the problematic `httpbin-tests` test suite by default. Only enable+  it when the `dev` flag is enabled. In that case it is expected that an+  httpbin server is run locally at `localhost:1234`.++## Req 3.13.1++* Switched the non-pure test suite to use https://httpbun.org instead of+  https://httpbin.org since the latter proved to be highly unreliable+  lately.++* Switched from `connection` to `crypton-connection`.++* Builds with GHC 9.6.1.++## Req 3.13.0++* Add `headerRedacted` function to add header fields, which will be with+  redacted values on print.+ ## Req 3.12.0  * Add `isStatusCodeException` function.
Network/HTTP/Req.hs view
@@ -1,20 +1,9 @@-{-# LANGUAGE BangPatterns #-}-{-# LANGUAGE CPP #-} {-# LANGUAGE DataKinds #-}-{-# LANGUAGE DeriveDataTypeable #-}-{-# LANGUAGE DeriveGeneric #-}-{-# LANGUAGE DeriveLift #-}-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE LambdaCase #-}-{-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE QuasiQuotes #-}-{-# LANGUAGE RankNTypes #-} {-# LANGUAGE RecordWildCards #-} {-# LANGUAGE RoleAnnotations #-}-{-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE StandaloneDeriving #-} {-# LANGUAGE TemplateHaskellQuotes #-} {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE UndecidableInstances #-}@@ -161,6 +150,7 @@     -- *** Headers     header,     attachHeader,+    headerRedacted,      -- *** Cookies     -- $cookies@@ -213,69 +203,72 @@   ) where -import qualified Blaze.ByteString.Builder as BB+import Blaze.ByteString.Builder qualified as BB import Control.Applicative import Control.Arrow (first, second) import Control.Exception hiding (Handler (..), TypeError)+import Control.Monad (guard, void, (>=>)) import Control.Monad.Base import Control.Monad.Catch (Handler (..), MonadCatch, MonadMask, MonadThrow) import Control.Monad.IO.Class import Control.Monad.IO.Unlift-import Control.Monad.Reader+import Control.Monad.Reader (ReaderT (ReaderT), ask, lift, runReaderT) import Control.Monad.Trans.Accum (AccumT) import Control.Monad.Trans.Cont (ContT) import Control.Monad.Trans.Control import Control.Monad.Trans.Except (ExceptT) import Control.Monad.Trans.Identity (IdentityT) import Control.Monad.Trans.Maybe (MaybeT)-import qualified Control.Monad.Trans.RWS.CPS as RWS.CPS-import qualified Control.Monad.Trans.RWS.Lazy as RWS.Lazy-import qualified Control.Monad.Trans.RWS.Strict as RWS.Strict+import Control.Monad.Trans.RWS.CPS qualified as RWS.CPS+import Control.Monad.Trans.RWS.Lazy qualified as RWS.Lazy+import Control.Monad.Trans.RWS.Strict qualified as RWS.Strict import Control.Monad.Trans.Select (SelectT)-import qualified Control.Monad.Trans.State.Lazy as State.Lazy-import qualified Control.Monad.Trans.State.Strict as State.Strict-import qualified Control.Monad.Trans.Writer.CPS as Writer.CPS-import qualified Control.Monad.Trans.Writer.Lazy as Writer.Lazy-import qualified Control.Monad.Trans.Writer.Strict as Writer.Strict+import Control.Monad.Trans.State.Lazy qualified as State.Lazy+import Control.Monad.Trans.State.Strict qualified as State.Strict+import Control.Monad.Trans.Writer.CPS qualified as Writer.CPS+import Control.Monad.Trans.Writer.Lazy qualified as Writer.Lazy+import Control.Monad.Trans.Writer.Strict qualified as Writer.Strict import Control.Retry import Data.Aeson (FromJSON (..), ToJSON (..))-import qualified Data.Aeson as A+import Data.Aeson qualified as A import Data.ByteString (ByteString)-import qualified Data.ByteString as B-import qualified Data.ByteString.Lazy as BL-import qualified Data.CaseInsensitive as CI+import Data.ByteString qualified as B+import Data.ByteString.Lazy qualified as BL+import Data.CaseInsensitive qualified as CI import Data.Data (Data)+import Data.Default.Class (def) import Data.Function (on) import Data.IORef import Data.Kind (Constraint, Type) import Data.List (foldl', nubBy) import Data.List.NonEmpty (NonEmpty (..))-import qualified Data.List.NonEmpty as NE+import Data.List.NonEmpty qualified as NE import Data.Maybe (fromMaybe) import Data.Proxy import Data.Semigroup (Endo (..))+import Data.Set qualified as S import Data.Text (Text)-import qualified Data.Text as T-import qualified Data.Text.Encoding as T+import Data.Text qualified as T+import Data.Text.Encoding qualified as T import Data.Typeable (Typeable, cast) import GHC.Generics import GHC.TypeLits-import qualified Language.Haskell.TH as TH-import qualified Language.Haskell.TH.Quote as TH-import qualified Language.Haskell.TH.Syntax as TH-import qualified Network.Connection as NC-import qualified Network.HTTP.Client as L-import qualified Network.HTTP.Client.Internal as LI-import qualified Network.HTTP.Client.MultipartFormData as LM-import qualified Network.HTTP.Client.TLS as L-import qualified Network.HTTP.Types as Y+import Language.Haskell.TH qualified as TH+import Language.Haskell.TH.Quote qualified as TH+import Language.Haskell.TH.Syntax qualified as TH+import Network.Connection qualified as NC+import Network.HTTP.Client qualified as L+import Network.HTTP.Client.Internal qualified as LI+import Network.HTTP.Client.MultipartFormData qualified as LM+import Network.HTTP.Client.TLS qualified as L+import Network.HTTP.Types qualified as Y import System.IO.Unsafe (unsafePerformIO) import Text.URI (URI)-import qualified Text.URI as URI-import qualified Text.URI.QQ as QQ-import qualified Web.Authenticate.OAuth as OAuth+import Text.URI qualified as URI+import Text.URI.QQ qualified as QQ+import Web.Authenticate.OAuth qualified as OAuth import Web.FormUrlEncoded (FromForm (..), ToForm (..))-import qualified Web.FormUrlEncoded as Form+import Web.FormUrlEncoded qualified as Form import Web.HttpApiData (ToHttpApiData (..))  ----------------------------------------------------------------------------@@ -496,7 +489,7 @@ -- -- @since 3.7.0 reqHandler ::-  MonadHttp m =>+  (MonadHttp m) =>   -- | How to get final result from a 'L.Response'   (L.Response L.BodyReader -> IO b) ->   -- | 'L.Request' to perform@@ -594,7 +587,7 @@ -- | Perform an action using the global implicit 'L.Manager' that the rest -- of the library uses. This allows to reuse connections that the -- 'L.Manager' controls.-withReqManager :: MonadIO m => (L.Manager -> m a) -> m a+withReqManager :: (MonadIO m) => (L.Manager -> m a) -> m a withReqManager m = liftIO (readIORef globalManager) >>= m  -- | The global 'L.Manager' that 'req' uses. Here we just go with the@@ -614,7 +607,7 @@   let settings =         L.mkManagerSettingsContext           (Just context)-          (NC.TLSSettingsSimple False False False)+          def           Nothing   manager <- L.newManager settings   newIORef manager@@ -637,7 +630,7 @@ -- | A type class for monads that support performing HTTP requests. -- Typically, you only need to define the 'handleHttpException' method -- unless you want to tweak 'HttpConfig'.-class MonadIO m => MonadHttp m where+class (MonadIO m) => MonadHttp m where   -- | This method describes how to deal with 'HttpException' that was   -- caught by the library. One option is to re-throw it if you are OK with   -- exceptions, but if you prefer working with something like@@ -721,7 +714,7 @@     -- | Max length of preview fragment of response body.     --     -- @since 3.6.0-    httpConfigBodyPreviewLength :: forall a. Num a => a+    httpConfigBodyPreviewLength :: forall a. (Num a) => a   }   deriving (Typeable) @@ -811,27 +804,27 @@   getHttpConfig = lift getHttpConfig  -- | @since 3.10.0-instance MonadHttp m => MonadHttp (ContT r m) where+instance (MonadHttp m) => MonadHttp (ContT r m) where   handleHttpException = lift . handleHttpException   getHttpConfig = lift getHttpConfig  -- | @since 3.10.0-instance MonadHttp m => MonadHttp (ExceptT e m) where+instance (MonadHttp m) => MonadHttp (ExceptT e m) where   handleHttpException = lift . handleHttpException   getHttpConfig = lift getHttpConfig  -- | @since 3.10.0-instance MonadHttp m => MonadHttp (IdentityT m) where+instance (MonadHttp m) => MonadHttp (IdentityT m) where   handleHttpException = lift . handleHttpException   getHttpConfig = lift getHttpConfig  -- | @since 3.10.0-instance MonadHttp m => MonadHttp (MaybeT m) where+instance (MonadHttp m) => MonadHttp (MaybeT m) where   handleHttpException = lift . handleHttpException   getHttpConfig = lift getHttpConfig  -- | @since 3.10.0-instance MonadHttp m => MonadHttp (ReaderT r m) where+instance (MonadHttp m) => MonadHttp (ReaderT r m) where   handleHttpException = lift . handleHttpException   getHttpConfig = lift getHttpConfig @@ -851,17 +844,17 @@   getHttpConfig = lift getHttpConfig  -- | @since 3.10.0-instance MonadHttp m => MonadHttp (SelectT r m) where+instance (MonadHttp m) => MonadHttp (SelectT r m) where   handleHttpException = lift . handleHttpException   getHttpConfig = lift getHttpConfig  -- | @since 3.10.0-instance MonadHttp m => MonadHttp (State.Lazy.StateT s m) where+instance (MonadHttp m) => MonadHttp (State.Lazy.StateT s m) where   handleHttpException = lift . handleHttpException   getHttpConfig = lift getHttpConfig  -- | @since 3.10.0-instance MonadHttp m => MonadHttp (State.Strict.StateT s m) where+instance (MonadHttp m) => MonadHttp (State.Strict.StateT s m) where   handleHttpException = lift . handleHttpException   getHttpConfig = lift getHttpConfig @@ -885,7 +878,7 @@ -- -- @since 0.4.0 runReq ::-  MonadIO m =>+  (MonadIO m) =>   -- | 'HttpConfig' to use   HttpConfig ->   -- | Computation to run@@ -990,7 +983,7 @@   -- | Return name of the method as a 'ByteString'.   httpMethodName :: Proxy a -> ByteString -instance HttpMethod method => RequestComponent (Tagged "method" method) where+instance (HttpMethod method) => RequestComponent (Tagged "method" method) where   getRequestMod _ = Endo $ \x ->     x {L.method = httpMethodName (Proxy :: Proxy method)} @@ -1038,19 +1031,14 @@  -- With template-haskell >=2.15 and text >=1.2.4 Lift can be derived, however -- the derived lift forgets the type of the scheme.-instance Typeable scheme => TH.Lift (Url scheme) where+instance (Typeable scheme) => TH.Lift (Url scheme) where   lift url =     TH.dataToExpQ (fmap liftText . cast) url `TH.sigE` case url of       Url Http _ -> [t|Url 'Http|]       Url Https _ -> [t|Url 'Https|]     where       liftText t = TH.AppE (TH.VarE 'T.pack) <$> TH.lift (T.unpack t)--#if MIN_VERSION_template_haskell(2,17,0)   liftTyped = TH.Code . TH.unsafeTExpCoerce . TH.lift-#elif MIN_VERSION_template_haskell(2,16,0)-  liftTyped = TH.unsafeTExpCoerce . TH.lift-#endif  -- | Given host name, produce a 'Url' which has “http” as its scheme and -- empty path. This also sets port to @80@.@@ -1066,7 +1054,7 @@ -- path segment can be of any type that is an instance of 'ToHttpApiData'. infixl 5 /~ -(/~) :: ToHttpApiData a => Url scheme -> a -> Url scheme+(/~) :: (ToHttpApiData a) => Url scheme -> a -> Url scheme Url secure path /~ segment = Url secure (NE.cons (toUrlPiece segment) path)  -- | A type-constrained version of @('/~')@ to remove ambiguity in the cases@@ -1254,7 +1242,7 @@ -- charset=utf-8\"@ value. newtype ReqBodyJson a = ReqBodyJson a -instance ToJSON a => HttpBody (ReqBodyJson a) where+instance (ToJSON a) => HttpBody (ReqBodyJson a) where   getRequestBody (ReqBodyJson a) = L.RequestBodyLBS (A.encode a)   getRequestContentType _ = pure "application/json; charset=utf-8" @@ -1353,7 +1341,7 @@ -- | Create 'ReqBodyMultipart' request body from a collection of 'LM.Part's. -- -- @since 0.2.0-reqBodyMultipart :: MonadIO m => [LM.Part] -> m ReqBodyMultipart+reqBodyMultipart :: (MonadIO m) => [LM.Part] -> m ReqBodyMultipart reqBodyMultipart parts = liftIO $ do   boundary <- LM.webkitBoundary   body <- LM.renderParts boundary parts@@ -1393,7 +1381,7 @@     TypeError       ('Text "This HTTP method does not allow attaching a request body.") -instance HttpBody body => RequestComponent (Tagged "body" body) where+instance (HttpBody body) => RequestComponent (Tagged "body" body) where   getRequestMod (Tagged body) = Endo $ \x ->     x       { L.requestBody = getRequestBody body,@@ -1463,7 +1451,7 @@  -- | Finalize given 'L.Request' by applying a finalizer from the given -- 'Option' (if it has any).-finalizeRequest :: MonadIO m => Option scheme -> L.Request -> m L.Request+finalizeRequest :: (MonadIO m) => Option scheme -> L.Request -> m L.Request finalizeRequest (Option _ mfinalizer) = liftIO . fromMaybe pure mfinalizer  ----------------------------------------------------------------------------@@ -1496,7 +1484,7 @@ -- This operator is defined in terms of 'queryParam': -- -- > queryFlag name = queryParam name (Nothing :: Maybe ())-queryFlag :: QueryParam param => Text -> param+queryFlag :: (QueryParam param) => Text -> param queryFlag name = queryParam name (Nothing :: Maybe ())  -- | Construct query parameters from a 'ToForm' instance. This function@@ -1526,7 +1514,7 @@   -- 'Nothing', it won't be included at all (i.e. you create a flag this   -- way). It's recommended to use @('=:')@ and 'queryFlag' instead of this   -- method, because they are easier to read.-  queryParam :: ToHttpApiData a => Text -> Maybe a -> param+  queryParam :: (ToHttpApiData a) => Text -> Maybe a -> param    -- | Get the query parameter names and values set by 'queryParam'.   --@@ -1560,6 +1548,14 @@ attachHeader name value x =   x {L.requestHeaders = (CI.mk name, value) : L.requestHeaders x} +-- | Same as 'header', but with redacted values on print.+--+-- @since 3.13.0+headerRedacted :: ByteString -> ByteString -> Option scheme+headerRedacted name value = withRequest $ \x ->+  let y = attachHeader name value x+   in y {L.redactHeaders = CI.mk name `S.insert` L.redactHeaders y}+ ---------------------------------------------------------------------------- -- Request—Optional parameters—Cookies @@ -1767,7 +1763,7 @@ newtype JsonResponse a = JsonResponse (L.Response a)   deriving (Show) -instance FromJSON a => HttpResponse (JsonResponse a) where+instance (FromJSON a) => HttpResponse (JsonResponse a) where   type HttpResponseBody (JsonResponse a) = a   toVanillaResponse (JsonResponse r) = r   getHttpResponse r = do@@ -1883,14 +1879,14 @@  -- | Get the response body. responseBody ::-  HttpResponse response =>+  (HttpResponse response) =>   response ->   HttpResponseBody response responseBody = L.responseBody . toVanillaResponse  -- | Get the response status code. responseStatusCode ::-  HttpResponse response =>+  (HttpResponse response) =>   response ->   Int responseStatusCode =@@ -1898,7 +1894,7 @@  -- | Get the response status message. responseStatusMessage ::-  HttpResponse response =>+  (HttpResponse response) =>   response ->   ByteString responseStatusMessage =@@ -1906,7 +1902,7 @@  -- | Lookup a particular header from a response. responseHeader ::-  HttpResponse response =>+  (HttpResponse response) =>   -- | Response interpretation   response ->   -- | Header to lookup@@ -1918,7 +1914,7 @@  -- | Get the response 'L.CookieJar'. responseCookieJar ::-  HttpResponse response =>+  (HttpResponse response) =>   response ->   L.CookieJar responseCookieJar = L.responseCookieJar . toVanillaResponse
− Setup.hs
@@ -1,6 +0,0 @@-module Main (main) where--import Distribution.Simple--main :: IO ()-main = defaultMain
httpbin-tests/Network/HTTP/ReqSpec.hs view
@@ -8,24 +8,25 @@ module Network.HTTP.ReqSpec (spec) where  import Control.Exception-import Control.Monad.Reader+import Control.Monad (forM_) import Control.Monad.Trans.Control import Data.Aeson (ToJSON (..), Value (..), object, (.=))-import qualified Data.Aeson as A-import qualified Data.Aeson.KeyMap as Aeson.KeyMap-import qualified Data.ByteString as B-import qualified Data.ByteString.Lazy as BL+import Data.Aeson qualified as A+import Data.Aeson.KeyMap qualified as Aeson.KeyMap+import Data.ByteString qualified as B+import Data.ByteString.Lazy qualified as BL import Data.Functor.Identity (runIdentity) import Data.Maybe (fromJust) import Data.Proxy import Data.Text (Text)-import qualified Data.Text as T-import qualified Data.Text.Encoding as T-import qualified Data.Text.IO as TIO-import qualified Network.HTTP.Client as L-import qualified Network.HTTP.Client.MultipartFormData as LM-import Network.HTTP.Req-import qualified Network.HTTP.Types as Y+import Data.Text qualified as T+import Data.Text.Encoding qualified as T+import Data.Text.IO qualified as TIO+import Network.HTTP.Client qualified as L+import Network.HTTP.Client.MultipartFormData qualified as LM+import Network.HTTP.Req hiding (req)+import Network.HTTP.Req qualified as Req+import Network.HTTP.Types qualified as Y import Test.Hspec import Test.QuickCheck @@ -84,8 +85,7 @@               .= object                 [ "Accept-Encoding" .= ("gzip" :: Text),                   "Foo" .= ("bar" :: Text),-                  "Baz" .= ("quux" :: Text),-                  "Host" .= ("httpbin.org" :: Text)+                  "Baz" .= ("quux" :: Text)                 ]           ]       responseStatusCode r `shouldBe` 200@@ -97,11 +97,10 @@       (stripFunnyHeaders . stripOrigin) (responseBody r)         `shouldBe` object           [ "args" .= emptyObject,-            "url" .= ("https://httpbin.org/get" :: Text),+            "url" .= ("http://localhost:1234/get" :: Text),             "headers"               .= object-                [ "Accept-Encoding" .= ("gzip" :: Text),-                  "Host" .= ("httpbin.org" :: Text)+                [ "Accept-Encoding" .= ("gzip" :: Text)                 ]           ]       responseHeader r "Content-Type" `shouldBe` return "application/json"@@ -118,12 +117,11 @@           [ "args" .= emptyObject,             "json" .= text,             "data" .= reflected,-            "url" .= ("https://httpbin.org/post" :: Text),+            "url" .= ("http://localhost:1234/post" :: Text),             "headers"               .= object                 [ "Content-Type" .= ("application/json; charset=utf-8" :: Text),                   "Accept-Encoding" .= ("gzip" :: Text),-                  "Host" .= ("httpbin.org" :: Text),                   "Content-Length" .= show (T.length reflected)                 ],             "files" .= emptyObject,@@ -147,12 +145,11 @@           [ "args" .= emptyObject,             "json" .= Null,             "data" .= ("" :: Text),-            "url" .= ("https://httpbin.org/post" :: Text),+            "url" .= ("http://localhost:1234/post" :: Text),             "headers"               .= object                 [ "Content-Type" .= T.decodeUtf8 contentType,                   "Accept-Encoding" .= ("gzip" :: Text),-                  "Host" .= ("httpbin.org" :: Text),                   "Content-Length" .= ("242" :: Text)                 ],             "files" .= emptyObject,@@ -177,11 +174,10 @@           [ "args" .= emptyObject,             "json" .= Null,             "data" .= contents,-            "url" .= ("https://httpbin.org/patch" :: Text),+            "url" .= ("http://localhost:1234/patch" :: Text),             "headers"               .= object                 [ "Accept-Encoding" .= ("gzip" :: Text),-                  "Host" .= ("httpbin.org" :: Text),                   "Content-Length" .= show (T.length contents)                 ],             "files" .= emptyObject,@@ -203,12 +199,11 @@           [ "args" .= emptyObject,             "json" .= Null,             "data" .= ("" :: Text),-            "url" .= ("https://httpbin.org/put" :: Text),+            "url" .= ("http://localhost:1234/put" :: Text),             "headers"               .= object                 [ "Content-Type" .= ("application/x-www-form-urlencoded" :: Text),                   "Accept-Encoding" .= ("gzip" :: Text),-                  "Host" .= ("httpbin.org" :: Text),                   "Content-Length" .= ("18" :: Text)                 ],             "files" .= emptyObject,@@ -306,7 +301,7 @@             (httpbin /: "basic-auth" /~ user /~ password)             NoReqBody             ignoreResponse-            (basicAuth (T.encodeUtf8 user) (T.encodeUtf8 password))+            (basicAuthUnsafe (T.encodeUtf8 user) (T.encodeUtf8 password))         responseStatusCode r `shouldBe` 200         responseStatusMessage r `shouldBe` "OK" @@ -406,9 +401,29 @@     doit _ _ = error "Oops!"  -- | 'Url' representing <https://httpbin.org>.-httpbin :: Url 'Https-httpbin = https "httpbin.org"+httpbin :: Url 'Http+httpbin = http "localhost" +req ::+  ( MonadHttp m,+    HttpMethod method,+    HttpBody body,+    HttpResponse response,+    HttpBodyAllowed (AllowsBody method) (ProvidesBody body)+  ) =>+  method ->+  Url scheme ->+  body ->+  Proxy response ->+  Option scheme ->+  m response+req method url body responseProxy options =+  Req.req method url body responseProxy (options <> defaultOptions)++-- | Options to apply by default.+defaultOptions :: Option scheme+defaultOptions = port 1234+ -- | Remove “origin” field from JSON value. Origin may change, we don't want -- to depend on that. stripOrigin :: Value -> Value@@ -417,20 +432,37 @@  -- | Remove funny headers that might break the tests. stripFunnyHeaders :: Value -> Value-stripFunnyHeaders (Object m) =-  let f (Object p) = Object $ Aeson.KeyMap.filterWithKey (\k _ -> k `elem` hs) p-      f value = value-      hs =-        [ "Content-Type",-          "Accept-Encoding",-          "Host",-          "Content-Length",-          "Foo",-          "Baz"-        ]-   in Object (runIdentity (Aeson.KeyMap.alterF (pure . fmap f) "headers" m))-stripFunnyHeaders value = value+stripFunnyHeaders = \case+  Object m ->+    Object+      ( runIdentity+          ( Aeson.KeyMap.alterF+              (pure . fmap stripFunnyHeaders')+              "headers"+              m+          )+      )+  value -> value +-- | Similar to 'stripFunnyHeaders', but acts directly on the argument+-- without trying to access its "headers" field.+stripFunnyHeaders' :: Value -> Value+stripFunnyHeaders' = \case+  Object p ->+    Object $+      Aeson.KeyMap.filterWithKey+        (\k _ -> k `elem` whitelistedHeaders)+        p+  value -> value+  where+    whitelistedHeaders =+      [ "Content-Type",+        "Accept-Encoding",+        "Content-Length",+        "Foo",+        "Baz"+      ]+ -- | This is a complete test case that makes use of <https://httpbin.org> to -- get various response status codes. checkStatusCode :: Int -> SpecWith ()@@ -471,7 +503,7 @@ emptyObject = Object Aeson.KeyMap.empty  -- | Get a rendered JSON value as 'Text'.-reflectJSON :: ToJSON a => a -> Text+reflectJSON :: (ToJSON a) => a -> Text reflectJSON = T.decodeUtf8 . BL.toStrict . A.encode  -- | Clarify to the type checker that the inner computation is in the 'IO'
pure-tests/Network/HTTP/ReqSpec.hs view
@@ -13,41 +13,41 @@  module Network.HTTP.ReqSpec (spec) where -import qualified Blaze.ByteString.Builder as BB+import Blaze.ByteString.Builder qualified as BB import Control.Exception (throwIO) import Control.Monad import Control.Retry import Data.Aeson (ToJSON (..))-import qualified Data.Aeson as A+import Data.Aeson qualified as A import Data.ByteString (ByteString)-import qualified Data.ByteString as B-import qualified Data.ByteString.Char8 as B8-import qualified Data.ByteString.Lazy as BL-import qualified Data.CaseInsensitive as CI+import Data.ByteString qualified as B+import Data.ByteString.Char8 qualified as B8+import Data.ByteString.Lazy qualified as BL+import Data.CaseInsensitive qualified as CI import Data.Either (isRight)-import qualified Data.List.NonEmpty as NE+import Data.List.NonEmpty qualified as NE import Data.Maybe (fromJust, fromMaybe, isJust, isNothing) import Data.Proxy import Data.Text (Text)-import qualified Data.Text as T-import qualified Data.Text.Encoding as T+import Data.Text qualified as T+import Data.Text.Encoding qualified as T import Data.Time import Data.Typeable (Typeable, eqT) import GHC.Exts (IsList (..)) import GHC.Generics-import qualified Language.Haskell.TH as TH-import qualified Language.Haskell.TH.Quote as TH-import qualified Network.HTTP.Client as L+import Language.Haskell.TH qualified as TH+import Language.Haskell.TH.Quote qualified as TH+import Network.HTTP.Client qualified as L import Network.HTTP.Req-import qualified Network.HTTP.Types as Y-import qualified Network.HTTP.Types.Header as Y+import Network.HTTP.Types qualified as Y+import Network.HTTP.Types.Header qualified as Y import Test.Hspec import Test.Hspec.Core.Spec (SpecM) import Test.QuickCheck import Text.URI (URI)-import qualified Text.URI as URI-import qualified Text.URI.QQ as QQ-import qualified Web.FormUrlEncoded as F+import Text.URI qualified as URI+import Text.URI.QQ qualified as QQ+import Web.FormUrlEncoded qualified as F  spec :: Spec spec = do@@ -413,7 +413,7 @@         -- 'Https, Option _) type checks, so we can catch if the type of scheme         -- is unspecified.         let testTypeOfQuoterResult ::-              forall a s. Typeable a => (a, Option s) -> Bool+              forall a s. (Typeable a) => (a, Option s) -> Bool             testTypeOfQuoterResult _ = isJust $ eqT @a @(Url 'Https)          in property $ testTypeOfQuoterResult [urlQ|https://example.org/|]       it "doesn't work for invalid urls" $
req.cabal view
@@ -1,11 +1,11 @@ cabal-version:   2.4 name:            req-version:         3.12.0+version:         3.13.4 license:         BSD-3-Clause license-file:    LICENSE.md maintainer:      Mark Karpov <markkarpov92@gmail.com> author:          Mark Karpov <markkarpov92@gmail.com>-tested-with:     ghc ==8.10.7 ghc ==9.0.2 ghc ==9.2.1+tested-with:     ghc ==9.6.3 ghc ==9.8.2 ghc ==9.10.1 homepage:        https://github.com/mrkkrp/req bug-reports:     https://github.com/mrkkrp/req/issues synopsis:        HTTP client library@@ -31,71 +31,70 @@  library     exposed-modules:  Network.HTTP.Req-    default-language: Haskell2010+    default-language: GHC2021     build-depends:         aeson >=0.9 && <3,         authenticate-oauth >=1.5 && <1.8,-        base >=4.13 && <5.0,+        base >=4.15 && <5,         blaze-builder >=0.3 && <0.5,-        bytestring >=0.10.8 && <0.12,+        bytestring >=0.10.8 && <0.13,         case-insensitive >=0.2 && <1.3,-        connection >=0.2.2 && <0.4,+        containers >=0.5 && <0.7,+        crypton-connection >=0.3 && <0.5,+        data-default-class,         exceptions >=0.6 && <0.11,-        http-api-data >=0.2 && <0.5,-        http-client >=0.7 && <0.8,+        http-api-data >=0.2 && <0.7,+        http-client >=0.7.13.1 && <0.8,         http-client-tls >=0.3.2 && <0.4,-        http-types >=0.8 && <10.0,+        http-types >=0.8 && <10,         modern-uri >=0.3 && <0.4,         monad-control >=1.0 && <1.1,         mtl >=2.0 && <3.0,         retry >=0.8 && <0.10,-        template-haskell >=2.14 && <2.19,-        text >=0.2 && <2.1,-        time >=1.2 && <1.13,-        transformers >=0.5.3.0 && <0.6,+        template-haskell >=2.19 && <2.23,+        text >=0.2 && <2.2,+        transformers >=0.5.3.0 && <0.7,         transformers-base,         unliftio-core >=0.1.1 && <0.3      if flag(dev)-        ghc-options: -O0 -Wall -Werror+        ghc-options:+            -Wall -Werror -Wpartial-fields -Wunused-packages+            -Wno-unused-imports      else         ghc-options: -O2 -Wall -    if flag(dev)-        ghc-options:-            -Wcompat -Wincomplete-record-updates -Wincomplete-uni-patterns-            -Wnoncanonical-monad-instances- test-suite pure-tests     type:               exitcode-stdio-1.0     main-is:            Spec.hs-    build-tool-depends: hspec-discover:hspec-discover >=2.0 && <3.0+    build-tool-depends: hspec-discover:hspec-discover >=2 && <3     hs-source-dirs:     pure-tests     other-modules:      Network.HTTP.ReqSpec-    default-language:   Haskell2010+    default-language:   GHC2021     build-depends:-        QuickCheck >=2.7 && <3.0,+        QuickCheck >=2.7 && <3,         aeson >=0.9 && <3,-        base >=4.13 && <5.0,+        base >=4.15 && <5.0,         blaze-builder >=0.3 && <0.5,-        bytestring >=0.10.8 && <0.12,+        bytestring >=0.10.8 && <0.13,         case-insensitive >=0.2 && <1.3,-        hspec >=2.0 && <3.0,-        hspec-core >=2.0 && <3.0,-        http-api-data >=0.2 && <0.5,+        hspec >=2.0 && <3,+        hspec-core >=2.0 && <3,+        http-api-data >=0.2 && <0.7,         http-client >=0.7 && <0.8,-        http-types >=0.8 && <10.0,+        http-types >=0.8 && <10,         modern-uri >=0.3 && <0.4,-        mtl >=2.0 && <3.0,         req,         retry >=0.8 && <0.10,-        template-haskell >=2.14 && <2.19,-        text >=0.2 && <2.1,+        template-haskell >=2.19 && <2.23,+        text >=0.2 && <2.2,         time >=1.2 && <1.13      if flag(dev)-        ghc-options: -O0 -Wall -Werror+        ghc-options:+            -Wall -Werror -Wredundant-constraints -Wpartial-fields+            -Wunused-packages      else         ghc-options: -O2 -Wall@@ -103,25 +102,26 @@ test-suite httpbin-tests     type:               exitcode-stdio-1.0     main-is:            Spec.hs-    build-tool-depends: hspec-discover:hspec-discover >=2.0 && <3.0+    build-tool-depends: hspec-discover:hspec-discover >=2 && <3     hs-source-dirs:     httpbin-tests     other-modules:      Network.HTTP.ReqSpec-    default-language:   Haskell2010+    default-language:   GHC2021     build-depends:-        QuickCheck >=2.7 && <3.0,+        QuickCheck >=2.7 && <3,         aeson >=2 && <3,-        base >=4.13 && <5.0,-        bytestring >=0.10.8 && <0.12,+        base >=4.15 && <5,+        bytestring >=0.10.8 && <0.13,         hspec >=2.0 && <3.0,         http-client >=0.7 && <0.8,-        http-types >=0.8 && <10.0,+        http-types >=0.8 && <10,         monad-control >=1.0 && <1.1,-        mtl >=2.0 && <3.0,         req,-        text >=0.2 && <2.1+        text >=0.2 && <2.2      if flag(dev)-        ghc-options: -O0 -Wall -Werror+        ghc-options:+            -Wall -Werror -Wredundant-constraints -Wpartial-fields+            -Wunused-packages      else-        ghc-options: -O2 -Wall+        buildable: False