1{-# LANGUAGE CPP #-} 2{-# LANGUAGE DeriveDataTypeable #-} 3{-# LANGUAGE DeriveTraversable #-} 4{-# LANGUAGE RankNTypes #-} 5{-# LANGUAGE OverloadedStrings #-} 6module Network.HTTP.Client.Types 7 ( BodyReader 8 , Connection (..) 9 , StatusHeaders (..) 10 , HttpException (..) 11 , HttpExceptionContent (..) 12 , unHttpExceptionContentWrapper 13 , throwHttp 14 , toHttpException 15 , Cookie (..) 16 , equalCookie 17 , equivCookie 18 , compareCookies 19 , CookieJar (..) 20 , equalCookieJar 21 , equivCookieJar 22 , Proxy (..) 23 , RequestBody (..) 24 , Popper 25 , NeedsPopper 26 , GivesPopper 27 , Request (..) 28 , Response (..) 29 , ResponseClose (..) 30 , Manager (..) 31 , HasHttpManager (..) 32 , ConnsMap (..) 33 , ManagerSettings (..) 34 , NonEmptyList (..) 35 , ConnHost (..) 36 , ConnKey (..) 37 , ProxyOverride (..) 38 , StreamFileStatus (..) 39 , ResponseTimeout (..) 40 ) where 41 42import qualified Data.Typeable as T (Typeable) 43import Network.HTTP.Types 44import Control.Exception (Exception, SomeException, throwIO) 45import Data.Word (Word64) 46import qualified Data.ByteString as S 47import qualified Data.ByteString.Lazy as L 48import Blaze.ByteString.Builder (Builder, fromLazyByteString, fromByteString, toLazyByteString) 49import Data.Int (Int64) 50import Data.Foldable (Foldable) 51import Data.Monoid (Monoid(..)) 52import Data.Semigroup (Semigroup(..)) 53import Data.String (IsString, fromString) 54import Data.Time (UTCTime) 55import Data.Traversable (Traversable) 56import qualified Data.List as DL 57import Network.Socket (HostAddress) 58import Data.IORef 59import qualified Network.Socket as NS 60import qualified Data.Map as Map 61import Data.Text (Text) 62import Data.Streaming.Zlib (ZlibException) 63import Data.CaseInsensitive as CI 64import Data.KeyedPool (KeyedPool) 65 66-- | An @IO@ action that represents an incoming response body coming from the 67-- server. Data provided by this action has already been gunzipped and 68-- de-chunked, and respects any content-length headers present. 69-- 70-- The action gets a single chunk of data from the response body, or an empty 71-- bytestring if no more data is available. 72-- 73-- Since 0.4.0 74type BodyReader = IO S.ByteString 75 76data Connection = Connection 77 { connectionRead :: IO S.ByteString 78 -- ^ If no more data, return empty. 79 , connectionUnread :: S.ByteString -> IO () 80 -- ^ Return data to be read next time. 81 , connectionWrite :: S.ByteString -> IO () 82 -- ^ Send data to server 83 , connectionClose :: IO () 84 -- ^ Close connection. Any successive operation on the connection 85 -- (except closing) should fail with `ConnectionClosed` exception. 86 -- It is allowed to close connection multiple times. 87 } 88 deriving T.Typeable 89 90data StatusHeaders = StatusHeaders Status HttpVersion RequestHeaders 91 deriving (Show, Eq, Ord, T.Typeable) 92 93-- | A newtype wrapper which is not exported from this library but is an 94-- instance of @Exception@. This allows @HttpExceptionContent@ to be thrown 95-- (via this wrapper), but users of the library can't accidentally try to catch 96-- it (when they /should/ be trying to catch 'HttpException'). 97-- 98-- @since 0.5.0 99newtype HttpExceptionContentWrapper = HttpExceptionContentWrapper 100 { unHttpExceptionContentWrapper :: HttpExceptionContent 101 } 102 deriving (Show, T.Typeable) 103instance Exception HttpExceptionContentWrapper 104 105throwHttp :: HttpExceptionContent -> IO a 106throwHttp = throwIO . HttpExceptionContentWrapper 107 108toHttpException :: Request -> HttpExceptionContentWrapper -> HttpException 109toHttpException req (HttpExceptionContentWrapper e) = HttpExceptionRequest req e 110 111-- | An exception which may be generated by this library 112-- 113-- @since 0.5.0 114data HttpException 115 = HttpExceptionRequest Request HttpExceptionContent 116 -- ^ Most exceptions are specific to a 'Request'. Inspect the 117 -- 'HttpExceptionContent' value for details on what occurred. 118 -- 119 -- @since 0.5.0 120 | InvalidUrlException String String 121 -- ^ A URL (first field) is invalid for a given reason 122 -- (second argument). 123 -- 124 -- @since 0.5.0 125 deriving (Show, T.Typeable) 126instance Exception HttpException 127 128data HttpExceptionContent 129 = StatusCodeException (Response ()) S.ByteString 130 -- ^ Generated by the @parseUrlThrow@ function when the 131 -- server returns a non-2XX response status code. 132 -- 133 -- May include the beginning of the response body. 134 -- 135 -- @since 0.5.0 136 | TooManyRedirects [Response L.ByteString] 137 -- ^ The server responded with too many redirects for a 138 -- request. 139 -- 140 -- Contains the list of encountered responses containing 141 -- redirects in reverse chronological order; including last 142 -- redirect, which triggered the exception and was not 143 -- followed. 144 -- 145 -- @since 0.5.0 146 | OverlongHeaders 147 -- ^ Either too many headers, or too many total bytes in a 148 -- single header, were returned by the server, and the 149 -- memory exhaustion protection in this library has kicked 150 -- in. 151 -- 152 -- @since 0.5.0 153 | ResponseTimeout 154 -- ^ The server took too long to return a response. This can 155 -- be altered via 'responseTimeout' or 156 -- 'managerResponseTimeout'. 157 -- 158 -- @since 0.5.0 159 | ConnectionTimeout 160 -- ^ Attempting to connect to the server timed out. 161 -- 162 -- @since 0.5.0 163 | ConnectionFailure SomeException 164 -- ^ An exception occurred when trying to connect to the 165 -- server. 166 -- 167 -- @since 0.5.0 168 | InvalidStatusLine S.ByteString 169 -- ^ The status line returned by the server could not be parsed. 170 -- 171 -- @since 0.5.0 172 | InvalidHeader S.ByteString 173 -- ^ The given response header line could not be parsed 174 -- 175 -- @since 0.5.0 176 | InvalidRequestHeader S.ByteString 177 -- ^ The given request header is not compliant (e.g. has newlines) 178 -- 179 -- @since 0.5.14 180 | InternalException SomeException 181 -- ^ An exception was raised by an underlying library when 182 -- performing the request. Most often, this is caused by a 183 -- failing socket action or a TLS exception. 184 -- 185 -- @since 0.5.0 186 | ProxyConnectException S.ByteString Int Status 187 -- ^ A non-200 status code was returned when trying to 188 -- connect to the proxy server on the given host and port. 189 -- 190 -- @since 0.5.0 191 | NoResponseDataReceived 192 -- ^ No response data was received from the server at all. 193 -- This exception may deserve special handling within the 194 -- library, since it may indicate that a pipelining has been 195 -- used, and a connection thought to be open was in fact 196 -- closed. 197 -- 198 -- @since 0.5.0 199 | TlsNotSupported 200 -- ^ Exception thrown when using a @Manager@ which does not 201 -- have support for secure connections. Typically, you will 202 -- want to use @tlsManagerSettings@ from @http-client-tls@ 203 -- to overcome this. 204 -- 205 -- @since 0.5.0 206 | WrongRequestBodyStreamSize Word64 Word64 207 -- ^ The request body provided did not match the expected size. 208 -- 209 -- Provides the expected and actual size. 210 -- 211 -- @since 0.4.31 212 | ResponseBodyTooShort Word64 Word64 213 -- ^ The returned response body is too short. Provides the 214 -- expected size and actual size. 215 -- 216 -- @since 0.5.0 217 | InvalidChunkHeaders 218 -- ^ A chunked response body had invalid headers. 219 -- 220 -- @since 0.5.0 221 | IncompleteHeaders 222 -- ^ An incomplete set of response headers were returned. 223 -- 224 -- @since 0.5.0 225 | InvalidDestinationHost S.ByteString 226 -- ^ The host we tried to connect to is invalid (e.g., an 227 -- empty string). 228 | HttpZlibException ZlibException 229 -- ^ An exception was thrown when inflating a response body. 230 -- 231 -- @since 0.5.0 232 | InvalidProxyEnvironmentVariable Text Text 233 -- ^ Values in the proxy environment variable were invalid. 234 -- Provides the environment variable name and its value. 235 -- 236 -- @since 0.5.0 237 | ConnectionClosed 238 -- ^ Attempted to use a 'Connection' which was already closed 239 -- 240 -- @since 0.5.0 241 | InvalidProxySettings Text 242 -- ^ Proxy settings are not valid (Windows specific currently) 243 -- @since 0.5.7 244 deriving (Show, T.Typeable) 245 246-- Purposely not providing this instance, since we don't want users to 247-- accidentally try and catch these exceptions instead of HttpException 248-- 249-- instance Exception HttpExceptionContent 250 251 252-- This corresponds to the description of a cookie detailed in Section 5.3 \"Storage Model\" 253data Cookie = Cookie 254 { cookie_name :: S.ByteString 255 , cookie_value :: S.ByteString 256 , cookie_expiry_time :: UTCTime 257 , cookie_domain :: S.ByteString 258 , cookie_path :: S.ByteString 259 , cookie_creation_time :: UTCTime 260 , cookie_last_access_time :: UTCTime 261 , cookie_persistent :: Bool 262 , cookie_host_only :: Bool 263 , cookie_secure_only :: Bool 264 , cookie_http_only :: Bool 265 } 266 deriving (Read, Show, T.Typeable) 267 268newtype CookieJar = CJ { expose :: [Cookie] } 269 deriving (Read, Show, T.Typeable) 270 271-- | Instead of '(==)'. 272-- 273-- Since there was some confusion in the history of this library about how the 'Eq' instance 274-- should work, it was removed for clarity, and replaced by 'equal' and 'equiv'. 'equal' 275-- gives you equality of all fields of the 'Cookie' record. 276-- 277-- @since 0.7.0 278equalCookie :: Cookie -> Cookie -> Bool 279equalCookie a b = and 280 [ cookie_name a == cookie_name b 281 , cookie_value a == cookie_value b 282 , cookie_expiry_time a == cookie_expiry_time b 283 , cookie_domain a == cookie_domain b 284 , cookie_path a == cookie_path b 285 , cookie_creation_time a == cookie_creation_time b 286 , cookie_last_access_time a == cookie_last_access_time b 287 , cookie_persistent a == cookie_persistent b 288 , cookie_host_only a == cookie_host_only b 289 , cookie_secure_only a == cookie_secure_only b 290 , cookie_http_only a == cookie_http_only b 291 ] 292 293-- | Equality of name, domain, path only. This corresponds to step 11 of the algorithm 294-- described in Section 5.3 \"Storage Model\". See also: 'equal'. 295-- 296-- @since 0.7.0 297equivCookie :: Cookie -> Cookie -> Bool 298equivCookie a b = name_matches && domain_matches && path_matches 299 where name_matches = cookie_name a == cookie_name b 300 domain_matches = CI.foldCase (cookie_domain a) == CI.foldCase (cookie_domain b) 301 path_matches = cookie_path a == cookie_path b 302 303-- | Instead of @instance Ord Cookie@. See 'equalCookie', 'equivCookie'. 304-- 305-- @since 0.7.0 306compareCookies :: Cookie -> Cookie -> Ordering 307compareCookies c1 c2 308 | S.length (cookie_path c1) > S.length (cookie_path c2) = LT 309 | S.length (cookie_path c1) < S.length (cookie_path c2) = GT 310 | cookie_creation_time c1 > cookie_creation_time c2 = GT 311 | otherwise = LT 312 313-- | See 'equalCookie'. 314-- 315-- @since 0.7.0 316equalCookieJar :: CookieJar -> CookieJar -> Bool 317equalCookieJar (CJ cj1) (CJ cj2) = and $ zipWith equalCookie cj1 cj2 318 319-- | See 'equalCookieJar', 'equalCookie'. 320-- 321-- @since 0.7.0 322equivCookieJar :: CookieJar -> CookieJar -> Bool 323equivCookieJar cj1 cj2 = and $ 324 zipWith equivCookie (DL.sortBy compareCookies $ expose cj1) (DL.sortBy compareCookies $ expose cj2) 325 326instance Semigroup CookieJar where 327 (CJ a) <> (CJ b) = CJ (DL.nubBy equivCookie $ DL.sortBy mostRecentFirst $ a <> b) 328 where mostRecentFirst c1 c2 = 329 -- inverse so that recent cookies are kept by nub over older 330 if cookie_creation_time c1 > cookie_creation_time c2 331 then LT 332 else GT 333 334-- | Since 1.9 335instance Data.Monoid.Monoid CookieJar where 336 mempty = CJ [] 337#if !(MIN_VERSION_base(4,11,0)) 338 mappend = (<>) 339#endif 340 341-- | Define a HTTP proxy, consisting of a hostname and port number. 342 343data Proxy = Proxy 344 { proxyHost :: S.ByteString -- ^ The host name of the HTTP proxy. 345 , proxyPort :: Int -- ^ The port number of the HTTP proxy. 346 } 347 deriving (Show, Read, Eq, Ord, T.Typeable) 348 349-- | When using one of the 'RequestBodyStream' \/ 'RequestBodyStreamChunked' 350-- constructors, you must ensure that the 'GivesPopper' can be called multiple 351-- times. Usually this is not a problem. 352-- 353-- The 'RequestBodyStreamChunked' will send a chunked request body. Note that 354-- not all servers support this. Only use 'RequestBodyStreamChunked' if you 355-- know the server you're sending to supports chunked request bodies. 356-- 357-- Since 0.1.0 358data RequestBody 359 = RequestBodyLBS L.ByteString 360 | RequestBodyBS S.ByteString 361 | RequestBodyBuilder Int64 Builder 362 | RequestBodyStream Int64 (GivesPopper ()) 363 | RequestBodyStreamChunked (GivesPopper ()) 364 | RequestBodyIO (IO RequestBody) 365 -- ^ Allows creation of a @RequestBody@ inside the @IO@ monad, which is 366 -- useful for making easier APIs (like @setRequestBodyFile@). 367 -- 368 -- @since 0.4.28 369 deriving T.Typeable 370-- | 371-- 372-- Since 0.4.12 373instance IsString RequestBody where 374 fromString str = RequestBodyBS (fromString str) 375instance Monoid RequestBody where 376 mempty = RequestBodyBS S.empty 377#if !(MIN_VERSION_base(4,11,0)) 378 mappend = (<>) 379#endif 380 381instance Semigroup RequestBody where 382 x0 <> y0 = 383 case (simplify x0, simplify y0) of 384 (Left (i, x), Left (j, y)) -> RequestBodyBuilder (i + j) (x <> y) 385 (Left x, Right y) -> combine (builderToStream x) y 386 (Right x, Left y) -> combine x (builderToStream y) 387 (Right x, Right y) -> combine x y 388 where 389 combine (Just i, x) (Just j, y) = RequestBodyStream (i + j) (combine' x y) 390 combine (_, x) (_, y) = RequestBodyStreamChunked (combine' x y) 391 392 combine' :: GivesPopper () -> GivesPopper () -> GivesPopper () 393 combine' x y f = x $ \x' -> y $ \y' -> combine'' x' y' f 394 395 combine'' :: Popper -> Popper -> NeedsPopper () -> IO () 396 combine'' x y f = do 397 istate <- newIORef $ Left (x, y) 398 f $ go istate 399 400 go istate = do 401 state <- readIORef istate 402 case state of 403 Left (x, y) -> do 404 bs <- x 405 if S.null bs 406 then do 407 writeIORef istate $ Right y 408 y 409 else return bs 410 Right y -> y 411 412simplify :: RequestBody -> Either (Int64, Builder) (Maybe Int64, GivesPopper ()) 413simplify (RequestBodyLBS lbs) = Left (L.length lbs, fromLazyByteString lbs) 414simplify (RequestBodyBS bs) = Left (fromIntegral $ S.length bs, fromByteString bs) 415simplify (RequestBodyBuilder len b) = Left (len, b) 416simplify (RequestBodyStream i gp) = Right (Just i, gp) 417simplify (RequestBodyStreamChunked gp) = Right (Nothing, gp) 418simplify (RequestBodyIO _mbody) = error "FIXME No support for Monoid on RequestBodyIO" 419 420builderToStream :: (Int64, Builder) -> (Maybe Int64, GivesPopper ()) 421builderToStream (len, builder) = 422 (Just len, gp) 423 where 424 gp np = do 425 ibss <- newIORef $ L.toChunks $ toLazyByteString builder 426 np $ do 427 bss <- readIORef ibss 428 case bss of 429 [] -> return S.empty 430 bs:bss' -> do 431 writeIORef ibss bss' 432 return bs 433 434-- | A function which generates successive chunks of a request body, provider a 435-- single empty bytestring when no more data is available. 436-- 437-- Since 0.1.0 438type Popper = IO S.ByteString 439 440-- | A function which must be provided with a 'Popper'. 441-- 442-- Since 0.1.0 443type NeedsPopper a = Popper -> IO a 444 445-- | A function which will provide a 'Popper' to a 'NeedsPopper'. This 446-- seemingly convoluted structure allows for creation of request bodies which 447-- allocate scarce resources in an exception safe manner. 448-- 449-- Since 0.1.0 450type GivesPopper a = NeedsPopper a -> IO a 451 452-- | All information on how to connect to a host and what should be sent in the 453-- HTTP request. 454-- 455-- If you simply wish to download from a URL, see 'parseRequest'. 456-- 457-- The constructor for this data type is not exposed. Instead, you should use 458-- either the 'defaultRequest' value, or 'parseRequest' to 459-- construct from a URL, and then use the records below to make modifications. 460-- This approach allows http-client to add configuration options without 461-- breaking backwards compatibility. 462-- 463-- For example, to construct a POST request, you could do something like: 464-- 465-- > initReq <- parseRequest "http://www.example.com/path" 466-- > let req = initReq 467-- > { method = "POST" 468-- > } 469-- 470-- For more information, please see 471-- <http://www.yesodweb.com/book/settings-types>. 472-- 473-- Since 0.1.0 474data Request = Request 475 { method :: Method 476 -- ^ HTTP request method, eg GET, POST. 477 -- 478 -- Since 0.1.0 479 , secure :: Bool 480 -- ^ Whether to use HTTPS (ie, SSL). 481 -- 482 -- Since 0.1.0 483 , host :: S.ByteString 484 -- ^ Requested host name, used for both the IP address to connect to and 485 -- the @host@ request header. 486 -- 487 -- Since 0.1.0 488 , port :: Int 489 -- ^ The port to connect to. Also used for generating the @host@ request header. 490 -- 491 -- Since 0.1.0 492 , path :: S.ByteString 493 -- ^ Everything from the host to the query string. 494 -- 495 -- Since 0.1.0 496 , queryString :: S.ByteString 497 -- ^ Query string appended to the path. 498 -- 499 -- Since 0.1.0 500 , requestHeaders :: RequestHeaders 501 -- ^ Custom HTTP request headers 502 -- 503 -- The Content-Length and Transfer-Encoding headers are set automatically 504 -- by this module, and shall not be added to @requestHeaders@. 505 -- 506 -- If not provided by the user, @Host@ will automatically be set based on 507 -- the @host@ and @port@ fields. 508 -- 509 -- Moreover, the Accept-Encoding header is set implicitly to gzip for 510 -- convenience by default. This behaviour can be overridden if needed, by 511 -- setting the header explicitly to a different value. In order to omit the 512 -- Accept-Header altogether, set it to the empty string \"\". If you need an 513 -- empty Accept-Header (i.e. requesting the identity encoding), set it to a 514 -- non-empty white-space string, e.g. \" \". See RFC 2616 section 14.3 for 515 -- details about the semantics of the Accept-Header field. If you request a 516 -- content-encoding not supported by this module, you will have to decode 517 -- it yourself (see also the 'decompress' field). 518 -- 519 -- Note: Multiple header fields with the same field-name will result in 520 -- multiple header fields being sent and therefore it\'s the responsibility 521 -- of the client code to ensure that the rules from RFC 2616 section 4.2 522 -- are honoured. 523 -- 524 -- Since 0.1.0 525 , requestBody :: RequestBody 526 -- ^ Request body to be sent to the server. 527 -- 528 -- Since 0.1.0 529 , proxy :: Maybe Proxy 530 -- ^ Optional HTTP proxy. 531 -- 532 -- Since 0.1.0 533 , hostAddress :: Maybe HostAddress 534 -- ^ Optional resolved host address. May not be used by all backends. 535 -- 536 -- Since 0.1.0 537 , rawBody :: Bool 538 -- ^ If @True@, a chunked and\/or gzipped body will not be 539 -- decoded. Use with caution. 540 -- 541 -- Since 0.1.0 542 , decompress :: S.ByteString -> Bool 543 -- ^ Predicate to specify whether gzipped data should be 544 -- decompressed on the fly (see 'alwaysDecompress' and 545 -- 'browserDecompress'). Argument is the mime type. 546 -- Default: browserDecompress. 547 -- 548 -- Since 0.1.0 549 , redirectCount :: Int 550 -- ^ How many redirects to follow when getting a resource. 0 means follow 551 -- no redirects. Default value: 10. 552 -- 553 -- Since 0.1.0 554 , checkResponse :: Request -> Response BodyReader -> IO () 555 -- ^ Check the response immediately after receiving the status and headers. 556 -- This can be useful for throwing exceptions on non-success status codes. 557 -- 558 -- In previous versions of http-client, this went under the name 559 -- @checkStatus@, but was renamed to avoid confusion about the new default 560 -- behavior (doing nothing). 561 -- 562 -- @since 0.5.0 563 , responseTimeout :: ResponseTimeout 564 -- ^ Number of microseconds to wait for a response (see 'ResponseTimeout' 565 -- for more information). Default: use 'managerResponseTimeout' (which by 566 -- default is 30 seconds). 567 -- 568 -- Since 0.1.0 569 , cookieJar :: Maybe CookieJar 570 -- ^ A user-defined cookie jar. 571 -- If 'Nothing', no cookie handling will take place, \"Cookie\" headers 572 -- in 'requestHeaders' will be sent raw, and 'responseCookieJar' will be 573 -- empty. 574 -- 575 -- Since 0.1.0 576 577 , requestVersion :: HttpVersion 578 -- ^ HTTP version to send to server. 579 -- 580 -- Default: HTTP 1.1 581 -- 582 -- Since 0.4.3 583 584 , onRequestBodyException :: SomeException -> IO () 585 -- ^ How to deal with exceptions thrown while sending the request. 586 -- 587 -- Default: ignore @IOException@s, rethrow all other exceptions. 588 -- 589 -- Since: 0.4.6 590 591 , requestManagerOverride :: Maybe Manager 592 -- ^ A 'Manager' value that should override whatever @Manager@ value was 593 -- passed in to the HTTP request function manually. This is useful when 594 -- dealing with implicit global managers, such as in @Network.HTTP.Simple@ 595 -- 596 -- @since 0.4.28 597 598 , shouldStripHeaderOnRedirect :: HeaderName -> Bool 599 -- ^ Decide whether a header must be stripped from the request 600 -- when following a redirect. Default: keep all headers intact. 601 -- 602 -- @since 0.6.2 603 } 604 deriving T.Typeable 605 606-- | How to deal with timing out on retrieval of response headers. 607-- 608-- @since 0.5.0 609data ResponseTimeout 610 = ResponseTimeoutMicro !Int 611 -- ^ Wait the given number of microseconds for response headers to 612 -- load, then throw an exception 613 | ResponseTimeoutNone 614 -- ^ Wait indefinitely 615 | ResponseTimeoutDefault 616 -- ^ Fall back to the manager setting ('managerResponseTimeout') or, in its 617 -- absence, Wait 30 seconds and then throw an exception. 618 deriving (Eq, Show) 619 620instance Show Request where 621 show x = unlines 622 [ "Request {" 623 , " host = " ++ show (host x) 624 , " port = " ++ show (port x) 625 , " secure = " ++ show (secure x) 626 , " requestHeaders = " ++ show (DL.map redactSensitiveHeader (requestHeaders x)) 627 , " path = " ++ show (path x) 628 , " queryString = " ++ show (queryString x) 629 --, " requestBody = " ++ show (requestBody x) 630 , " method = " ++ show (method x) 631 , " proxy = " ++ show (proxy x) 632 , " rawBody = " ++ show (rawBody x) 633 , " redirectCount = " ++ show (redirectCount x) 634 , " responseTimeout = " ++ show (responseTimeout x) 635 , " requestVersion = " ++ show (requestVersion x) 636 , "}" 637 ] 638 639redactSensitiveHeader :: Header -> Header 640redactSensitiveHeader ("Authorization", _) = ("Authorization", "<REDACTED>") 641redactSensitiveHeader h = h 642 643-- | A simple representation of the HTTP response. 644-- 645-- Since 0.1.0 646data Response body = Response 647 { responseStatus :: Status 648 -- ^ Status code of the response. 649 -- 650 -- Since 0.1.0 651 , responseVersion :: HttpVersion 652 -- ^ HTTP version used by the server. 653 -- 654 -- Since 0.1.0 655 , responseHeaders :: ResponseHeaders 656 -- ^ Response headers sent by the server. 657 -- 658 -- Since 0.1.0 659 , responseBody :: body 660 -- ^ Response body sent by the server. 661 -- 662 -- Since 0.1.0 663 , responseCookieJar :: CookieJar 664 -- ^ Cookies set on the client after interacting with the server. If 665 -- cookies have been disabled by setting 'cookieJar' to @Nothing@, then 666 -- this will always be empty. 667 -- 668 -- Since 0.1.0 669 , responseClose' :: ResponseClose 670 -- ^ Releases any resource held by this response. If the response body 671 -- has not been fully read yet, doing so after this call will likely 672 -- be impossible. 673 -- 674 -- Since 0.1.0 675 } 676 deriving (Show, T.Typeable, Functor, Data.Foldable.Foldable, Data.Traversable.Traversable) 677 678-- Purposely not providing this instance. It used to use 'equivCookieJar' 679-- semantics before 0.7.0, but should, if anything, use 'equalCookieJar' 680-- semantics. 681-- 682-- instance Exception Eq 683 684newtype ResponseClose = ResponseClose { runResponseClose :: IO () } 685 deriving T.Typeable 686instance Show ResponseClose where 687 show _ = "ResponseClose" 688 689-- | Settings for a @Manager@. Please use the 'defaultManagerSettings' function and then modify 690-- individual settings. For more information, see <http://www.yesodweb.com/book/settings-types>. 691-- 692-- Since 0.1.0 693data ManagerSettings = ManagerSettings 694 { managerConnCount :: Int 695 -- ^ Number of connections to a single host to keep alive. Default: 10. 696 -- 697 -- Since 0.1.0 698 , managerRawConnection :: IO (Maybe NS.HostAddress -> String -> Int -> IO Connection) 699 -- ^ Create an insecure connection. 700 -- 701 -- Since 0.1.0 702 , managerTlsConnection :: IO (Maybe NS.HostAddress -> String -> Int -> IO Connection) 703 -- ^ Create a TLS connection. Default behavior: throw an exception that TLS is not supported. 704 -- 705 -- Since 0.1.0 706 , managerTlsProxyConnection :: IO (S.ByteString -> (Connection -> IO ()) -> String -> Maybe NS.HostAddress -> String -> Int -> IO Connection) 707 -- ^ Create a TLS proxy connection. Default behavior: throw an exception that TLS is not supported. 708 -- 709 -- Since 0.2.2 710 , managerResponseTimeout :: ResponseTimeout 711 -- ^ Default timeout to be applied to requests which do not provide a 712 -- timeout value. 713 -- 714 -- Default is 30 seconds 715 -- 716 -- @since 0.5.0 717 , managerRetryableException :: SomeException -> Bool 718 -- ^ Exceptions for which we should retry our request if we were reusing an 719 -- already open connection. In the case of IOExceptions, for example, we 720 -- assume that the connection was closed on the server and therefore open a 721 -- new one. 722 -- 723 -- Since 0.1.0 724 , managerWrapException :: forall a. Request -> IO a -> IO a 725 -- ^ Action wrapped around all attempted @Request@s, usually used to wrap 726 -- up exceptions in library-specific types. 727 -- 728 -- Default: wrap all @IOException@s in the @InternalException@ constructor. 729 -- 730 -- @since 0.5.0 731 , managerIdleConnectionCount :: Int 732 -- ^ Total number of idle connection to keep open at a given time. 733 -- 734 -- This limit helps deal with the case where you are making a large number 735 -- of connections to different hosts. Without this limit, you could run out 736 -- of file descriptors. Additionally, it can be set to zero to prevent 737 -- reuse of any connections. Doing this is useful when the server your application 738 -- is talking to sits behind a load balancer. 739 -- 740 -- Default: 512 741 -- 742 -- Since 0.3.7 743 , managerModifyRequest :: Request -> IO Request 744 -- ^ Perform the given modification to a @Request@ before performing it. 745 -- 746 -- This function may be called more than once during request processing. 747 -- see https://github.com/snoyberg/http-client/issues/350 748 -- 749 -- Default: no modification 750 -- 751 -- Since 0.4.4 752 , managerModifyResponse :: Response BodyReader -> IO (Response BodyReader) 753 -- ^ Perform the given modification to a @Response@ after receiving it. 754 -- 755 -- Default: no modification 756 -- 757 -- @since 0.5.5 758 , managerProxyInsecure :: ProxyOverride 759 -- ^ How HTTP proxy server settings should be discovered. 760 -- 761 -- Default: respect the @proxy@ value on the @Request@ itself. 762 -- 763 -- Since 0.4.7 764 , managerProxySecure :: ProxyOverride 765 -- ^ How HTTPS proxy server settings should be discovered. 766 -- 767 -- Default: respect the @proxy@ value on the @Request@ itself. 768 -- 769 -- Since 0.4.7 770 } 771 deriving T.Typeable 772 773-- | How the HTTP proxy server settings should be discovered. 774-- 775-- Since 0.4.7 776newtype ProxyOverride = ProxyOverride 777 { runProxyOverride :: Bool -> IO (Request -> Request) 778 } 779 deriving T.Typeable 780 781-- | Keeps track of open connections for keep-alive. 782-- 783-- If possible, you should share a single 'Manager' between multiple threads and requests. 784-- 785-- Since 0.1.0 786data Manager = Manager 787 { mConns :: KeyedPool ConnKey Connection 788 , mResponseTimeout :: ResponseTimeout 789 -- ^ Copied from 'managerResponseTimeout' 790 , mRetryableException :: SomeException -> Bool 791 , mWrapException :: forall a. Request -> IO a -> IO a 792 , mModifyRequest :: Request -> IO Request 793 , mSetProxy :: Request -> Request 794 , mModifyResponse :: Response BodyReader -> IO (Response BodyReader) 795 -- ^ See 'managerProxy' 796 } 797 deriving T.Typeable 798 799class HasHttpManager a where 800 getHttpManager :: a -> Manager 801instance HasHttpManager Manager where 802 getHttpManager = id 803 804data ConnsMap 805 = ManagerClosed 806 | ManagerOpen {-# UNPACK #-} !Int !(Map.Map ConnKey (NonEmptyList Connection)) 807 808data NonEmptyList a = 809 One a UTCTime | 810 Cons a Int UTCTime (NonEmptyList a) 811 deriving T.Typeable 812 813-- | Hostname or resolved host address. 814data ConnHost = 815 HostName Text | 816 HostAddress NS.HostAddress 817 deriving (Eq, Show, Ord, T.Typeable) 818 819-- | @ConnKey@ consists of a hostname, a port and a @Bool@ 820-- specifying whether to use SSL. 821data ConnKey 822 = CKRaw (Maybe HostAddress) {-# UNPACK #-} !S.ByteString !Int 823 | CKSecure (Maybe HostAddress) {-# UNPACK #-} !S.ByteString !Int 824 | CKProxy 825 {-# UNPACK #-} !S.ByteString 826 !Int 827 828 -- Proxy-Authorization request header 829 (Maybe S.ByteString) 830 831 -- ultimate host 832 {-# UNPACK #-} !S.ByteString 833 834 -- ultimate port 835 !Int 836 deriving (Eq, Show, Ord, T.Typeable) 837 838-- | Status of streaming a request body from a file. 839-- 840-- Since 0.4.9 841data StreamFileStatus = StreamFileStatus 842 { fileSize :: Int64 843 , readSoFar :: Int64 844 , thisChunkSize :: Int 845 } 846 deriving (Eq, Show, Ord, T.Typeable) 847