úÎőTďB      !"#$%&'()*+,-./0123456789:;<=>?@A Trustworthy+;HMB)Note: only works for nonnegative naturalsCDEFGHIJKLMNOBIO CGFEDHIJKLMNOBNone+"PQRSTUVWXYZ[\]^"PRUV"PQRSTUVWXYZ[\]^None+#A connection to a web server._5will be used as the Host: header in the HTTP request.`,called when the connection should be closed.$jCreate a raw Connection object from the given parts. This is primarily of use when teseting, for example: łfakeConnection :: IO Connection fakeConnection = do o <- Streams.nullOutput i <- Streams.nullInput c <- makeConnection "www.example.com" (return()) o i return cris an idiom we use frequently in testing and benchmarking, usually replacing the InputStream with something like: Z x' <- S.readFile "properly-formatted-response.txt" i <- Streams.fromByteString x'2If you're going to do that, keep in mind that you must  have CR-LF pairs after each header line and between the header and body to be compliant with the HTTP protocol; otherwise, parsers will reject your message.% Given an IO action producing a #L, and a computation that needs one, runs the computation, cleaning up the  Connection afterwards. Ř x <- withConnection (openConnection "s3.example.com" 80) $ (\c -> do q <- buildRequest $ do http GET "/bucket42/object/149" sendRequest c q emptyBody ... return "blah")Lwhich can make the code making an HTTP request a lot more straight-forward.Wraps Control.Exception's a.&gIn order to make a request you first establish the TCP connection to the server over which to send it.lOrdinarily you would supply the host part of the URL here and it will be used as the value of the HTTP 1.1 Host:M field. However, you can specify any server name or IP addresss and set the Host: value later with  when building the request.Usage is as follows: D c <- openConnection "localhost" 80 ... closeConnection cMore likely, you'll use %3 to wrap the call in order to ensure finalization.úHTTP pipelining is supported; you can reuse the connection to a web server, but it's up to you to ensure you match the number of requests sent to the number of responses read, and to process those responses in order. This is all assuming that the serverď supports pipelining; be warned that not all do. Web browsers go to extraordinary lengths to probe this; you probably only want to do pipelining under controlled conditions. Otherwise just open a new connection for subsequent requests.')Open a secure connection to a web server. Ľimport OpenSSL (withOpenSSL) main :: IO () main = do ctx <- baselineContextSSL c <- openConnectionSSL ctx "api.github.com" 443 ... closeConnection c„If you want to tune the parameters used in making SSL connections, manually specify certificates, etc, then setup your own context: simport OpenSSL.Session (SSLContext) import qualified OpenSSL.Session as SSL ... ctx <- SSL.context ...See OpenSSL.Session.$Crypto is as provided by the system openssl library, as wrapped by the  HsOpenSSL package and openssl-streams.#/There is no longer a need to call  withOpenSSLE explicitly; the initialization is invoked once per process for you/(Having composed a Č object with the headers and metadata for this connection, you can now send the request to the server, along with the entity body, if there is one. For the rather common case of HTTP requests like  that don't send data, use . as the output stream:  sendRequest c q emptyBodyFor  and  requests, you can use / or 0: to send content to the server, or you can work with the  io-streams API directly: _ sendRequest c q (\o -> Streams.write (Just (Builder.fromString "Hello World\n")) o))2Get the virtual hostname that will be used as the Host:R header in the HTTP 1.1 request. Per RFC 2616 § 14.23, this will be of the form  hostname:port? if the port number is other than the default, ie 80 for HTTP.+ÓGet the headers that will be sent with this request. You likely won't need this but there are some corner cases where people need to make calculations based on all the headers before they go out over the wire.WIf you'd like the request headers as an association list, import the header functions: import Network.Http.Types then use  as follows:.let kvs = retreiveHeaders $ getHeadersFull c q:t kvs:: [(ByteString, ByteString)],Handle the response coming back from the server. This function hands control to a handler function you supply, passing you the ) object with the response headers and an b containing the entity body.YFor example, if you just wanted to print the first chunk of the content from the server: › receiveResponse c (\p i -> do m <- Streams.read i case m of Just bytes -> putStr bytes Nothing -> return ()):Obviously, you can do more sophisticated things with the b(, which is the whole point of having an  io-streams based HTTP client library.BThe final value from the handler function is the return value of receiveResponse, if you need it.Throws "O if it doesn't know how to handle the compression format used in the response.-!This is a specialized variant of , that  explicitly¸ does not handle the content encoding of the response body stream (it will not decompress anything). Unless you really want the raw gzipped content coming down from the server, use receiveResponse..mUse this for the common case of the HTTP methods that only send headers and which have no entity body, i.e.  requests./JSpecify a local file to be sent to the server as the body of the request.You use this partially applied: , sendRequest c q (fileBody "/etc/passwd")Note that the type of (fileBody "/path/to/file")2 is just what you need for the third argument to (, namely:t filePath "hello.txt" :: OutputStream Builder -> IO ()0Read from a pre-existing bĐ and pipe that through to the connection to the server. This is useful in the general case where something else has handed you stream to read from and you want to use it as the entity body for the request.You use this partially applied: h i <- getStreamFromVault -- magic, clearly sendRequest c q (inputStreamBody i)xThis function maps "Builder.fromByteString" over the input, which will be efficient if the ByteString chunks are large.10Print the response headers and response body to stdout. You can use this with ,G or one of the convenience functions when testing. For example, doing: ś c <- openConnection "kernel.operationaldynamics.com" 58080 q <- buildRequest $ do http GET "/time" sendRequest c q emptyBody receiveResponse c debugHandlerwould print out: ÇHTTP/1.1 200 OK Transfer-Encoding: chunked Content-Type: text/plain Vary: Accept-Encoding Server: Snap/0.9.2.4 Content-Encoding: gzip Date: Mon, 21 Jan 2013 06:13:37 GMT Mon 21 Jan 13, 06:13:37.303Zor thereabouts.2ĽSometimes you just want the entire response body as a single blob. This function concatonates all the bytes from the response into a ByteString. If using the main  http-streams# API, you would use it as follows: 6 ... x' <- receiveResponse c concatHandler ...xThe methods in the convenience API all take a function to handle the response; this function is passed directly to the ,K call underlying the request. Thus this utility function can be used for get as well: @ x' <- get "http://www.example.com/document.txt" concatHandlerĎEither way, the usual caveats about allocating a single object from streaming I/O apply: do not use this if you are not absolutely certain that the response body will fit in a reasonable amount of memory.ĄNote that this function makes no discrimination based on the response's HTTP status code. You're almost certainly better off writing your own handler function.3ŽShutdown the connection. You need to call this release the underlying socket file descriptor and related network resources. To do so reliably, use this in conjunction with & in a call to a: ˙-- -- Make connection, cleaning up afterward -- foo :: IO ByteString foo = bracket (openConnection "localhost" 80) (closeConnection) (doStuff) -- -- Actually use Connection to send Request and receive Response -- doStuff :: Connection -> IO ByteString or, just use %.€While returning a ByteString is probably the most common use case, you could conceivably do more processing of the response in doStuff and have it and foo return a different type.#c_`de$will be used as the Host: header in the HTTP request.9an action to be called when the connection is terminated./write end of the HTTP client-server connection..read end of the HTTP client-server connection.%&'f()*+,-./0123g"#c_`de$%&'()*+,-./0123#c_`de$%&'f()*+,-./0123gNone+; hURL-escapes a string (see  3http://tools.ietf.org/html/rfc2396.html#section-2.4)iURL-escapes a string (see  3http://tools.ietf.org/html/rfc2396.html#section-2.4 ) into a j.8iModify the context being used to configure the SSL tunnel used by the convenience API functions to make https://, connections. The default is that setup by :.9˙(Given a URL, work out whether it is normal or secure, and then open the connection to the webserver including setting the appropriate default port if one was not specified in the URL. This is what powers the convenience API, but you may find it useful in composing your own similar functions.‘For example (on the assumption that your server behaves when given an absolute URI as the request path), this will open a connection to server www.example.com port 443 and request  /photo.jpg: ‹ let url = "https://www.example.com/photo.jpg" c <- establishConnection url q <- buildRequest $ do http GET url ...:JCreates a basic SSL context. This is the SSL context used if you make an  "https://"j request using one of the convenience functions. It configures OpenSSL to use the default set of ciphers.xOn Linux systems, this function also configures OpenSSL to verify certificates using the system certificates stored in /etc/ssl/certs.On other systems, &no certificate validation is performed by the generated kÓ because there is no canonical place to find the set of system certificates. When using this library on a non-Linux system, you are encouraged to install the system certificates somewhere and create your own k.;ĽIssue an HTTP GET request and pass the resultant response to the supplied handler function. This code will silently follow redirects, to a maximum depth of 5 hops.The handler function is as for ,P, so you can use one of the supplied convenience handlers if you're in a hurry: 8 x' <- get "http://www.bbc.co.uk/news/" concatHandlerľBut as ever the disadvantage of doing this is that you're not doing anything intelligent with the HTTP response status code. If you want an exception raised in the event of a non 2xx response, you can use: 9 x' <- get "http://www.bbc.co.uk/news/" concatHandler']but for anything more refined you'll find it easy to simply write your own handler function.Throws 6% if more than 5 redirects are thrown.<USend content to a server via an HTTP POST request. Use this function if you have an l with the body content.=Send form data to a server via an HTTP POST request. This is the usual use case; most services expect the body to be MIME type !application/x-www-form-urlencoded‡ as this is what conventional web browsers send on form submission. If you want to POST to a URL with an arbitrary Content-Type, use <.>˙Specify name/value pairs to be sent to the server in the manner used by web browsers when submitting a form via a POST request. Parameters will be URL encoded per RFC 2396 and combined into a single string which will be sent as the body of your request.You use this partially applied: ‘ let nvs = [("name","Kermit"), ("type","frog")] ("role","stagehand")] sendRequest c q (encodedFormBody nvs)-Note that it's going to be up to you to call  with a value of #"application/x-www-form-urlencoded"( when building the Request object; the = convenience (which uses this encodedFormBody1 function) takes care of this for you, obviously.?˜Place content on the server at the given URL via an HTTP PUT request, specifying the content type and a function to write the content to the supplied l. You might see: Ź put "http://s3.example.com/bucket42/object149" "text/plain" (fileBody "hello.txt") (\p i -> do putStr $ show p Streams.connect i stdout)@A special case of 2^, this function will return the entire response body as a single ByteString, but will throw 4, if the response status code was other than 2xx.A0If you're working with a data stream that is in application/json!, then chances are you're using aeson[ to handle the JSON to Haskell decoding. If so, then this helper function might be of use. 5 v <- get "http://api.example.com/v1/" jsonHandler*This function feeds the input body to the    attoparsec Parser in order to get the aeson Value type. This is then marshalled to your type represeting the source data, via the FromJSON typeclass.@The above example was actually insufficient; when working with aeson you need to fix the type so it knows what FromJSON instance to use. Let's say you're getting Person objects, then it would be L v <- get "http://api.example.com/v1/person/461" jsonHandler :: IO Person=assuming your Person type had a FromJSON instance, of course.Note˙!This function parses a single top level JSON object or array, which is all you're supposed to get if it's a valid document. People do all kinds of crazy things though, so beware. Also, this function (like the "concatHander" convenience) loads the entire response into memory; it's not  streamingž; if you're receiving a document which is (say) a very long array of objects then you may want to implement your own handler function, perhaps using "Streams.parserToInputStream" and the    combinators directly  with a result type of InputStream Value, perhaps  by which you could then iterate over the Values one at a time in constant space.456m7hinop89q:rs;Resource to GET from.9Handler function to receive the response from the server.tuv<Resource to POST to.)MIME type of the request body being sent.,Handler function to write content to server.9Handler function to receive the response from the server.=Resource to POST to.3List of name=value pairs. Will be sent URL-encoded.9Handler function to receive the response from the server.>?Resource to PUT to.)MIME type of the request body being sent.,Handler function to write content to server.9Handler function to receive the response from the server.@Awxy456m789:;v<=>?@A456m7hinop89q:rs;tuv<=>?@Awxy Andrew Cowie ExperimentalNoneB  !"#$%&'()*+,-./0123456789:;<=>?@AB#&  )(./0>,-" 12@45A3%7;6<=?':89$! +*z                   ! " # $ % & ' ( ) * * + , - . /0123456789:;<=>?@ABBCDEFGHIJKLMNOPQRSTUVWXYZ[\0]^_`abcdefghijklmnopqr1stuvwxyz{|}~pqC€‚ƒ„…†‡ˆ‰Š‹Œhttp-streams-0.7.2.6Network.Http.ClientNetwork.Http.UtilitiesNetwork.Http.ResponseParserNetwork.Http.Connection setHostnameNetwork.Http.TypesretreiveHeadersNetwork.Http.InconvenienceData.Aeson.Parserjson' Data.AesonParserhttp-common-0.7.2.0Network.Http.RequestBuildersetExpectContinuesetTransferEncodingsetContentLengthsetContentTypesetAuthorizationBasic setAccept' setAccept setHeaderhttp buildRequestRequestBuilder ContentTypeNetwork.Http.Internal getHeadergetStatusMessage getStatusCodeHostnamePortGETHEADPOSTPUTDELETETRACEOPTIONSCONNECTPATCHMethodRequest StatusCodeResponse getHeadersHeadersUnexpectedCompression ConnectionmakeConnectionwithConnectionopenConnectionopenConnectionSSL sendRequest getHostnamegetRequestHeadersgetHeadersFullreceiveResponsereceiveResponseRaw emptyBodyfileBodyinputStreamBody debugHandler concatHandlercloseConnectionHttpClientErrorTooManyRedirectsURLmodifyContextSSLestablishConnectionbaselineContextSSLgetpostpostFormencodedFormBodyputconcatHandler' jsonHandler unsafeFromNatCSBadCRLastIsCRNoCR FoundCRLF parseRequestreadResponseLinefindCRLFsplitChbreakCh splitHeaderisLWSreadHeaderFields __BITE_SIZE__readResponseHeaderparseStatusLinecrlfreadResponseBody readDecimalreadChunkedBody consumeChunksreadNtransferChunkSizereadFixedLengthBodyreadUnlimitedBodyreadCompressedBody $fExceptionUnexpectedCompressioncHostcClosebaseControl.Exception.Basebracketio-streams-1.3.0.0System.IO.Streams.Internal InputStreamcOutcIncloseSSL$fShowConnection urlEncodeurlEncodeBuilderbytestring-0.10.4.0 Data.ByteString.Builder.InternalBuilderHsOpenSSL-0.11.1.1OpenSSL.Session SSLContext OutputStreamhexdurlEncodeTableglobal establishparseURLpathgetN wrapRedirectsplitURI$fShowHttpClientError$fExceptionHttpClientError$fExceptionTooManyRedirects