master
go 118 lines 4.15 KB
Raw
1 package cli
2
3 import (
4 "context"
5 "encoding/json"
6 "fmt"
7 "io"
8 "net/http"
9 "testing"
10
11 "github.com/ipfs/go-cid"
12 "github.com/ipfs/kubo/core/commands"
13 "github.com/ipfs/kubo/test/cli/harness"
14 "github.com/libp2p/go-libp2p"
15 "github.com/libp2p/go-libp2p/core/peer"
16 libp2phttp "github.com/libp2p/go-libp2p/p2p/http"
17 "github.com/multiformats/go-multiaddr"
18 manet "github.com/multiformats/go-multiaddr/net"
19 "github.com/stretchr/testify/require"
20 )
21
22 func TestGatewayOverLibp2p(t *testing.T) {
23 t.Parallel()
24 nodes := harness.NewT(t).NewNodes(2).Init()
25
26 // Setup streaming functionality
27 nodes.ForEachPar(func(node *harness.Node) {
28 node.IPFS("config", "--json", "Experimental.Libp2pStreamMounting", "true")
29 })
30
31 gwNode := nodes[0]
32 p2pProxyNode := nodes[1]
33
34 nodes.StartDaemons().Connect()
35 defer nodes.StopDaemons()
36
37 // Add data to the gateway node
38 cidDataOnGatewayNode := cid.MustParse(gwNode.IPFSAddStr("Hello Worlds2!"))
39 r := gwNode.GatewayClient().Get(fmt.Sprintf("/ipfs/%s?format=raw", cidDataOnGatewayNode))
40 blockDataOnGatewayNode := []byte(r.Body)
41
42 // Add data to the non-gateway node
43 cidDataNotOnGatewayNode := cid.MustParse(p2pProxyNode.IPFSAddStr("Hello Worlds!"))
44 r = p2pProxyNode.GatewayClient().Get(fmt.Sprintf("/ipfs/%s?format=raw", cidDataNotOnGatewayNode))
45 blockDataNotOnGatewayNode := []byte(r.Body)
46 _ = blockDataNotOnGatewayNode
47
48 // Setup one of the nodes as http to http-over-libp2p proxy
49 p2pProxyNode.IPFS("p2p", "forward", "--allow-custom-protocol", "/http/1.1", "/ip4/127.0.0.1/tcp/0", fmt.Sprintf("/p2p/%s", gwNode.PeerID()))
50 lsOutput := commands.P2PLsOutput{}
51 if err := json.Unmarshal(p2pProxyNode.IPFS("p2p", "ls", "--enc=json").Stdout.Bytes(), &lsOutput); err != nil {
52 t.Fatal(err)
53 }
54 require.Len(t, lsOutput.Listeners, 1)
55 p2pProxyNodeHTTPListenMA, err := multiaddr.NewMultiaddr(lsOutput.Listeners[0].ListenAddress)
56 require.NoError(t, err)
57
58 p2pProxyNodeHTTPListenAddr, err := manet.ToNetAddr(p2pProxyNodeHTTPListenMA)
59 require.NoError(t, err)
60
61 t.Run("DoesNotWorkWithoutExperimentalConfig", func(t *testing.T) {
62 _, err := http.Get(fmt.Sprintf("http://%s/ipfs/%s?format=raw", p2pProxyNodeHTTPListenAddr, cidDataOnGatewayNode))
63 require.Error(t, err)
64 })
65
66 // Enable the experimental feature and reconnect the nodes
67 gwNode.IPFS("config", "--json", "Experimental.GatewayOverLibp2p", "true")
68 gwNode.StopDaemon().StartDaemon()
69 t.Cleanup(func() { gwNode.StopDaemon() })
70 nodes.Connect()
71
72 // Note: the bare HTTP requests here assume that the gateway is mounted at `/`
73 t.Run("WillNotServeRemoteContent", func(t *testing.T) {
74 resp, err := http.Get(fmt.Sprintf("http://%s/ipfs/%s?format=raw", p2pProxyNodeHTTPListenAddr, cidDataNotOnGatewayNode))
75 require.NoError(t, err)
76 require.Equal(t, http.StatusNotFound, resp.StatusCode)
77 })
78
79 t.Run("WillNotServeDeserializedResponses", func(t *testing.T) {
80 resp, err := http.Get(fmt.Sprintf("http://%s/ipfs/%s", p2pProxyNodeHTTPListenAddr, cidDataOnGatewayNode))
81 require.NoError(t, err)
82 require.Equal(t, http.StatusNotAcceptable, resp.StatusCode)
83 })
84
85 t.Run("ServeBlock", func(t *testing.T) {
86 t.Run("UsingKuboProxy", func(t *testing.T) {
87 resp, err := http.Get(fmt.Sprintf("http://%s/ipfs/%s?format=raw", p2pProxyNodeHTTPListenAddr, cidDataOnGatewayNode))
88 require.NoError(t, err)
89 defer resp.Body.Close()
90 require.Equal(t, 200, resp.StatusCode)
91 body, err := io.ReadAll(resp.Body)
92 require.NoError(t, err)
93 require.Equal(t, blockDataOnGatewayNode, body)
94 })
95 t.Run("UsingLibp2pClientWithPathDiscovery", func(t *testing.T) {
96 clientHost, err := libp2p.New(libp2p.NoListenAddrs)
97 require.NoError(t, err)
98 err = clientHost.Connect(context.Background(), peer.AddrInfo{
99 ID: gwNode.PeerID(),
100 Addrs: gwNode.SwarmAddrs(),
101 })
102 require.NoError(t, err)
103
104 client, err := (&libp2phttp.Host{StreamHost: clientHost}).NamespacedClient("/ipfs/gateway", peer.AddrInfo{ID: gwNode.PeerID()})
105 require.NoError(t, err)
106
107 resp, err := client.Get(fmt.Sprintf("/ipfs/%s?format=raw", cidDataOnGatewayNode))
108 require.NoError(t, err)
109 defer resp.Body.Close()
110 require.Equal(t, 200, resp.StatusCode)
111
112 body, err := io.ReadAll(resp.Body)
113 require.NoError(t, err)
114
115 require.Equal(t, blockDataOnGatewayNode, body)
116 })
117 })
118 }