From 26f99575fc517294456d0f920fb2a2ef97c3c72d Mon Sep 17 00:00:00 2001 From: Hector Sanjuan Date: Fri, 17 Aug 2018 19:08:08 +0200 Subject: [PATCH 1/2] Support streaming HTTP requests. Currently, our round-tripper assumed that requests and response's bodies were fully read within the function. It closed the stream (connection) as soon as it returned. This caused streaming requests to fail, as it managed to close the connection before the response body was fully read. This commit closes the connection only after the response's body is read by the user. It also writes the request in a separate go-routine, so that it does not have to be fully written to start reading the response. --- p2phttp.go | 46 +++++++++++++++++++++++++++++++++++++--------- 1 file changed, 37 insertions(+), 9 deletions(-) diff --git a/p2phttp.go b/p2phttp.go index 5c5bf4c..1b44353 100644 --- a/p2phttp.go +++ b/p2phttp.go @@ -47,6 +47,8 @@ package p2phttp import ( "bufio" + "io" + "net" "net/http" gostream "github.com/hsanjuan/go-libp2p-gostream" @@ -65,13 +67,22 @@ type RoundTripper struct { h host.Host } +// we wrap the response body and close the stream +// only when it's closed. +type respBody struct { + io.ReadCloser + conn net.Conn +} + +// Closes the response's body and the connection. +func (rb *respBody) Close() error { + rb.conn.Close() + return rb.ReadCloser.Close() +} + // RoundTrip executes a single HTTP transaction, returning // a Response for the provided Request. func (rt *RoundTripper) RoundTrip(r *http.Request) (*http.Response, error) { - if r.Body != nil { - defer r.Body.Close() - } - addr := r.Host if addr == "" { addr = r.URL.Host @@ -84,17 +95,34 @@ func (rt *RoundTripper) RoundTrip(r *http.Request) (*http.Response, error) { conn, err := gostream.Dial(rt.h, peer.ID(pid), P2PProtocol) if err != nil { + if r.Body != nil { + r.Body.Close() + } return nil, err } - defer conn.Close() - err = r.Write(conn) + // Write the request while reading the response + go func() { + err := r.Write(conn) + if err != nil { + conn.Close() + } + if r.Body != nil { + r.Body.Close() + } + }() + + resp, err := http.ReadResponse(bufio.NewReader(conn), r) if err != nil { - return nil, err + return resp, err + } + + resp.Body = &respBody{ + ReadCloser: resp.Body, + conn: conn, } - reader := bufio.NewReader(conn) - return http.ReadResponse(reader, r) + return resp, nil } // NewTransport returns a new RoundTripper which uses the provided From cc104ab25de065a7f87bbe577816c720521d91bb Mon Sep 17 00:00:00 2001 From: Hector Sanjuan Date: Fri, 17 Aug 2018 19:11:12 +0200 Subject: [PATCH 2/2] gx publish 1.1.0 --- .gx/lastpubver | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.gx/lastpubver b/.gx/lastpubver index 0cc995e..2123257 100644 --- a/.gx/lastpubver +++ b/.gx/lastpubver @@ -1 +1 @@ -1.0.8: QmSMWoH8wKuViGUe2ZDr3kDijbzkk81nY71zV1ApibFLxF +1.1.0: QmeyKL7WDSPhnhozCB3oC51j5pDs7DnCGWPyVaxgwpncA6 diff --git a/package.json b/package.json index da74c14..e9f76ea 100644 --- a/package.json +++ b/package.json @@ -25,6 +25,6 @@ "license": "MIT", "name": "go-libp2p-http", "releaseCmd": "git commit -a -m \"gx publish $VERSION\"", - "version": "1.0.8" + "version": "1.1.0" }