1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202
|
--
-- HTTP client for use with io-streams
--
-- Copyright © 2012-2021 Athae Eredh Siniath and Others
--
-- The code in this file, and the program it is a part of, is
-- made available to you by its authors as open source software:
-- you can redistribute it and/or modify it under the terms of
-- the BSD licence.
--
{-# LANGUAGE OverloadedStrings #-}
{-# OPTIONS -fno-warn-orphans #-}
-- |
-- Maintainer: Andrew Cowie
-- Stability: Experimental
--
-- /Overview/
--
-- A simple HTTP client library, using the Snap Framework's @io-streams@
-- library to handle the streaming I\/O. The @http-streams@ API is designed
-- for ease of use when querying web services and dealing with the result.
--
-- Given:
--
-- > {-# LANGUAGE OverloadedStrings #-}
-- >
-- > import System.IO.Streams (InputStream, OutputStream, stdout)
-- > import qualified System.IO.Streams as Streams
-- > import qualified Data.ByteString as S
--
-- and this library:
--
-- > import Network.Http.Client
--
-- the underlying API is straight-forward. In particular, constructing the
-- 'Request' to send is quick and to the point:
--
-- @
-- main :: IO ()
-- main = do
-- \ c <- 'openConnection' \"www.example.com\" 80
--
-- \ let q = 'buildRequest1' $ do
-- 'http' GET \"\/\"
-- 'setAccept' \"text/html\"
--
-- \ 'sendRequest' c q 'emptyBody'
--
-- \ `receiveResponse` c (\\p i -> do
-- xm <- Streams.read i
-- case xm of
-- Just x -> S.putStr x
-- Nothing -> \"\")
--
-- \ 'closeConnection' c
-- @
--
-- which would print the first chunk of the response back from the
-- server. Obviously in real usage you'll do something more interesting
-- with the 'Response' in the handler function, and consume the entire
-- response body from the InputStream ByteString.
--
-- Because this is all happening in 'IO' (the defining feature of
-- @io-streams@!), you can ensure resource cleanup on normal or
-- abnormal termination by using @Control.Exception@'s standard
-- 'Control.Exception.bracket' function; see 'closeConnection' for an
-- example. For the common case we have a utility function which
-- wraps @bracket@ for you:
--
-- @
-- foo :: IO ByteString
-- foo = 'withConnection' ('openConnection' \"www.example.com\" 80) doStuff
--
-- doStuff :: Connection -> IO ByteString
-- @
--
-- There are also a set of convenience APIs that do just that, along with
-- the tedious bits like parsing URLs. For example, to do an HTTP GET and
-- stream the response body to stdout, you can simply do:
--
-- @
-- 'get' \"http:\/\/www.example.com\/file.txt\" (\\p i -> Streams.connect i stdout)
-- @
--
-- which on the one hand is \"easy\" while on the other exposes the the
-- 'Response' and InputStream for you to read from. Of course, messing
-- around with URLs is all a bit inefficient, so if you already have e.g.
-- hostname and path, or if you need more control over the request being
-- created, then the underlying @http-streams@ API is simple enough to use
-- directly.
--
module Network.Http.Client (
-- * Connecting to server
Hostname,
Port,
Connection,
openConnection,
openConnectionUnix,
-- * Building Requests
-- | You setup a request using the RequestBuilder monad, and
-- get the resultant Request object by running 'buildRequest1'. The
-- first call doesn't have to be to 'http', but it looks better when
-- it is, don't you think?
Method(..),
RequestBuilder,
buildRequest1,
buildRequest,
http,
setHostname,
setAccept,
setAccept',
setAuthorizationBasic,
ContentType,
setContentType,
setContentLength,
FieldName,
Boundary,
randomBoundary,
setContentMultipart,
setExpectContinue,
setTransferEncoding,
setHeader,
-- * Sending HTTP request
Request,
Response,
getHostname,
sendRequest,
emptyBody,
simpleBody,
fileBody,
inputStreamBody,
encodedFormBody,
multipartFormBody,
Part,
simplePart,
filePart,
inputStreamPart,
jsonBody,
-- * Processing HTTP response
receiveResponse,
receiveResponseRaw,
unsafeReceiveResponse,
UnexpectedCompression,
StatusCode,
getStatusCode,
getStatusMessage,
getHeader,
debugHandler,
simpleHandler,
simpleHandler',
HttpClientError(..),
jsonHandler,
-- * Resource cleanup
closeConnection,
withConnection,
-- * Convenience APIs
-- | Some simple functions for making requests with useful defaults.
-- There's no @head@ function for the usual reason of needing to
-- avoid collision with @Prelude@.
--
-- These convenience functions work with @http@ and @https@, but
-- note that if you retrieve an @https@ URL, you /must/ wrap your
-- @main@ function with 'OpenSSL.withOpenSSL' to initialize the
-- native openssl library code.
--
URL,
get,
TooManyRedirects,
post,
postForm,
put,
-- * Secure connections
openConnectionSSL,
baselineContextSSL,
modifyContextSSL,
establishConnection,
-- * Testing support
makeConnection,
Headers,
getHeaders,
getHeadersFull,
packBoundary,
-- * Deprecated
concatHandler,
concatHandler',
getRequestHeaders
) where
import Network.Http.Types
import Network.Http.Connection
import Network.Http.Inconvenience
|