>A58      !"#$%&'()*+,-./01234567NoneThe map of headers in a  or . Note that HTTP 9 header field names are case insensitive, so if you call  setHeader  on a field that'6s already defined but with a different capitalization & you will replace the existing value. =A description of the response received from the server. Note 3 unlike other HTTP libraries, the response body is not a part > of this object; that will be streamed in by you when calling  receiveResponse. Like ,  has a Show instance that will output E the status line and response headers as they were received from the  server. CA description of the request that will be sent to the server. Note 2 unlike other HTTP libraries, the request body is not a part of this D object; that will be streamed out by you when actually sending the  request with  sendRequest.  has a useful Show' instance that will output the request A line and headers (as it will be sent over the wire but with the \r 8 characters stripped) which can be handy for debugging. Note that the Host: header is not set until   is called, so you will not see * it in the Show instance (unless you call  setHostname to override  the value inherited from the  Connection). HTTP Methods, as per RFC 2616 #Get the HTTP response status code. @Get the HTTP response status message. Keep in mind that this is  not normative; whereas  values are authoritative. =Lookup a header in the response. HTTP header field names are E case-insensitive, so you can specify the name to lookup however you $ like. If the header is not present Nothing will be returned.  2 let n = case getHeader p "Content-Length" of * Just x' -> read x' :: Int  Nothing -> 0 Dwhich of course is essentially what goes on inside the library when   http-streams7 receives a response from the server and has to figure  out how many bytes to read. EThere is a fair bit of complexity in some of the other HTTP response D fields, so there are a number of specialized functions for reading  those values where we've found them useful. C89:;<=>?@ABCDEFGHIJKLMNOPQRSTUVW XYZ[\]^_`abcdefgh789<=>?@ABCDEFGHIJKLMNOPQRSTUVW X[^_`ac89:;<?>=@BACDEFGHIJLKMPONQRSTUVW  XYZ[\]^_`abcdefgh Trustworthyi*Note: only works for nonnegative naturals jklmnopqrstuvipv jnmlkopqrstuviNonewxyz{|}~z}~wxyz{|}~NoneA connection to a web server. 6will be used as the Host: header in the HTTP request. -called when the connection should be closed. =Create 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 c Cis an idiom we use frequently in testing and benchmarking, usually 0 replacing the InputStream with something like:  8 x' <- S.readFile "properly-formatted-response.txt" % i <- Streams.fromByteString x' If you'+re going to do that, keep in mind that you must have CR-LF A 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 , and a computation 7 that needs one, runs the computation, cleaning up the   Connection afterwards.  J x <- withConnection (openConnection "s3.example.com" 80) $ (\c -> do  q <- buildRequest $ do - http GET "/bucket42/object/149" # sendRequest c q emptyBody  ...  return "blah") :which can make the code making an HTTP request a lot more  straight-forward. Wraps Control.Exception's . 7In order to make a request you first establish the TCP 1 connection to the server over which to send it. FOrdinarily you would supply the host part of the URL here and it will & be used as the value of the HTTP 1.1 Host: field. However, you can 4 specify any server name or IP addresss and set the Host: value  later with  when building the  request. Usage is as follows:  ( c <- openConnection "localhost" 80  ...  closeConnection c More likely, you'll use  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 E requests sent to the number of responses read, and to process those 3 responses in order. This is all assuming that the server supports ; pipelining; be warned that not all do. Web browsers go to C extraordinary lengths to probe this; you probably only want to do C pipelining under controlled conditions. Otherwise just open a new % connection for subsequent requests. *Open a secure connection to a web server. BYou need to wrap this (and subsequent code using this connection)  within a call to  :   import OpenSSL (withOpenSSL)   main :: IO ()  main = withOpenSSL $ do  ctx <- baselineContextSSL 5 c <- openConnectionSSL ctx "api.github.com" 443  ...  closeConnection c CIf you want to tune the parameters used in making SSL connections, B manually specify certificates, etc, then setup your own context:  % import 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. Having composed a * object with the headers and metadata for D this connection, you can now send the request to the server, along F 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 emptyBody For   and   requests, you can use  or  5 to send content to the server, or you can work with  the  io-streams API directly:  sendRequest c q (\o -> F Streams.write (Just (Builder.fromString "Hello World\n")) o) 2Get the virtual hostname that will be used as the Host: header in F the HTTP 1.1 request. Per RFC 2616 14.23, this will be of the form   hostname:port5 if the port number is other than the default, ie 80  for HTTP. ?Handle the response coming back from the server. This function A hands control to a handler function you supply, passing you the  ) object with the response headers and an   containing the entity body. @For example, if you just wanted to print the first chunk of the  content from the server:  # receiveResponse c (\p i -> do  m <- Streams.read b  case m of ( Just bytes -> putStr bytes & Nothing -> return ()) 9Obviously, you can do more sophisticated things with the  (, which is the whole point of having an  io-streams  based HTTP client library. CThe final value from the handler function. is the return value of  receiveResponse, if you need it. @Use this for the common case of the HTTP methods that only send - headers and which have no entity body, i.e.  requests. ASpecify 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") is just what $ you need for the third argument to  , namely :t filePath "hello.txt" :: OutputStream Builder -> IO ()Read from a pre-existing  and pipe that through to the D connection to the server. This is useful in the general case where G 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:  B i <- getStreamFromVault -- magic, clearly ) sendRequest c q (inputStreamBody i) This function maps Builder.fromByteString over the input, which will 2 be efficient if the ByteString chunks are large. 0Print the response headers and response body to stdout . You can  use this with % 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 debugHandler would 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.303Z or thereabouts. CSometimes you just want the entire response body as a single blob. C 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:   ... * x' <- receiveResponse c concatHandler  ... EThe methods in the convenience API all take a function to handle the 3 response; this function is passed directly to the  E call underlying the request. Thus this utility function can be used  for get as well:  B x' <- get "http://www.example.com/document.txt" concatHandler 1Either 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. !;Shutdown the connection. You need to call this release the E underlying socket file descriptor and related network resources. To . do so reliably, use this in conjunction with  in a  call to :   -- + -- Make connection, cleaning up afterward  --   foo :: IO ByteString  foo = bracket $ (openConnection "localhost" 80)  (closeConnection)  (doStuff)   -- A -- Actually use Connection to send Request and receive Response  --  ( doStuff :: Connection -> IO ByteString  or, just use . CWhile 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. will be used as the Host: header in the HTTP request. :an action to be called when the connection is terminated. 0write end of the HTTP client-server connection. /read end of the HTTP client-server connection.  ! ! ! None #<The RequestBuilder monad allows you to abuse do-notation to  conveniently setup a  object. $CRun a RequestBuilder, yielding a Request object you can use on the  given connection.   q <- buildRequest $ do & http POST "/api/v1/messages" + setContentType "application/json" + setHostname "clue.example.com" 80  setAccept "text/html" . setHeader "X-WhoDoneIt" "The Butler"  Obviously it's up to you to later actually send JSON data. Note FThe API of this function changed from version 0.3.1 to verison 0.4.0; H the original requirement to pass a Connection object has been removed, ? thereby allowing you to build your Request before opening the  connection to the web server. %>Begin constructing a Request, starting with the request line. &Set the [virtual]2 hostname for the request. In ordinary conditions  you won't need to call this, as the Host: header is a required D header in HTTP 1.1 and is set directly from the name of the server  you connected to when calling . '?Set a generic header to be sent in the HTTP request. The other B methods in the RequestBuilder API are expressed in terms of this A function, but we recommend you use them where offered for their  stronger types. (@Indicate the content type you are willing to receive in a reply # from the server. For more complex Accept: headers, use  ). )AIndicate the content types you are willing to receive in a reply = from the server in order of preference. A call of the form:  ) setAccept' [("text/html", 1.0), / ("application/xml", 0.8), ! ("*/*", 0)] will result in an Accept: header value of  text/html; q=1.0, application/ xml; q=0.8, */*; q=0.0 as you  would expect. *9Set username and password credentials per the HTTP basic  authentication method.  7 setAuthorizationBasic "Aladdin" "open sesame" will result in an Authorization: header value of  "Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==. Basic authentication does not" use a message digest function to E encipher the password; the above string is only base-64 encoded and @ is thus plain-text visible to any observer on the wire and all B caches and servers at the other end, making basic authentication D completely insecure. A number of web services, however, use SSL to C encrypt the connection that then use HTTP basic authentication to D validate requests. Keep in mind in these cases the secret is still C sent to the servers on the other side and passes in clear through * all layers after the SSL termination. Do not use basic F authentication to protect secure or user-originated privacy-sensitve  information. +CSet the MIME type corresponding to the body of the request you are  sending. Defaults to "text/plain", so usually you need to set  this if  ting. ,2Specify the length of the request body, in bytes. (RFC 2616 requires that we either send a Content-Length header or  use Transfer-Encoding: chunked#. If you know the exact size ahead B of time, then call this function; the body content will still be  streamed out by  io-streams! in more-or-less constant space. 4This function is special: in a PUT or POST request,  http-streams ' will assume chunked transfer-encoding unless you specify a content B length here, in which case you need to ensure your body function # writes precisely that many bytes. ->Specify that this request should set the expectation that the 9 server needs to approve the request before you send it. 4This function is special: in a PUT or POST request,  http-streams / will wait for the server to reply with an HTTP/1.1 100 Continue D status before sending the entity body. This is handled internally; E you will get the real response (be it successful 2xx, client error,  4xx, or server error 5xx) in . In theory, it * should be 417 if the expectation failed. 1Only bother with this if you know the service you're talking to  requires clients to send an Expect: 100-continue header and will % handle it properly. Most servers don' t do any precondition checking, E automatically send an intermediate 100 response, and then just read B the body regardless, making this a bit of a no-op in most cases. "#$%&'()*+,- "#$%&'()*+,-"#$%&'()*+,- None URL-escapes a string (see   3http://tools.ietf.org/html/rfc2396.html#section-2.4) URL-escapes a string (see   3http://tools.ietf.org/html/rfc2396.html#section-2.4 ) into a . /BModify 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 1. 0?Given a URL, work out whether it is normal or secure, and then < open the connection to the webserver including setting the D appropriate default port if one was not specified in the URL. This C is what powers the convenience API, but you may find it useful in ' composing your own similar functions. CFor example (on the assumption that your server behaves when given C an absolute URI as the request path), this will open a connection  to server www.example.com port 443 and request / photo.jpg: 3 let url = "https://www.example.com/photo.jpg"  " c <- establishConnection url  q <- buildRequest $ do  http GET url  ... 1ICreates a basic SSL context. This is the SSL context used if you make an  "https://"4 request using one of the convenience functions. It 7 configures OpenSSL to use the default set of ciphers. BOn Linux systems, this function also configures OpenSSL to verify 6 certificates using the system certificates stored in /etc/ssl/certs. On other systems, &no certificate validation is performed by the  generated - 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 . 2AIssue an HTTP GET request and pass the resultant response to the F supplied handler function. This code will silently follow redirects,  to a maximum depth of 5 hops. The handler function is as for , so you can use one , of the supplied convenience handlers if you're in a hurry:  : x' <- get "http://www.bbc.co.uk/news/" concatHandler 6But as ever the disadvantage of doing this is that you' re not doing F 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:  ; 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. 3<Send content to a server via an HTTP POST request. Use this  function if you have an  with the body content. 4ASend 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 D web browsers send on form submission. If you want to POST to a URL % with an arbitrary Content-Type, use 3. 5 Specify name/3value pairs to be sent to the server in the manner A used by web browsers when submitting a form via a POST request. A 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 4 convenience (which uses this  encodedFormBody2 function) takes care of this for you, obviously. 6=Place content on the server at the given URL via an HTTP PUT B request, specifying the content type and a function to write the  content to the supplied . You might see: A put "http://s3.example.com/bucket42/object149" "text/plain" , (fileBody "hello.txt") (\p i -> do  putStr $ show p ' Streams.connect i stdout) 7A special case of   , this function will return the @ entire response body as a single ByteString, but will throw an 6 exception if the response status code was other than 2xx. ./012Resource to GET from. :Handler function to receive the response from the server. 3Resource to POST to. *MIME type of the request body being sent. -Handler function to write content to server. :Handler function to receive the response from the server. 4Resource to POST to. 4List of name=value pairs. Will be sent URL-encoded. :Handler function to receive the response from the server. 56Resource to PUT to. *MIME type of the request body being sent. -Handler function to write content to server. :Handler function to receive the response from the server. 7./01234567./01234567 Experimental Andrew CowieNone8  !"#$%&'()*+,-./012345678 #$%&()*"+,-'5 7!.23461/0   !"#$%&'()*+ , - . /  0 1 2 3 4 5 6 7 8 9 : ; < = > ? @AABCDEFGHIJ KLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}}~_ -      http-streams-0.5.0.2Network.Http.ClientNetwork.Http.TypesNetwork.Http.Connection sendRequestNetwork.Http.UtilitiesNetwork.Http.ResponseParser setHostnameOpenSSL withOpenSSLNetwork.Http.RequestBuilderNetwork.Http.InconvenienceHeadersResponse StatusCodeRequestMethodPATCHCONNECTOPTIONSTRACEDELETEPUTPOSTHEADGET getStatusCodegetStatusMessage getHeader ConnectionPortHostnamemakeConnectionwithConnectionopenConnectionopenConnectionSSL getHostnamereceiveResponse emptyBodyfileBodyinputStreamBody debugHandler concatHandlercloseConnection ContentTypeRequestBuilder buildRequesthttp setHeader setAccept setAccept'setAuthorizationBasicsetContentTypesetContentLengthsetExpectContinueURLmodifyContextSSLestablishConnectionbaselineContextSSLgetpostpostFormencodedFormBodyputconcatHandler'HttpParseExceptionWrapunWrapContentEncodingDeflateGzipIdentityTransferEncodingChunkedNone pStatusCode pStatusMsgpTransferEncodingpContentEncodingpContentLengthpHeaders ExpectModeContinueNormal EntityBodyStaticChunkingEmptyqMethodqHostqPathqBodyqExpectqHeaderscomposeRequestBytescrlfspcomposeResponseBytes joinHeaderscombine emptyHeaders updateHeader removeHeader buildHeaders addHeader lookupHeader$fExceptionHttpParseException $fShowHeaders$fShowResponse $fShowRequest $fEqMethod unsafeFromNatCSBadCRLastIsCRNoCR FoundCRLF parseRequestreadResponseLinefindCRLFsplitChbreakCh splitHeaderisLWSreadHeaderFieldsUnexpectedCompression __BITE_SIZE__readResponseHeaderparseStatusLinereadResponseBody readDecimalreadChunkedBody consumeChunksreadNtransferChunkSizereadFixedLengthBodyreadCompressedBody $fExceptionUnexpectedCompressioncHostcClosebaseControl.Exception.Basebracketio-streams-1.0.2.2System.IO.Streams.Internal InputStreamcOutcIncloseSSL$fShowConnection deleteHeader setEntityBody setExpectMode urlEncodeurlEncodeBuilderblaze-builder-0.3.1.1'Blaze.ByteString.Builder.Internal.TypesBuilderHsOpenSSL-0.10.3.3OpenSSL.Session SSLContext OutputStreamHttpClientErrorTooManyRedirectshexdurlEncodeTableglobal establishparseURLpathgetN wrapRedirect$fShowHttpClientError$fExceptionHttpClientError$fExceptionTooManyRedirects