Repository: libp2p/go-libp2p
Pull request #2595 (2023-10-06 08:43:27)

swarm: add loopback to low timeout filter
@sukunrt suggested lowering `swarm.WithDialTimeoutLocal` to prevent our [tests from timing out](https://github.com/plprobelab/zikade/issues/48) because of [blocking dials](https://github.com/libp2p/go-libp2p/issues/2589). In our tests, we connect via loopback addresses, and I noticed that the `swarm.WithDialTimeoutLocal` wasn't applied.

In this PR, I added the loopback CIDR to the list of CIDRs to which the local timeout applies. 

There are a few more ranges from http://www.iana.org/assignments/iana-ipv4-special-registry/iana-ipv4-special-registry.xhtml that aren't in that list. I'm not sure if there's a reason or if it was just forgotten. I'm happy to extend this PR to add the missing ones as well.

These are missing:

```csv
"/ip4/192.0.0.9/ipcidr/32"
"/ip4/192.0.0.10/ipcidr/32"
"/ip4/192.31.196.0/ipcidr/24"
"/ip4/192.52.193.0/ipcidr/24"
"/ip4/192.88.99.0/ipcidr/24"
"/ip4/192.175.48.0/ipcidr/24"
"/ip4/198.18.0.0/ipcidr/15"
```

dennis-tra: Changed to use `manet.IsPrivateAddr` 👍 


Patch:
diff --git a/examples/libp2p-host/README.md b/examples/libp2p-host/README.md
index e187f067..966ee0e1 100644
--- a/examples/libp2p-host/README.md
+++ b/examples/libp2p-host/README.md
@@ -84,7 +84,7 @@ defer h2.Close()
 fmt.Printf("Hello World, my second hosts ID is %s\n", h2.ID())
 ```
 
-And thats it, you have a libp2p host and you're ready to start doing some awesome p2p networking!
+And that's it, you have a libp2p host and you're ready to start doing some awesome p2p networking!
 
 In future guides we will go over ways to use hosts, configure them differently (hint: there are a huge number of ways to set these up), and interesting ways to apply this technology to various applications you might want to build.
 
diff --git a/p2p/http/libp2phttp.go b/p2p/http/libp2phttp.go
index d8158153..87f8f9a3 100644
--- a/p2p/http/libp2phttp.go
+++ b/p2p/http/libp2phttp.go
@@ -370,7 +370,9 @@ func (h *Host) SetHTTPHandlerAtPath(p protocol.ID, path string, handler http.Han
 	}
 	h.WellKnownHandler.AddProtocolMeta(p, ProtocolMeta{Path: path})
 	h.serveMuxInit()
-	h.ServeMux.Handle(path, http.StripPrefix(path, handler))
+	// Do not trim the trailing / from path
+	// This allows us to serve `/a/b` when we mount a handler for `/b` at path `/a`
+	h.ServeMux.Handle(path, http.StripPrefix(strings.TrimSuffix(path, "/"), handler))
 }
 
 // PeerMetadataGetter lets RoundTrippers implement a specific way of caching a peer's protocol mapping.
diff --git a/p2p/net/swarm/addrs.go b/p2p/net/swarm/addrs.go
deleted file mode 100644
index 392900e0..00000000
--- a/p2p/net/swarm/addrs.go
+++ /dev/null
@@ -1,39 +0,0 @@
-package swarm
-
-import (
-	ma "github.com/multiformats/go-multiaddr"
-	manet "github.com/multiformats/go-multiaddr/net"
-)
-
-// http://www.iana.org/assignments/iana-ipv4-special-registry/iana-ipv4-special-registry.xhtml
-var lowTimeoutFilters = ma.NewFilters()
-
-func init() {
-	for _, p := range []string{
-		"/ip4/10.0.0.0/ipcidr/8",
-		"/ip4/100.64.0.0/ipcidr/10",
-		"/ip4/169.254.0.0/ipcidr/16",
-		"/ip4/172.16.0.0/ipcidr/12",
-		"/ip4/192.0.0.0/ipcidr/24",
-		"/ip4/192.0.0.0/ipcidr/29",
-		"/ip4/192.0.0.8/ipcidr/32",
-		"/ip4/192.0.0.170/ipcidr/32",
-		"/ip4/192.0.0.171/ipcidr/32",
-		"/ip4/192.0.2.0/ipcidr/24",
-		"/ip4/192.168.0.0/ipcidr/16",
-		"/ip4/198.18.0.0/ipcidr/15",
-		"/ip4/198.51.100.0/ipcidr/24",
-		"/ip4/203.0.113.0/ipcidr/24",
-		"/ip4/240.0.0.0/ipcidr/4",
-	} {
-		f, err := ma.NewMultiaddr(p)
-		if err != nil {
-			panic("error in lowTimeoutFilters init: " + err.Error())
-		}
-		ipnet, err := manet.MultiaddrToIPNet(f)
-		if err != nil {
-			panic("error in lowTimeoutFilters init: " + err.Error())
-		}
-		lowTimeoutFilters.AddFilter(*ipnet, ma.ActionDeny)
-	}
-}
diff --git a/p2p/net/swarm/swarm_dial.go b/p2p/net/swarm/swarm_dial.go
index 761ab96c..3bf80091 100644
--- a/p2p/net/swarm/swarm_dial.go
+++ b/p2p/net/swarm/swarm_dial.go
@@ -507,7 +507,7 @@ func (s *Swarm) filterKnownUndialables(p peer.ID, addrs []ma.Multiaddr) (goodAdd
 // limiting that occur without using extra goroutines per addr
 func (s *Swarm) limitedDial(ctx context.Context, p peer.ID, a ma.Multiaddr, resp chan dialResult) {
 	timeout := s.dialTimeout
-	if lowTimeoutFilters.AddrBlocked(a) && s.dialTimeoutLocal < s.dialTimeout {
+	if manet.IsPrivateAddr(a) && s.dialTimeoutLocal < s.dialTimeout {
 		timeout = s.dialTimeoutLocal
 	}
 	s.limiter.AddDialJob(&dialJob{


Test patch:
diff --git a/docs/flaky-tests.md b/docs/flaky-tests.md
index e65800ac..667dd77a 100644
--- a/docs/flaky-tests.md
+++ b/docs/flaky-tests.md
@@ -28,7 +28,7 @@ processes are vying for CPU time.
   sudo cgset -r cpu.cfs_quota_us=10000 cpulimit
   sudo cgset -r cpu.cfs_period_us=1000000 cpulimit
 
-  # Run a shell with in our limited environemnt
+  # Run a shell with in our limited environment
   sudo cgexec -g cpu:cpulimit bash
 
   # In the shell, run the test
diff --git a/p2p/host/peerstore/test/peerstore_suite.go b/p2p/host/peerstore/test/peerstore_suite.go
index 576b8fd4..da8f6f4a 100644
--- a/p2p/host/peerstore/test/peerstore_suite.go
+++ b/p2p/host/peerstore/test/peerstore_suite.go
@@ -144,7 +144,7 @@ func testGetStreamBeforePeerAdded(ps pstore.Peerstore) func(t *testing.T) {
 				t.Fatal("channel shouldnt be closed yet")
 			}
 			if a == nil {
-				t.Fatal("got a nil address, thats weird")
+				t.Fatal("got a nil address, that's weird")
 			}
 			count++
 			if received[a.String()] {
@@ -195,7 +195,7 @@ func testAddrStreamDuplicates(ps pstore.Peerstore) func(t *testing.T) {
 		var count int
 		for a := range ach {
 			if a == nil {
-				t.Fatal("got a nil address, thats weird")
+				t.Fatal("got a nil address, that's weird")
 			}
 			count++
 			if received[a.String()] {
diff --git a/p2p/http/libp2phttp_test.go b/p2p/http/libp2phttp_test.go
index 8a95bed6..6e29fbd6 100644
--- a/p2p/http/libp2phttp_test.go
+++ b/p2p/http/libp2phttp_test.go
@@ -10,6 +10,7 @@ import (
 	"crypto/x509"
 	"crypto/x509/pkix"
 	"encoding/json"
+	"fmt"
 	"io"
 	"math/big"
 	"net"
@@ -419,3 +420,68 @@ func TestCustomServeMux(t *testing.T) {
 	require.NoError(t, err)
 	require.Equal(t, 200, resp.StatusCode)
 }
+
+func TestSetHandlerAtPath(t *testing.T) {
+	hf := func(w http.ResponseWriter, r *http.Request) {
+		w.Header().Add("Content-Type", "text/plain")
+		w.Write([]byte("Hello World"))
+	}
+	tests := []struct {
+		prefix, rest string
+		paths200     []string
+		paths404     []string
+	}{
+		{
+			prefix:   "/",
+			rest:     "/",
+			paths200: []string{"/", "/a/", "/b", "/a/b"},
+		},
+		{
+			prefix:   "/a",
+			rest:     "/b/",
+			paths200: []string{"/a/b/", "///a///b/", "/a/b/c"},
+			// Not being able to serve /a/b when handling /a/b/ is a rather annoying limitation
+			// of http.StripPrefix mechanism. This happens because /a/b is redirected to /b/
+			// as the prefix /a is stripped when the redirect happens
+			paths404: []string{"/a/b", "/a", "/b", "/a/a"},
+		},
+		{
+			prefix:   "/",
+			rest:     "/b/",
+			paths200: []string{"/b", "/b/c", "/b/c/"},
+			paths404: []string{"/", "/a/b"},
+		},
+	}
+	for i, tc := range tests {
+		t.Run(fmt.Sprintf("%d", i), func(t *testing.T) {
+			nestedMx := http.NewServeMux()
+			nestedMx.HandleFunc(tc.rest, hf)
+			server := libp2phttp.Host{
+				ListenAddrs:       []ma.Multiaddr{ma.StringCast("/ip4/127.0.0.1/tcp/0/http")},
+				InsecureAllowHTTP: true,
+			}
+			server.SetHTTPHandlerAtPath("test", tc.prefix, nestedMx)
+			go func() {
+				server.Serve()
+			}()
+			defer server.Close()
+			addrs := server.Addrs()
+			require.Equal(t, 1, len(addrs))
+			port, err := addrs[0].ValueForProtocol(ma.P_TCP)
+			require.NoError(t, err)
+			httpAddr := fmt.Sprintf("http://127.0.0.1:%s", port)
+			for _, p := range tc.paths200 {
+				resp, err := http.Get(httpAddr + p)
+				require.NoError(t, err)
+				require.Equal(t, 200, resp.StatusCode, "path:%s", p)
+				resp.Body.Close()
+			}
+			for _, p := range tc.paths404 {
+				resp, _ := http.Get(httpAddr + p)
+				require.Equal(t, 404, resp.StatusCode, "path:%s", p)
+				resp.Body.Close()
+			}
+		})
+	}
+
+}