Skip to content

Commit

Permalink
libp2phttp: don't strip / suffix when mounting handler (#2552)
Browse files Browse the repository at this point in the history
  • Loading branch information
sukunrt committed Oct 18, 2023
1 parent 38f7beb commit 1055b76
Show file tree
Hide file tree
Showing 2 changed files with 69 additions and 1 deletion.
4 changes: 3 additions & 1 deletion p2p/http/libp2phttp.go
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
66 changes: 66 additions & 0 deletions p2p/http/libp2phttp_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"crypto/x509"
"crypto/x509/pkix"
"encoding/json"
"fmt"
"io"
"math/big"
"net"
Expand Down Expand Up @@ -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()
}
})
}

}

0 comments on commit 1055b76

Please sign in to comment.