Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use go-libp2p-http #4

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
92 changes: 14 additions & 78 deletions core/corehttp/proxy.go
Original file line number Diff line number Diff line change
@@ -1,19 +1,17 @@
package corehttp

import (
"bufio"
"fmt"
"io"
"net"
"net/http"
"net/http/httputil"
"net/url"
"strings"

core "github.com/ipfs/go-ipfs/core"

p2phttp "gx/ipfs/QmWmzdApcPtLYzdCsp7ZYuSwaa3rjPXv9KoaYMkvS3Hnas/go-libp2p-http"
protocol "gx/ipfs/QmZNkThpqfVXs9GNbexPrfBbXSLNYeKrE7jwFM2oqHbyqN/go-libp2p-protocol"
peer "gx/ipfs/QmbNepETomvmXfz1X5pHNFD2QuPqnqi47dTd94QJWSorQ3/go-libp2p-peer"
inet "gx/ipfs/QmfDPh144WGBqRxZb1TGDHerbMnZATrHZggAPw7putNnBq/go-libp2p-net"
)

// ProxyOption is an endpoint for proxying a HTTP request to another ipfs peer
Expand All @@ -27,23 +25,26 @@ func ProxyOption() ServeOption {
return
}

// open connect to peer
stream, err := ipfsNode.P2P.PeerHost.NewStream(request.Context(), parsedRequest.target, protocol.ID("/x/"+parsedRequest.name))
request.Host = "" // Let URL's Host take precedence.
request.URL.Path = parsedRequest.httpPath
target, err := url.Parse(fmt.Sprintf("libp2p://%s", parsedRequest.target))
if err != nil {
msg := fmt.Sprintf("Failed to open stream '%v' to target peer '%v'", parsedRequest.name, parsedRequest.target)
handleError(w, msg, err, 500)
handleError(w, "Failed to parse url", err, 400)
return
}
//send proxy request and response to client
newReverseHTTPProxy(parsedRequest, stream).ServeHTTP(w, request)

rt := p2phttp.NewTransport(ipfsNode.P2P.PeerHost, p2phttp.ProtocolOption(parsedRequest.name))
proxy := httputil.NewSingleHostReverseProxy(target)
proxy.Transport = rt
proxy.ServeHTTP(w, request)
})
return mux, nil
}
}

type proxyRequest struct {
target peer.ID
name string
target string
name protocol.ID
httpPath string // path to send to the proxy-host
}

Expand All @@ -57,76 +58,11 @@ func parseRequest(request *http.Request) (*proxyRequest, error) {
return nil, fmt.Errorf("Invalid request path '%s'", path)
}

peerID, err := peer.IDB58Decode(split[3])

if err != nil {
return nil, err
}

return &proxyRequest{peerID, split[4], "/" + split[5]}, nil
return &proxyRequest{split[3], protocol.ID(split[4]), split[5]}, nil
}

func handleError(w http.ResponseWriter, msg string, err error, code int) {
w.WriteHeader(code)
fmt.Fprintf(w, "%s: %s\n", msg, err)
log.Warningf("server error: %s: %s", err)
}

func newReverseHTTPProxy(req *proxyRequest, streamToPeer inet.Stream) *httputil.ReverseProxy {
director := func(r *http.Request) {
r.URL.Path = req.httpPath //the scheme etc. doesn't matter
}

return &httputil.ReverseProxy{
Director: director,
Transport: &roundTripper{streamToPeer}}
}

type roundTripper struct {
stream inet.Stream
}

// we wrap the response body and close the stream
// only when it's closed.
type respBody struct {
io.ReadCloser
stream inet.Stream
}

// Closes the response's body and the connection.
func (rb *respBody) Close() error {
if err := rb.stream.Close(); err != nil {
rb.stream.Reset()
} else {
go inet.AwaitEOF(rb.stream)
}
return rb.ReadCloser.Close()
}

func (rt *roundTripper) RoundTrip(req *http.Request) (*http.Response, error) {

sendRequest := func() {
err := req.Write(rt.stream)
if err != nil {
rt.stream.Close()
}
if req.Body != nil {
req.Body.Close()
}
}
//send request while reading response
go sendRequest()
s := bufio.NewReader(rt.stream)

resp, err := http.ReadResponse(s, req)
if err != nil {
return resp, err
}

resp.Body = &respBody{
ReadCloser: resp.Body,
stream: rt.stream,
}

return resp, nil
}
7 changes: 4 additions & 3 deletions core/corehttp/proxy_test.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
package corehttp

import (
"github.com/ipfs/go-ipfs/thirdparty/assert"
"net/http"
"strings"
"testing"

"github.com/ipfs/go-ipfs/thirdparty/assert"
)

func TestParseRequest(t *testing.T) {
Expand All @@ -15,9 +16,9 @@ func TestParseRequest(t *testing.T) {
if err != nil {
t.Error(err)
}
assert.True(parsed.httpPath == "path/to/index.txt", t, "proxy request path")
assert.True(parsed.httpPath == "/path/to/index.txt", t, "proxy request path")
assert.True(parsed.name == "test-name", t, "proxy request name")
assert.True(parsed.target.Pretty() == "QmT8JtU54XSmC38xSb1XHFSMm775VuTeajg7LWWWTAwzxT", t, "proxy request peer-id")
assert.True(parsed.target == "QmT8JtU54XSmC38xSb1XHFSMm775VuTeajg7LWWWTAwzxT", t, "proxy request peer-id")
}

func TestParseRequestInvalidPath(t *testing.T) {
Expand Down
6 changes: 6 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -574,6 +574,12 @@
"hash": "QmbyJLe6SdVR5VLjtcoLdKhUuV4RT9a1FxX28zaWnY34d8",
"name": "go-random-files",
"version": "1.0.0"
},
{
"author": "hsanjuan",
"hash": "QmWmzdApcPtLYzdCsp7ZYuSwaa3rjPXv9KoaYMkvS3Hnas",
"name": "go-libp2p-http",
"version": "1.1.3"
}
],
"gxVersion": "0.10.0",
Expand Down