diff --git a/p2p/http/example_test.go b/p2p/http/example_test.go index 3c96f12b58..8726388405 100644 --- a/p2p/http/example_test.go +++ b/p2p/http/example_test.go @@ -117,3 +117,205 @@ func ExampleHTTPHost_overLibp2pStreams() { // Output: Hello HTTP } + +func ExampleHTTPHost_Serve() { + server := libp2phttp.HTTPHost{ + ServeInsecureHTTP: true, // For our example, we'll allow insecure HTTP + ListenAddrs: []ma.Multiaddr{ma.StringCast("/ip4/127.0.0.1/tcp/50221/http")}, + } + + go server.Serve() + defer server.Close() + + fmt.Println(server.Addrs()) + + // Output: [/ip4/127.0.0.1/tcp/50221/http] +} + +func ExampleHTTPHost_SetHTTPHandler() { + server := libp2phttp.HTTPHost{ + ServeInsecureHTTP: true, // For our example, we'll allow insecure HTTP + ListenAddrs: []ma.Multiaddr{ma.StringCast("/ip4/127.0.0.1/tcp/50222/http")}, + } + + server.SetHTTPHandler("/hello/1", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.Header().Add("Content-Type", "text/plain") + w.Write([]byte("Hello World")) + })) + + go server.Serve() + defer server.Close() + + port, err := server.Addrs()[0].ValueForProtocol(ma.P_TCP) + if err != nil { + log.Fatal(err) + } + + resp, err := http.Get("http://127.0.0.1:" + port + "/hello/1/") + if err != nil { + log.Fatal(err) + } + defer resp.Body.Close() + respBody, err := io.ReadAll(resp.Body) + if err != nil { + log.Fatal(err) + } + + fmt.Println(string(respBody)) + + // Output: Hello World +} + +func ExampleHTTPHost_SetHTTPHandlerAtPath() { + server := libp2phttp.HTTPHost{ + ServeInsecureHTTP: true, // For our example, we'll allow insecure HTTP + ListenAddrs: []ma.Multiaddr{ma.StringCast("/ip4/127.0.0.1/tcp/50224/http")}, + } + + server.SetHTTPHandlerAtPath("/hello/1", "/other-place/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.Header().Add("Content-Type", "text/plain") + w.Write([]byte("Hello World")) + })) + + go server.Serve() + defer server.Close() + + port, err := server.Addrs()[0].ValueForProtocol(ma.P_TCP) + if err != nil { + log.Fatal(err) + } + + resp, err := http.Get("http://127.0.0.1:" + port + "/other-place/") + if err != nil { + log.Fatal(err) + } + defer resp.Body.Close() + respBody, err := io.ReadAll(resp.Body) + if err != nil { + log.Fatal(err) + } + + fmt.Println(string(respBody)) + + // Output: Hello World +} + +func ExampleHTTPHost_NamespacedClient() { + var client libp2phttp.HTTPHost + + // Create the server + server := libp2phttp.HTTPHost{ + ServeInsecureHTTP: true, // For our example, we'll allow insecure HTTP + ListenAddrs: []ma.Multiaddr{ma.StringCast("/ip4/127.0.0.1/tcp/50221/http")}, + } + + server.SetHTTPHandlerAtPath("/hello/1", "/other-place/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.Header().Add("Content-Type", "text/plain") + w.Write([]byte("Hello World")) + })) + + go server.Serve() + defer server.Close() + + // Create an http.Client that is namespaced to this protocol. + httpClient, err := client.NamespacedClient("/hello/1", peer.AddrInfo{ID: server.PeerID(), Addrs: server.Addrs()}) + if err != nil { + log.Fatal(err) + } + + resp, err := httpClient.Get("/") + if err != nil { + log.Fatal(err) + } + defer resp.Body.Close() + respBody, err := io.ReadAll(resp.Body) + if err != nil { + log.Fatal(err) + } + + fmt.Println(string(respBody)) + + // Output: Hello World +} + +func ExampleHTTPHost_NamespaceRoundTripper() { + var client libp2phttp.HTTPHost + + // Create the server + server := libp2phttp.HTTPHost{ + ServeInsecureHTTP: true, // For our example, we'll allow insecure HTTP + ListenAddrs: []ma.Multiaddr{ma.StringCast("/ip4/127.0.0.1/tcp/50223/http")}, + } + + server.SetHTTPHandler("/hello/1", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.Header().Add("Content-Type", "text/plain") + w.Write([]byte("Hello World")) + })) + + go server.Serve() + defer server.Close() + + // Create an http.Roundtripper for the server + rt, err := client.NewRoundTripper(peer.AddrInfo{ID: server.PeerID(), Addrs: server.Addrs()}) + if err != nil { + log.Fatal(err) + } + + // Namespace this roundtripper to a specific protocol + rt, err = client.NamespaceRoundTripper(rt, "/hello/1", server.PeerID()) + if err != nil { + log.Fatal(err) + } + + resp, err := (&http.Client{Transport: rt}).Get("/") + if err != nil { + log.Fatal(err) + } + defer resp.Body.Close() + respBody, err := io.ReadAll(resp.Body) + if err != nil { + log.Fatal(err) + } + + fmt.Println(string(respBody)) + + // Output: Hello World +} + +func ExampleHTTPHost_NewRoundTripper() { + var client libp2phttp.HTTPHost + + // Create the server + server := libp2phttp.HTTPHost{ + ServeInsecureHTTP: true, // For our example, we'll allow insecure HTTP + ListenAddrs: []ma.Multiaddr{ma.StringCast("/ip4/127.0.0.1/tcp/50225/http")}, + } + + server.SetHTTPHandler("/hello/1", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.Header().Add("Content-Type", "text/plain") + w.Write([]byte("Hello World")) + })) + + go server.Serve() + defer server.Close() + + // Create an http.Roundtripper for the server + rt, err := client.NewRoundTripper(peer.AddrInfo{ID: server.PeerID(), Addrs: server.Addrs()}) + if err != nil { + log.Fatal(err) + } + + resp, err := (&http.Client{Transport: rt}).Get("/hello/1") + if err != nil { + log.Fatal(err) + } + defer resp.Body.Close() + respBody, err := io.ReadAll(resp.Body) + if err != nil { + log.Fatal(err) + } + + fmt.Println(string(respBody)) + + // Output: Hello World +} diff --git a/p2p/http/libp2phttp.go b/p2p/http/libp2phttp.go index 944bea38e3..5cf592316a 100644 --- a/p2p/http/libp2phttp.go +++ b/p2p/http/libp2phttp.go @@ -480,15 +480,15 @@ func (rt *namespacedRoundTripper) RoundTrip(r *http.Request) (*http.Response, er } // NamespaceRoundTripper returns an http.RoundTripper that are scoped to the given protocol on the given server. -func (h *HTTPHost) NamespaceRoundTripper(roundtripper http.RoundTripper, p protocol.ID, server peer.ID) (namespacedRoundTripper, error) { +func (h *HTTPHost) NamespaceRoundTripper(roundtripper http.RoundTripper, p protocol.ID, server peer.ID) (*namespacedRoundTripper, error) { protos, err := h.getAndStorePeerMetadata(roundtripper, server) if err != nil { - return namespacedRoundTripper{}, err + return &namespacedRoundTripper{}, err } v, ok := protos[p] if !ok { - return namespacedRoundTripper{}, fmt.Errorf("no protocol %s for server %s", p, server) + return &namespacedRoundTripper{}, fmt.Errorf("no protocol %s for server %s", p, server) } path := v.Path @@ -499,10 +499,10 @@ func (h *HTTPHost) NamespaceRoundTripper(roundtripper http.RoundTripper, p proto u, err := url.Parse(path) if err != nil { - return namespacedRoundTripper{}, fmt.Errorf("invalid path %s for protocol %s for server %s", v.Path, p, server) + return &namespacedRoundTripper{}, fmt.Errorf("invalid path %s for protocol %s for server %s", v.Path, p, server) } - return namespacedRoundTripper{ + return &namespacedRoundTripper{ RoundTripper: roundtripper, protocolPrefix: u.Path, protocolPrefixRaw: u.RawPath, @@ -525,7 +525,7 @@ func (h *HTTPHost) NamespacedClient(p protocol.ID, server peer.AddrInfo, opts .. return http.Client{}, err } - return http.Client{Transport: &nrt}, nil + return http.Client{Transport: nrt}, nil } // NewRoundTripper returns an http.RoundTripper that can fulfill and HTTP diff --git a/p2p/http/libp2phttp_test.go b/p2p/http/libp2phttp_test.go index 6cf65da5f2..2e171c0acc 100644 --- a/p2p/http/libp2phttp_test.go +++ b/p2p/http/libp2phttp_test.go @@ -188,7 +188,7 @@ func TestRoundTrippers(t *testing.T) { require.NoError(t, err) nrt, err := h.NamespaceRoundTripper(rt, "/hello", serverHost.ID()) require.NoError(t, err) - client := &http.Client{Transport: &nrt} + client := &http.Client{Transport: nrt} resp, err = client.Get("/") require.NoError(t, err) } else {