Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to inspect the body of an outgoing HTTP request created with `http-client` (Haskell)

Tags:

http

haskell

I am using Haskell to send a POST HTTP request via the http-client package, but as a response i am getting an error from the remote server. I would like to inspect my request in order to be sure that i am sending the expected parameters in the body.

I managed to bind my request to a variable in the Haskell interpreter, but i can't figure out how to see its body. When i use requestBody on my request i get a value of type RequestBody, but it is not an instance of show.

In the library i can't find any helpful function. There are just many constructors, and some functions related to a Popper type.

How can i inspect that value? This seems a common use case to me, yet the library doesn't seem to support it. Am i using it wrong?

Edit:

I know what Wireshark is and how to use it, but i expect to be able to programmatically inspect what i am sending

like image 484
danza Avatar asked Apr 03 '16 22:04

danza


1 Answers

RequestBody has five constructors.

data RequestBody
    = RequestBodyLBS L.ByteString
    | RequestBodyBS S.ByteString
    | RequestBodyBuilder Int64 Builder
    | RequestBodyStream Int64 (GivesPopper ())
    | RequestBodyStreamChunked (GivesPopper ())

First two are wrappers of bytestring, the third is a Blaze.ByteString.Builder which can be easily converted to bytestring, the last two are functions of type (IO ByteString -> IO a) -> IO a as the type synonym showed:

type Popper = IO S.ByteString
type NeedsPopper a = Popper -> IO a
type GivesPopper a = NeedsPopper a -> IO a

feed them >>= print multiple times and you will get the complete request body printed to console.

You should not do this because these GivesPopper () generators can only be executed once: if you extract the content beforehand then the request body will not be sent to the server. That's why they didn't provide a Show instance for RequestBody data type. You'd better capture the buckets containing your http request with e.g. Wireshark.


I have a data structure in my code and i don't see why i shouldn't be able to inspect it. You mention that inspecting the request might somehow consume it. This is weird in a language like Haskell where immutability and explicit side effects are the rule

That's right for most of the types in Haskell, but Popper is actually IO S.ByteString, a bytestring stream (usually) populated by a file handler, while handler in Haskell is an MVar which is not so different from variables in imperative languages: it may be a value or null, may be assigned and reassigned and the side effect is visible globally.

An example from Network.HTTP.Client.MultipartFormData:

streamFile :: FilePath -> GivesPopper ()
streamFile fp np =
    withFile fp ReadMode $ np . go
  where
    -- go :: Handle -> Popper 
    go h = BS.hGetSome h defaultChunkSize
like image 68
zakyggaps Avatar answered Nov 15 '22 04:11

zakyggaps