Browse Source

etcdserver/etcdhttp: treat /v2/admin/members and /v2/admin/members/ equally

Jonathan Boulle 11 years ago
parent
commit
387639e802
2 changed files with 30 additions and 3 deletions
  1. 12 3
      etcdserver/etcdhttp/client.go
  2. 18 0
      etcdserver/etcdhttp/client_test.go

+ 12 - 3
etcdserver/etcdhttp/client.go

@@ -43,7 +43,7 @@ import (
 const (
 const (
 	keysPrefix               = "/v2/keys"
 	keysPrefix               = "/v2/keys"
 	deprecatedMachinesPrefix = "/v2/machines"
 	deprecatedMachinesPrefix = "/v2/machines"
-	adminMembersPrefix       = "/v2/admin/members/"
+	adminMembersPrefix       = "/v2/admin/members"
 	statsPrefix              = "/v2/stats"
 	statsPrefix              = "/v2/stats"
 	versionPrefix            = "/version"
 	versionPrefix            = "/version"
 )
 )
@@ -80,6 +80,7 @@ func NewClientHandler(server *etcdserver.EtcdServer) http.Handler {
 	mux.HandleFunc(statsPrefix+"/self", sh.serveSelf)
 	mux.HandleFunc(statsPrefix+"/self", sh.serveSelf)
 	mux.HandleFunc(statsPrefix+"/leader", sh.serveLeader)
 	mux.HandleFunc(statsPrefix+"/leader", sh.serveLeader)
 	mux.Handle(adminMembersPrefix, amh)
 	mux.Handle(adminMembersPrefix, amh)
+	mux.Handle(adminMembersPrefix+"/", amh)
 	mux.Handle(deprecatedMachinesPrefix, dmh)
 	mux.Handle(deprecatedMachinesPrefix, dmh)
 	return mux
 	return mux
 }
 }
@@ -159,7 +160,7 @@ func (h *adminMembersHandler) ServeHTTP(w http.ResponseWriter, r *http.Request)
 
 
 	switch r.Method {
 	switch r.Method {
 	case "GET":
 	case "GET":
-		if s := strings.TrimPrefix(r.URL.Path, adminMembersPrefix); s != "" {
+		if trimPrefix(r.URL.Path, adminMembersPrefix) != "" {
 			http.NotFound(w, r)
 			http.NotFound(w, r)
 			return
 			return
 		}
 		}
@@ -203,7 +204,7 @@ func (h *adminMembersHandler) ServeHTTP(w http.ResponseWriter, r *http.Request)
 			log.Printf("etcdhttp: %v", err)
 			log.Printf("etcdhttp: %v", err)
 		}
 		}
 	case "DELETE":
 	case "DELETE":
-		idStr := strings.TrimPrefix(r.URL.Path, adminMembersPrefix)
+		idStr := trimPrefix(r.URL.Path, adminMembersPrefix)
 		id, err := strconv.ParseUint(idStr, 16, 64)
 		id, err := strconv.ParseUint(idStr, 16, 64)
 		if err != nil {
 		if err != nil {
 			http.Error(w, err.Error(), http.StatusBadRequest)
 			http.Error(w, err.Error(), http.StatusBadRequest)
@@ -516,6 +517,14 @@ func getBool(form url.Values, key string) (b bool, err error) {
 	return
 	return
 }
 }
 
 
+// trimPrefix removes a given prefix and any slash following the prefix
+// e.g.: trimPrefix("foo", "foo") == trimPrefix("foo/", "foo") == ""
+func trimPrefix(p, prefix string) (s string) {
+	s = strings.TrimPrefix(p, prefix)
+	s = strings.TrimPrefix(s, "/")
+	return
+}
+
 func newMemberCollection(ms []*etcdserver.Member) httptypes.MemberCollection {
 func newMemberCollection(ms []*etcdserver.Member) httptypes.MemberCollection {
 	c := httptypes.MemberCollection(make([]httptypes.Member, len(ms)))
 	c := httptypes.MemberCollection(make([]httptypes.Member, len(ms)))
 
 

+ 18 - 0
etcdserver/etcdhttp/client_test.go

@@ -574,6 +574,7 @@ func TestServeAdminMembers(t *testing.T) {
 		wbody string
 		wbody string
 	}{
 	}{
 		{adminMembersPrefix, http.StatusOK, "application/json", wmc},
 		{adminMembersPrefix, http.StatusOK, "application/json", wmc},
+		{adminMembersPrefix + "/", http.StatusOK, "application/json", wmc},
 		{path.Join(adminMembersPrefix, "100"), http.StatusNotFound, "text/plain; charset=utf-8", "404 page not found\n"},
 		{path.Join(adminMembersPrefix, "100"), http.StatusNotFound, "text/plain; charset=utf-8", "404 page not found\n"},
 		{path.Join(adminMembersPrefix, "foobar"), http.StatusNotFound, "text/plain; charset=utf-8", "404 page not found\n"},
 		{path.Join(adminMembersPrefix, "foobar"), http.StatusNotFound, "text/plain; charset=utf-8", "404 page not found\n"},
 	}
 	}
@@ -1540,3 +1541,20 @@ func TestTrimNodeExternPrefix(t *testing.T) {
 		}
 		}
 	}
 	}
 }
 }
+
+func TestTrimPrefix(t *testing.T) {
+	tests := []struct {
+		in     string
+		prefix string
+		w      string
+	}{
+		{"/v2/admin/members", "/v2/admin/members", ""},
+		{"/v2/admin/members/", "/v2/admin/members", ""},
+		{"/v2/admin/members/foo", "/v2/admin/members", "foo"},
+	}
+	for i, tt := range tests {
+		if g := trimPrefix(tt.in, tt.prefix); g != tt.w {
+			t.Errorf("#%d: trimPrefix = %q, want %q", i, g, tt.w)
+		}
+	}
+}