http-client icon indicating copy to clipboard operation
http-client copied to clipboard

Support middleware for http-client requests / responses?

Open iand675 opened this issue 10 years ago • 6 comments

I'm interested in building something similar to VCR for http-client. Would you be open to exposing a way to hook into the manager's requests and responses so that way apps that use http-client can transparently make use of something like this?

iand675 avatar Oct 14 '15 21:10 iand675

I think that's already possible by modifying managerRawConnection and managerTlsConnection. Have you tried playing with that?

On Thu, Oct 15, 2015, 12:05 AM Ian Duncan [email protected] wrote:

I'm interested in building something similar to VCR https://relishapp.com/vcr/vcr/docs for http-client. Would you be open to exposing a way to hook into the manager's requests and responses so that way apps that use http-client can transparently make use of something like this?

— Reply to this email directly or view it on GitHub https://github.com/snoyberg/http-client/issues/163.

snoyberg avatar Oct 15 '15 03:10 snoyberg

I am also interested in something like this. As far as I can tell, managerRawConnection is only called once per host. So if you get http://httpbin.org/get, it will be called. But if you get that same URL again, it won't be called.

I would love to have something like managerModifyRequest that took a Request and returned an IO (Response a). That would make adding client middleware a piece of cake.

I'm not familiar with http-client's internals, so maybe I missed something with managerRawConnection.

tfausak avatar Apr 03 '16 15:04 tfausak

I'd like this too - I need to sign requests which involves reading the value of Content-Length. At the moment I'm manually setting this before signing so that I know the value, but it would be nice to be able to hook in somewhere after the automatic headers have been set.

Porges avatar Mar 08 '18 23:03 Porges

I'd also like this! Our usecase is that we want to execute some IO after establishing any TLS connection, but not if the connection was already established and is lying around in the pool. Is anyone aware of any workarounds?

neongreen avatar Jun 26 '18 09:06 neongreen

Is anyone aware of any workarounds?

P.S. For now we'll just hack something crude:

The current idea for the workaround is to fork http-client and make withConnection tell us whether a connection is fresh or not.

neongreen avatar Jun 26 '18 09:06 neongreen

So I've done a bunch of horrible stuff here: https://github.com/snoyberg/http-client/compare/master...neongreen:connection-guts. There are three changes:

  • I added a version of withConnection that exposes the Managed Connection and therefore I can see whether the connection has been used before or not.

  • I added a way to override the Connection used by a particular Request.

  • I can now get the underlying socket/transport/whatever for a particular Connection and do something socket-specific with it.

It fits our usecase (doing something socket-specific after establishing a connection), but it doesn't allow setting hooks and I don't think it's good enough to go into http-client proper. Anyway, perhaps someone else who stumbles upon this issue will find it useful -- which is why I feel comfortable spamming people here :slightly_smiling_face:

(I also secretly hope that someone will find all of this horrible enough to propose a better solution.)

Sample usage:

withConnection' req man Reuse $ \mConn -> do
    -- If we see this connection for the first time, verify fingerprints
    let conn = managedResource mConn
    case (managedReused mConn, fromDynamic @SSL (connectionRaw conn)) of
        (True, _) -> pure ()
        (_, Nothing) -> error "I really expected a TLS connection"
        (_, Just ssl) -> verifyFingerprints ssl
    -- Make a request using this connection and return it back to the pool
    httpLbs req{connectionOverride=mConn} man

neongreen avatar Jun 26 '18 15:06 neongreen